blob: b603f070dd4e812102ad5cb58ebb4b0d589e15b1 [file] [log] [blame]
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001/*==============================================================================
Laurence Lundbladed92a6162018-11-01 11:38:35 +07002 Copyright (c) 2016-2018, The Linux Foundation.
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003 Copyright (c) 2018-2024, Laurence Lundblade.
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02004 Copyright (c) 2021, Arm Limited.
Laurence Lundbladed92a6162018-11-01 11:38:35 +07005 All rights reserved.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08006
Laurence Lundblade0dbc9172018-11-01 14:17:21 +07007Redistribution and use in source and binary forms, with or without
8modification, are permitted provided that the following conditions are
9met:
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above
13 copyright notice, this list of conditions and the following
14 disclaimer in the documentation and/or other materials provided
15 with the distribution.
16 * Neither the name of The Linux Foundation nor the names of its
17 contributors, nor the name "Laurence Lundblade" may be used to
18 endorse or promote products derived from this software without
19 specific prior written permission.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080020
Laurence Lundblade0dbc9172018-11-01 14:17:21 +070021THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
22WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
24ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
25BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
30OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Laurence Lundbladeee851742020-01-08 08:37:05 -080032 =============================================================================*/
Laurence Lundblade624405d2018-09-18 20:10:47 -070033
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080034
Laurence Lundblade844bb5c2020-03-01 17:27:25 -080035#include "qcbor/qcbor_decode.h"
Laurence Lundblade67257dc2020-07-27 03:33:37 -070036#include "qcbor/qcbor_spiffy_decode.h"
Laurence Lundblade3f1318a2021-01-04 18:26:44 -080037#include "ieee754.h" /* Does not use math.h */
Laurence Lundbladec7114722020-08-13 05:11:40 -070038
39#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade3f1318a2021-01-04 18:26:44 -080040
41#include <math.h> /* For isnan(), llround(), llroudf(), round(), roundf(),
42 * pow(), exp2()
43 */
44#include <fenv.h> /* feclearexcept(), fetestexcept() */
45
Laurence Lundbladee2c893c2020-12-26 17:41:53 -080046#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070047
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070048
Laurence Lundblade68cb61c2023-02-12 13:21:44 -080049#if (defined(__GNUC__) && !defined(__clang__))
Laurence Lundblade8e36f812024-01-26 10:59:29 -070050/*
Laurence Lundblade68cb61c2023-02-12 13:21:44 -080051 * This is how the -Wmaybe-uninitialized compiler warning is
52 * handled. It can’t be ignored because some version of gcc enable it
53 * with -Wall which is a common and useful gcc warning option. It also
54 * can’t be ignored because it is the goal of QCBOR to compile clean
55 * out of the box in all environments.
56 *
57 * The big problem with -Wmaybe-uninitialized is that it generates
58 * false positives. It complains things are uninitialized when they
59 * are not. This is because it is not a thorough static analyzer. This
60 * is why “maybe” is in its name. The problem is it is just not
61 * thorough enough to understand all the code (and someone saw fit to
62 * put it in gcc and worse to enable it with -Wall).
63 *
64 * One solution would be to change the code so -Wmaybe-uninitialized
65 * doesn’t get confused, for example adding an unnecessary extra
66 * initialization to zero. (If variables were truly uninitialized, the
67 * correct path is to understand the code thoroughly and set them to
68 * the correct value at the correct time; in essence this is already
69 * done; -Wmaybe-uninitialized just can’t tell). This path is not
70 * taken because it makes the code bigger and is kind of the tail
71 * wagging the dog.
72 *
73 * The solution here is to just use a pragma to disable it for the
74 * whole file. Disabling it for each line makes the code fairly ugly
75 * requiring #pragma to push, pop and ignore. Another reason is the
76 * warnings issues vary by version of gcc and which optimization
77 * optimizations are selected. Another reason is that compilers other
78 * than gcc don’t have -Wmaybe-uninitialized.
79 *
80 * One may ask how to be sure these warnings are false positives and
81 * not real issues. 1) The code has been read carefully to check. 2)
82 * Testing is pretty thorough. 3) This code has been run through
83 * thorough high-quality static analyzers.
84 *
85 * In particularly, most of the warnings are about
86 * Item.Item->uDataType being uninitialized. QCBORDecode_GetNext()
87 * *always* sets this value and test case confirm
88 * this. -Wmaybe-uninitialized just can't tell.
89 *
90 * https://stackoverflow.com/questions/5080848/disable-gcc-may-be-used-uninitialized-on-a-particular-variable
91 */
92#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
Laurence Lundblade8e36f812024-01-26 10:59:29 -070093#endif
Laurence Lundblade68cb61c2023-02-12 13:21:44 -080094
95
96
Laurence Lundblade3f1318a2021-01-04 18:26:44 -080097
Laurence Lundbladea9489f82020-09-12 13:50:56 -070098#define SIZEOF_C_ARRAY(array,type) (sizeof(array)/sizeof(type))
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070099
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700100
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800101
102
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700103static bool
104QCBORItem_IsMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700105{
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700106 const uint8_t uDataType = Item.uDataType;
Laurence Lundblade02625d42020-06-25 14:41:41 -0700107 return uDataType == QCBOR_TYPE_MAP ||
Laurence Lundblade62cae932024-06-03 13:16:17 -0700108#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
109 uDataType == QCBOR_TYPE_MAP_AS_ARRAY ||
Laurence Lundblade78a66132024-06-06 12:19:59 -0700110#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade62cae932024-06-03 13:16:17 -0700111 uDataType == QCBOR_TYPE_ARRAY;
Laurence Lundblade02625d42020-06-25 14:41:41 -0700112}
113
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700114static bool
115QCBORItem_IsEmptyDefiniteLengthMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700116{
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700117 if(!QCBORItem_IsMapOrArray(Item)){
Laurence Lundblade02625d42020-06-25 14:41:41 -0700118 return false;
119 }
120
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700121 if(Item.val.uCount != 0) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700122 return false;
123 }
124 return true;
125}
126
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700127static bool
128QCBORItem_IsIndefiniteLengthMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700129{
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800130#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700131 if(!QCBORItem_IsMapOrArray(Item)){
Laurence Lundblade02625d42020-06-25 14:41:41 -0700132 return false;
133 }
134
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700135 if(Item.val.uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700136 return false;
137 }
138 return true;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800139#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700140 (void)Item;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800141 return false;
142#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700143}
144
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700145/* Return true if the labels in Item1 and Item2 are the same.
146 Works only for integer and string labels. Returns false
147 for any other type. */
148static bool
149QCBORItem_MatchLabel(const QCBORItem Item1, const QCBORItem Item2)
150{
151 if(Item1.uLabelType == QCBOR_TYPE_INT64) {
152 if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
153 return true;
154 }
Laurence Lundblade78a66132024-06-06 12:19:59 -0700155#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700156 } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
157 if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
158 return true;
159 }
160 } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
161 if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
162 return true;
163 }
164 } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
165 if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
166 return true;
167 }
Laurence Lundblade78a66132024-06-06 12:19:59 -0700168#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700169 }
170
171 /* Other label types are never matched */
172 return false;
173}
174
175
176/*
177 Returns true if Item1 and Item2 are the same type
178 or if either are of QCBOR_TYPE_ANY.
179 */
180static bool
181QCBORItem_MatchType(const QCBORItem Item1, const QCBORItem Item2)
182{
183 if(Item1.uDataType == Item2.uDataType) {
184 return true;
185 } else if(Item1.uDataType == QCBOR_TYPE_ANY) {
186 return true;
187 } else if(Item2.uDataType == QCBOR_TYPE_ANY) {
188 return true;
189 }
190 return false;
191}
192
Laurence Lundblade02625d42020-06-25 14:41:41 -0700193
Laurence Lundbladeee851742020-01-08 08:37:05 -0800194/*===========================================================================
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700195 DecodeNesting -- Tracking array/map/sequence/bstr-wrapped nesting
Laurence Lundbladeee851742020-01-08 08:37:05 -0800196 ===========================================================================*/
197
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700198/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800199 * See comments about and typedef of QCBORDecodeNesting in qcbor_private.h,
200 * the data structure all these functions work on.
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700201 */
202
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700203
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700204static uint8_t
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700205DecodeNesting_GetCurrentLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700206{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700207 const ptrdiff_t nLevel = pNesting->pCurrent - &(pNesting->pLevels[0]);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800208 /* Limit in DecodeNesting_Descend against more than
209 * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
Laurence Lundblade02625d42020-06-25 14:41:41 -0700210 */
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700211 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700212}
213
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700214
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700215static uint8_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700216DecodeNesting_GetBoundedModeLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700217{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700218 const ptrdiff_t nLevel = pNesting->pCurrentBounded - &(pNesting->pLevels[0]);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800219 /* Limit in DecodeNesting_Descend against more than
220 * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
Laurence Lundblade02625d42020-06-25 14:41:41 -0700221 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700222 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700223}
224
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700225
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700226static uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700227DecodeNesting_GetMapOrArrayStart(const QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700228{
229 return pNesting->pCurrentBounded->u.ma.uStartOffset;
230}
231
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700232
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700233static bool
Laurence Lundblade085d7952020-07-24 10:26:30 -0700234DecodeNesting_IsBoundedEmpty(const QCBORDecodeNesting *pNesting)
235{
236 if(pNesting->pCurrentBounded->u.ma.uCountCursor == QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
237 return true;
238 } else {
239 return false;
240 }
241}
242
243
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700244static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700245DecodeNesting_IsCurrentAtTop(const QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700246{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700247 if(pNesting->pCurrent == &(pNesting->pLevels[0])) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700248 return true;
249 } else {
250 return false;
251 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700252}
253
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700254
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700255static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700256DecodeNesting_IsCurrentDefiniteLength(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700257{
258 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800259 /* Not a map or array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700260 return false;
261 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800262
263#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700264 if(pNesting->pCurrent->u.ma.uCountTotal == QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800265 /* Is indefinite */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700266 return false;
267 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800268
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800269#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
270
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800271 /* All checks passed; is a definte length map or array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700272 return true;
273}
274
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700275static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700276DecodeNesting_IsCurrentBstrWrapped(const QCBORDecodeNesting *pNesting)
Laurence Lundblade642282a2020-06-23 12:00:33 -0700277{
278 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800279 /* is a byte string */
Laurence Lundblade642282a2020-06-23 12:00:33 -0700280 return true;
281 }
282 return false;
283}
284
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700285
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700286static bool
287DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700288{
289 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
290 return true;
291 }
Laurence Lundblade02625d42020-06-25 14:41:41 -0700292 if(pNesting->pCurrent->u.ma.uStartOffset != QCBOR_NON_BOUNDED_OFFSET) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700293 return true;
294 }
295 return false;
296}
297
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700298
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700299static void
300DecodeNesting_SetMapOrArrayBoundedMode(QCBORDecodeNesting *pNesting, bool bIsEmpty, size_t uStart)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700301{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800302 /* Should be only called on maps and arrays */
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700303 /*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800304 * DecodeNesting_EnterBoundedMode() checks to be sure uStart is not
305 * larger than DecodeNesting_EnterBoundedMode which keeps it less than
306 * uin32_t so the cast is safe.
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700307 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700308 pNesting->pCurrent->u.ma.uStartOffset = (uint32_t)uStart;
Laurence Lundblade085d7952020-07-24 10:26:30 -0700309
310 if(bIsEmpty) {
311 pNesting->pCurrent->u.ma.uCountCursor = QCBOR_COUNT_INDICATES_ZERO_LENGTH;
312 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700313}
314
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700315
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700316static void
317DecodeNesting_ClearBoundedMode(QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700318{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700319 pNesting->pCurrent->u.ma.uStartOffset = QCBOR_NON_BOUNDED_OFFSET;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700320}
321
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700322
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700323static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700324DecodeNesting_IsAtEndOfBoundedLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700325{
326 if(pNesting->pCurrentBounded == NULL) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800327 /* No bounded map or array set up */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700328 return false;
329 }
330 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800331 /* Not a map or array; end of those is by byte count */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700332 return false;
333 }
Laurence Lundblade6ab01fb2020-10-01 13:04:49 -0700334 if(!DecodeNesting_IsCurrentBounded(pNesting)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800335 /* In a traveral at a level deeper than the bounded level */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700336 return false;
337 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800338 /* Works for both definite- and indefinitelength maps/arrays */
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800339 if(pNesting->pCurrentBounded->u.ma.uCountCursor != 0 &&
340 pNesting->pCurrentBounded->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800341 /* Count is not zero, still unconsumed item */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700342 return false;
343 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800344 /* All checks passed, got to the end of an array or map*/
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700345 return true;
346}
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700347
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700348
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700349static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700350DecodeNesting_IsEndOfDefiniteLengthMapOrArray(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700351{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800352 /* Must only be called on map / array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700353 if(pNesting->pCurrent->u.ma.uCountCursor == 0) {
354 return true;
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700355 } else {
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700356 return false;
357 }
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700358}
359
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700360
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700361static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700362DecodeNesting_IsCurrentTypeMap(const QCBORDecodeNesting *pNesting)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700363{
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700364 if(pNesting->pCurrent->uLevelType == CBOR_MAJOR_TYPE_MAP) {
365 return true;
366 } else {
367 return false;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700368 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700369}
370
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700371
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700372static bool
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700373DecodeNesting_IsBoundedType(const QCBORDecodeNesting *pNesting, uint8_t uType)
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700374{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700375 if(pNesting->pCurrentBounded == NULL) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700376 return false;
377 }
Laurence Lundblade02625d42020-06-25 14:41:41 -0700378
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700379 uint8_t uItemDataType = pNesting->pCurrentBounded->uLevelType;
Laurence Lundblade62cae932024-06-03 13:16:17 -0700380#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700381 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
382 uItemDataType = QCBOR_TYPE_ARRAY;
383 }
Laurence Lundblade78a66132024-06-06 12:19:59 -0700384#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700385
386 if(uItemDataType != uType) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700387 return false;
388 }
389
390 return true;
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700391}
392
Laurence Lundblade02625d42020-06-25 14:41:41 -0700393
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700394static void
Laurence Lundblade6c8a4442020-06-22 22:16:11 -0700395DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700396{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800397 /* Only call on a definite-length array / map */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700398 pNesting->pCurrent->u.ma.uCountCursor--;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700399}
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700400
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700401
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700402static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700403DecodeNesting_ReverseDecrement(QCBORDecodeNesting *pNesting)
404{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800405 /* Only call on a definite-length array / map */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700406 pNesting->pCurrent->u.ma.uCountCursor++;
407}
408
409
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700410static void
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700411DecodeNesting_Ascend(QCBORDecodeNesting *pNesting)
412{
413 pNesting->pCurrent--;
414}
415
Laurence Lundblade02625d42020-06-25 14:41:41 -0700416
417static QCBORError
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700418DecodeNesting_Descend(QCBORDecodeNesting *pNesting, uint8_t uType)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700419{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800420 /* Error out if nesting is too deep */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700421 if(pNesting->pCurrent >= &(pNesting->pLevels[QCBOR_MAX_ARRAY_NESTING])) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700422 return QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP;
Laurence Lundblade02625d42020-06-25 14:41:41 -0700423 }
424
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800425 /* The actual descend */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700426 pNesting->pCurrent++;
427
428 pNesting->pCurrent->uLevelType = uType;
429
430 return QCBOR_SUCCESS;
431}
432
433
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700434static QCBORError
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800435DecodeNesting_EnterBoundedMapOrArray(QCBORDecodeNesting *pNesting,
436 bool bIsEmpty,
437 size_t uOffset)
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700438{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700439 /*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800440 * Should only be called on map/array.
441 *
442 * Have descended into this before this is called. The job here is
443 * just to mark it in bounded mode.
444 *
445 * Check against QCBOR_MAX_DECODE_INPUT_SIZE make sure that
446 * uOffset doesn't collide with QCBOR_NON_BOUNDED_OFFSET.
447 *
448 * Cast of uOffset to uint32_t for cases where SIZE_MAX < UINT32_MAX.
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700449 */
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -0800450 if((uint32_t)uOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700451 return QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700452 }
453
Laurence Lundblade0750fc42020-06-20 21:02:34 -0700454 pNesting->pCurrentBounded = pNesting->pCurrent;
Laurence Lundblade085d7952020-07-24 10:26:30 -0700455
456 DecodeNesting_SetMapOrArrayBoundedMode(pNesting, bIsEmpty, uOffset);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700457
458 return QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700459}
460
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700461
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700462static QCBORError
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700463DecodeNesting_DescendMapOrArray(QCBORDecodeNesting *pNesting,
Laurence Lundblade02625d42020-06-25 14:41:41 -0700464 uint8_t uQCBORType,
465 uint64_t uCount)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700466{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700467 QCBORError uError = QCBOR_SUCCESS;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700468
469 if(uCount == 0) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800470 /* Nothing to do for empty definite-length arrays. They are just are
471 * effectively the same as an item that is not a map or array.
472 */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700473 goto Done;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800474 /* Empty indefinite-length maps and arrays are handled elsewhere */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700475 }
476
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800477 /* Error out if arrays is too long to handle */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700478 if(uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH &&
479 uCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700480 uError = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700481 goto Done;
482 }
483
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700484 uError = DecodeNesting_Descend(pNesting, uQCBORType);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700485 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700486 goto Done;
487 }
488
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800489 /* Fill in the new map/array level. Check above makes casts OK. */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -0700490 pNesting->pCurrent->u.ma.uCountCursor = (uint16_t)uCount;
491 pNesting->pCurrent->u.ma.uCountTotal = (uint16_t)uCount;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700492
493 DecodeNesting_ClearBoundedMode(pNesting);
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700494
495Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700496 return uError;;
497}
498
499
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700500static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700501DecodeNesting_LevelUpCurrent(QCBORDecodeNesting *pNesting)
502{
503 pNesting->pCurrent = pNesting->pCurrentBounded - 1;
504}
505
506
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700507static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700508DecodeNesting_LevelUpBounded(QCBORDecodeNesting *pNesting)
509{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700510 while(pNesting->pCurrentBounded != &(pNesting->pLevels[0])) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700511 pNesting->pCurrentBounded--;
512 if(DecodeNesting_IsCurrentBounded(pNesting)) {
513 break;
514 }
515 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700516}
517
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800518
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700519static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700520DecodeNesting_SetCurrentToBoundedLevel(QCBORDecodeNesting *pNesting)
521{
522 pNesting->pCurrent = pNesting->pCurrentBounded;
523}
524
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700525
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700526static QCBORError
Laurence Lundblade02625d42020-06-25 14:41:41 -0700527DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting,
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700528 uint32_t uEndOffset,
529 uint32_t uStartOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700530{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700531 QCBORError uError;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700532
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700533 uError = DecodeNesting_Descend(pNesting, QCBOR_TYPE_BYTE_STRING);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700534 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700535 goto Done;
536 }
537
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800538 /* Fill in the new byte string level */
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700539 pNesting->pCurrent->u.bs.uSavedEndOffset = uEndOffset;
540 pNesting->pCurrent->u.bs.uBstrStartOffset = uStartOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700541
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800542 /* Bstr wrapped levels are always bounded */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700543 pNesting->pCurrentBounded = pNesting->pCurrent;
544
545Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700546 return uError;;
547}
548
Laurence Lundbladed0304932020-06-27 10:59:38 -0700549
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700550static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700551DecodeNesting_ZeroMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700552{
553 pNesting->pCurrent->u.ma.uCountCursor = 0;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700554}
555
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700556
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700557static void
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800558DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting)
559{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700560 if(pNesting->pCurrent->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
561 pNesting->pCurrentBounded->u.ma.uCountCursor = pNesting->pCurrentBounded->u.ma.uCountTotal;
562 }
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800563}
564
565
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700566static void
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700567DecodeNesting_Init(QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700568{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700569 /* Assumes that *pNesting has been zero'd before this call. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700570 pNesting->pLevels[0].uLevelType = QCBOR_TYPE_BYTE_STRING;
571 pNesting->pCurrent = &(pNesting->pLevels[0]);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700572}
573
574
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700575static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800576DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting,
577 QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700578{
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700579 *pSave = *pNesting;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700580}
581
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700582
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700583static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800584DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting,
585 const QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700586{
587 *pNesting = *pSave;
588}
589
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700590
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700591static uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700592DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700593{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700594 return pMe->pCurrentBounded->u.bs.uSavedEndOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700595}
596
597
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800598
599
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800600#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladeee851742020-01-08 08:37:05 -0800601/*===========================================================================
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800602 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
603
604 The following four functions are pretty wrappers for invocation of
605 the string allocator supplied by the caller.
606
Laurence Lundbladeee851742020-01-08 08:37:05 -0800607 ===========================================================================*/
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800608
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700609static void
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800610StringAllocator_Free(const QCBORInternalAllocator *pMe, const void *pMem)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800611{
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300612 /* This cast to uintptr_t suppresses the "-Wcast-qual" warnings.
613 * This is the one place where the const needs to be cast away so const can
614 * be use in the rest of the code.
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800615 */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300616 (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, 0);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800617}
618
Laurence Lundbladeee851742020-01-08 08:37:05 -0800619// StringAllocator_Reallocate called with pMem NULL is
620// equal to StringAllocator_Allocate()
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700621static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800622StringAllocator_Reallocate(const QCBORInternalAllocator *pMe,
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800623 const void *pMem,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800624 size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800625{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800626 /* See comment in StringAllocator_Free() */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300627 return (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, uSize);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800628}
629
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700630static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800631StringAllocator_Allocate(const QCBORInternalAllocator *pMe, size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800632{
633 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
634}
635
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700636static void
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800637StringAllocator_Destruct(const QCBORInternalAllocator *pMe)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800638{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800639 /* See comment in StringAllocator_Free() */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800640 if(pMe->pfAllocator) {
641 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
642 }
643}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800644#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800645
646
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800647
648
Laurence Lundbladeee851742020-01-08 08:37:05 -0800649/*===========================================================================
650 QCBORDecode -- The main implementation of CBOR decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700651
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800652 See qcbor/qcbor_decode.h for definition of the object
653 used here: QCBORDecodeContext
Laurence Lundbladeee851742020-01-08 08:37:05 -0800654 ===========================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700655/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800656 * Public function, see header file
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700657 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700658void
659QCBORDecode_Init(QCBORDecodeContext *pMe,
660 UsefulBufC EncodedCBOR,
661 QCBORDecodeMode nDecodeMode)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700662{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800663 memset(pMe, 0, sizeof(QCBORDecodeContext));
664 UsefulInputBuf_Init(&(pMe->InBuf), EncodedCBOR);
665 /* Don't bother with error check on decode mode. If a bad value is
666 * passed it will just act as if the default normal mode of 0 was set.
667 */
668 pMe->uDecodeMode = (uint8_t)nDecodeMode;
669 DecodeNesting_Init(&(pMe->nesting));
670
671 /* Inialize me->auMappedTags to CBOR_TAG_INVALID16. See
672 * GetNext_TaggedItem() and MapTagNumber(). */
673 memset(pMe->auMappedTags, 0xff, sizeof(pMe->auMappedTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700674}
675
676
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800677#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
678
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700679/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800680 * Public function, see header file
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700681 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700682void
683QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
684 QCBORStringAllocate pfAllocateFunction,
685 void *pAllocateContext,
686 bool bAllStrings)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700687{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800688 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
689 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
690 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700691}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800692#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700693
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800694
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800695
696
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800697/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800698 * Deprecated public function, see header file
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800699 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700700void
701QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pMe,
702 const QCBORTagListIn *pTagList)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700703{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800704 /* This does nothing now. It is retained for backwards compatibility */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700705 (void)pMe;
706 (void)pTagList;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700707}
708
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700709
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800710
711
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700712/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800713 * Decoding items is done in six layers, one calling the next one
714 * down. If a layer has no work to do for a particular item, it
715 * returns quickly.
716 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700717 * 1. QCBORDecode_Private_GetNextTagContent - The top layer processes
718 * tagged data items, turning them into the local C representation.
719 * For the most simple it is just associating a QCBOR_TYPE with the
720 * data. For the complex ones that an aggregate of data items, there
721 * is some further decoding and some limited recursion.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800722 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700723 * 2. QCBORDecode_Private_GetNextMapOrArray - This manages the
724 * beginnings and ends of maps and arrays. It tracks descending into
725 * and ascending out of maps/arrays. It processes breaks that
726 * terminate indefinite-length maps and arrays.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800727 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700728 * 3. QCBORDecode_Private_GetNextMapEntry - This handles the combining
729 * of two items, the label and the data, that make up a map entry. It
730 * only does work on maps. It combines the label and data items into
731 * one labeled item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800732 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700733 * 4. QCBORDecode_Private_GetNextTagNumber - This decodes type 6 tag
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800734 * numbers. It turns the tag numbers into bit flags associated with
735 * the data item. No actual decoding of the contents of the tag is
736 * performed here.
737 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700738 * 5. QCBORDecode_Private_GetNextFullString - This assembles the
739 * sub-items that make up an indefinite-length string into one string
740 * item. It uses the string allocator to create contiguous space for
741 * the item. It processes all breaks that are part of
742 * indefinite-length strings.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800743 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700744 * 6. QCBOR_Private_DecodeAtomicDataItem - This decodes the atomic
745 * data items in CBOR. Each atomic data item has a "major type", an
746 * integer "argument" and optionally some content. For text and byte
747 * strings, the content is the bytes that make up the string. These
748 * are the smallest data items that are considered to be well-formed.
749 * The content may also be other data items in the case of aggregate
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800750 * types. They are not handled in this layer.
751 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700752 * This uses about 350 bytes of stack. This number comes from
753 * instrumenting (printf address of stack variables) the code on x86
754 * compiled for size optimization.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700755 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800756
757
758/*
759 * Note about use of int and unsigned variables.
760 *
761 * See http://www.unix.org/whitepapers/64bit.html for reasons int is
762 * used carefully here, and in particular why it isn't used in the
763 * public interface. Also see
764 * https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers
765 *
766 * Int is used for values that need less than 16-bits and would be
767 * subject to integer promotion and result in complaining from static
768 * analyzers.
769 */
770
771
772/**
773 * @brief Decode the CBOR head, the type and argument.
774 *
775 * @param[in] pUInBuf The input buffer to read from.
776 * @param[out] pnMajorType The decoded major type.
777 * @param[out] puArgument The decoded argument.
778 * @param[out] pnAdditionalInfo The decoded Lower 5 bits of initial byte.
779 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -0700780 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved features
781 * @retval QCBOR_ERR_HIT_END Unexpected end of input
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800782 *
783 * This decodes the CBOR "head" that every CBOR data item has. See
784 * longer explaination of the head in documentation for
785 * QCBOREncode_EncodeHead().
786 *
787 * This does the network->host byte order conversion. The conversion
788 * here also results in the conversion for floats in addition to that
789 * for lengths, tags and integer values.
790 *
791 * The int type is preferred to uint8_t for some variables as this
792 * avoids integer promotions, can reduce code size and makes static
793 * analyzers happier.
794 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700795static QCBORError
796QCBOR_Private_DecodeHead(UsefulInputBuf *pUInBuf,
797 int *pnMajorType,
798 uint64_t *puArgument,
799 int *pnAdditionalInfo)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700800{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800801 QCBORError uReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800802
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800803 /* Get the initial byte that every CBOR data item has and break it
804 * down. */
805 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800806 const int nTmpMajorType = nInitialByte >> 5;
807 const int nAdditionalInfo = nInitialByte & 0x1f;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800808
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800809 /* Where the argument accumulates */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800810 uint64_t uArgument;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800811
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800812 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800813 /* Need to get 1,2,4 or 8 additional argument bytes. Map
814 * LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length.
815 */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800816 static const uint8_t aIterate[] = {1,2,4,8};
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800817
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800818 /* Loop getting all the bytes in the argument */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800819 uArgument = 0;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800820 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800821 /* This shift and add gives the endian conversion. */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800822 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
823 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800824 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800825 /* The reserved and thus-far unused additional info values */
826 uReturn = QCBOR_ERR_UNSUPPORTED;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800827 goto Done;
828 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800829 /* Less than 24, additional info is argument or 31, an
830 * indefinite-length. No more bytes to get.
831 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800832 uArgument = (uint64_t)nAdditionalInfo;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700833 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800834
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700835 if(UsefulInputBuf_GetError(pUInBuf)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800836 uReturn = QCBOR_ERR_HIT_END;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700837 goto Done;
838 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800839
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800840 /* All successful if arrived here. */
841 uReturn = QCBOR_SUCCESS;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800842 *pnMajorType = nTmpMajorType;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800843 *puArgument = uArgument;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800844 *pnAdditionalInfo = nAdditionalInfo;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800845
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700846Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800847 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700848}
849
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800850
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800851/**
852 * @brief Decode integer types, major types 0 and 1.
853 *
Laurence Lundblade95606972024-06-07 11:32:12 -0700854 * @param[in] nMajorType The CBOR major type (0 or 1).
855 * @param[in] uArgument The argument from the head.
856 * @param[in] nAdditionalInfo So it can be error-checked.
857 * @param[out] pDecodedItem The filled in decoded item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800858 *
Laurence Lundblade95606972024-06-07 11:32:12 -0700859 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered.
860 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800861 *
862 * Must only be called when major type is 0 or 1.
863 *
864 * CBOR doesn't explicitly specify two's compliment for integers but
865 * all CPUs use it these days and the test vectors in the RFC are
866 * so. All integers in the CBOR structure are positive and the major
867 * type indicates positive or negative. CBOR can express positive
868 * integers up to 2^x - 1 where x is the number of bits and negative
869 * integers down to 2^x. Note that negative numbers can be one more
870 * away from zero than positive. Stdint, as far as I can tell, uses
871 * two's compliment to represent negative integers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700872 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700873static QCBORError
874QCBOR_Private_DecodeInteger(const int nMajorType,
875 const uint64_t uArgument,
Laurence Lundblade62cae932024-06-03 13:16:17 -0700876 const int nAdditionalInfo,
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700877 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700878{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800879 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800880
Laurence Lundblade62cae932024-06-03 13:16:17 -0700881 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
882 uReturn = QCBOR_ERR_BAD_INT;
883 goto Done;
884 }
885
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700886 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800887 if (uArgument <= INT64_MAX) {
888 pDecodedItem->val.int64 = (int64_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700889 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800890
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700891 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800892 pDecodedItem->val.uint64 = uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700893 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700894 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800895
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700896 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800897 if(uArgument <= INT64_MAX) {
898 /* CBOR's representation of negative numbers lines up with
899 * the two-compliment representation. A negative integer has
900 * one more in range than a positive integer. INT64_MIN is
901 * equal to (-INT64_MAX) - 1.
902 */
903 pDecodedItem->val.int64 = (-(int64_t)uArgument) - 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700904 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800905
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700906 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800907 /* C can't represent a negative integer in this range so it
908 * is an error.
909 */
910 uReturn = QCBOR_ERR_INT_OVERFLOW;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700911 }
912 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800913
Laurence Lundblade62cae932024-06-03 13:16:17 -0700914Done:
915 return uReturn;
916}
917
918
Laurence Lundblade95606972024-06-07 11:32:12 -0700919/**
920 * @brief Decode text and byte strings
921 *
922 * @param[in] pMe Decoder context.
923 * @param[in] bAllocate Whether to allocate and copy string.
924 * @param[in] nMajorType Whether it is a byte or text string.
925 * @param[in] uStrLen The length of the string.
926 * @param[in] nAdditionalInfo Whether it is an indefinite-length string.
927 * @param[out] pDecodedItem The filled-in decoded item.
928 *
929 * @retval QCBOR_ERR_HIT_END Unexpected end of input.
930 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
931 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
932 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator
933 *
934 * This reads @c uStrlen bytes from the input and fills in @c
935 * pDecodedItem. If @c bAllocate is true, then memory for the string
936 * is allocated.
937 */
Laurence Lundblade62cae932024-06-03 13:16:17 -0700938static QCBORError
Laurence Lundblade95606972024-06-07 11:32:12 -0700939QCBOR_Private_DecodeString(QCBORDecodeContext *pMe,
940 const bool bAllocate,
941 const int nMajorType,
942 const uint64_t uStrLen,
943 const int nAdditionalInfo,
944 QCBORItem *pDecodedItem)
945{
946 QCBORError uReturn = QCBOR_SUCCESS;
947
948 /* ---- Figure out the major type ---- */
949 #if CBOR_MAJOR_TYPE_BYTE_STRING + 4 != QCBOR_TYPE_BYTE_STRING
950 #error QCBOR_TYPE_BYTE_STRING not lined up with major type
951 #endif
952
953 #if CBOR_MAJOR_TYPE_TEXT_STRING + 4 != QCBOR_TYPE_TEXT_STRING
954 #error QCBOR_TYPE_TEXT_STRING not lined up with major type
955 #endif
956 pDecodedItem->uDataType = (uint8_t)(nMajorType + 4);
957
958 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
959 /* --- Just the head of an indefinite-length string --- */
960 pDecodedItem->val.string = (UsefulBufC){NULL, QCBOR_STRING_LENGTH_INDEFINITE};
961
962 } else {
963 /* --- A definite-length string --- */
964 /* --- (which might be a chunk of an indefinte-length string) --- */
965
966 /* CBOR lengths can be 64 bits, but size_t is not 64 bits on all
967 * CPUs. This check makes the casts to size_t below safe.
968 *
969 * The max is 4 bytes less than the largest sizeof() so this can be
970 * tested by putting a SIZE_MAX length in the CBOR test input (no
971 * one will care the limit on strings is 4 bytes shorter).
972 */
973 if(uStrLen > SIZE_MAX-4) {
974 uReturn = QCBOR_ERR_STRING_TOO_LONG;
975 goto Done;
976 }
977
978 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(&(pMe->InBuf), (size_t)uStrLen);
979 if(UsefulBuf_IsNULLC(Bytes)) {
980 /* Failed to get the bytes for this string item */
981 uReturn = QCBOR_ERR_HIT_END;
982 goto Done;
983 }
984
985#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
986 if(bAllocate) {
987 /* --- Put string in allocated memory --- */
988
989 /* Note that this is not where allocation to coalesce
990 * indefinite-length strings is done. This is for when the
991 * caller has requested all strings be allocated. Disabling
992 * indefinite length strings also disables this allocate-all
993 * option.
994 */
995
996 if(pMe->StringAllocator.pfAllocator == NULL) {
997 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
998 goto Done;
999 }
1000 UsefulBuf NewMem = StringAllocator_Allocate(&(pMe->StringAllocator), (size_t)uStrLen);
1001 if(UsefulBuf_IsNULL(NewMem)) {
1002 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1003 goto Done;
1004 }
1005 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
1006 pDecodedItem->uDataAlloc = 1;
1007 goto Done;
1008 }
1009#else
1010 (void)bAllocate;
1011#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1012
1013 /* --- Normal case with no string allocator --- */
1014 pDecodedItem->val.string = Bytes;
1015 }
1016
1017Done:
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 */
1043static QCBORError
1044QCBOR_Private_DecodeArrayOrMap(const uint8_t uMode,
1045 const int nMajorType,
1046 const uint64_t uItemCount,
1047 const int nAdditionalInfo,
1048 QCBORItem *pDecodedItem)
Laurence Lundblade62cae932024-06-03 13:16:17 -07001049{
1050 QCBORError uReturn;
1051
Laurence Lundblade95606972024-06-07 11:32:12 -07001052 /* ------ 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 }
Laurence Lundblade62cae932024-06-03 13:16:17 -07001101 }
Laurence Lundblade95606972024-06-07 11:32:12 -07001102 }
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 */
1121static QCBORError
1122QCBOR_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 }
Laurence Lundblade62cae932024-06-03 13:16:17 -07001134#else /* QCBOR_DISABLE_TAGS */
Laurence Lundbladecfd8a2c2024-06-06 21:01:42 -07001135 (void)nAdditionalInfo;
1136 (void)uArgument;
1137 (void)pDecodedItem;
Laurence Lundblade95606972024-06-07 11:32:12 -07001138 return QCBOR_ERR_TAGS_DISABLED;
Laurence Lundblade62cae932024-06-03 13:16:17 -07001139#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001140}
1141
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001142
1143/* Make sure #define value line up as DecodeSimple counts on this. */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001144#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
Laurence Lundblade0f99d692018-09-26 14:39:28 -07001160#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
1161#error QCBOR_TYPE_BREAK macro value wrong
1162#endif
1163
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001164#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
Laurence Lundblade9b334962020-08-27 10:55:53 -07001172
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001173/**
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 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001180 * @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.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001186 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001187static QCBORError
1188QCBOR_Private_DecodeType7(const int nAdditionalInfo,
1189 const uint64_t uArgument,
1190 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001191{
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 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001199 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001200
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001201 switch(nAdditionalInfo) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001202 /* No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they
1203 * are caught before this is called.
1204 */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001205
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001206 case HALF_PREC_FLOAT: /* 25 */
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -07001207#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001208 /* 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);
Laurence Lundblade67bd5512018-11-02 21:44:06 +07001213 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001214#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001215 uReturn = FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001216 break;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001217 case SINGLE_PREC_FLOAT: /* 26 */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001218#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001219 /* 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 */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001227 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001228 const float f = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uArgument);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001229#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001230 /* In the normal case, use HW to convert float to
1231 * double. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001232 pDecodedItem->val.dfnum = (double)f;
1233 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001234#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001235 /* Use of float HW is disabled, return as a float. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001236 pDecodedItem->val.fnum = f;
1237 pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
1238
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001239 /* 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 */
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001244#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001245 }
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001246#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1247 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001248 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001249
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001250 case DOUBLE_PREC_FLOAT: /* 27 */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001251#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001252 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uArgument);
Laurence Lundblade67bd5512018-11-02 21:44:06 +07001253 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001254#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1255 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001256 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001257
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001258 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 */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001264
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001265 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;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001271 goto Done;
1272 }
Laurence Lundblade5e390822019-01-06 12:35:01 -08001273 /* FALLTHROUGH */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001274
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001275 default: /* 0-19 */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001276 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001277 /* 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
Laurence Lundbladeee851742020-01-08 08:37:05 -08001281 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001282 pDecodedItem->val.uSimple = (uint8_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001283 break;
1284 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001285
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001286Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001287 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001288}
1289
1290
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001291/**
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001292 * @brief Decode a single primitive data item (decode layer 6).
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001293 *
Laurence Lundblade95606972024-06-07 11:32:12 -07001294 * @param[in] pMe Decoder context.
1295 * @param[in] bAllocateStrings If true, use allocator for strings.
1296 * @param[out] pDecodedItem The filled-in decoded item.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001297 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001298 * @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.
Laurence Lundblade95606972024-06-07 11:32:12 -07001304 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001305 * @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.
Laurence Lundblade95606972024-06-07 11:32:12 -07001314 * @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.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001317 *
Laurence Lundblade95606972024-06-07 11:32:12 -07001318 * This decodes the most primitive / atomic data item. It does no
1319 * combining of data items.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001320 */
1321static QCBORError
Laurence Lundblade95606972024-06-07 11:32:12 -07001322QCBOR_Private_DecodeAtomicDataItem(QCBORDecodeContext *pMe,
1323 const bool bAllocateStrings,
1324 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001325{
1326 QCBORError uReturn;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001327 int nMajorType = 0;
1328 uint64_t uArgument = 0;
1329 int nAdditionalInfo = 0;
1330
Laurence Lundblade95606972024-06-07 11:32:12 -07001331 /* Decode the "head" that every CBOR item has into the major type,
1332 * length and the additional info.
1333 */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001334 uReturn = QCBOR_Private_DecodeHead(&(pMe->InBuf), &nMajorType, &uArgument, &nAdditionalInfo);
Laurence Lundblade95606972024-06-07 11:32:12 -07001335 if(uReturn != QCBOR_SUCCESS) {
1336 return uReturn;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001337 }
1338
Laurence Lundblade95606972024-06-07 11:32:12 -07001339 memset(pDecodedItem, 0, sizeof(QCBORItem));
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 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001345 switch (nMajorType) {
1346 case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
1347 case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
Laurence Lundblade95606972024-06-07 11:32:12 -07001348 return QCBOR_Private_DecodeInteger(nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001349 break;
1350
1351 case CBOR_MAJOR_TYPE_BYTE_STRING: /* Major type 2 */
1352 case CBOR_MAJOR_TYPE_TEXT_STRING: /* Major type 3 */
Laurence Lundblade95606972024-06-07 11:32:12 -07001353 return QCBOR_Private_DecodeString(pMe, bAllocateStrings, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001354 break;
1355
1356 case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */
1357 case CBOR_MAJOR_TYPE_MAP: /* Major type 5 */
Laurence Lundblade95606972024-06-07 11:32:12 -07001358 return QCBOR_Private_DecodeArrayOrMap(pMe->uDecodeMode, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001359 break;
1360
1361 case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */
Laurence Lundblade95606972024-06-07 11:32:12 -07001362 return QCBOR_Private_DecodeTag(uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001363 break;
1364
1365 case CBOR_MAJOR_TYPE_SIMPLE:
1366 /* Major type 7: float, double, true, false, null... */
Laurence Lundblade95606972024-06-07 11:32:12 -07001367 return QCBOR_Private_DecodeType7(nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001368 break;
1369
1370 default:
1371 /* Never happens because DecodeHead() should never return > 7 */
Laurence Lundblade95606972024-06-07 11:32:12 -07001372 return QCBOR_ERR_UNSUPPORTED;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001373 break;
1374 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001375}
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 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001384 * @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.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001405 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001406 * If @c pDecodedItem is not an indefinite-length string, this does nothing.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001407 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001408 * 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.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001412 *
1413 * Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001414 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001415static QCBORError
1416QCBORDecode_Private_GetNextFullString(QCBORDecodeContext *pMe,
1417 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001418{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001419 /* 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 */
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001426 QCBORError uReturn;
Laurence Lundblade78a66132024-06-06 12:19:59 -07001427
1428 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, pMe->bStringAllocateAll, pDecodedItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001429 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001430 goto Done;
1431 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001432
Laurence Lundblade78a66132024-06-06 12:19:59 -07001433 /* Skip out if not an indefinite-length string */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001434 const uint8_t uStringType = pDecodedItem->uDataType;
Laurence Lundblade78a66132024-06-06 12:19:59 -07001435 if(uStringType != QCBOR_TYPE_BYTE_STRING &&
1436 uStringType != QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001437 goto Done;
1438 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001439 if(pDecodedItem->val.string.len != QCBOR_STRING_LENGTH_INDEFINITE) {
1440 goto Done;
1441 }
1442
1443#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001444 /* Can't decode indefinite-length strings without a string allocator */
Laurence Lundblade78a66132024-06-06 12:19:59 -07001445 if(!pMe->StringAllocator.pfAllocator) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001446 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1447 goto Done;
1448 }
1449
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001450 /* Loop getting chunks of the indefinite-length string */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001451 UsefulBufC FullString = NULLUsefulBufC;
1452
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001453 for(;;) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001454 /* Get QCBORItem for next chunk */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001455 QCBORItem StringChunkItem;
Laurence Lundblade78a66132024-06-06 12:19:59 -07001456 /* Pass a false to DecodeAtomicDataItem() because the
1457 * individual string chunks in an indefinite-length must not
1458 * be allocated. They are always copied into the allocated contiguous
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001459 * buffer allocated here.
1460 */
Laurence Lundblade78a66132024-06-06 12:19:59 -07001461 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &StringChunkItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001462 if(uReturn) {
1463 break;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001464 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001465
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001466 /* Is item is the marker for end of the indefinite-length string? */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001467 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001468 /* String is complete */
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001469 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301470 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001471 break;
1472 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001473
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001474 /* All chunks must be of the same type, the type of the item
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001475 * that introduces the indefinite-length string. This also
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001476 * catches errors where the chunk is not a string at all and an
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001477 * indefinite-length string inside an indefinite-length string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001478 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001479 if(StringChunkItem.uDataType != uStringType ||
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001480 StringChunkItem.val.string.len == QCBOR_STRING_LENGTH_INDEFINITE) {
1481 uReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001482 break;
1483 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001484
David Navarro9123e5b2022-03-28 16:04:03 +02001485 if (StringChunkItem.val.string.len > 0) {
1486 /* The first time throurgh FullString.ptr is NULL and this is
1487 * equivalent to StringAllocator_Allocate(). Subsequently it is
1488 * not NULL and a reallocation happens.
1489 */
Laurence Lundblade78a66132024-06-06 12:19:59 -07001490 UsefulBuf NewMem = StringAllocator_Reallocate(&(pMe->StringAllocator),
David Navarro9123e5b2022-03-28 16:04:03 +02001491 FullString.ptr,
1492 FullString.len + StringChunkItem.val.string.len);
David Navarro9123e5b2022-03-28 16:04:03 +02001493 if(UsefulBuf_IsNULL(NewMem)) {
1494 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1495 break;
1496 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001497
David Navarro9123e5b2022-03-28 16:04:03 +02001498 /* Copy new string chunk to the end of accumulated string */
1499 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001500 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001501 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001502
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001503 if(uReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
1504 /* Getting the item failed, clean up the allocated memory */
Laurence Lundblade78a66132024-06-06 12:19:59 -07001505 StringAllocator_Free(&(pMe->StringAllocator), FullString.ptr);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001506 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001507#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1508 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1509#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001510
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001511Done:
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001512 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001513}
1514
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001515
Laurence Lundblade37286c02022-09-03 10:05:02 -07001516#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001517/**
1518 * @brief This converts a tag number to a shorter mapped value for storage.
1519 *
1520 * @param[in] pMe The decode context.
1521 * @param[in] uUnMappedTag The tag number to map
1522 * @param[out] puMappedTagNumer The stored tag number.
1523 *
1524 * @return error code.
1525 *
1526 * The main point of mapping tag numbers is make QCBORItem
1527 * smaller. With this mapping storage of 4 tags takes up 8
1528 * bytes. Without, it would take up 32 bytes.
1529 *
1530 * This maps tag numbers greater than QCBOR_LAST_UNMAPPED_TAG.
1531 * QCBOR_LAST_UNMAPPED_TAG is a little smaller than MAX_UINT16.
1532 *
1533 * See also UnMapTagNumber() and @ref QCBORItem.
1534 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001535static QCBORError
1536QCBORDecode_Private_MapTagNumber(QCBORDecodeContext *pMe,
1537 const uint64_t uUnMappedTag,
1538 uint16_t *puMappedTagNumer)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001539{
1540 if(uUnMappedTag > QCBOR_LAST_UNMAPPED_TAG) {
1541 unsigned uTagMapIndex;
1542 /* Is there room in the tag map, or is it in it already? */
1543 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
1544 if(pMe->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID64) {
1545 break;
1546 }
1547 if(pMe->auMappedTags[uTagMapIndex] == uUnMappedTag) {
1548 break;
1549 }
1550 }
1551 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
1552 return QCBOR_ERR_TOO_MANY_TAGS;
1553 }
1554
1555 /* Covers the cases where tag is new and were it is already in the map */
1556 pMe->auMappedTags[uTagMapIndex] = uUnMappedTag;
1557 *puMappedTagNumer = (uint16_t)(uTagMapIndex + QCBOR_LAST_UNMAPPED_TAG + 1);
1558
1559 } else {
1560 *puMappedTagNumer = (uint16_t)uUnMappedTag;
1561 }
1562
1563 return QCBOR_SUCCESS;
1564}
1565
1566
1567/**
1568 * @brief This converts a mapped tag number to the actual tag number.
1569 *
1570 * @param[in] pMe The decode context.
1571 * @param[in] uMappedTagNumber The stored tag number.
1572 *
1573 * @return The actual tag number is returned or
1574 * @ref CBOR_TAG_INVALID64 on error.
1575 *
1576 * This is the reverse of MapTagNumber()
1577 */
1578static uint64_t
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001579QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe,
1580 const uint16_t uMappedTagNumber)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001581{
1582 if(uMappedTagNumber <= QCBOR_LAST_UNMAPPED_TAG) {
1583 return uMappedTagNumber;
1584 } else if(uMappedTagNumber == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07001585 return CBOR_TAG_INVALID64;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001586 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001587 /* This won't be negative because of code below in
1588 * MapTagNumber()
1589 */
1590 const unsigned uIndex = uMappedTagNumber - (QCBOR_LAST_UNMAPPED_TAG + 1);
1591 return pMe->auMappedTags[uIndex];
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001592 }
1593}
Laurence Lundblade37286c02022-09-03 10:05:02 -07001594#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001595
Laurence Lundblade9b334962020-08-27 10:55:53 -07001596
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001597/**
1598 * @brief Aggregate all tags wrapping a data item (decode layer 4).
1599 *
1600 * @param[in] pMe Decoder context
1601 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001602 *
1603 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1604 * features
1605 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1606 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1607 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1608 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1609 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1610 * of half-precision disabled
1611 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1612 * float decode is disabled.
1613 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1614 * simple type in input.
1615 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1616 * in input, but indefinite
1617 * lengths disabled.
1618 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1619 * but no string allocator.
1620 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1621 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1622 * input, but indefinite-length
1623 * strings are disabled.
1624 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001625 *
1626 * This loops getting atomic data items until one is not a tag
1627 * number. Usually this is largely pass-through because most
1628 * item are not tag numbers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001629 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001630static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001631QCBORDecode_Private_GetNextTagNumber(QCBORDecodeContext *pMe,
1632 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001633{
Laurence Lundblade37286c02022-09-03 10:05:02 -07001634#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001635 /* Accummulate the tags from multiple items here and then copy them
1636 * into the last item, the non-tag item.
1637 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001638 uint16_t auItemsTags[QCBOR_MAX_TAGS_PER_ITEM];
1639
1640 /* Initialize to CBOR_TAG_INVALID16 */
1641 #if CBOR_TAG_INVALID16 != 0xffff
1642 /* Be sure the memset does the right thing. */
1643 #err CBOR_TAG_INVALID16 tag not defined as expected
1644 #endif
1645 memset(auItemsTags, 0xff, sizeof(auItemsTags));
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001646
Laurence Lundblade9b334962020-08-27 10:55:53 -07001647 QCBORError uReturn = QCBOR_SUCCESS;
1648
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001649 /* Loop fetching data items until the item fetched is not a tag */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001650 for(;;) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001651 QCBORError uErr = QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07001652 if(uErr != QCBOR_SUCCESS) {
1653 uReturn = uErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001654 goto Done;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001655 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001656
Laurence Lundblade9b334962020-08-27 10:55:53 -07001657 if(pDecodedItem->uDataType != QCBOR_TYPE_TAG) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001658 /* Successful exit from loop; maybe got some tags, maybe not */
1659 memcpy(pDecodedItem->uTags, auItemsTags, sizeof(auItemsTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001660 break;
1661 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001662
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001663 if(auItemsTags[QCBOR_MAX_TAGS_PER_ITEM - 1] != CBOR_TAG_INVALID16) {
1664 /* No room in the tag list */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001665 uReturn = QCBOR_ERR_TOO_MANY_TAGS;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001666 /* Continue on to get all tags wrapping this item even though
1667 * it is erroring out in the end. This allows decoding to
1668 * continue. This is a resource limit error, not a problem
1669 * with being well-formed CBOR.
1670 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001671 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001672 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001673 /* Slide tags over one in the array to make room at index 0.
1674 * Must use memmove because the move source and destination
1675 * overlap.
1676 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001677 memmove(&auItemsTags[1],
1678 auItemsTags,
1679 sizeof(auItemsTags) - sizeof(auItemsTags[0]));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001680
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001681 /* Map the tag */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001682 uint16_t uMappedTagNumber = 0;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001683 uReturn = QCBORDecode_Private_MapTagNumber(pMe, pDecodedItem->val.uTagV, &uMappedTagNumber);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001684 /* Continue even on error so as to consume all tags wrapping
1685 * this data item so decoding can go on. If MapTagNumber()
1686 * errors once it will continue to error.
1687 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001688 auItemsTags[0] = uMappedTagNumber;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001689 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001690
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001691Done:
Laurence Lundblade9b334962020-08-27 10:55:53 -07001692 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001693
Laurence Lundblade37286c02022-09-03 10:05:02 -07001694#else /* QCBOR_DISABLE_TAGS */
1695
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07001696 return QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07001697
1698#endif /* QCBOR_DISABLE_TAGS */
1699}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001700
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001701
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001702/**
1703 * @brief Combine a map entry label and value into one item (decode layer 3).
1704 *
1705 * @param[in] pMe Decoder context
1706 * @param[out] pDecodedItem The decoded item that work is done on.
1707 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001708 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1709 * features
1710 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1711 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1712 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1713 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1714 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1715 * of half-precision disabled
1716 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1717 * float decode is disabled.
1718 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1719 * simple type in input.
1720 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1721 * in input, but indefinite
1722 * lengths disabled.
1723 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1724 * but no string allocator.
1725 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1726 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1727 * input, but indefinite-length
1728 * strings are disabled.
1729 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1730 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1731 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001732 *
Laurence Lundblade62cae932024-06-03 13:16:17 -07001733 * If the current nesting level is a map, then this
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001734 * combines pairs of items into one data item with a label
1735 * and value.
1736 *
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07001737 * This is passthrough if the current nesting level is
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001738 * not a map.
1739 *
1740 * This also implements maps-as-array mode where a map
1741 * is treated like an array to allow caller to do their
1742 * own label processing.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001743 */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001744
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001745static QCBORError
1746QCBORDecode_Private_GetNextMapEntry(QCBORDecodeContext *pMe,
1747 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001748{
Laurence Lundblade62cae932024-06-03 13:16:17 -07001749 QCBORItem LabelItem;
1750 QCBORError uErr;
1751
1752 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1753 if(QCBORDecode_IsUnrecoverableError(uErr)) {
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001754 goto Done;
1755 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001756
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001757 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
1758 /* Break can't be a map entry */
1759 goto Done;
1760 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001761
Laurence Lundblade62cae932024-06-03 13:16:17 -07001762 if(!DecodeNesting_IsCurrentTypeMap(&(pMe->nesting))) {
1763 /* Not decoding a map; nothing to do */
1764 /* This is where maps-as-arrays is effected too */
1765 goto Done;
1766 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001767
Laurence Lundblade62cae932024-06-03 13:16:17 -07001768 /* Decoding a map entry, so the item so far is the label; must get value */
1769 LabelItem = *pDecodedItem;
1770 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1771 if(QCBORDecode_IsUnrecoverableError(uErr)) {
1772 goto Done;
1773 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001774
Laurence Lundblade62cae932024-06-03 13:16:17 -07001775 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
1776 pDecodedItem->uLabelType = LabelItem.uDataType;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001777
Laurence Lundblade62cae932024-06-03 13:16:17 -07001778#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1779 /* QCBOR_DECODE_MODE_MAP_STRINGS_ONLY was a bad idea. Maybe
1780 * get rid of it in QCBOR 2.0
1781 */
1782 if(pMe->uDecodeMode == QCBOR_DECODE_MODE_MAP_STRINGS_ONLY &&
1783 LabelItem.uDataType != QCBOR_TYPE_TEXT_STRING) {
1784 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
1785 goto Done;
1786 }
1787#endif /* !QCBOR_DISABLE_NON_INTEGER_LABELS */
1788
1789 switch(LabelItem.uDataType) {
1790 case QCBOR_TYPE_INT64:
1791 pDecodedItem->label.int64 = LabelItem.val.int64;
1792 break;
1793
1794#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1795 case QCBOR_TYPE_UINT64:
1796 pDecodedItem->label.uint64 = LabelItem.val.uint64;
1797 break;
1798
1799 case QCBOR_TYPE_TEXT_STRING:
1800 case QCBOR_TYPE_BYTE_STRING:
1801 pDecodedItem->label.string = LabelItem.val.string;
1802 break;
1803#endif /* !QCBOR_DISABLE_NON_INTEGER_LABELS */
1804
1805 /* case QCBOR_TYPE_BREAK:
1806 uErr = 99;
1807 goto Done; */
1808
1809 default:
1810 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
1811 goto Done;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001812 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001813
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001814Done:
Laurence Lundblade62cae932024-06-03 13:16:17 -07001815 return uErr;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001816}
1817
1818
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001819#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001820/**
1821 * @brief Peek and see if next data item is a break;
1822 *
Laurence Lundblade62cae932024-06-03 13:16:17 -07001823 * param[in] pUIB UsefulInputBuf to read from.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001824 * @param[out] pbNextIsBreak Indicate if next was a break or not.
1825 *
1826 * @return Any decoding error.
1827 *
1828 * See if next item is a CBOR break. If it is, it is consumed,
1829 * if not it is not consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07001830*/
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001831static QCBORError
Laurence Lundblade62cae932024-06-03 13:16:17 -07001832QCBOR_Private_NextIsBreak(QCBORDecodeContext *pMe, bool *pbNextIsBreak)
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001833{
1834 *pbNextIsBreak = false;
Laurence Lundblade62cae932024-06-03 13:16:17 -07001835 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) != 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001836 QCBORItem Peek;
Laurence Lundblade62cae932024-06-03 13:16:17 -07001837 size_t uPeek = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade78a66132024-06-06 12:19:59 -07001838 QCBORError uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &Peek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001839 if(uReturn != QCBOR_SUCCESS) {
1840 return uReturn;
1841 }
1842 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001843 /* It is not a break, rewind so it can be processed normally. */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001844 UsefulInputBuf_Seek(&(pMe->InBuf), uPeek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001845 } else {
1846 *pbNextIsBreak = true;
1847 }
1848 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001849
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001850 return QCBOR_SUCCESS;
1851}
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001852#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001853
1854
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001855/**
1856 * @brief Ascend up nesting levels if all items in them have been consumed.
1857 *
1858 * @param[in] pMe The decode context.
1859 * @param[in] bMarkEnd If true mark end of maps/arrays with count of zero.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001860 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001861 *
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001862 * An item was just consumed, now figure out if it was the
1863 * end of an array/map map that can be closed out. That
1864 * may in turn close out the above array/map...
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001865 *
1866 * When ascending indefinite-length arrays and maps, this will correctly
1867 * consume the break for the level above. This is a problem for the
1868 * implementation of QCBORDecode_GetArray() that must not return
1869 * that break. @c pbBreak is set to true to indicate that one
1870 * byte should be removed.
1871 *
1872 * Improvement: this could reduced further if indef is disabled
1873 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001874static QCBORError
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001875QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd, bool *pbBreak)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001876{
1877 QCBORError uReturn;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001878
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001879 /* Loop ascending nesting levels as long as there is ascending to do */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001880 while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001881 if(pbBreak) {
1882 *pbBreak = false;
1883 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001884
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001885 if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) {
1886 /* Nesting level is bstr-wrapped CBOR */
1887
1888 /* Ascent for bstr-wrapped CBOR is always by explicit call
1889 * so no further ascending can happen.
1890 */
1891 break;
1892
1893 } else if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
1894 /* Level is a definite-length array/map */
1895
1896 /* Decrement the item count the definite-length array/map */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001897 DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(&(pMe->nesting));
1898 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001899 /* Didn't close out array/map, so all work here is done */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001900 break;
1901 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001902 /* All items in a definite-length array were consumed so it
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001903 * is time to ascend one level. This happens below.
1904 */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001905
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001906#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001907 } else {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001908 /* Level is an indefinite-length array/map. */
1909
1910 /* Check for a break which is what ends indefinite-length arrays/maps */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001911 bool bIsBreak = false;
Laurence Lundblade62cae932024-06-03 13:16:17 -07001912 uReturn = QCBOR_Private_NextIsBreak(pMe, &bIsBreak);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001913 if(uReturn != QCBOR_SUCCESS) {
1914 goto Done;
1915 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001916
1917 if(!bIsBreak) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001918 /* Not a break so array/map does not close out. All work is done */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001919 break;
1920 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001921
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001922 /* It was a break in an indefinitelength map / array so
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001923 * it is time to ascend one level.
1924 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001925 if(pbBreak) {
1926 *pbBreak = true;
1927 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001928
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001929#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001930 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001931
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001932
1933 /* All items in the array/map have been consumed. */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001934
Laurence Lundblade93d89472020-10-03 22:30:50 -07001935 /* But ascent in bounded mode is only by explicit call to
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001936 * QCBORDecode_ExitBoundedMode().
1937 */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07001938 if(DecodeNesting_IsCurrentBounded(&(pMe->nesting))) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001939 /* Set the count to zero for definite-length arrays to indicate
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001940 * cursor is at end of bounded array/map */
Laurence Lundbladed0304932020-06-27 10:59:38 -07001941 if(bMarkEnd) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001942 /* Used for definite and indefinite to signal end */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07001943 DecodeNesting_ZeroMapOrArrayCount(&(pMe->nesting));
Laurence Lundbladed0304932020-06-27 10:59:38 -07001944
Laurence Lundblade2c1faf92020-06-26 22:43:56 -07001945 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001946 break;
1947 }
1948
1949 /* Finally, actually ascend one level. */
1950 DecodeNesting_Ascend(&(pMe->nesting));
1951 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001952
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001953 uReturn = QCBOR_SUCCESS;
1954
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001955#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001956Done:
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001957#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1958
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001959 return uReturn;
1960}
1961
1962
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001963/**
1964 * @brief Ascending & Descending out of nesting levels (decode layer 2).
1965 *
1966 * @param[in] pMe Decoder context
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001967 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001968 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001969
1970 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1971 * features
1972 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1973 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1974 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1975 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1976 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1977 * of half-precision disabled
1978 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1979 * float decode is disabled.
1980 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1981 * simple type in input.
1982 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1983 * in input, but indefinite
1984 * lengths disabled.
1985 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1986 * but no string allocator.
1987 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1988 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1989 * input, but indefinite-length
1990 * strings are disabled.
1991 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1992 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1993 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
1994 * @retval QCBOR_ERR_NO_MORE_ITEMS Need more items for map or array.
1995 * @retval QCBOR_ERR_BAD_BREAK Indefinite-length break in wrong
1996 * place.
1997 * @retval QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP Nesting deeper than QCBOR
1998 * can handle.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001999 *
2000 * This handles the traversal descending into and asecnding out of
2001 * maps, arrays and bstr-wrapped CBOR. It figures out the ends of
2002 * definite- and indefinte-length maps and arrays by looking at the
2003 * item count or finding CBOR breaks. It detects the ends of the
2004 * top-level sequence and of bstr-wrapped CBOR by byte count.
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002005 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002006static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002007QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002008 bool *pbBreak,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002009 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002010{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002011 QCBORError uReturn;
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002012 /* ==== First: figure out if at the end of a traversal ==== */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002013
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002014 /* If out of bytes to consume, it is either the end of the
2015 * top-level sequence of some bstr-wrapped CBOR that was entered.
2016 *
2017 * In the case of bstr-wrapped CBOR, the length of the
2018 * UsefulInputBuf was set to that of the bstr-wrapped CBOR. When
2019 * the bstr-wrapped CBOR is exited, the length is set back to the
2020 * top-level's length or to the next highest bstr-wrapped CBOR.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002021 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002022 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) == 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002023 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002024 goto Done;
2025 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07002026
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002027 /* Check to see if at the end of a bounded definite-length map or
2028 * array. The check for a break ending indefinite-length array is
2029 * later in QCBORDecode_NestLevelAscender().
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002030 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002031 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002032 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002033 goto Done;
2034 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002035
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002036 /* ==== Next: not at the end, so get another item ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002037 uReturn = QCBORDecode_Private_GetNextMapEntry(pMe, pDecodedItem);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002038 if(QCBORDecode_IsUnrecoverableError(uReturn)) {
2039 /* Error is so bad that traversal is not possible. */
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002040 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002041 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05302042
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002043 /* Breaks ending arrays/maps are processed later in the call to
2044 * QCBORDecode_NestLevelAscender(). They should never show up here.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002045 */
Laurence Lundblade6de37062018-10-15 12:22:42 +05302046 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002047 uReturn = QCBOR_ERR_BAD_BREAK;
Laurence Lundblade6de37062018-10-15 12:22:42 +05302048 goto Done;
Laurence Lundblade5b8c5852018-10-14 21:11:42 +05302049 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002050
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002051 /* Record the nesting level for this data item before processing
2052 * any of decrementing and descending.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002053 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002054 pDecodedItem->uNestingLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002055
Laurence Lundblade642282a2020-06-23 12:00:33 -07002056
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002057 /* ==== Next: Process the item for descent, ascent, decrement... ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002058 if(QCBORItem_IsMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002059 /* If the new item is a map or array, descend.
2060 *
2061 * Empty indefinite-length maps and arrays are descended into,
2062 * but then ascended out of in the next chunk of code.
2063 *
2064 * Maps and arrays do count as items in the map/array that
2065 * encloses them so a decrement needs to be done for them too,
2066 * but that is done only when all the items in them have been
2067 * processed, not when they are opened with the exception of an
2068 * empty map or array.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002069 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002070 QCBORError uDescendErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002071 uDescendErr = DecodeNesting_DescendMapOrArray(&(pMe->nesting),
Laurence Lundblade642282a2020-06-23 12:00:33 -07002072 pDecodedItem->uDataType,
2073 pDecodedItem->val.uCount);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002074 if(uDescendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002075 /* This error is probably a traversal error and it overrides
2076 * the non-traversal error.
2077 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002078 uReturn = uDescendErr;
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002079 goto Done;
2080 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002081 }
2082
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002083 if(!QCBORItem_IsMapOrArray(*pDecodedItem) ||
2084 QCBORItem_IsEmptyDefiniteLengthMapOrArray(*pDecodedItem) ||
2085 QCBORItem_IsIndefiniteLengthMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002086 /* The following cases are handled here:
2087 * - A non-aggregate item like an integer or string
2088 * - An empty definite-length map or array
2089 * - An indefinite-length map or array that might be empty or might not.
2090 *
2091 * QCBORDecode_NestLevelAscender() does the work of decrementing the count
2092 * for an definite-length map/array and break detection for an
2093 * indefinite-0length map/array. If the end of the map/array was
2094 * reached, then it ascends nesting levels, possibly all the way
2095 * to the top level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002096 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002097 QCBORError uAscendErr;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002098 uAscendErr = QCBORDecode_Private_NestLevelAscender(pMe, true, pbBreak);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002099 if(uAscendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002100 /* This error is probably a traversal error and it overrides
2101 * the non-traversal error.
2102 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002103 uReturn = uAscendErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002104 goto Done;
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002105 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05302106 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002107
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002108 /* ==== Last: tell the caller the nest level of the next item ==== */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002109 /* Tell the caller what level is next. This tells them what
2110 * maps/arrays were closed out and makes it possible for them to
2111 * reconstruct the tree with just the information returned in a
2112 * QCBORItem.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002113 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002114 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07002115 /* At end of a bounded map/array; uNextNestLevel 0 to indicate this */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002116 pDecodedItem->uNextNestLevel = 0;
2117 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002118 pDecodedItem->uNextNestLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002119 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002120
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002121Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002122 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002123}
2124
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002125
Laurence Lundblade37286c02022-09-03 10:05:02 -07002126#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002127/**
2128 * @brief Shift 0th tag out of the tag list.
2129 *
2130 * pDecodedItem[in,out] The data item to convert.
2131 *
2132 * The 0th tag is discarded. \ref CBOR_TAG_INVALID16 is
2133 * shifted into empty slot at the end of the tag list.
2134 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002135static void
2136QCBOR_Private_ShiftTags(QCBORItem *pDecodedItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002137{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002138 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM-1; i++) {
2139 pDecodedItem->uTags[i] = pDecodedItem->uTags[i+1];
2140 }
2141 pDecodedItem->uTags[QCBOR_MAX_TAGS_PER_ITEM-1] = CBOR_TAG_INVALID16;
Laurence Lundblade9b334962020-08-27 10:55:53 -07002142}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002143#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002144
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002145
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002146/**
2147 * @brief Convert different epoch date formats in to the QCBOR epoch date format
2148 *
2149 * pDecodedItem[in,out] The data item to convert.
2150 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002151 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2152 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2153 * floating-point date disabled.
2154 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2155 * all floating-point disabled.
2156 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2157 * error decoding date.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002158 *
2159 * The epoch date tag defined in QCBOR allows for floating-point
2160 * dates. It even allows a protocol to flop between date formats when
2161 * ever it wants. Floating-point dates aren't that useful as they are
2162 * only needed for dates beyond the age of the earth.
2163 *
2164 * This converts all the date formats into one format of an unsigned
2165 * integer plus a floating-point fraction.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002166 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002167static QCBORError
2168QCBOR_Private_DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002169{
Laurence Lundbladec7114722020-08-13 05:11:40 -07002170 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002171
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002172#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade59289e52019-12-30 13:44:37 -08002173 pDecodedItem->val.epochDate.fSecondsFraction = 0;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002174#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002175
2176 switch (pDecodedItem->uDataType) {
2177
2178 case QCBOR_TYPE_INT64:
2179 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
2180 break;
2181
2182 case QCBOR_TYPE_UINT64:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002183 /* This only happens for CBOR type 0 > INT64_MAX so it is
2184 * always an overflow.
2185 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07002186 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2187 goto Done;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002188 break;
2189
2190 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade9682a532020-06-06 18:33:04 -07002191 case QCBOR_TYPE_FLOAT:
2192#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade59289e52019-12-30 13:44:37 -08002193 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002194 /* Convert working value to double if input was a float */
Laurence Lundblade3ed0bca2020-07-14 22:50:10 -07002195 const double d = pDecodedItem->uDataType == QCBOR_TYPE_DOUBLE ?
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002196 pDecodedItem->val.dfnum :
2197 (double)pDecodedItem->val.fnum;
2198
2199 /* The conversion from float to integer requires overflow
2200 * detection since floats can be much larger than integers.
2201 * This implementation errors out on these large float values
2202 * since they are beyond the age of the earth.
2203 *
2204 * These constants for the overflow check are computed by the
2205 * compiler. They are not computed at run time.
2206 *
2207 * The factor of 0x7ff is added/subtracted to avoid a
2208 * rounding error in the wrong direction when the compiler
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002209 * computes these constants. There is rounding because a
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002210 * 64-bit integer has 63 bits of precision where a double
2211 * only has 53 bits. Without the 0x7ff factor, the compiler
2212 * may round up and produce a double for the bounds check
2213 * that is larger than can be stored in a 64-bit integer. The
2214 * amount of 0x7ff is picked because it has 11 bits set.
2215 *
2216 * Without the 0x7ff there is a ~30 minute range of time
2217 * values 10 billion years in the past and in the future
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002218 * where this code could go wrong. Some compilers
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002219 * generate a warning or error without the 0x7ff.
2220 */
2221 const double dDateMax = (double)(INT64_MAX - 0x7ff);
2222 const double dDateMin = (double)(INT64_MIN + 0x7ff);
2223
2224 if(isnan(d) || d > dDateMax || d < dDateMin) {
Laurence Lundbladec7114722020-08-13 05:11:40 -07002225 uReturn = QCBOR_ERR_DATE_OVERFLOW;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002226 goto Done;
2227 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002228
2229 /* The actual conversion */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002230 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
Laurence Lundblade2feb1e12020-07-15 03:50:45 -07002231 pDecodedItem->val.epochDate.fSecondsFraction =
2232 d - (double)pDecodedItem->val.epochDate.nSeconds;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002233 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002234#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade4b270642020-08-14 12:53:07 -07002235
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002236 uReturn = QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundblade4b270642020-08-14 12:53:07 -07002237 goto Done;
2238
Laurence Lundblade9682a532020-06-06 18:33:04 -07002239#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002240 break;
2241
2242 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002243 /* It's the arrays and maps that are unrecoverable because
2244 * they are not consumed here. Since this is just an error
2245 * condition, no extra code is added here to make the error
2246 * recoverable for non-arrays and maps like strings. */
2247 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002248 goto Done;
2249 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002250
Laurence Lundblade59289e52019-12-30 13:44:37 -08002251 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
2252
2253Done:
Laurence Lundbladec7114722020-08-13 05:11:40 -07002254 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002255}
2256
2257
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002258/**
2259 * @brief Convert the days epoch date.
2260 *
2261 * pDecodedItem[in,out] The data item to convert.
2262 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002263 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2264 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2265 * floating-point date disabled.
2266 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2267 * all floating-point disabled.
2268 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2269 * error decoding date.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002270 *
2271 * This is much simpler than the other epoch date format because
2272 * floating-porint is not allowed. This is mostly a simple type check.
2273 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002274static QCBORError
2275QCBOR_Private_DecodeDaysEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002276{
2277 QCBORError uReturn = QCBOR_SUCCESS;
2278
2279 switch (pDecodedItem->uDataType) {
2280
2281 case QCBOR_TYPE_INT64:
2282 pDecodedItem->val.epochDays = pDecodedItem->val.int64;
2283 break;
2284
2285 case QCBOR_TYPE_UINT64:
2286 /* This only happens for CBOR type 0 > INT64_MAX so it is
2287 * always an overflow.
2288 */
2289 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2290 goto Done;
2291 break;
2292
2293 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002294 /* It's the arrays and maps that are unrecoverable because
2295 * they are not consumed here. Since this is just an error
2296 * condition, no extra code is added here to make the error
2297 * recoverable for non-arrays and maps like strings. */
2298 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002299 goto Done;
2300 break;
2301 }
2302
2303 pDecodedItem->uDataType = QCBOR_TYPE_DAYS_EPOCH;
2304
2305Done:
2306 return uReturn;
2307}
2308
2309
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002310#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade37286c02022-09-03 10:05:02 -07002311
2312/* Forward declaration is necessary for
2313 * QCBORDecode_MantissaAndExponent(). to be able to decode bignum
2314 * tags in the mantissa. If the mantissa is a decimal fraction or big
2315 * float in error, this will result in a recurive call to
2316 * QCBORDecode_MantissaAndExponent(), but the recursion will unwined
2317 * correctly and the correct error is returned.
2318 */
2319static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002320QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2321 QCBORItem *pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002322
2323
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002324/**
2325 * @brief Decode decimal fractions and big floats.
2326 *
2327 * @param[in] pMe The decode context.
2328 * @param[in,out] pDecodedItem On input the array data item that
2329 * holds the mantissa and exponent. On
2330 * output the decoded mantissa and
2331 * exponent.
2332 *
2333 * @returns Decoding errors from getting primitive data items or
2334 * \ref QCBOR_ERR_BAD_EXP_AND_MANTISSA.
2335 *
Laurence Lundblade37286c02022-09-03 10:05:02 -07002336 * When called pDecodedItem must be the array with two members, the
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002337 * exponent and mantissa.
2338 *
2339 * This will fetch and decode the exponent and mantissa and put the
2340 * result back into pDecodedItem.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002341 *
2342 * This does no checking or processing of tag numbers. That is to be
2343 * done by the code that calls this.
2344 *
2345 * This stuffs the type of the mantissa into pDecodedItem with the expectation
2346 * the caller will process it.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002347 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002348static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002349QCBORDecode_Private_ExpMantissa(QCBORDecodeContext *pMe,
2350 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002351{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002352 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002353
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002354 /* --- Make sure it is an array; track nesting level of members --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002355 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002356 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002357 goto Done;
2358 }
2359
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002360 /* A check for pDecodedItem->val.uCount == 2 would work for
Laurence Lundblade37286c02022-09-03 10:05:02 -07002361 * definite-length arrays, but not for indefinite. Instead remember
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002362 * the nesting level the two integers must be at, which is one
2363 * deeper than that of the array.
2364 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002365 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
2366
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002367 /* --- Get the exponent --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002368 QCBORItem exponentItem;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002369 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, &exponentItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002370 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002371 goto Done;
2372 }
2373 if(exponentItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002374 /* Array is empty or a map/array encountered when expecting an int */
2375 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002376 goto Done;
2377 }
2378 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002379 /* Data arriving as an unsigned int < INT64_MAX has been
2380 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2381 * also means that the only data arriving here of type
2382 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2383 * and thus an error that will get handled in the next else.
2384 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002385 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
2386 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002387 /* Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX */
2388 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002389 goto Done;
2390 }
2391
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002392 /* --- Get the mantissa --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002393 QCBORItem mantissaItem;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002394 uReturn = QCBORDecode_Private_GetNextTagContent(pMe, &mantissaItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002395 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002396 goto Done;
2397 }
2398 if(mantissaItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002399 /* Mantissa missing or map/array encountered when expecting number */
2400 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002401 goto Done;
2402 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002403 /* Stuff the mantissa data type into the item to send it up to the
2404 * the next level. */
2405 pDecodedItem->uDataType = mantissaItem.uDataType;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002406 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002407 /* Data arriving as an unsigned int < INT64_MAX has been
2408 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2409 * also means that the only data arriving here of type
2410 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2411 * and thus an error that will get handled in an else below.
2412 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002413 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002414#ifndef QCBOR_DISABLE_TAGS
2415 /* With tags fully disabled a big number mantissa will error out
2416 * in the call to QCBORDecode_GetNextWithTags() because it has
2417 * a tag number.
2418 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07002419 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM ||
2420 mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002421 /* Got a good big num mantissa */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002422 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002423#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002424 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002425 /* Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX */
2426 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002427 goto Done;
2428 }
2429
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002430 /* --- Check that array only has the two numbers --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002431 if(mantissaItem.uNextNestLevel == nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002432 /* Extra items in the decimal fraction / big float */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002433 /* Improvement: this should probably be an unrecoverable error. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002434 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002435 goto Done;
2436 }
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002437 pDecodedItem->uNextNestLevel = mantissaItem.uNextNestLevel;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002438
2439Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002440 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002441}
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002442#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002443
2444
Laurence Lundblade37286c02022-09-03 10:05:02 -07002445#ifndef QCBOR_DISABLE_TAGS
2446
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002447#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002448/**
2449 * @brief Decode the MIME type tag
2450 *
2451 * @param[in,out] pDecodedItem The item to decode.
2452 *
2453 * Handle the text and binary MIME type tags. Slightly too complicated
2454 * f or ProcessTaggedString() because the RFC 7049 MIME type was
2455 * incorreclty text-only.
2456 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002457static QCBORError
2458QCBOR_Private_DecodeMIME(QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002459{
2460 if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) {
2461 pDecodedItem->uDataType = QCBOR_TYPE_MIME;
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07002462 } else if(pDecodedItem->uDataType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002463 pDecodedItem->uDataType = QCBOR_TYPE_BINARY_MIME;
2464 } else {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002465 /* It's the arrays and maps that are unrecoverable because
2466 * they are not consumed here. Since this is just an error
2467 * condition, no extra code is added here to make the error
2468 * recoverable for non-arrays and maps like strings. */
2469 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002470 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002471
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002472 return QCBOR_SUCCESS;
2473}
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002474#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002475
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002476/**
Laurence Lundblade99615302020-11-29 11:19:47 -08002477 * Table of CBOR tags whose content is either a text string or a byte
2478 * string. The table maps the CBOR tag to the QCBOR type. The high-bit
2479 * of uQCBORtype indicates the content should be a byte string rather
2480 * than a text string
2481 */
2482struct StringTagMapEntry {
2483 uint16_t uTagNumber;
2484 uint8_t uQCBORtype;
2485};
2486
2487#define IS_BYTE_STRING_BIT 0x80
2488#define QCBOR_TYPE_MASK ~IS_BYTE_STRING_BIT
2489
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002490static const struct StringTagMapEntry QCBOR_Private_StringTagMap[] = {
Laurence Lundblade99615302020-11-29 11:19:47 -08002491 {CBOR_TAG_DATE_STRING, QCBOR_TYPE_DATE_STRING},
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002492 {CBOR_TAG_DAYS_STRING, QCBOR_TYPE_DAYS_STRING},
Laurence Lundblade99615302020-11-29 11:19:47 -08002493 {CBOR_TAG_POS_BIGNUM, QCBOR_TYPE_POSBIGNUM | IS_BYTE_STRING_BIT},
2494 {CBOR_TAG_NEG_BIGNUM, QCBOR_TYPE_NEGBIGNUM | IS_BYTE_STRING_BIT},
2495 {CBOR_TAG_CBOR, QBCOR_TYPE_WRAPPED_CBOR | IS_BYTE_STRING_BIT},
2496 {CBOR_TAG_URI, QCBOR_TYPE_URI},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002497#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002498 {CBOR_TAG_B64URL, QCBOR_TYPE_BASE64URL},
2499 {CBOR_TAG_B64, QCBOR_TYPE_BASE64},
2500 {CBOR_TAG_REGEX, QCBOR_TYPE_REGEX},
2501 {CBOR_TAG_BIN_UUID, QCBOR_TYPE_UUID | IS_BYTE_STRING_BIT},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002502#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade99615302020-11-29 11:19:47 -08002503 {CBOR_TAG_CBOR_SEQUENCE, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE | IS_BYTE_STRING_BIT},
2504 {CBOR_TAG_INVALID16, QCBOR_TYPE_NONE}
2505};
2506
2507
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002508/**
2509 * @brief Process standard CBOR tags whose content is a string
2510 *
2511 * @param[in] uTag The tag.
2512 * @param[in,out] pDecodedItem The data item.
2513 *
2514 * @returns This returns QCBOR_SUCCESS if the tag was procssed,
2515 * \ref QCBOR_ERR_UNSUPPORTED if the tag was not processed and
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002516 * \ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT if the content type was wrong for the tag.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002517 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002518 * Process the CBOR tags that whose content is a byte string or a text
2519 * string and for which the string is just passed on to the caller.
2520 *
2521 * This maps the CBOR tag to the QCBOR type and checks the content
2522 * type. Nothing more. It may not be the most important
Laurence Lundbladec02e13e2020-12-06 05:45:41 -08002523 * functionality, but it part of implementing as much of RFC 8949 as
Laurence Lundblade99615302020-11-29 11:19:47 -08002524 * possible.
Laurence Lundblade99615302020-11-29 11:19:47 -08002525 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002526static QCBORError
2527QCBOR_Private_ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002528{
Laurence Lundblade99615302020-11-29 11:19:47 -08002529 /* This only works on tags that were not mapped; no need for other yet */
2530 if(uTag > QCBOR_LAST_UNMAPPED_TAG) {
2531 return QCBOR_ERR_UNSUPPORTED;
2532 }
2533
2534 unsigned uIndex;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002535 for(uIndex = 0; QCBOR_Private_StringTagMap[uIndex].uTagNumber != CBOR_TAG_INVALID16; uIndex++) {
2536 if(QCBOR_Private_StringTagMap[uIndex].uTagNumber == uTag) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002537 break;
2538 }
2539 }
2540
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002541 const uint8_t uQCBORType = QCBOR_Private_StringTagMap[uIndex].uQCBORtype;
Laurence Lundblade99615302020-11-29 11:19:47 -08002542 if(uQCBORType == QCBOR_TYPE_NONE) {
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002543 /* repurpose this error to mean not handled here */
Laurence Lundblade99615302020-11-29 11:19:47 -08002544 return QCBOR_ERR_UNSUPPORTED;
2545 }
2546
2547 uint8_t uExpectedType = QCBOR_TYPE_TEXT_STRING;
2548 if(uQCBORType & IS_BYTE_STRING_BIT) {
2549 uExpectedType = QCBOR_TYPE_BYTE_STRING;
2550 }
2551
2552 if(pDecodedItem->uDataType != uExpectedType) {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002553 /* It's the arrays and maps that are unrecoverable because
2554 * they are not consumed here. Since this is just an error
2555 * condition, no extra code is added here to make the error
2556 * recoverable for non-arrays and maps like strings. */
2557 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002558 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002559
Laurence Lundblade99615302020-11-29 11:19:47 -08002560 pDecodedItem->uDataType = (uint8_t)(uQCBORType & QCBOR_TYPE_MASK);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002561 return QCBOR_SUCCESS;
2562}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002563#endif /* QCBOR_DISABLE_TAGS */
2564
2565
2566#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002567/**
2568 * @brief Figures out data type for exponent mantissa tags.
2569 *
2570 * @param[in] uTagToProcess Either @ref CBOR_TAG_DECIMAL_FRACTION or
2571 * @ref CBOR_TAG_BIG_FLOAT.
2572 * @param[in] pDecodedItem Item being decoded.
2573 *
2574 * @returns One of the 6 values between \ref QCBOR_TYPE_DECIMAL_FRACTION
2575 * and @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM.
2576 *
2577 * Does mapping between a CBOR tag number and a QCBOR type. with a
2578 * little bit of logic and arithmatic.
2579 *
2580 * Used in serveral contexts. Does the work where sometimes the data
2581 * item is explicitly tagged and sometimes not.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002582 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002583static uint8_t
2584QCBOR_Private_ExpMantissaDataType(const uint16_t uTagToProcess,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002585 const QCBORItem *pDecodedItem)
Laurence Lundblade37286c02022-09-03 10:05:02 -07002586{
2587 uint8_t uBase = uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ?
2588 QCBOR_TYPE_DECIMAL_FRACTION :
2589 QCBOR_TYPE_BIGFLOAT;
2590 if(pDecodedItem->uDataType != QCBOR_TYPE_INT64) {
2591 uBase = (uint8_t)(uBase + pDecodedItem->uDataType - QCBOR_TYPE_POSBIGNUM + 1);
2592 }
2593 return uBase;
2594}
2595#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002596
2597
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002598/**
2599 * @brief Decode tag content for select tags (decoding layer 1).
2600 *
2601 * @param[in] pMe The decode context.
2602 * @param[out] pDecodedItem The decoded item.
2603 *
2604 * @return Decoding error code.
2605 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002606 * CBOR tag numbers for the item were decoded in GetNext_TaggedItem(),
2607 * but the whole tag was not decoded. Here, the whole tags (tag number
2608 * and tag content) that are supported by QCBOR are decoded. This is a
2609 * quick pass through for items that are not tags.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002610 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002611static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002612QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2613 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002614{
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002615 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002616
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002617 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pDecodedItem);
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002618 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002619 goto Done;
2620 }
2621
Laurence Lundblade37286c02022-09-03 10:05:02 -07002622#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002623 /* When there are no tag numbers for the item, this exits first
2624 * thing and effectively does nothing.
2625 *
2626 * This loops over all the tag numbers accumulated for this item
2627 * trying to decode and interpret them. This stops at the end of
2628 * the list or at the first tag number that can't be interpreted by
2629 * this code. This is effectively a recursive processing of the
2630 * tags number list that handles nested tags.
2631 */
2632 while(1) {
2633 /* Don't bother to unmap tags via QCBORITem.uTags since this
2634 * code only works on tags less than QCBOR_LAST_UNMAPPED_TAG.
2635 */
2636 const uint16_t uTagToProcess = pDecodedItem->uTags[0];
Laurence Lundblade59289e52019-12-30 13:44:37 -08002637
Laurence Lundblade99615302020-11-29 11:19:47 -08002638 if(uTagToProcess == CBOR_TAG_INVALID16) {
2639 /* Hit the end of the tag list. A successful exit. */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002640 break;
2641
Laurence Lundblade99615302020-11-29 11:19:47 -08002642 } else if(uTagToProcess == CBOR_TAG_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002643 uReturn = QCBOR_Private_DecodeDateEpoch(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002644
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002645 } else if(uTagToProcess == CBOR_TAG_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002646 uReturn = QCBOR_Private_DecodeDaysEpoch(pDecodedItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002647
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002648#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade99615302020-11-29 11:19:47 -08002649 } else if(uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ||
2650 uTagToProcess == CBOR_TAG_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002651 uReturn = QCBORDecode_Private_ExpMantissa(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002652 /* --- Which is it, decimal fraction or a bigfloat? --- */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002653 pDecodedItem->uDataType = QCBOR_Private_ExpMantissaDataType(uTagToProcess, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002654
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002655#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002656#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002657 } else if(uTagToProcess == CBOR_TAG_MIME ||
2658 uTagToProcess == CBOR_TAG_BINARY_MIME) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002659 uReturn = QCBOR_Private_DecodeMIME(pDecodedItem);
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002660#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002661
Laurence Lundblade99615302020-11-29 11:19:47 -08002662 } else {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002663 /* See if it is a passthrough byte/text string tag; process if so */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002664 uReturn = QCBOR_Private_ProcessTaggedString(pDecodedItem->uTags[0], pDecodedItem);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002665
Laurence Lundblade99615302020-11-29 11:19:47 -08002666 if(uReturn == QCBOR_ERR_UNSUPPORTED) {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002667 /* It wasn't a passthrough byte/text string tag so it is
Laurence Lundblade99615302020-11-29 11:19:47 -08002668 * an unknown tag. This is the exit from the loop on the
2669 * first unknown tag. It is a successful exit.
2670 */
2671 uReturn = QCBOR_SUCCESS;
2672 break;
2673 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002674 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002675
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002676 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002677 /* Error exit from the loop */
2678 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002679 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002680
2681 /* A tag was successfully processed, shift it out of the list of
2682 * tags returned. This is the loop increment.
2683 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002684 QCBOR_Private_ShiftTags(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002685 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002686#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002687
2688Done:
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002689 return uReturn;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002690}
2691
2692
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002693/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002694 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002695 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002696QCBORError
2697QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2698{
2699 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002700 uErr = QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002701 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002702 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2703 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
2704 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002705 return uErr;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002706}
2707
2708
2709/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002710 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08002711 */
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002712QCBORError
2713QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2714{
2715 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2716 const UsefulInputBuf Save = pMe->InBuf;
2717
2718 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
2719
2720 pMe->nesting = SaveNesting;
2721 pMe->InBuf = Save;
2722
2723 return uErr;
2724}
2725
2726
2727/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002728 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002729 */
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002730void
2731QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2732{
2733 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002734 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2735 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002736 return;
2737 }
2738
2739 pMe->uLastError = (uint8_t)QCBORDecode_PeekNext(pMe, pDecodedItem);
2740}
2741
2742
2743/*
2744 * Public function, see header qcbor/qcbor_decode.h file
2745 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002746void
2747QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002748{
2749 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002750 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2751 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002752 return;
2753 }
2754
2755 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem);
2756}
2757
2758
2759/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002760 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002761 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002762QCBORError
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002763QCBORDecode_GetNextWithTags(QCBORDecodeContext *pMe,
2764 QCBORItem *pDecodedItem,
2765 QCBORTagListOut *pTags)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002766{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002767#ifndef QCBOR_DISABLE_TAGS
2768
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002769 QCBORError uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002770
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002771 uReturn = QCBORDecode_GetNext(pMe, pDecodedItem);
2772 if(uReturn != QCBOR_SUCCESS) {
2773 return uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002774 }
2775
2776 if(pTags != NULL) {
2777 pTags->uNumUsed = 0;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002778 /* Reverse the order because pTags is reverse of QCBORItem.uTags. */
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002779 for(int nTagIndex = QCBOR_MAX_TAGS_PER_ITEM-1; nTagIndex >=0; nTagIndex--) {
2780 if(pDecodedItem->uTags[nTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07002781 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002782 }
2783 if(pTags->uNumUsed >= pTags->uNumAllocated) {
2784 return QCBOR_ERR_TOO_MANY_TAGS;
2785 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002786 pTags->puTags[pTags->uNumUsed] = QCBORDecode_Private_UnMapTagNumber(pMe,pDecodedItem->uTags[nTagIndex]);
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002787 pTags->uNumUsed++;
2788 }
2789 }
2790
2791 return QCBOR_SUCCESS;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002792
2793#else /* QCBOR_DISABLE_TAGS */
2794 (void)pMe;
2795 (void)pDecodedItem;
2796 (void)pTags;
2797 return QCBOR_ERR_TAGS_DISABLED;
2798#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002799}
2800
2801
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002802/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002803 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05302804 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002805bool
2806QCBORDecode_IsTagged(QCBORDecodeContext *pMe,
2807 const QCBORItem *pItem,
2808 uint64_t uTag)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002809{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002810#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002811 for(unsigned uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) {
2812 if(pItem->uTags[uTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002813 break;
2814 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002815 if(QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uTagIndex]) == uTag) {
Laurence Lundbladef71e1622020-08-06 18:52:13 -07002816 return true;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002817 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002818 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002819#else /* QCBOR_TAGS_DISABLED */
2820 (void)pMe;
2821 (void)pItem;
2822 (void)uTag;
2823#endif /* QCBOR_TAGS_DISABLED */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002824
Laurence Lundbladef71e1622020-08-06 18:52:13 -07002825 return false;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002826}
2827
2828
2829/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002830 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002831 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002832QCBORError
2833QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002834{
Laurence Lundblade87495732021-02-26 10:05:55 -07002835 if(puConsumed != NULL) {
2836 *puConsumed = pMe->InBuf.cursor;
2837 }
2838
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002839 QCBORError uReturn = pMe->uLastError;
Laurence Lundblade085d7952020-07-24 10:26:30 -07002840
2841 if(uReturn != QCBOR_SUCCESS) {
2842 goto Done;
2843 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002844
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002845 /* Error out if all the maps/arrays are not closed out */
2846 if(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002847 uReturn = QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002848 goto Done;
2849 }
2850
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002851 /* Error out if not all the bytes are consumed */
2852 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf))) {
Laurence Lundblade085d7952020-07-24 10:26:30 -07002853 uReturn = QCBOR_ERR_EXTRA_BYTES;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002854 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002855
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002856Done:
Laurence Lundblade87495732021-02-26 10:05:55 -07002857 return uReturn;
2858}
2859
2860
2861/*
2862 * Public function, see header qcbor/qcbor_decode.h file
2863 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002864QCBORError
2865QCBORDecode_Finish(QCBORDecodeContext *pMe)
Laurence Lundblade87495732021-02-26 10:05:55 -07002866{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002867#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002868 /* Call the destructor for the string allocator if there is one.
2869 * Always called, even if there are errors; always have to clean up.
2870 */
2871 StringAllocator_Destruct(&(pMe->StringAllocator));
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002872#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002873
Laurence Lundblade87495732021-02-26 10:05:55 -07002874 return QCBORDecode_PartialFinish(pMe, NULL);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002875}
2876
2877
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002878/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002879 * Public function, see header qcbor/qcbor_decode.h file
2880 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002881uint64_t
2882QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
2883 const QCBORItem *pItem,
2884 uint32_t uIndex)
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002885{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002886#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002887 if(pItem->uDataType == QCBOR_TYPE_NONE) {
2888 return CBOR_TAG_INVALID64;
2889 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002890 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2891 return CBOR_TAG_INVALID64;
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002892 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002893 return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uIndex]);
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002894 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002895#else /* QCBOR_DISABLE_TAGS */
2896 (void)pMe;
2897 (void)pItem;
2898 (void)uIndex;
2899
2900 return CBOR_TAG_INVALID64;
2901#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002902}
2903
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002904
Laurence Lundblade9b334962020-08-27 10:55:53 -07002905/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002906 * Public function, see header qcbor/qcbor_decode.h file
2907 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002908uint64_t
2909QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe,
2910 uint32_t uIndex)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002911{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002912#ifndef QCBOR_DISABLE_TAGS
2913
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002914 if(pMe->uLastError != QCBOR_SUCCESS) {
2915 return CBOR_TAG_INVALID64;
2916 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002917 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2918 return CBOR_TAG_INVALID64;
2919 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002920 return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->uLastTags[uIndex]);
Laurence Lundblade9b334962020-08-27 10:55:53 -07002921 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002922#else /* QCBOR_DISABLE_TAGS */
2923 (void)pMe;
2924 (void)uIndex;
2925
2926 return CBOR_TAG_INVALID64;
2927#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07002928}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002929
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002930
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002931
2932
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002933#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladef6531662018-12-04 10:42:22 +09002934
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002935/* ===========================================================================
2936 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002937
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002938 This implements a simple sting allocator for indefinite-length
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002939 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
2940 implements the function type QCBORStringAllocate and allows easy
2941 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09002942
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002943 This particular allocator is built-in for convenience. The caller
2944 can implement their own. All of this following code will get
2945 dead-stripped if QCBORDecode_SetMemPool() is not called.
2946
2947 This is a very primitive memory allocator. It does not track
2948 individual allocations, only a high-water mark. A free or
2949 reallocation must be of the last chunk allocated.
2950
2951 The size of the pool and offset to free memory are packed into the
2952 first 8 bytes of the memory pool so we don't have to keep them in
2953 the decode context. Since the address of the pool may not be
2954 aligned, they have to be packed and unpacked as if they were
2955 serialized data of the wire or such.
2956
2957 The sizes packed in are uint32_t to be the same on all CPU types
2958 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08002959 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002960
2961
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002962static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08002963MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002964{
2965 // Use of UsefulInputBuf is overkill, but it is convenient.
2966 UsefulInputBuf UIB;
2967
Laurence Lundbladeee851742020-01-08 08:37:05 -08002968 // Just assume the size here. It was checked during SetUp so
2969 // the assumption is safe.
Laurence Lundblade93d89472020-10-03 22:30:50 -07002970 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem,QCBOR_DECODE_MIN_MEM_POOL_SIZE});
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002971 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
2972 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
2973 return UsefulInputBuf_GetError(&UIB);
2974}
2975
2976
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002977static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08002978MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002979{
2980 // Use of UsefulOutBuf is overkill, but convenient. The
2981 // length check performed here is useful.
2982 UsefulOutBuf UOB;
2983
2984 UsefulOutBuf_Init(&UOB, Pool);
2985 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
2986 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
2987 return UsefulOutBuf_GetError(&UOB);
2988}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002989
2990
2991/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002992 Internal function for an allocation, reallocation free and destuct.
2993
2994 Having only one function rather than one each per mode saves space in
2995 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002996
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002997 Code Reviewers: THIS FUNCTION DOES POINTER MATH
2998 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08002999static UsefulBuf
3000MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003001{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003002 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003003
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003004 uint32_t uPoolSize;
3005 uint32_t uFreeOffset;
3006
3007 if(uNewSize > UINT32_MAX) {
3008 // This allocator is only good up to 4GB. This check should
3009 // optimize out if sizeof(size_t) == sizeof(uint32_t)
3010 goto Done;
3011 }
3012 const uint32_t uNewSize32 = (uint32_t)uNewSize;
3013
3014 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
3015 goto Done;
3016 }
3017
3018 if(uNewSize) {
3019 if(pMem) {
3020 // REALLOCATION MODE
3021 // Calculate pointer to the end of the memory pool. It is
3022 // assumed that pPool + uPoolSize won't wrap around by
3023 // assuming the caller won't pass a pool buffer in that is
3024 // not in legitimate memory space.
3025 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
3026
3027 // Check that the pointer for reallocation is in the range of the
3028 // pool. This also makes sure that pointer math further down
3029 // doesn't wrap under or over.
3030 if(pMem >= pPool && pMem < pPoolEnd) {
3031 // Offset to start of chunk for reallocation. This won't
3032 // wrap under because of check that pMem >= pPool. Cast
3033 // is safe because the pool is always less than UINT32_MAX
3034 // because of check in QCBORDecode_SetMemPool().
3035 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3036
3037 // Check to see if the allocation will fit. uPoolSize -
3038 // uMemOffset will not wrap under because of check that
3039 // pMem is in the range of the uPoolSize by check above.
3040 if(uNewSize <= uPoolSize - uMemOffset) {
3041 ReturnValue.ptr = pMem;
3042 ReturnValue.len = uNewSize;
3043
3044 // Addition won't wrap around over because uNewSize was
3045 // checked to be sure it is less than the pool size.
3046 uFreeOffset = uMemOffset + uNewSize32;
3047 }
3048 }
3049 } else {
3050 // ALLOCATION MODE
3051 // uPoolSize - uFreeOffset will not underflow because this
3052 // pool implementation makes sure uFreeOffset is always
3053 // smaller than uPoolSize through this check here and
3054 // reallocation case.
3055 if(uNewSize <= uPoolSize - uFreeOffset) {
3056 ReturnValue.len = uNewSize;
3057 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08003058 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003059 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003060 }
3061 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003062 if(pMem) {
3063 // FREE MODE
3064 // Cast is safe because of limit on pool size in
3065 // QCBORDecode_SetMemPool()
3066 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3067 } else {
3068 // DESTRUCT MODE
3069 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003070 }
3071 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003072
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003073 UsefulBuf Pool = {pPool, uPoolSize};
3074 MemPool_Pack(Pool, uFreeOffset);
3075
3076Done:
3077 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003078}
3079
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003080
Laurence Lundbladef6531662018-12-04 10:42:22 +09003081/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003082 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09003083 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003084QCBORError
3085QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
3086 UsefulBuf Pool,
3087 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003088{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003089 // The pool size and free mem offset are packed into the beginning
Dave Thaler93c01182022-08-06 15:08:35 -04003090 // of the pool memory. This compile time check makes sure the
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003091 // constant in the header is correct. This check should optimize
3092 // down to nothing.
Dave Thaler93c01182022-08-06 15:08:35 -04003093#ifdef _MSC_VER
3094#pragma warning(push)
3095#pragma warning(disable:4127) // conditional expression is constant
3096#endif
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003097 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003098 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003099 }
Dave Thaler93c01182022-08-06 15:08:35 -04003100#ifdef _MSC_VER
3101#pragma warning(pop)
3102#endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003103
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003104 // The pool size and free offset packed in to the beginning of pool
3105 // memory are only 32-bits. This check will optimize out on 32-bit
3106 // machines.
3107 if(Pool.len > UINT32_MAX) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003108 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003109 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003110
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003111 // This checks that the pool buffer given is big enough.
3112 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003113 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003114 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003115
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003116 QCBORDecode_SetUpAllocator(pMe, MemPool_Function, Pool.ptr, bAllStrings);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003117
Laurence Lundblade30816f22018-11-10 13:40:22 +07003118 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003119}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003120#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003121
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003122
3123
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003124static void
3125QCBORDecode_Private_CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07003126{
Laurence Lundblade37286c02022-09-03 10:05:02 -07003127#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade9b334962020-08-27 10:55:53 -07003128 memcpy(pMe->uLastTags, pItem->uTags, sizeof(pItem->uTags));
Laurence Lundblade37286c02022-09-03 10:05:02 -07003129#else
3130 (void)pMe;
3131 (void)pItem;
3132#endif
Laurence Lundblade9b334962020-08-27 10:55:53 -07003133}
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003134
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003135
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003136/**
3137 * @brief Consume an entire map or array including its contents.
3138 *
3139 * @param[in] pMe The decoder context.
3140 * @param[in] pItemToConsume The array/map whose contents are to be
3141 * consumed.
3142 * @param[out] puNextNestLevel The next nesting level after the item was
3143 * fully consumed.
3144 *
3145 * This may be called when @c pItemToConsume is not an array or
3146 * map. In that case, this is just a pass through for @c puNextNestLevel
3147 * since there is nothing to do.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003148 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003149static QCBORError
3150QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
3151 const QCBORItem *pItemToConsume,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003152 bool *pbBreak,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003153 uint8_t *puNextNestLevel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003154{
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003155 QCBORError uReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003156 QCBORItem Item;
Laurence Lundblade9b334962020-08-27 10:55:53 -07003157
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003158 /* If it is a map or array, this will tell if it is empty. */
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003159 const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel);
3160
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003161 if(QCBORItem_IsMapOrArray(*pItemToConsume) && !bIsEmpty) {
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003162 /* There is only real work to do for non-empty maps and arrays */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003163
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003164 /* This works for definite- and indefinite-length maps and
3165 * arrays by using the nesting level
Laurence Lundblade1341c592020-04-11 14:19:05 -07003166 */
3167 do {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003168 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pbBreak, &Item);
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003169 if(QCBORDecode_IsUnrecoverableError(uReturn) ||
3170 uReturn == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003171 goto Done;
3172 }
3173 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003174
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003175 *puNextNestLevel = Item.uNextNestLevel;
3176
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003177 uReturn = QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003178
Laurence Lundblade1341c592020-04-11 14:19:05 -07003179 } else {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003180 /* pItemToConsume is not a map or array. Just pass the nesting
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003181 * level through. */
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003182 *puNextNestLevel = pItemToConsume->uNextNestLevel;
3183
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003184 uReturn = QCBOR_SUCCESS;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003185 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003186
3187Done:
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003188 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003189}
3190
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003191
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003192/*
3193 * Public function, see header qcbor/qcbor_decode.h file
3194 */
3195void
3196QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003197{
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003198 QCBORDecode_VGetNext(pMe, pDecodedItem);
3199
3200 if(pMe->uLastError == QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003201 pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL,
Máté Tóth-Pálc6d59682021-05-26 18:55:30 +02003202 &pDecodedItem->uNextNestLevel);
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003203 }
3204}
3205
3206
Laurence Lundblade11654912024-05-09 11:49:24 -07003207/*
3208 * Public function, see header qcbor/qcbor_decode.h file
3209 */
3210uint32_t
3211QCBORDecode_Tell(QCBORDecodeContext *pMe)
3212{
3213 size_t uCursorOffset;
3214
3215 if(pMe->uLastError != QCBOR_SUCCESS) {
3216 return UINT32_MAX;
3217 }
3218
3219 uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
3220
3221 if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
3222 return UINT32_MAX;
3223 } else {
3224 /* Cast is safe because decoder input size is restricted. */
3225 return (uint32_t)uCursorOffset;
3226 }
3227}
3228
3229
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003230/**
3231 * @brief Rewind cursor to start as if map or array were just entered.
3232 *
3233 * @param[in] pMe The decoding context
3234 *
3235 * This affects the nesting tracking and the UsefulInputBuf.
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003236 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003237static void
3238QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003239{
3240 /* Reset nesting tracking to the deepest bounded level */
3241 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3242
3243 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3244
3245 /* Reposition traversal cursor to the start of the map/array */
3246 UsefulInputBuf_Seek(&(pMe->InBuf),
3247 DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
3248}
3249
3250
3251/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003252 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003253 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003254void
3255QCBORDecode_Rewind(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003256{
3257 if(pMe->nesting.pCurrentBounded != NULL) {
3258 /* In a bounded map, array or bstr-wrapped CBOR */
3259
3260 if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
3261 /* In bstr-wrapped CBOR. */
3262
3263 /* Reposition traversal cursor to start of wrapping byte string */
3264 UsefulInputBuf_Seek(&(pMe->InBuf),
3265 pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
3266 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3267
3268 } else {
3269 /* In a map or array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003270 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003271 }
3272
3273 } else {
3274 /* Not in anything bounded */
3275
3276 /* Reposition traversal cursor to the start of input CBOR */
3277 UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
3278
3279 /* Reset nesting tracking to beginning of input. */
3280 DecodeNesting_Init(&(pMe->nesting));
3281 }
3282
3283 pMe->uLastError = QCBOR_SUCCESS;
3284}
3285
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003286
Laurence Lundblade9b334962020-08-27 10:55:53 -07003287
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003288
3289
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003290typedef struct {
3291 void *pCBContext;
3292 QCBORItemCallback pfCallback;
3293} MapSearchCallBack;
3294
3295typedef struct {
3296 size_t uStartOffset;
3297 uint16_t uItemCount;
3298} MapSearchInfo;
3299
3300
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003301/**
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003302 * @brief Search a map for a set of items.
3303 *
3304 * @param[in] pMe The decode context to search.
3305 * @param[in,out] pItemArray The items to search for and the items found.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003306 * @param[out] pInfo Several bits of meta-info returned by search.
3307 * @param[in] pCallBack Callback object or @c NULL.
3308 * TODO: fix params
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003309 *
3310 * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map.
3311 *
3312 * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label)
3313 * were found for one of the labels being
3314 * search for. This duplicate detection is
3315 * only performed for items in pItemArray,
3316 * not every item in the map.
3317 *
3318 * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was
3319 * wrong for the matchd label.
3320 *
3321 * @retval Also errors returned by QCBORDecode_GetNext().
3322 *
3323 * On input, \c pItemArray contains a list of labels and data types of
3324 * items to be found.
3325 *
3326 * On output, the fully retrieved items are filled in with values and
3327 * such. The label was matched, so it never changes.
3328 *
3329 * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE.
3330 *
3331 * This also finds the ends of maps and arrays when they are exited.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003332 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003333static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003334QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
3335 QCBORItem *pItemArray,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003336 MapSearchInfo *pInfo,
3337 MapSearchCallBack *pCallBack)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003338{
Laurence Lundbladee6f15112020-07-23 18:44:16 -07003339 QCBORError uReturn;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003340 uint64_t uFoundItemBitMap = 0;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07003341
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003342 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003343 uReturn = pMe->uLastError;
3344 goto Done2;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003345 }
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003346
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003347 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) &&
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003348 pItemArray->uLabelType != QCBOR_TYPE_NONE) {
3349 /* QCBOR_TYPE_NONE as first item indicates just looking
3350 for the end of an array, so don't give error. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003351 uReturn = QCBOR_ERR_MAP_NOT_ENTERED;
3352 goto Done2;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003353 }
3354
Laurence Lundblade085d7952020-07-24 10:26:30 -07003355 if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) {
3356 // It is an empty bounded array or map
3357 if(pItemArray->uLabelType == QCBOR_TYPE_NONE) {
3358 // Just trying to find the end of the map or array
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003359 pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003360 uReturn = QCBOR_SUCCESS;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003361 } else {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003362 // Nothing is ever found in an empty array or map. All items
3363 // are marked as not found below.
Laurence Lundblade085d7952020-07-24 10:26:30 -07003364 uReturn = QCBOR_SUCCESS;
3365 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003366 goto Done2;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003367 }
3368
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003369 QCBORDecodeNesting SaveNesting;
Laurence Lundblade11654912024-05-09 11:49:24 -07003370 size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003371 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3372
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003373 /* Reposition to search from the start of the map / array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003374 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundblade1341c592020-04-11 14:19:05 -07003375
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003376 /*
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003377 Loop over all the items in the map or array. Each item
3378 could be a map or array, but label matching is only at
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003379 the main level. This handles definite- and indefinite-
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003380 length maps and arrays. The only reason this is ever
3381 called on arrays is to find their end position.
3382
3383 This will always run over all items in order to do
3384 duplicate detection.
3385
3386 This will exit with failure if it encounters an
3387 unrecoverable error, but continue on for recoverable
3388 errors.
3389
3390 If a recoverable error occurs on a matched item, then
3391 that error code is returned.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003392 */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07003393 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003394 if(pInfo) {
3395 pInfo->uItemCount = 0;
3396 }
Máté Tóth-Pál2f2aa5f2021-05-17 21:35:09 +02003397 uint8_t uNextNestLevel;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003398 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003399 /* Remember offset of the item because sometimes it has to be returned */
Laurence Lundblade1341c592020-04-11 14:19:05 -07003400 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003401
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003402 /* Get the item */
3403 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003404 QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003405 if(QCBORDecode_IsUnrecoverableError(uResult)) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003406 /* The map/array can't be decoded when unrecoverable errors occur */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003407 uReturn = uResult;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003408 goto Done;
3409 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003410 if(uResult == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003411 /* Unexpected end of map or array. */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003412 uReturn = uResult;
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003413 goto Done;
3414 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003415
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003416 /* See if item has one of the labels that are of interest */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003417 bool bMatched = false;
3418 for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003419 if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003420 /* A label match has been found */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003421 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
3422 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003423 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003424 }
Laurence Lundblade63926052021-03-29 16:05:51 -07003425 if(uResult != QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003426 /* The label matches, but the data item is in error.
3427 * It is OK to have recoverable errors on items that are not
3428 * matched. */
Laurence Lundblade63926052021-03-29 16:05:51 -07003429 uReturn = uResult;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003430 goto Done;
3431 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003432 if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) {
Laurence Lundblade63926052021-03-29 16:05:51 -07003433 /* The data item is not of the type(s) requested */
3434 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003435 goto Done;
3436 }
3437
Laurence Lundblade1341c592020-04-11 14:19:05 -07003438 /* Successful match. Return the item. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003439 pItemArray[nIndex] = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003440 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003441 if(pInfo) {
3442 pInfo->uStartOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003443 }
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003444 bMatched = true;
3445 }
3446 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003447
3448
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003449 if(!bMatched && pCallBack != NULL) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003450 /*
3451 Call the callback on unmatched labels.
3452 (It is tempting to do duplicate detection here, but that would
3453 require dynamic memory allocation because the number of labels
3454 that might be encountered is unbounded.)
3455 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003456 uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item);
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003457 if(uReturn != QCBOR_SUCCESS) {
3458 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003459 }
3460 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003461
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003462 /*
3463 Consume the item whether matched or not. This
3464 does the work of traversing maps and array and
3465 everything in them. In this loop only the
3466 items at the current nesting level are examined
3467 to match the labels.
3468 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003469 uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel);
Laurence Lundbladec7114722020-08-13 05:11:40 -07003470 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003471 goto Done;
3472 }
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003473
3474 if(pInfo) {
3475 pInfo->uItemCount++;
3476 }
3477
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003478 } while (uNextNestLevel >= uMapNestLevel);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003479
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003480 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003481
3482 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003483
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003484 // Check here makes sure that this won't accidentally be
3485 // QCBOR_MAP_OFFSET_CACHE_INVALID which is larger than
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003486 // QCBOR_MAX_DECODE_INPUT_SIZE.
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -08003487 // Cast to uint32_t to possibly address cases where SIZE_MAX < UINT32_MAX
3488 if((uint32_t)uEndOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003489 uReturn = QCBOR_ERR_INPUT_TOO_LARGE;
3490 goto Done;
3491 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003492 /* Cast OK because encoded CBOR is limited to UINT32_MAX */
3493 pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003494
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003495 Done:
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003496 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade11654912024-05-09 11:49:24 -07003497 UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos);
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003498
3499 Done2:
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003500 /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */
Laurence Lundbladec7114722020-08-13 05:11:40 -07003501 for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003502 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003503 pItemArray[i].uDataType = QCBOR_TYPE_NONE;
3504 pItemArray[i].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003505 }
3506 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003507
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003508 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003509}
3510
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003511
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003512/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003513 * Public function, see header qcbor/qcbor_decode.h file
3514 */
3515void
3516QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
3517 int64_t nLabel,
3518 uint8_t uQcborType,
3519 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003520{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003521 if(pMe->uLastError != QCBOR_SUCCESS) {
3522 return;
3523 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003524
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003525 QCBORItem OneItemSeach[2];
3526 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3527 OneItemSeach[0].label.int64 = nLabel;
3528 OneItemSeach[0].uDataType = uQcborType;
3529 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003530
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003531 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003532
3533 *pItem = OneItemSeach[0];
3534
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003535 if(uReturn != QCBOR_SUCCESS) {
3536 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003537 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003538 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003539 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003540 }
3541
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003542 Done:
3543 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003544}
3545
3546
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003547/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003548 * Public function, see header qcbor/qcbor_decode.h file
3549 */
3550void
3551QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
3552 const char *szLabel,
3553 uint8_t uQcborType,
3554 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003555{
Laurence Lundbladeda095972020-06-06 18:35:33 -07003556 if(pMe->uLastError != QCBOR_SUCCESS) {
3557 return;
3558 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003559
Laurence Lundblade78a66132024-06-06 12:19:59 -07003560#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003561 QCBORItem OneItemSeach[2];
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003562 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3563 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3564 OneItemSeach[0].uDataType = uQcborType;
3565 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003566
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003567 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
3568
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003569 if(uReturn != QCBOR_SUCCESS) {
3570 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003571 }
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003572 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003573 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003574 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003575 }
3576
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003577 *pItem = OneItemSeach[0];
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003578Done:
Laurence Lundblade78a66132024-06-06 12:19:59 -07003579
3580#else
Laurence Lundblade9533c482024-06-06 21:41:10 -07003581 (void)pMe;
3582 (void)szLabel;
3583 (void)uQcborType;
3584 (void)pItem;
Laurence Lundblade78a66132024-06-06 12:19:59 -07003585 QCBORError uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
3586#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
3587
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003588 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003589}
3590
3591
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003592
3593/**
3594 * @brief Semi-private. Get pointer, length and item for an array or map.
3595 *
3596 * @param[in] pMe The decode context.
3597 * @param[in] uType CBOR major type, either array/map.
3598 * @param[out] pItem The item for the array/map.
3599 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3600 *
3601 * The next item to be decoded must be a map or array as specified by \c uType.
3602 *
3603 * \c pItem will be filled in with the label and tags of the array or map
3604 * in addition to \c pEncodedCBOR giving the pointer and length of the
3605 * encoded CBOR.
3606 *
3607 * When this is complete, the traversal cursor is at the end of the array or
3608 * map that was retrieved.
3609 */
3610void
3611QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe,
3612 const uint8_t uType,
3613 QCBORItem *pItem,
3614 UsefulBufC *pEncodedCBOR)
3615{
3616 QCBORError uErr;
3617 uint8_t uNestLevel;
3618 size_t uStartingCursor;
3619 size_t uStartOfReturned;
3620 size_t uEndOfReturned;
3621 size_t uTempSaveCursor;
3622 bool bInMap;
3623 QCBORItem LabelItem;
3624 bool EndedByBreak;
3625
3626 uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3627 bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting));
3628
3629 /* Could call GetNext here, but don't need to because this
3630 * is only interested in arrays and maps. */
3631 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem);
3632 if(uErr != QCBOR_SUCCESS) {
3633 pMe->uLastError = (uint8_t)uErr;
3634 return;
3635 }
3636
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003637 uint8_t uItemDataType = pItem->uDataType;
Laurence Lundblade62cae932024-06-03 13:16:17 -07003638#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003639 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
3640 uItemDataType = QCBOR_TYPE_ARRAY;
3641 }
Laurence Lundblade78a66132024-06-06 12:19:59 -07003642#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003643
3644 if(uItemDataType != uType) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003645 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
3646 return;
3647 }
3648
3649 if(bInMap) {
3650 /* If the item is in a map, the start of the array/map
3651 * itself, not the label, must be found. Do this by
3652 * rewinding to the starting position and fetching
3653 * just the label data item. QCBORDecode_Private_GetNextTagNumber()
3654 * doesn't do any of the array/map item counting or nesting
3655 * level tracking. Used here it will just fetech the label
3656 * data item.
3657 *
3658 * Have to save the cursor and put it back to the position
3659 * after the full item once the label as been fetched by
3660 * itself.
3661 */
3662 uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3663 UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor);
3664
3665 /* Item has been fetched once so safe to ignore error */
3666 (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem);
3667
3668 uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3669 UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor);
3670 } else {
3671 uStartOfReturned = uStartingCursor;
3672 }
3673
3674 /* Consume the entire array/map to find the end */
3675 uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel);
3676 if(uErr != QCBOR_SUCCESS) {
3677 pMe->uLastError = (uint8_t)uErr;
3678 goto Done;
3679 }
3680
3681 /* Fill in returned values */
3682 uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3683 if(EndedByBreak) {
3684 /* When ascending nesting levels, a break for the level above
3685 * was consumed. That break is not a part of what is consumed here. */
3686 uEndOfReturned--;
3687 }
3688 pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned);
3689 pEncodedCBOR->len = uEndOfReturned - uStartOfReturned;
3690
3691Done:
3692 return;
3693}
3694
3695
3696/**
3697 * @brief Semi-private. Get pointer, length and item count of an array or map.
3698 *
3699 * @param[in] pMe The decode context.
3700 * @param[in] pTarget The label and type of the array or map to retrieve.
3701 * @param[out] pItem The item for the array/map.
3702 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3703 *
3704 * The next item to be decoded must be a map or array as specified by \c uType.
3705 *
3706 * When this is complete, the traversal cursor is unchanged.
3707 */void
3708QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe,
3709 QCBORItem *pTarget,
3710 QCBORItem *pItem,
3711 UsefulBufC *pEncodedCBOR)
3712{
3713 MapSearchInfo Info;
3714 QCBORDecodeNesting SaveNesting;
3715 size_t uSaveCursor;
3716
3717 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL);
3718 if(pMe->uLastError != QCBOR_SUCCESS) {
3719 return;
3720 }
3721
3722 /* Save the whole position of things so they can be restored.
3723 * so the cursor position is unchanged by this operation, like
3724 * all the other GetXxxxInMap() operations. */
3725 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3726 uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3727
3728 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3729 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
3730 QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR);
3731
3732 UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor);
3733 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
3734}
3735
3736
3737
3738
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003739/**
3740 * @brief Is a QCBOR_TYPE in the type list?
3741 *
3742 * @param[in] uDataType Type to check for.
3743 * @param[in] puTypeList List to check.
3744 *
3745 * @retval QCBOR_SUCCESS If in the list.
3746 * @retval QCBOR_ERR_UNEXPECTED_TYPE Not in the list.
3747 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07003748static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003749QCBOR_Private_CheckTypeList(const int uDataType,
3750 const uint8_t puTypeList[QCBOR_TAGSPEC_NUM_TYPES])
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003751{
3752 for(size_t i = 0; i < QCBOR_TAGSPEC_NUM_TYPES; i++) {
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003753 if(uDataType == puTypeList[i]) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003754 return QCBOR_SUCCESS;
3755 }
3756 }
3757 return QCBOR_ERR_UNEXPECTED_TYPE;
3758}
3759
Laurence Lundblade67257dc2020-07-27 03:33:37 -07003760
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003761/**
Laurence Lundblade37286c02022-09-03 10:05:02 -07003762 * Match a tag/type specification against the type of the item.
3763 *
3764 * @param[in] TagSpec Specification for matching tags.
3765 * @param[in] pItem The item to check.
3766 *
3767 * @retval QCBOR_SUCCESS \c uDataType is allowed by @c TagSpec
3768 * @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec
3769 *
3770 * This checks the item data type of untagged items as well as of
3771 * tagged items against a specification to see if decoding should
3772 * proceed.
3773 *
3774 * This relies on the automatic tag decoding done by QCBOR that turns
3775 * tag numbers into particular QCBOR_TYPEs so there is no actual
3776 * comparsion of tag numbers, just of QCBOR_TYPEs.
3777 *
3778 * This checks the data item type as possibly representing the tag
3779 * number or as the tag content type.
3780 *
3781 * If QCBOR_DISABLE_TAGS is #defined, this primarily checks the item
3782 * data type against the allowed tag content types. It will also error out
3783 * if the caller tries to require a tag because there is no way that can
3784 * ever be fulfilled.
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003785 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07003786static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003787QCBOR_Private_CheckTagRequirement(const QCBOR_Private_TagSpec TagSpec,
3788 const QCBORItem *pItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07003789{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003790 const int nItemType = pItem->uDataType; /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade37286c02022-09-03 10:05:02 -07003791 const int nTagReq = TagSpec.uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
3792
3793#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003794 /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003795 if(!(TagSpec.uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS) &&
3796 pItem->uTags[0] != CBOR_TAG_INVALID16) {
3797 /* There are tags that QCBOR couldn't process on this item and
Laurence Lundblade37286c02022-09-03 10:05:02 -07003798 * the caller has told us there should not be.
3799 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003800 return QCBOR_ERR_UNEXPECTED_TYPE;
3801 }
3802
Laurence Lundblade9b334962020-08-27 10:55:53 -07003803 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
Laurence Lundblade37286c02022-09-03 10:05:02 -07003804 /* Must match the tag number and only the tag */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003805 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003806 }
3807
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003808 QCBORError uReturn = QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003809 if(uReturn == QCBOR_SUCCESS) {
3810 return QCBOR_SUCCESS;
3811 }
3812
3813 if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
3814 /* Must match the content type and only the content type.
Laurence Lundblade37286c02022-09-03 10:05:02 -07003815 * There was no match just above so it is a fail. */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003816 return QCBOR_ERR_UNEXPECTED_TYPE;
3817 }
3818
Laurence Lundblade37286c02022-09-03 10:05:02 -07003819 /* QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG: If here it can match either the tag or the content
3820 * and it hasn't matched the content, so the end
3821 * result is whether it matches the tag. This is
3822 * the tag optional case that the CBOR standard discourages.
3823 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003824
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003825 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003826
Laurence Lundblade37286c02022-09-03 10:05:02 -07003827#else /* QCBOR_DISABLE_TAGS */
3828 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
3829 return QCBOR_ERR_UNEXPECTED_TYPE;
3830 }
3831
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07003832 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade37286c02022-09-03 10:05:02 -07003833
3834#endif /* QCBOR_DISABLE_TAGS */
3835}
Laurence Lundblade9b334962020-08-27 10:55:53 -07003836
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003837
3838/**
3839 * @brief Get an item by label to match a tag specification.
3840 *
3841 * @param[in] pMe The decode context.
3842 * @param[in] nLabel The label to search map for.
3843 * @param[in] TagSpec The tag number specification to match.
3844 * @param[out] pItem The item found.
3845 *
3846 * This finds the item with the given label in currently open
3847 * map. Then checks that its tag number and types matches the tag
3848 * specification. If not, an error is set in the decode context.
3849 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003850static void
3851QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
3852 const int64_t nLabel,
3853 const QCBOR_Private_TagSpec TagSpec,
3854 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003855{
3856 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
3857 if(pMe->uLastError != QCBOR_SUCCESS) {
3858 return;
3859 }
3860
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003861 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003862}
3863
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07003864
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003865/**
3866 * @brief Get an item by label to match a tag specification.
3867 *
3868 * @param[in] pMe The decode context.
3869 * @param[in] szLabel The label to search map for.
3870 * @param[in] TagSpec The tag number specification to match.
3871 * @param[out] pItem The item found.
3872 *
3873 * This finds the item with the given label in currently open
3874 * map. Then checks that its tag number and types matches the tag
3875 * specification. If not, an error is set in the decode context.
3876 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003877static void
3878QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
3879 const char *szLabel,
3880 const QCBOR_Private_TagSpec TagSpec,
3881 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003882{
3883 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
3884 if(pMe->uLastError != QCBOR_SUCCESS) {
3885 return;
3886 }
3887
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003888 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003889}
3890
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003891
3892/**
3893 * @brief Semi-private to get an string by label to match a tag specification.
3894 *
3895 * @param[in] pMe The decode context.
3896 * @param[in] nLabel The label to search map for.
3897 * @param[in] TagSpec The tag number specification to match.
3898 * @param[out] pString The string found.
3899 *
3900 * This finds the string with the given label in currently open
3901 * map. Then checks that its tag number and types matches the tag
3902 * specification. If not, an error is set in the decode context.
3903 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003904void
3905QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
3906 const int64_t nLabel,
3907 const QCBOR_Private_TagSpec TagSpec,
3908 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003909{
3910 QCBORItem Item;
3911 QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
3912 if(pMe->uLastError == QCBOR_SUCCESS) {
3913 *pString = Item.val.string;
3914 }
3915}
3916
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003917
3918/**
3919 * @brief Semi-private to get an string by label to match a tag specification.
3920 *
3921 * @param[in] pMe The decode context.
3922 * @param[in] szLabel The label to search map for.
3923 * @param[in] TagSpec The tag number specification to match.
3924 * @param[out] pString The string found.
3925 *
3926 * This finds the string with the given label in currently open
3927 * map. Then checks that its tag number and types matches the tag
3928 * specification. If not, an error is set in the decode context.
3929 */void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003930QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
3931 const char * szLabel,
3932 const QCBOR_Private_TagSpec TagSpec,
3933 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003934{
3935 QCBORItem Item;
3936 QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
3937 if(pMe->uLastError == QCBOR_SUCCESS) {
3938 *pString = Item.val.string;
3939 }
3940}
Laurence Lundblade1341c592020-04-11 14:19:05 -07003941
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003942
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003943/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003944 * Public function, see header qcbor/qcbor_decode.h file
3945 */
3946void
3947QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003948{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003949 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL);
Laurence Lundblade5f53f832020-09-03 12:00:14 -07003950 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003951}
3952
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003953/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003954 * Public function, see header qcbor/qcbor_decode.h file
3955 */
3956void
3957QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe,
3958 QCBORItem *pItemList,
3959 void *pCallbackCtx,
3960 QCBORItemCallback pfCB)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003961{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003962 MapSearchCallBack CallBack;
3963 CallBack.pCBContext = pCallbackCtx;
3964 CallBack.pfCallback = pfCB;
3965
3966 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack);
3967
Laurence Lundblade5f53f832020-09-03 12:00:14 -07003968 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003969}
3970
3971
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08003972/**
3973 * @brief Search for a map/array by label and enter it
3974 *
3975 * @param[in] pMe The decode context.
3976 * @param[in] pSearch The map/array to search for.
3977 *
3978 * @c pSearch is expected to contain one item of type map or array
3979 * with the label specified. The current bounded map will be searched for
3980 * this and if found will be entered.
3981 *
3982 * If the label is not found, or the item found is not a map or array,
3983 * the error state is set.
3984 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003985static void
3986QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07003987{
Laurence Lundblade323f8a92020-09-06 19:43:09 -07003988 // The first item in pSearch is the one that is to be
3989 // entered. It should be the only one filled in. Any other
3990 // will be ignored unless it causes an error.
Laurence Lundblade34691b92020-05-18 22:25:25 -07003991 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07003992 return;
3993 }
3994
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003995 MapSearchInfo Info;
3996 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pSearch, &Info, NULL);
Laurence Lundblade34691b92020-05-18 22:25:25 -07003997 if(pMe->uLastError != QCBOR_SUCCESS) {
3998 return;
3999 }
4000
Laurence Lundblade9b334962020-08-27 10:55:53 -07004001 if(pSearch->uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004002 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004003 return;
4004 }
4005
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004006
4007 /* The map or array was found. Now enter it.
4008 *
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004009 * QCBORDecode_EnterBoundedMapOrArray() used here, requires the
4010 * next item for the pre-order traversal cursor to be the map/array
4011 * found by MapSearch(). The next few lines of code force the
4012 * cursor to that.
4013 *
4014 * There is no need to retain the old cursor because
4015 * QCBORDecode_EnterBoundedMapOrArray() will set it to the
4016 * beginning of the map/array being entered.
4017 *
4018 * The cursor is forced by: 1) setting the input buffer position to
4019 * the item offset found by MapSearch(), 2) setting the map/array
4020 * counter to the total in the map/array, 3) setting the nesting
4021 * level. Setting the map/array counter to the total is not
4022 * strictly correct, but this is OK because this cursor only needs
4023 * to be used to get one item and MapSearch() has already found it
4024 * confirming it exists.
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004025 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004026 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004027
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004028 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
4029
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004030 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07004031
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004032 QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004033}
4034
4035
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004036/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004037 * Public function, see header qcbor/qcbor_decode.h file
4038 */
4039void
4040QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004041{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004042 QCBORItem OneItemSeach[2];
4043 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4044 OneItemSeach[0].label.int64 = nLabel;
4045 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4046 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004047
Laurence Lundblade9b334962020-08-27 10:55:53 -07004048 /* The map to enter was found, now finish off entering it. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004049 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004050}
4051
4052
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004053/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004054 * Public function, see header qcbor/qcbor_decode.h file
4055 */
4056void
4057QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004058{
Laurence Lundblade78a66132024-06-06 12:19:59 -07004059#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004060 QCBORItem OneItemSeach[2];
4061 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4062 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4063 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4064 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004065
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004066 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade78a66132024-06-06 12:19:59 -07004067#else
Laurence Lundblade9533c482024-06-06 21:41:10 -07004068 (void)szLabel;
4069 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade78a66132024-06-06 12:19:59 -07004070#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004071}
4072
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004073/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004074 * Public function, see header qcbor/qcbor_decode.h file
4075 */
4076void
4077QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07004078{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004079 QCBORItem OneItemSeach[2];
4080 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4081 OneItemSeach[0].label.int64 = nLabel;
4082 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4083 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004084
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004085 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07004086}
4087
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004088/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004089 * Public function, see header qcbor/qcbor_decode.h file
4090 */
4091void
4092QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundblade34691b92020-05-18 22:25:25 -07004093{
Laurence Lundblade78a66132024-06-06 12:19:59 -07004094#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004095 QCBORItem OneItemSeach[2];
4096 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4097 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4098 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4099 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004100
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004101 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade78a66132024-06-06 12:19:59 -07004102#else
Laurence Lundblade9533c482024-06-06 21:41:10 -07004103 (void)szLabel;
4104 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade78a66132024-06-06 12:19:59 -07004105#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade1341c592020-04-11 14:19:05 -07004106}
4107
4108
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004109/**
4110 * @brief Semi-private to do the the work for EnterMap() and EnterArray().
4111 *
4112 * @param[in] pMe The decode context
4113 * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY.
4114 * @param[out] pItem The data item for the map or array entered.
4115 *
4116 * The next item in the traversal must be a map or array. This
4117 * consumes that item and does the book keeping to enter the map or
4118 * array.
4119 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004120void
4121QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe,
4122 const uint8_t uType,
4123 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004124{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004125 QCBORError uErr;
4126
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004127 /* Must only be called on maps and arrays. */
Laurence Lundblade34691b92020-05-18 22:25:25 -07004128 if(pMe->uLastError != QCBOR_SUCCESS) {
4129 // Already in error state; do nothing.
4130 return;
4131 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07004132
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004133 /* Get the data item that is the map or array being entered. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004134 QCBORItem Item;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004135 uErr = QCBORDecode_GetNext(pMe, &Item);
4136 if(uErr != QCBOR_SUCCESS) {
4137 goto Done;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07004138 }
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004139
4140 uint8_t uItemDataType = Item.uDataType;
Laurence Lundblade78a66132024-06-06 12:19:59 -07004141
Laurence Lundblade62cae932024-06-03 13:16:17 -07004142#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004143 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) {
4144 uItemDataType = QCBOR_TYPE_ARRAY;
4145 }
Laurence Lundblade78a66132024-06-06 12:19:59 -07004146#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade95606972024-06-07 11:32:12 -07004147
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004148 if(uItemDataType != uType) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004149 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
4150 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004151 }
4152
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004153 QCBORDecode_Private_CopyTags(pMe, &Item);
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004154
4155
Laurence Lundbladef0499502020-08-01 11:55:57 -07004156 const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
Laurence Lundblade085d7952020-07-24 10:26:30 -07004157 if(bIsEmpty) {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004158 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
4159 // Undo decrement done by QCBORDecode_GetNext() so the the
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004160 // the decrement when exiting the map/array works correctly
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004161 pMe->nesting.pCurrent->u.ma.uCountCursor++;
4162 }
Laurence Lundblade93d89472020-10-03 22:30:50 -07004163 // Special case to increment nesting level for zero-length maps
4164 // and arrays entered in bounded mode.
Laurence Lundbladee6f15112020-07-23 18:44:16 -07004165 DecodeNesting_Descend(&(pMe->nesting), uType);
4166 }
4167
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004168 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004169
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004170 uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty,
4171 UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004172
Laurence Lundblade6545d1b2020-10-14 11:13:13 -07004173 if(pItem != NULL) {
4174 *pItem = Item;
4175 }
4176
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004177Done:
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004178 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004179}
4180
Laurence Lundblade02625d42020-06-25 14:41:41 -07004181
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004182/**
4183 * @brief Exit a bounded map, array or bstr (semi-private).
4184 *
4185 * @param[in] pMe Decode context.
4186 * @param[in] uEndOffset The input buffer offset of the end of item exited.
4187 *
4188 * @returns QCBOR_SUCCESS or an error code.
4189 *
4190 * This is the common work for exiting a level that is a bounded map,
4191 * array or bstr wrapped CBOR.
4192 *
4193 * One chunk of work is to set up the pre-order traversal so it is at
4194 * the item just after the bounded map, array or bstr that is being
4195 * exited. This is somewhat complex.
4196 *
4197 * The other work is to level-up the bounded mode to next higest
4198 * bounded mode or the top level if there isn't one.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004199 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004200static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004201QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
4202 const uint32_t uEndOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004203{
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004204 QCBORError uErr;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004205
Laurence Lundblade02625d42020-06-25 14:41:41 -07004206 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004207 * First the pre-order-traversal byte offset is positioned to the
4208 * item just after the bounded mode item that was just consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004209 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004210 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
4211
Laurence Lundblade02625d42020-06-25 14:41:41 -07004212 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004213 * Next, set the current nesting level to one above the bounded
4214 * level that was just exited.
4215 *
4216 * DecodeNesting_CheckBoundedType() is always called before this
4217 * and makes sure pCurrentBounded is valid.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004218 */
4219 DecodeNesting_LevelUpCurrent(&(pMe->nesting));
4220
4221 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004222 * This does the complex work of leveling up the pre-order
4223 * traversal when the end of a map or array or another bounded
4224 * level is reached. It may do nothing, or ascend all the way to
4225 * the top level.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004226 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004227 uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004228 if(uErr != QCBOR_SUCCESS) {
4229 goto Done;
4230 }
4231
Laurence Lundblade02625d42020-06-25 14:41:41 -07004232 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004233 * This makes the next highest bounded level the current bounded
4234 * level. If there is no next highest level, then no bounded mode
4235 * is in effect.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004236 */
4237 DecodeNesting_LevelUpBounded(&(pMe->nesting));
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004238
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004239 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004240
4241Done:
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004242 return uErr;
4243}
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004244
Laurence Lundblade02625d42020-06-25 14:41:41 -07004245
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004246/**
4247 * @brief Get started exiting a map or array (semi-private)
4248 *
4249 * @param[in] pMe The decode context
4250 * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP
4251 *
4252 * This does some work for map and array exiting (but not
4253 * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel()
4254 * is called to do the rest.
4255 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004256void
4257QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe,
4258 const uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004259{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004260 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07004261 /* Already in error state; do nothing. */
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004262 return;
4263 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004264
Laurence Lundblade02625d42020-06-25 14:41:41 -07004265 QCBORError uErr;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004266
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004267 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004268 uErr = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004269 goto Done;
4270 }
4271
Laurence Lundblade02625d42020-06-25 14:41:41 -07004272 /*
4273 Have to set the offset to the end of the map/array
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004274 that is being exited. If there is no cached value,
Laurence Lundblade02625d42020-06-25 14:41:41 -07004275 from previous map search, then do a dummy search.
4276 */
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004277 if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004278 QCBORItem Dummy;
4279 Dummy.uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004280 uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL);
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004281 if(uErr != QCBOR_SUCCESS) {
4282 goto Done;
4283 }
4284 }
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004285
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004286 uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004287
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004288Done:
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004289 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004290}
4291
4292
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004293/**
4294 * @brief The main work of entering some byte-string wrapped CBOR.
4295 *
4296 * @param[in] pMe The decode context.
4297 * @param[in] pItem The byte string item.
4298 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX
4299 * @param[out] pBstr Pointer and length of byte string entered.
4300 *
4301 * This is called once the byte string item has been decoded to do all
4302 * the book keeping work for descending a nesting level into the
4303 * nested CBOR.
4304 *
4305 * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement.
4306 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004307static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004308QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe,
4309 const QCBORItem *pItem,
4310 const uint8_t uTagRequirement,
4311 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004312{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004313 if(pBstr) {
4314 *pBstr = NULLUsefulBufC;
4315 }
4316
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004317 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004318 /* Already in error state; do nothing. */
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004319 return pMe->uLastError;
4320 }
4321
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004322 QCBORError uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004323
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004324 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004325 {
4326 uTagRequirement,
4327 {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE},
4328 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4329 };
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004330
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004331 uError = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004332 if(uError != QCBOR_SUCCESS) {
4333 goto Done;
4334 }
4335
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004336 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004337 /* Reverse the decrement done by GetNext() for the bstr so the
4338 * increment in QCBORDecode_NestLevelAscender() called by
4339 * ExitBoundedLevel() will work right.
4340 */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004341 DecodeNesting_ReverseDecrement(&(pMe->nesting));
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07004342 }
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004343
4344 if(pBstr) {
4345 *pBstr = pItem->val.string;
4346 }
4347
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004348 /* This saves the current length of the UsefulInputBuf and then
4349 * narrows the UsefulInputBuf to start and length of the wrapped
4350 * CBOR that is being entered.
4351 *
4352 * Most of these calls are simple inline accessors so this doesn't
4353 * amount to much code.
4354 */
4355
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004356 const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004357 /* This check makes the cast of uPreviousLength to uint32_t below safe. */
4358 if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004359 uError = QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladef76a2622020-08-06 19:51:03 -07004360 goto Done;
4361 }
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004362
4363 const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
4364 pItem->val.string.ptr);
4365 /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
4366 if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
4367 /* This should never happen because pItem->val.string.ptr should
4368 * always be valid since it was just returned.
4369 */
4370 uError = QCBOR_ERR_INPUT_TOO_LARGE;
4371 goto Done;
4372 }
4373
4374 const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
4375
4376 UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004377 UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004378
Laurence Lundblade02625d42020-06-25 14:41:41 -07004379 uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004380 (uint32_t)uPreviousLength,
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004381 (uint32_t)uStartOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004382Done:
4383 return uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004384}
4385
4386
Laurence Lundblade02625d42020-06-25 14:41:41 -07004387/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004388 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004389 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004390void
4391QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe,
4392 const uint8_t uTagRequirement,
4393 UsefulBufC *pBstr)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004394{
4395 if(pMe->uLastError != QCBOR_SUCCESS) {
4396 // Already in error state; do nothing.
4397 return;
4398 }
4399
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004400 /* Get the data item that is the byte string being entered */
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004401 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004402 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4403 if(pMe->uLastError != QCBOR_SUCCESS) {
4404 return;
4405 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004406
Laurence Lundblade31fddb72024-05-13 13:03:35 -07004407 if(Item.uDataAlloc) {
4408 pMe->uLastError = QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
4409 return;
4410 }
4411
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004412 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4413 &Item,
4414 uTagRequirement,
4415 pBstr);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004416}
4417
4418
Laurence Lundblade02625d42020-06-25 14:41:41 -07004419/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004420 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004421 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004422void
4423QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe,
4424 const int64_t nLabel,
4425 const uint8_t uTagRequirement,
4426 UsefulBufC *pBstr)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004427{
4428 QCBORItem Item;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004429 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004430
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004431 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4432 &Item,
4433 uTagRequirement,
4434 pBstr);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004435}
4436
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004437
Laurence Lundblade02625d42020-06-25 14:41:41 -07004438/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004439 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004440 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004441void
4442QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe,
4443 const char *szLabel,
4444 const uint8_t uTagRequirement,
4445 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004446{
4447 QCBORItem Item;
4448 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4449
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004450 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4451 &Item,
4452 uTagRequirement,
4453 pBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004454}
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004455
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004456
Laurence Lundblade02625d42020-06-25 14:41:41 -07004457/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004458 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004459 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004460void
4461QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004462{
Laurence Lundblade02625d42020-06-25 14:41:41 -07004463 if(pMe->uLastError != QCBOR_SUCCESS) {
4464 // Already in error state; do nothing.
4465 return;
4466 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004467
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004468 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004469 pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade02625d42020-06-25 14:41:41 -07004470 return;
4471 }
4472
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004473 const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
4474
Laurence Lundblade02625d42020-06-25 14:41:41 -07004475 /*
4476 Reset the length of the UsefulInputBuf to what it was before
4477 the bstr wrapped CBOR was entered.
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004478 */
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004479 UsefulInputBuf_SetBufferLength(&(pMe->InBuf),
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004480 DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004481
4482
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004483 QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004484 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004485}
4486
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004487
Laurence Lundbladee6430642020-03-14 21:15:44 -07004488
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004489/**
4490 * @brief Process simple type true and false, a boolean
4491 *
4492 * @param[in] pMe The decode context.
4493 * @param[in] pItem The item with either true or false.
4494 * @param[out] pBool The boolean value output.
4495 *
4496 * Sets the internal error if the item isn't a true or a false. Also
4497 * records any tag numbers as the tag numbers of the last item.
4498 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004499static void
4500QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe,
4501 const QCBORItem *pItem,
4502 bool *pBool)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004503{
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004504 if(pMe->uLastError != QCBOR_SUCCESS) {
4505 /* Already in error state, do nothing */
4506 return;
4507 }
4508
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004509 switch(pItem->uDataType) {
4510 case QCBOR_TYPE_TRUE:
4511 *pBool = true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004512 break;
4513
4514 case QCBOR_TYPE_FALSE:
4515 *pBool = false;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004516 break;
4517
4518 default:
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004519 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004520 break;
4521 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004522 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004523}
Laurence Lundbladee6430642020-03-14 21:15:44 -07004524
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004525
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004526/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004527 * Public function, see header qcbor/qcbor_decode.h file
4528 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004529void
4530QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004531{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004532 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004533 /* Already in error state, do nothing */
Laurence Lundbladee6430642020-03-14 21:15:44 -07004534 return;
4535 }
4536
Laurence Lundbladec4537442020-04-14 18:53:22 -07004537 QCBORItem Item;
4538
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004539 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4540
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004541 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004542}
4543
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004544
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004545/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004546 * Public function, see header qcbor/qcbor_decode.h file
4547 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004548void
4549QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe,
4550 const int64_t nLabel,
4551 bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004552{
4553 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004554 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004555
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004556 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004557}
4558
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004559
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004560/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004561 * Public function, see header qcbor/qcbor_decode.h file
4562 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004563void
4564QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe,
4565 const char *szLabel,
4566 bool *pValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004567{
4568 QCBORItem Item;
4569 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4570
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004571 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004572}
4573
4574
4575
Laurence Lundbladec7114722020-08-13 05:11:40 -07004576
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004577/**
4578 * @brief Common processing for an epoch date.
4579 *
4580 * @param[in] pMe The decode context.
4581 * @param[in] pItem The item with the date.
4582 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4583 * @param[out] pnTime The returned date.
4584 *
4585 * Common processing for the date tag. Mostly make sure the tag
4586 * content is correct and copy forward any further other tag numbers.
4587 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004588static void
4589QCBORDecode_Private_ProcessEpochDate(QCBORDecodeContext *pMe,
4590 QCBORItem *pItem,
4591 const uint8_t uTagRequirement,
4592 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004593{
4594 if(pMe->uLastError != QCBOR_SUCCESS) {
4595 // Already in error state, do nothing
4596 return;
4597 }
4598
4599 QCBORError uErr;
4600
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004601 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladec7114722020-08-13 05:11:40 -07004602 {
4603 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004604 {QCBOR_TYPE_DATE_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4605 {QCBOR_TYPE_INT64, QCBOR_TYPE_DOUBLE, QCBOR_TYPE_FLOAT, QCBOR_TYPE_UINT64}
Laurence Lundbladec7114722020-08-13 05:11:40 -07004606 };
4607
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004608 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004609 if(uErr != QCBOR_SUCCESS) {
4610 goto Done;
4611 }
4612
4613 if(pItem->uDataType != QCBOR_TYPE_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004614 uErr = QCBOR_Private_DecodeDateEpoch(pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004615 if(uErr != QCBOR_SUCCESS) {
4616 goto Done;
4617 }
4618 }
4619
Laurence Lundblade9b334962020-08-27 10:55:53 -07004620 // Save the tags in the last item's tags in the decode context
4621 // for QCBORDecode_GetNthTagOfLast()
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004622 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07004623
Laurence Lundbladec7114722020-08-13 05:11:40 -07004624 *pnTime = pItem->val.epochDate.nSeconds;
4625
4626Done:
4627 pMe->uLastError = (uint8_t)uErr;
4628}
4629
4630
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004631
4632/*
4633 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4634 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004635void
4636QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
4637 uint8_t uTagRequirement,
4638 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004639{
4640 if(pMe->uLastError != QCBOR_SUCCESS) {
4641 // Already in error state, do nothing
4642 return;
4643 }
4644
4645 QCBORItem Item;
4646 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4647
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004648 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004649}
4650
4651
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004652/*
4653 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4654 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07004655void
4656QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
4657 int64_t nLabel,
4658 uint8_t uTagRequirement,
4659 int64_t *pnTime)
4660{
4661 QCBORItem Item;
4662 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004663 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004664}
4665
4666
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004667/*
4668 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4669 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07004670void
4671QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
4672 const char *szLabel,
4673 uint8_t uTagRequirement,
4674 int64_t *pnTime)
4675{
4676 QCBORItem Item;
4677 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004678 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004679}
4680
4681
4682
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004683/**
4684 * @brief Common processing for an epoch date.
4685 *
4686 * @param[in] pMe The decode context.
4687 * @param[in] pItem The item with the date.
4688 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4689 * @param[out] pnDays The returned day count.
4690 *
4691 * Common processing for the RFC 8943 day-count tag. Mostly make sure
4692 * the tag content is correct and copy forward any further other tag
4693 * numbers.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004694 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004695static void
4696QCBORDecode_Private_ProcessEpochDays(QCBORDecodeContext *pMe,
4697 QCBORItem *pItem,
4698 uint8_t uTagRequirement,
4699 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004700{
4701 if(pMe->uLastError != QCBOR_SUCCESS) {
4702 /* Already in error state, do nothing */
4703 return;
4704 }
4705
4706 QCBORError uErr;
4707
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004708 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004709 {
4710 uTagRequirement,
4711 {QCBOR_TYPE_DAYS_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4712 {QCBOR_TYPE_INT64, QCBOR_TYPE_UINT64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4713 };
4714
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004715 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004716 if(uErr != QCBOR_SUCCESS) {
4717 goto Done;
4718 }
4719
4720 if(pItem->uDataType != QCBOR_TYPE_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004721 uErr = QCBOR_Private_DecodeDaysEpoch(pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004722 if(uErr != QCBOR_SUCCESS) {
4723 goto Done;
4724 }
4725 }
4726
4727 /* Save the tags in the last item's tags in the decode context
4728 * for QCBORDecode_GetNthTagOfLast()
4729 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004730 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004731
4732 *pnDays = pItem->val.epochDays;
4733
4734Done:
4735 pMe->uLastError = (uint8_t)uErr;
4736}
4737
4738
4739/*
4740 * Public function, see header qcbor/qcbor_decode.h
4741 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004742void
4743QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe,
4744 uint8_t uTagRequirement,
4745 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004746{
4747 if(pMe->uLastError != QCBOR_SUCCESS) {
4748 /* Already in error state, do nothing */
4749 return;
4750 }
4751
4752 QCBORItem Item;
4753 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4754
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004755 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004756}
4757
4758
4759/*
4760 * Public function, see header qcbor/qcbor_decode.h
4761 */
4762void
4763QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe,
4764 int64_t nLabel,
4765 uint8_t uTagRequirement,
4766 int64_t *pnDays)
4767{
4768 QCBORItem Item;
4769 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004770 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004771}
4772
4773
4774/*
4775 * Public function, see header qcbor/qcbor_decode.h
4776 */
4777void
4778QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe,
4779 const char *szLabel,
4780 uint8_t uTagRequirement,
4781 int64_t *pnDays)
4782{
4783 QCBORItem Item;
4784 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004785 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004786}
4787
4788
4789
Laurence Lundblade37286c02022-09-03 10:05:02 -07004790/*
4791 * @brief Get a string that matches the type/tag specification.
4792 */
4793void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004794QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
4795 const QCBOR_Private_TagSpec TagSpec,
4796 UsefulBufC *pBstr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004797{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004798 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade37286c02022-09-03 10:05:02 -07004799 /* Already in error state, do nothing */
Laurence Lundbladec4537442020-04-14 18:53:22 -07004800 return;
4801 }
4802
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004803 QCBORError uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004804 QCBORItem Item;
4805
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004806 uError = QCBORDecode_GetNext(pMe, &Item);
4807 if(uError != QCBOR_SUCCESS) {
4808 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004809 return;
4810 }
4811
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004812 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004813
4814 if(pMe->uLastError == QCBOR_SUCCESS) {
4815 *pBstr = Item.val.string;
Laurence Lundbladeab40c6f2020-08-28 11:24:58 -07004816 } else {
4817 *pBstr = NULLUsefulBufC;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004818 }
4819}
4820
Laurence Lundbladec4537442020-04-14 18:53:22 -07004821
4822
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004823
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004824/**
4825 * @brief Common processing for a big number tag.
4826 *
4827 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4828 * @param[in] pItem The item with the date.
4829 * @param[out] pValue The returned big number
4830 * @param[out] pbIsNegative The returned sign of the big number.
4831 *
4832 * Common processing for the big number tag. Mostly make sure
4833 * the tag content is correct and copy forward any further other tag
4834 * numbers.
4835 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004836static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004837QCBOR_Private_ProcessBigNum(const uint8_t uTagRequirement,
4838 const QCBORItem *pItem,
4839 UsefulBufC *pValue,
4840 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004841{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004842 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004843 {
4844 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004845 {QCBOR_TYPE_POSBIGNUM, QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4846 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004847 };
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004848
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004849 QCBORError uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004850 if(uErr != QCBOR_SUCCESS) {
4851 return uErr;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004852 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004853
4854 *pValue = pItem->val.string;
4855
4856 if(pItem->uDataType == QCBOR_TYPE_POSBIGNUM) {
4857 *pbIsNegative = false;
4858 } else if(pItem->uDataType == QCBOR_TYPE_NEGBIGNUM) {
4859 *pbIsNegative = true;
4860 }
4861
4862 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004863}
4864
4865
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004866/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004867 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004868 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004869void
4870QCBORDecode_GetBignum(QCBORDecodeContext *pMe,
4871 const uint8_t uTagRequirement,
4872 UsefulBufC *pValue,
4873 bool *pbIsNegative)
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004874{
4875 if(pMe->uLastError != QCBOR_SUCCESS) {
4876 // Already in error state, do nothing
4877 return;
4878 }
4879
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004880 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004881 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
4882 if(uError != QCBOR_SUCCESS) {
4883 pMe->uLastError = (uint8_t)uError;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004884 return;
4885 }
4886
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004887 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4888 &Item,
4889 pValue,
4890 pbIsNegative);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004891}
4892
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004893
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004894/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004895 * Public function, see header qcbor/qcbor_spiffy_decode.h
4896 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004897void
4898QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe,
4899 const int64_t nLabel,
4900 const uint8_t uTagRequirement,
4901 UsefulBufC *pValue,
4902 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004903{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004904 QCBORItem Item;
4905 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004906 if(pMe->uLastError != QCBOR_SUCCESS) {
4907 return;
4908 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004909
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004910 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4911 &Item,
4912 pValue,
4913 pbIsNegative);
Laurence Lundbladec4537442020-04-14 18:53:22 -07004914}
4915
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004916
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004917/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004918 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004919 */
4920void
4921QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe,
4922 const char *szLabel,
4923 const uint8_t uTagRequirement,
4924 UsefulBufC *pValue,
4925 bool *pbIsNegative)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004926{
4927 QCBORItem Item;
4928 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004929 if(pMe->uLastError != QCBOR_SUCCESS) {
4930 return;
4931 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004932
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004933 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4934 &Item,
4935 pValue,
4936 pbIsNegative);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004937}
4938
4939
4940
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004941/**
4942 * @brief Common processing for MIME tag (semi-private).
4943 *
4944 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4945 * @param[in] pItem The item with the date.
4946 * @param[out] pMessage The returned MIME message.
4947 * @param[out] pbIsTag257 If true, binary MIME, if not, text MIME.
4948 *
4949 * Common processing for the MIME tag. Mostly make sure the tag
4950 * content is correct and copy forward any further other tag
4951 * numbers. See QCBORDecode_GetMIMEMessage().
4952 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004953QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004954QCBORDecode_Private_GetMIME(const uint8_t uTagRequirement,
Laurence Lundblade37286c02022-09-03 10:05:02 -07004955 const QCBORItem *pItem,
4956 UsefulBufC *pMessage,
4957 bool *pbIsTag257)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004958{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004959 const QCBOR_Private_TagSpec TagSpecText =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004960 {
4961 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004962 {QCBOR_TYPE_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4963 {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004964 };
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004965 const QCBOR_Private_TagSpec TagSpecBinary =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004966 {
4967 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004968 {QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4969 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004970 };
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004971
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004972 QCBORError uReturn;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004973
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004974 if(QCBOR_Private_CheckTagRequirement(TagSpecText, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004975 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07004976 if(pbIsTag257 != NULL) {
4977 *pbIsTag257 = false;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004978 }
4979 uReturn = QCBOR_SUCCESS;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004980 } else if(QCBOR_Private_CheckTagRequirement(TagSpecBinary, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004981 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07004982 if(pbIsTag257 != NULL) {
4983 *pbIsTag257 = true;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004984 }
4985 uReturn = QCBOR_SUCCESS;
4986
4987 } else {
4988 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
4989 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07004990
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004991 return uReturn;
4992}
4993
Laurence Lundblade93d89472020-10-03 22:30:50 -07004994// Improvement: add methods for wrapped CBOR, a simple alternate
4995// to EnterBstrWrapped
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004996
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004997
4998
4999
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005000#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundbladee6430642020-03-14 21:15:44 -07005001
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005002/**
5003 * @brief Prototype for conversion of exponent and mantissa to unsigned integer.
5004 *
5005 * @param[in] uMantissa The mantissa.
5006 * @param[in] nExponent The exponent.
5007 * @param[out] puResult The resulting integer.
5008 *
5009 * Concrete implementations of this are for exponent base 10 and 2 supporting
5010 * decimal fractions and big floats.
5011 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005012typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005013
5014
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005015/**
5016 * @brief Base 10 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5017 *
5018 * @param[in] uMantissa The unsigned integer mantissa.
5019 * @param[in] nExponent The signed integer exponent.
5020 * @param[out] puResult Place to return the unsigned integer result.
5021 *
5022 * This computes: mantissa * 10 ^^ exponent as for a decimal fraction. The output is a 64-bit
5023 * unsigned integer.
5024 *
5025 * There are many inputs for which the result will not fit in the
5026 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5027 * be returned.
5028 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005029static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005030QCBOR_Private_Exponentitate10(const uint64_t uMantissa,
5031 int64_t nExponent,
5032 uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005033{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005034 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005035
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005036 if(uResult != 0) {
5037 /* This loop will run a maximum of 19 times because
5038 * UINT64_MAX < 10 ^^ 19. More than that will cause
5039 * exit with the overflow error
5040 */
5041 for(; nExponent > 0; nExponent--) {
5042 if(uResult > UINT64_MAX / 10) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005043 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005044 }
5045 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005046 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005047
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005048 for(; nExponent < 0; nExponent++) {
5049 uResult = uResult / 10;
5050 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005051 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005052 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005053 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005054 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005055 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07005056
5057 *puResult = uResult;
5058
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005059 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005060}
5061
5062
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005063/**
5064 * @brief Base 2 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5065 *
5066 * @param[in] uMantissa The unsigned integer mantissa.
5067 * @param[in] nExponent The signed integer exponent.
5068 * @param[out] puResult Place to return the unsigned integer result.
5069 *
5070 * This computes: mantissa * 2 ^^ exponent as for a big float. The
5071 * output is a 64-bit unsigned integer.
5072 *
5073 * There are many inputs for which the result will not fit in the
5074 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5075 * be returned.
5076 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005077static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005078QCBOR_Private_Exponentitate2(const uint64_t uMantissa,
5079 int64_t nExponent,
5080 uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005081{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005082 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005083
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005084 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005085
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005086 /* This loop will run a maximum of 64 times because INT64_MAX <
5087 * 2^31. More than that will cause exit with the overflow error
Laurence Lundbladee6430642020-03-14 21:15:44 -07005088 */
5089 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005090 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005091 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005092 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005093 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005094 nExponent--;
5095 }
5096
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005097 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005098 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005099 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005100 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005101 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005102 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005103 }
5104
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005105 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005106
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005107 return QCBOR_SUCCESS;
5108}
5109
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005110
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005111/**
5112 * @brief Exponentiate a signed mantissa and signed exponent to produce a signed result.
5113 *
5114 * @param[in] nMantissa Signed integer mantissa.
5115 * @param[in] nExponent Signed integer exponent.
5116 * @param[out] pnResult Place to put the signed integer result.
5117 * @param[in] pfExp Exponentiation function.
5118 *
5119 * @returns Error code
5120 *
5121 * \c pfExp performs exponentiation on and unsigned mantissa and
5122 * produces an unsigned result. This converts the mantissa from signed
5123 * and converts the result to signed. The exponentiation function is
5124 * either for base 2 or base 10 (and could be other if needed).
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005125 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005126static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005127QCBOR_Private_ExponentiateNN(const int64_t nMantissa,
5128 const int64_t nExponent,
5129 int64_t *pnResult,
5130 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005131{
5132 uint64_t uResult;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005133 uint64_t uMantissa;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005134
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005135 /* Take the absolute value and put it into an unsigned. */
5136 if(nMantissa >= 0) {
5137 /* Positive case is straightforward */
5138 uMantissa = (uint64_t)nMantissa;
5139 } else if(nMantissa != INT64_MIN) {
5140 /* The common negative case. See next. */
5141 uMantissa = (uint64_t)-nMantissa;
5142 } else {
5143 /* int64_t and uint64_t are always two's complement per the
5144 * C standard (and since QCBOR uses these it only works with
5145 * two's complement, which is pretty much universal these
5146 * days). The range of a negative two's complement integer is
5147 * one more that than a positive, so the simple code above might
5148 * not work all the time because you can't simply negate the
5149 * value INT64_MIN because it can't be represented in an
5150 * int64_t. -INT64_MIN can however be represented in a
5151 * uint64_t. Some compilers seem to recognize this case for the
5152 * above code and put the correct value in uMantissa, however
5153 * they are not required to do this by the C standard. This next
5154 * line does however work for all compilers.
5155 *
5156 * This does assume two's complement where -INT64_MIN ==
5157 * INT64_MAX + 1 (which wouldn't be true for one's complement or
5158 * sign and magnitude (but we know we're using two's complement
5159 * because int64_t requires it)).
5160 *
5161 * See these, particularly the detailed commentary:
5162 * https://stackoverflow.com/questions/54915742/does-c99-mandate-a-int64-t-type-be-available-always
5163 * https://stackoverflow.com/questions/37301078/is-negating-int-min-undefined-behaviour
5164 */
5165 uMantissa = (uint64_t)INT64_MAX+1;
5166 }
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005167
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005168 /* Call the exponentiator passed for either base 2 or base 10.
5169 * Here is where most of the overflow errors are caught. */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005170 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
5171 if(uReturn) {
5172 return uReturn;
5173 }
5174
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005175 /* Convert back to the sign of the original mantissa */
5176 if(nMantissa >= 0) {
5177 if(uResult > INT64_MAX) {
5178 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5179 }
5180 *pnResult = (int64_t)uResult;
5181 } else {
5182 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
5183 * of INT64_MIN. This assumes two's compliment representation
5184 * where INT64_MIN is one increment farther from 0 than
5185 * INT64_MAX. Trying to write -INT64_MIN doesn't work to get
5186 * this because the compiler makes it an int64_t which can't
5187 * represent -INT64_MIN. Also see above.
5188 */
5189 if(uResult > (uint64_t)INT64_MAX+1) {
5190 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5191 }
5192 *pnResult = -(int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005193 }
5194
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005195 return QCBOR_SUCCESS;
5196}
5197
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005198
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005199/**
5200 * @brief Exponentiate an unsigned mantissa and signed exponent to produce an unsigned result.
5201 *
5202 * @param[in] nMantissa Signed integer mantissa.
5203 * @param[in] nExponent Signed integer exponent.
5204 * @param[out] puResult Place to put the signed integer result.
5205 * @param[in] pfExp Exponentiation function.
5206 *
5207 * @returns Error code
5208 *
5209 * \c pfExp performs exponentiation on and unsigned mantissa and
5210 * produces an unsigned result. This errors out if the mantissa
5211 * is negative because the output is unsigned.
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005212 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005213static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005214QCBOR_Private_ExponentitateNU(const int64_t nMantissa,
5215 const int64_t nExponent,
5216 uint64_t *puResult,
5217 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005218{
5219 if(nMantissa < 0) {
5220 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5221 }
5222
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005223 /* Cast to unsigned is OK because of check for negative.
5224 * Cast to unsigned is OK because UINT64_MAX > INT64_MAX.
5225 * Exponentiation is straight forward
5226 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005227 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
5228}
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005229
5230
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005231/**
5232 * @brief Exponentiate an usnigned mantissa and unsigned exponent to produce an unsigned result.
5233 *
5234 * @param[in] uMantissa Unsigned integer mantissa.
5235 * @param[in] nExponent Unsigned integer exponent.
5236 * @param[out] puResult Place to put the unsigned integer result.
5237 * @param[in] pfExp Exponentiation function.
5238 *
5239 * @returns Error code
5240 *
5241 * \c pfExp performs exponentiation on and unsigned mantissa and
5242 * produces an unsigned result so this is just a wrapper that does
5243 * nothing (and is likely inlined).
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005244 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005245static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005246QCBOR_Private_ExponentitateUU(const uint64_t uMantissa,
5247 const int64_t nExponent,
5248 uint64_t *puResult,
5249 fExponentiator pfExp)
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005250{
5251 return (*pfExp)(uMantissa, nExponent, puResult);
5252}
5253
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005254#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005255
5256
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005257
5258
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005259/**
5260 * @brief Convert a CBOR big number to a uint64_t.
5261 *
5262 * @param[in] BigNum Bytes of the big number to convert.
5263 * @param[in] uMax Maximum value allowed for the result.
5264 * @param[out] pResult Place to put the unsigned integer result.
5265 *
5266 * @returns Error code
5267 *
5268 * Many values will overflow because a big num can represent a much
5269 * larger range than uint64_t.
5270 */
5271static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005272QCBOR_Private_ConvertBigNumToUnsigned(const UsefulBufC BigNum,
5273 const uint64_t uMax,
5274 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005275{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005276 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005277
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005278 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005279 const uint8_t *pByte = BigNum.ptr;
5280 size_t uLen = BigNum.len;
5281 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07005282 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005283 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005284 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07005285 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005286 }
5287
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005288 *pResult = uResult;
5289 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005290}
5291
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005292
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005293/**
5294 * @brief Convert a CBOR postive big number to a uint64_t.
5295 *
5296 * @param[in] BigNum Bytes of the big number to convert.
5297 * @param[out] pResult Place to put the unsigned integer result.
5298 *
5299 * @returns Error code
5300 *
5301 * Many values will overflow because a big num can represent a much
5302 * larger range than uint64_t.
5303 */
5304static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005305QCBOR_Private_ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum,
5306 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005307{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005308 return QCBOR_Private_ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005309}
5310
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005311
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005312/**
5313 * @brief Convert a CBOR positive big number to an int64_t.
5314 *
5315 * @param[in] BigNum Bytes of the big number to convert.
5316 * @param[out] pResult Place to put the signed integer result.
5317 *
5318 * @returns Error code
5319 *
5320 * Many values will overflow because a big num can represent a much
5321 * larger range than int64_t.
5322 */
5323static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005324QCBOR_Private_ConvertPositiveBigNumToSigned(const UsefulBufC BigNum,
5325 int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005326{
5327 uint64_t uResult;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005328 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5329 INT64_MAX,
5330 &uResult);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005331 if(uError) {
5332 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005333 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005334 /* Cast is safe because ConvertBigNumToUnsigned limits to INT64_MAX */
Laurence Lundbladee6430642020-03-14 21:15:44 -07005335 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005336 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005337}
5338
5339
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005340/**
5341 * @brief Convert a CBOR negative big number to an int64_t.
5342 *
5343 * @param[in] BigNum Bytes of the big number to convert.
5344 * @param[out] pnResult Place to put the signed integer result.
5345 *
5346 * @returns Error code
5347 *
5348 * Many values will overflow because a big num can represent a much
5349 * larger range than int64_t.
5350 */
5351static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005352QCBOR_Private_ConvertNegativeBigNumToSigned(const UsefulBufC BigNum,
5353 int64_t *pnResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005354{
5355 uint64_t uResult;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005356 /* The negative integer furthest from zero for a C int64_t is
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005357 * INT64_MIN which is expressed as -INT64_MAX - 1. The value of a
5358 * negative number in CBOR is computed as -n - 1 where n is the
5359 * encoded integer, where n is what is in the variable BigNum. When
5360 * converting BigNum to a uint64_t, the maximum value is thus
5361 * INT64_MAX, so that when it -n - 1 is applied to it the result
5362 * will never be further from 0 than INT64_MIN.
5363 *
5364 * -n - 1 <= INT64_MIN.
5365 * -n - 1 <= -INT64_MAX - 1
5366 * n <= INT64_MAX.
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005367 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005368 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5369 INT64_MAX,
5370 &uResult);
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005371 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005372 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005373 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005374
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005375 /* Now apply -n - 1. The cast is safe because
5376 * ConvertBigNumToUnsigned() is limited to INT64_MAX which does fit
5377 * is the largest positive integer that an int64_t can
5378 * represent. */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005379 *pnResult = -(int64_t)uResult - 1;
5380
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005381 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005382}
5383
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005384
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005385
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005386
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005387/**
5388 * @brief Convert integers and floats to an int64_t.
5389 *
5390 * @param[in] pItem The item to convert.
5391 * @param[in] uConvertTypes Bit mask list of conversion options.
5392 * @param[out] pnValue The resulting converted value.
5393 *
5394 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5395 * in uConvertTypes.
5396 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5397 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5398 * or too small.
5399 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005400static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005401QCBOR_Private_ConvertInt64(const QCBORItem *pItem,
5402 const uint32_t uConvertTypes,
5403 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005404{
5405 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005406 case QCBOR_TYPE_FLOAT:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005407 case QCBOR_TYPE_DOUBLE:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005408#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005409 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005410 /* https://pubs.opengroup.org/onlinepubs/009695399/functions/llround.html
5411 http://www.cplusplus.com/reference/cmath/llround/
5412 */
5413 // Not interested in FE_INEXACT
5414 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005415 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5416 *pnValue = llround(pItem->val.dfnum);
5417 } else {
5418 *pnValue = lroundf(pItem->val.fnum);
5419 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005420 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5421 // llround() shouldn't result in divide by zero, but catch
5422 // it here in case it unexpectedly does. Don't try to
5423 // distinguish between the various exceptions because it seems
5424 // they vary by CPU, compiler and OS.
5425 return QCBOR_ERR_FLOAT_EXCEPTION;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005426 }
5427 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005428 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005429 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005430#else
5431 return QCBOR_ERR_HW_FLOAT_DISABLED;
5432#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005433 break;
5434
5435 case QCBOR_TYPE_INT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005436 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005437 *pnValue = pItem->val.int64;
5438 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005439 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005440 }
5441 break;
5442
5443 case QCBOR_TYPE_UINT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005444 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005445 if(pItem->val.uint64 < INT64_MAX) {
5446 *pnValue = pItem->val.int64;
5447 } else {
5448 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5449 }
5450 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005451 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005452 }
5453 break;
5454
5455 default:
5456 return QCBOR_ERR_UNEXPECTED_TYPE;
5457 }
5458 return QCBOR_SUCCESS;
5459}
5460
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005461
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005462/**
5463 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5464 *
5465 * @param[in] pMe The decode context.
5466 * @param[in] uConvertTypes Bit mask list of conversion options.
5467 * @param[out] pnValue Result of the conversion.
5468 * @param[in,out] pItem Temporary space to store Item, returned item.
5469 *
5470 * See QCBORDecode_GetInt64Convert().
5471 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005472void
5473QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pMe,
5474 uint32_t uConvertTypes,
5475 int64_t *pnValue,
5476 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005477{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07005478 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005479 return;
5480 }
5481
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005482 QCBORError uError = QCBORDecode_GetNext(pMe, pItem);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005483 if(uError) {
5484 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005485 return;
5486 }
5487
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005488 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005489 uConvertTypes,
5490 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005491}
5492
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005493/**
5494 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5495 *
5496 * @param[in] pMe The decode context.
5497 * @param[in] nLabel Label to find in map.
5498 * @param[in] uConvertTypes Bit mask list of conversion options.
5499 * @param[out] pnValue Result of the conversion.
5500 * @param[in,out] pItem Temporary space to store Item, returned item.
5501 *
5502 * See QCBORDecode_GetInt64ConvertInMapN().
5503 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005504void
5505QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pMe,
5506 int64_t nLabel,
5507 uint32_t uConvertTypes,
5508 int64_t *pnValue,
5509 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005510{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005511 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005512 if(pMe->uLastError != QCBOR_SUCCESS) {
5513 return;
5514 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005515
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005516 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5517 uConvertTypes,
5518 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005519}
5520
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005521/**
5522 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5523 *
5524 * @param[in] pMe The decode context.
5525 * @param[in] szLabel Label to find in map.
5526 * @param[in] uConvertTypes Bit mask list of conversion options.
5527 * @param[out] pnValue Result of the conversion.
5528 * @param[in,out] pItem Temporary space to store Item, returned item.
5529 *
5530 * See QCBORDecode_GetInt64ConvertInMapSZ().
5531 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005532void
5533QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5534 const char * szLabel,
5535 uint32_t uConvertTypes,
5536 int64_t *pnValue,
5537 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005538{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005539 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005540 if(pMe->uLastError != QCBOR_SUCCESS) {
5541 return;
5542 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005543
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005544 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5545 uConvertTypes,
5546 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005547}
5548
5549
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005550/**
5551 * @brief Convert many number types to an int64_t.
5552 *
5553 * @param[in] pItem The item to convert.
5554 * @param[in] uConvertTypes Bit mask list of conversion options.
5555 * @param[out] pnValue The resulting converted value.
5556 *
5557 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5558 * in uConvertTypes.
5559 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5560 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5561 * or too small.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005562 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005563static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005564QCBOR_Private_Int64ConvertAll(const QCBORItem *pItem,
5565 const uint32_t uConvertTypes,
5566 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005567{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005568 switch(pItem->uDataType) {
5569
5570 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005571 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005572 return QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005573 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005574 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005575 }
5576 break;
5577
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005578 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005579 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005580 return QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005581 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005582 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005583 }
5584 break;
5585
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005586#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005587 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005588 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005589 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005590 pItem->val.expAndMantissa.nExponent,
5591 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005592 &QCBOR_Private_Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005593 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005594 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005595 }
5596 break;
5597
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005598 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005599 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005600 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005601 pItem->val.expAndMantissa.nExponent,
5602 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005603 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005604 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005605 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005606 }
5607 break;
5608
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005609 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005610 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005611 int64_t nMantissa;
5612 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005613 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005614 if(uErr) {
5615 return uErr;
5616 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005617 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005618 pItem->val.expAndMantissa.nExponent,
5619 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005620 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005621 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005622 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005623 }
5624 break;
5625
5626 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005627 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005628 int64_t nMantissa;
5629 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005630 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005631 if(uErr) {
5632 return uErr;
5633 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005634 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005635 pItem->val.expAndMantissa.nExponent,
5636 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005637 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005638 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005639 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005640 }
5641 break;
5642
5643 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005644 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005645 int64_t nMantissa;
5646 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005647 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005648 if(uErr) {
5649 return uErr;
5650 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005651 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005652 pItem->val.expAndMantissa.nExponent,
5653 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005654 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005655 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005656 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005657 }
5658 break;
5659
5660 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005661 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005662 int64_t nMantissa;
5663 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005664 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005665 if(uErr) {
5666 return uErr;
5667 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005668 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005669 pItem->val.expAndMantissa.nExponent,
5670 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005671 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005672 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005673 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005674 }
5675 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005676#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005677
Laurence Lundbladee6430642020-03-14 21:15:44 -07005678
Laurence Lundbladec4537442020-04-14 18:53:22 -07005679 default:
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005680 return QCBOR_ERR_UNEXPECTED_TYPE; }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005681}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005682
5683
Laurence Lundbladec4537442020-04-14 18:53:22 -07005684/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005685 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005686 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005687void
5688QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe,
5689 const uint32_t uConvertTypes,
5690 int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005691{
5692 QCBORItem Item;
5693
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005694 QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005695
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005696 if(pMe->uLastError == QCBOR_SUCCESS) {
5697 // The above conversion succeeded
5698 return;
5699 }
5700
Laurence Lundbladef6c86662020-05-12 02:08:00 -07005701 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005702 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07005703 return;
5704 }
5705
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005706 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5707 uConvertTypes,
5708 pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005709}
5710
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005711
5712/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005713 * Public function, see header qcbor/qcbor_decode.h file
5714 */
5715void
5716QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
5717 const int64_t nLabel,
5718 const uint32_t uConvertTypes,
5719 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005720{
5721 QCBORItem Item;
5722
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005723 QCBORDecode_Private_GetInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07005724 nLabel,
5725 uConvertTypes,
5726 pnValue,
5727 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005728
5729 if(pMe->uLastError == QCBOR_SUCCESS) {
5730 // The above conversion succeeded
5731 return;
5732 }
5733
5734 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5735 // The above conversion failed in a way that code below can't correct
5736 return;
5737 }
5738
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005739 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5740 uConvertTypes,
5741 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005742}
5743
5744
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005745/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005746 * Public function, see header qcbor/qcbor_decode.h file
5747 */
5748void
5749QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
5750 const char *szLabel,
5751 const uint32_t uConvertTypes,
5752 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005753{
5754 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005755 QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07005756 szLabel,
5757 uConvertTypes,
5758 pnValue,
5759 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005760
5761 if(pMe->uLastError == QCBOR_SUCCESS) {
5762 // The above conversion succeeded
5763 return;
5764 }
5765
5766 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5767 // The above conversion failed in a way that code below can't correct
5768 return;
5769 }
5770
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005771 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5772 uConvertTypes,
5773 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005774}
5775
5776
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005777/**
5778 * @brief Convert many number types to an uint64_t.
5779 *
5780 * @param[in] pItem The item to convert.
5781 * @param[in] uConvertTypes Bit mask list of conversion options.
5782 * @param[out] puValue The resulting converted value.
5783 *
5784 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5785 * in uConvertTypes.
5786 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5787 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5788 * or too small.
5789 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005790static QCBORError
5791QCBOR_Private_ConvertUInt64(const QCBORItem *pItem,
5792 const uint32_t uConvertTypes,
5793 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005794{
5795 switch(pItem->uDataType) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005796 case QCBOR_TYPE_DOUBLE:
5797 case QCBOR_TYPE_FLOAT:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005798#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005799 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005800 // Can't use llround here because it will not convert values
5801 // greater than INT64_MAX and less than UINT64_MAX that
5802 // need to be converted so it is more complicated.
5803 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
5804 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5805 if(isnan(pItem->val.dfnum)) {
5806 return QCBOR_ERR_FLOAT_EXCEPTION;
5807 } else if(pItem->val.dfnum < 0) {
5808 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5809 } else {
5810 double dRounded = round(pItem->val.dfnum);
5811 // See discussion in DecodeDateEpoch() for
5812 // explanation of - 0x7ff
5813 if(dRounded > (double)(UINT64_MAX- 0x7ff)) {
5814 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5815 }
5816 *puValue = (uint64_t)dRounded;
5817 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005818 } else {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005819 if(isnan(pItem->val.fnum)) {
5820 return QCBOR_ERR_FLOAT_EXCEPTION;
5821 } else if(pItem->val.fnum < 0) {
5822 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5823 } else {
5824 float fRounded = roundf(pItem->val.fnum);
5825 // See discussion in DecodeDateEpoch() for
5826 // explanation of - 0x7ff
5827 if(fRounded > (float)(UINT64_MAX- 0x7ff)) {
5828 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5829 }
5830 *puValue = (uint64_t)fRounded;
5831 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005832 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005833 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5834 // round() and roundf() shouldn't result in exceptions here, but
5835 // catch them to be robust and thorough. Don't try to
5836 // distinguish between the various exceptions because it seems
5837 // they vary by CPU, compiler and OS.
5838 return QCBOR_ERR_FLOAT_EXCEPTION;
5839 }
5840
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005841 } else {
5842 return QCBOR_ERR_UNEXPECTED_TYPE;
5843 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005844#else
5845 return QCBOR_ERR_HW_FLOAT_DISABLED;
5846#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005847 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005848
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005849 case QCBOR_TYPE_INT64:
5850 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
5851 if(pItem->val.int64 >= 0) {
5852 *puValue = (uint64_t)pItem->val.int64;
5853 } else {
5854 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5855 }
5856 } else {
5857 return QCBOR_ERR_UNEXPECTED_TYPE;
5858 }
5859 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005860
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005861 case QCBOR_TYPE_UINT64:
5862 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
5863 *puValue = pItem->val.uint64;
5864 } else {
5865 return QCBOR_ERR_UNEXPECTED_TYPE;
5866 }
5867 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005868
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005869 default:
5870 return QCBOR_ERR_UNEXPECTED_TYPE;
5871 }
5872
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005873 return QCBOR_SUCCESS;
5874}
Laurence Lundbladec4537442020-04-14 18:53:22 -07005875
5876
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005877/**
5878 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5879 *
5880 * @param[in] pMe The decode context.
5881 * @param[in] uConvertTypes Bit mask list of conversion options.
5882 * @param[out] puValue Result of the conversion.
5883 * @param[in,out] pItem Temporary space to store Item, returned item.
5884 *
5885 * See QCBORDecode_GetUInt64Convert().
5886 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005887void
5888QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pMe,
5889 const uint32_t uConvertTypes,
5890 uint64_t *puValue,
5891 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005892{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005893 if(pMe->uLastError != QCBOR_SUCCESS) {
5894 return;
5895 }
5896
Laurence Lundbladec4537442020-04-14 18:53:22 -07005897 QCBORItem Item;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005898
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005899 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
5900 if(uError) {
5901 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005902 return;
5903 }
5904
Laurence Lundbladea826c502020-05-10 21:07:00 -07005905 if(pItem) {
5906 *pItem = Item;
5907 }
5908
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005909 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(&Item,
5910 uConvertTypes,
5911 puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005912}
5913
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005914
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005915/**
5916 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5917 *
5918 * @param[in] pMe The decode context.
5919 * @param[in] nLabel Label to find in map.
5920 * @param[in] uConvertTypes Bit mask list of conversion options.
5921 * @param[out] puValue Result of the conversion.
5922 * @param[in,out] pItem Temporary space to store Item, returned item.
5923 *
5924 * See QCBORDecode_GetUInt64ConvertInMapN().
5925 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005926void
5927QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe,
5928 const int64_t nLabel,
5929 const uint32_t uConvertTypes,
5930 uint64_t *puValue,
5931 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005932{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005933 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005934 if(pMe->uLastError != QCBOR_SUCCESS) {
5935 return;
5936 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005937
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005938 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
5939 uConvertTypes,
5940 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005941}
5942
5943
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005944/**
5945 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5946 *
5947 * @param[in] pMe The decode context.
5948 * @param[in] szLabel Label to find in map.
5949 * @param[in] uConvertTypes Bit mask list of conversion options.
5950 * @param[out] puValue Result of the conversion.
5951 * @param[in,out] pItem Temporary space to store Item, returned item.
5952 *
5953 * See QCBORDecode_GetUInt64ConvertInMapSZ().
5954 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005955void
5956QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5957 const char *szLabel,
5958 const uint32_t uConvertTypes,
5959 uint64_t *puValue,
5960 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005961{
5962 if(pMe->uLastError != QCBOR_SUCCESS) {
5963 return;
5964 }
5965
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005966 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005967 if(pMe->uLastError != QCBOR_SUCCESS) {
5968 return;
5969 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005970
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005971 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
5972 uConvertTypes,
5973 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005974}
5975
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005976
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005977/**
5978 * @brief Convert many number types to an unt64_t.
5979 *
5980 * @param[in] pItem The item to convert.
5981 * @param[in] uConvertTypes Bit mask list of conversion options.
5982 * @param[out] puValue The resulting converted value.
5983 *
5984 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5985 * in uConvertTypes.
5986 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5987 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5988 * or too small.
5989 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005990static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005991QCBOR_Private_UInt64ConvertAll(const QCBORItem *pItem,
5992 const uint32_t uConvertTypes,
5993 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005994{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08005995 switch(pItem->uDataType) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005996
5997 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005998 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005999 return QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006000 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006001 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006002 }
6003 break;
6004
6005 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006006 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006007 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6008 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006009 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006010 }
6011 break;
6012
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006013#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006014
6015 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006016 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006017 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006018 pItem->val.expAndMantissa.nExponent,
6019 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006020 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006021 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006022 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006023 }
6024 break;
6025
6026 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006027 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006028 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006029 pItem->val.expAndMantissa.nExponent,
6030 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006031 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006032 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006033 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006034 }
6035 break;
6036
6037 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006038 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006039 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006040 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006041 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006042 if(uErr != QCBOR_SUCCESS) {
6043 return uErr;
6044 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006045 return QCBOR_Private_ExponentitateUU(uMantissa,
6046 pItem->val.expAndMantissa.nExponent,
6047 puValue,
6048 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006049 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006050 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006051 }
6052 break;
6053
6054 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006055 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006056 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6057 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006058 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006059 }
6060 break;
6061
6062 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006063 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006064 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006065 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006066 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum,
6067 &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006068 if(uErr != QCBOR_SUCCESS) {
6069 return uErr;
6070 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006071 return QCBOR_Private_ExponentitateUU(uMantissa,
6072 pItem->val.expAndMantissa.nExponent,
6073 puValue,
6074 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006075 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006076 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006077 }
6078 break;
6079
6080 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006081 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006082 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6083 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006084 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006085 }
6086 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006087#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006088 default:
6089 return QCBOR_ERR_UNEXPECTED_TYPE;
6090 }
6091}
6092
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006093
Laurence Lundblade4e2da002020-06-13 23:08:31 -07006094/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006095 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006096 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006097void
6098QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe,
6099 const uint32_t uConvertTypes,
6100 uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006101{
6102 QCBORItem Item;
6103
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006104 QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006105
Laurence Lundbladef6c86662020-05-12 02:08:00 -07006106 if(pMe->uLastError == QCBOR_SUCCESS) {
6107 // The above conversion succeeded
6108 return;
6109 }
6110
6111 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6112 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07006113 return;
6114 }
6115
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006116 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6117 uConvertTypes,
6118 puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006119}
6120
Laurence Lundbladec4537442020-04-14 18:53:22 -07006121
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006122/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006123 * Public function, see header qcbor/qcbor_decode.h file
6124 */
6125void
6126QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
6127 const int64_t nLabel,
6128 const uint32_t uConvertTypes,
6129 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006130{
6131 QCBORItem Item;
6132
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006133 QCBORDecode_Private_GetUInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006134 nLabel,
6135 uConvertTypes,
6136 puValue,
6137 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006138
6139 if(pMe->uLastError == QCBOR_SUCCESS) {
6140 // The above conversion succeeded
6141 return;
6142 }
6143
6144 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6145 // The above conversion failed in a way that code below can't correct
6146 return;
6147 }
6148
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006149 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6150 uConvertTypes,
6151 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006152}
6153
6154
6155/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006156 * Public function, see header qcbor/qcbor_decode.h file
6157 */
6158void
6159QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
6160 const char *szLabel,
6161 const uint32_t uConvertTypes,
6162 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006163{
6164 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006165 QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006166 szLabel,
6167 uConvertTypes,
6168 puValue,
6169 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006170
6171 if(pMe->uLastError == QCBOR_SUCCESS) {
6172 // The above conversion succeeded
6173 return;
6174 }
6175
6176 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6177 // The above conversion failed in a way that code below can't correct
6178 return;
6179 }
6180
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006181 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6182 uConvertTypes,
6183 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006184}
6185
6186
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006187
6188
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006189#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006190/**
6191 * @brief Basic conversions to a double.
6192 *
6193 * @param[in] pItem The item to convert
6194 * @param[in] uConvertTypes Bit flags indicating source types for conversion
6195 * @param[out] pdValue The value converted to a double
6196 *
6197 * This does the conversions that don't need much object code,
6198 * the conversions from int, uint and float to double.
6199 *
6200 * See QCBOR_Private_DoubleConvertAll() for the full set
6201 * of conversions.
6202 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006203static QCBORError
6204QCBOR_Private_ConvertDouble(const QCBORItem *pItem,
6205 const uint32_t uConvertTypes,
6206 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006207{
6208 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006209 case QCBOR_TYPE_FLOAT:
6210#ifndef QCBOR_DISABLE_FLOAT_HW_USE
6211 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6212 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006213 // Simple cast does the job.
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006214 *pdValue = (double)pItem->val.fnum;
6215 } else {
6216 return QCBOR_ERR_UNEXPECTED_TYPE;
6217 }
6218 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006219#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006220 return QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006221#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006222 break;
6223
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006224 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006225 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6226 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006227 *pdValue = pItem->val.dfnum;
6228 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006229 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006230 }
6231 }
6232 break;
6233
6234 case QCBOR_TYPE_INT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006235#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006236 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006237 // A simple cast seems to do the job with no worry of exceptions.
6238 // There will be precision loss for some values.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006239 *pdValue = (double)pItem->val.int64;
6240
6241 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006242 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006243 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006244#else
6245 return QCBOR_ERR_HW_FLOAT_DISABLED;
6246#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006247 break;
6248
6249 case QCBOR_TYPE_UINT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006250#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006251 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006252 // A simple cast seems to do the job with no worry of exceptions.
6253 // There will be precision loss for some values.
6254 *pdValue = (double)pItem->val.uint64;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006255 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006256 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006257 }
6258 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006259#else
6260 return QCBOR_ERR_HW_FLOAT_DISABLED;
6261#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006262
6263 default:
6264 return QCBOR_ERR_UNEXPECTED_TYPE;
6265 }
6266
6267 return QCBOR_SUCCESS;
6268}
6269
6270
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006271/**
6272 * @brief Almost-public method to decode a number and convert to double (semi-private).
6273 *
6274 * @param[in] pMe The decode context.
6275 * @param[in] uConvertTypes Bit mask list of conversion options
6276 * @param[out] pdValue The output of the conversion.
6277 * @param[in,out] pItem Temporary space to store Item, returned item.
6278 *
6279 * See QCBORDecode_GetDoubleConvert().
6280 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006281void
6282QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pMe,
6283 const uint32_t uConvertTypes,
6284 double *pdValue,
6285 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07006286{
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006287 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07006288 return;
6289 }
6290
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006291 QCBORError uError = QCBORDecode_GetNext(pMe, pItem);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006292 if(uError) {
6293 pMe->uLastError = (uint8_t)uError;
6294 return;
6295 }
6296
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006297 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006298 uConvertTypes,
6299 pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006300}
Laurence Lundbladec4537442020-04-14 18:53:22 -07006301
Laurence Lundbladec4537442020-04-14 18:53:22 -07006302
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006303/**
6304 * @brief Almost-public method to decode a number and convert to double (semi-private).
6305 *
6306 * @param[in] pMe The decode context.
6307 * @param[in] nLabel Label to find in map.
6308 * @param[in] uConvertTypes Bit mask list of conversion options
6309 * @param[out] pdValue The output of the conversion.
6310 * @param[in,out] pItem Temporary space to store Item, returned item.
6311 *
6312 * See QCBORDecode_GetDoubleConvertInMapN().
6313 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006314void
6315QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pMe,
6316 const int64_t nLabel,
6317 const uint32_t uConvertTypes,
6318 double *pdValue,
6319 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006320{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006321 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006322 if(pMe->uLastError != QCBOR_SUCCESS) {
6323 return;
6324 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006325
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006326 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6327 uConvertTypes,
6328 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006329}
6330
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006331
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006332/**
6333 * @brief Almost-public method to decode a number and convert to double (semi-private).
6334 *
6335 * @param[in] pMe The decode context.
6336 * @param[in] szLabel Label to find in map.
6337 * @param[in] uConvertTypes Bit mask list of conversion options
6338 * @param[out] pdValue The output of the conversion.
6339 * @param[in,out] pItem Temporary space to store Item, returned item.
6340 *
6341 * See QCBORDecode_GetDoubleConvertInMapSZ().
6342 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006343void
6344QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe,
6345 const char *szLabel,
6346 const uint32_t uConvertTypes,
6347 double *pdValue,
6348 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006349{
6350 if(pMe->uLastError != QCBOR_SUCCESS) {
6351 return;
6352 }
6353
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006354 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006355 if(pMe->uLastError != QCBOR_SUCCESS) {
6356 return;
6357 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006358
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006359 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6360 uConvertTypes,
6361 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006362}
6363
6364
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006365#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006366/**
6367 * @brief Convert a big number to double-precision float.
6368 *
6369 * @param[in] BigNum The big number to convert
6370 *
6371 * @returns The double value.
6372 *
6373 * This will always succeed. It will lose precision for larger
6374 * numbers. If the big number is too large to fit (more than
6375 * 1.7976931348623157E+308) infinity will be returned. NaN is never
6376 * returned.
6377 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006378static double
6379QCBOR_Private_ConvertBigNumToDouble(const UsefulBufC BigNum)
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006380{
6381 double dResult;
6382
6383 dResult = 0.0;
6384 const uint8_t *pByte = BigNum.ptr;
6385 size_t uLen = BigNum.len;
6386 /* This will overflow and become the float value INFINITY if the number
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006387 * is too large to fit. */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006388 while(uLen--) {
6389 dResult = (dResult * 256.0) + (double)*pByte++;
6390 }
6391
6392 return dResult;
6393}
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006394#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6395
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006396
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006397
6398
6399/**
6400 * @brief Convert many number types to a double.
6401 *
6402 * @param[in] pItem The item to convert.
6403 * @param[in] uConvertTypes Bit mask list of conversion options.
6404 * @param[out] pdValue The resulting converted value.
6405 *
6406 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6407 * in uConvertTypes.
6408 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6409 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6410 * or too small.
6411 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006412static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006413QCBOR_Private_DoubleConvertAll(const QCBORItem *pItem,
6414 const uint32_t uConvertTypes,
6415 double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006416{
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006417#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07006418 /*
Laurence Lundblade16a207a2021-09-18 17:22:46 -07006419 * What Every Computer Scientist Should Know About Floating-Point Arithmetic
6420 * https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
6421 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006422 switch(pItem->uDataType) {
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006423
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006424#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006425 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006426 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006427 // Underflow gives 0, overflow gives infinity
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006428 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6429 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
6430 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006431 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006432 }
6433 break;
6434
6435 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006436 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006437 // Underflow gives 0, overflow gives infinity
6438 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6439 exp2((double)pItem->val.expAndMantissa.nExponent);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006440 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006441 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006442 }
6443 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006444#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006445
6446 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006447 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006448 *pdValue = QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006449 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006450 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006451 }
6452 break;
6453
6454 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006455 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006456 *pdValue = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006457 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006458 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006459 }
6460 break;
6461
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006462#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006463 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006464 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006465 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006466 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6467 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006468 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006469 }
6470 break;
6471
6472 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006473 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006474 double dMantissa = -QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006475 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6476 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006477 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006478 }
6479 break;
6480
6481 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006482 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006483 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006484 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6485 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006486 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006487 }
6488 break;
6489
6490 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006491 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006492 double dMantissa = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006493 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6494 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006495 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006496 }
6497 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006498#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006499
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006500 default:
6501 return QCBOR_ERR_UNEXPECTED_TYPE;
6502 }
6503
6504 return QCBOR_SUCCESS;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006505
6506#else
6507 (void)pItem;
6508 (void)uConvertTypes;
6509 (void)pdValue;
6510 return QCBOR_ERR_HW_FLOAT_DISABLED;
6511#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6512
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006513}
6514
6515
6516/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006517 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006518 */
6519void
6520QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe,
6521 const uint32_t uConvertTypes,
6522 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006523{
6524
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006525 QCBORItem Item;
6526
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006527 QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006528
6529 if(pMe->uLastError == QCBOR_SUCCESS) {
6530 // The above conversion succeeded
6531 return;
6532 }
6533
6534 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6535 // The above conversion failed in a way that code below can't correct
6536 return;
6537 }
6538
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006539 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6540 uConvertTypes,
6541 pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006542}
6543
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006544
6545/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006546 * Public function, see header qcbor/qcbor_decode.h file
6547 */
6548void
6549QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe,
6550 const int64_t nLabel,
6551 const uint32_t uConvertTypes,
6552 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006553{
6554 QCBORItem Item;
6555
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006556 QCBORDecode_Private_GetDoubleConvertInMapN(pMe,
6557 nLabel,
6558 uConvertTypes,
6559 pdValue,
6560 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006561
6562 if(pMe->uLastError == QCBOR_SUCCESS) {
6563 // The above conversion succeeded
6564 return;
6565 }
6566
6567 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6568 // The above conversion failed in a way that code below can't correct
6569 return;
6570 }
6571
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006572 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6573 uConvertTypes,
6574 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006575}
6576
6577
6578/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006579 * Public function, see header qcbor/qcbor_decode.h file
6580 */
6581void
6582QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe,
6583 const char *szLabel,
6584 const uint32_t uConvertTypes,
6585 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006586{
6587 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006588 QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe,
6589 szLabel,
6590 uConvertTypes,
6591 pdValue,
6592 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006593
6594 if(pMe->uLastError == QCBOR_SUCCESS) {
6595 // The above conversion succeeded
6596 return;
6597 }
6598
6599 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6600 // The above conversion failed in a way that code below can't correct
6601 return;
6602 }
6603
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006604 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6605 uConvertTypes,
6606 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006607}
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006608#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006609
6610
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006611
6612
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006613#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006614/**
6615 * @brief Convert an integer to a big number
6616 *
6617 * @param[in] uInt The integer to convert.
6618 * @param[in] Buffer The buffer to output the big number to.
6619 *
6620 * @returns The big number or NULLUsefulBufC is the buffer is to small.
6621 *
6622 * This always succeeds unless the buffer is too small.
6623 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006624static UsefulBufC
6625QCBOR_Private_ConvertIntToBigNum(uint64_t uInt, const UsefulBuf Buffer)
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006626{
6627 while((uInt & 0xff00000000000000UL) == 0) {
6628 uInt = uInt << 8;
6629 };
6630
6631 UsefulOutBuf UOB;
6632
6633 UsefulOutBuf_Init(&UOB, Buffer);
6634
6635 while(uInt) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006636 UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff00000000000000UL) >> 56));
6637 uInt = uInt << 8;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006638 }
6639
6640 return UsefulOutBuf_OutUBuf(&UOB);
6641}
6642
6643
Laurence Lundblade37286c02022-09-03 10:05:02 -07006644/**
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006645 * @brief Check and/or complete exponent and mantissa item.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006646 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006647 * @param[in] pMe The decoder context.
6648 * @param[in] TagSpec Expected type(s).
6649 * @param[in,out] pItem See below.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006650 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006651 * This is for decimal fractions and big floats, both of which are an
6652 * exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006653 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006654 * If the item item had a tag number indicating it was a
6655 * decimal fraction or big float, then the input @c pItem will
6656 * have been decoded as exponent and mantissa. If there was
6657 * no tag number, the caller is asking this be decoded as a
6658 * big float or decimal fraction and @c pItem just has the
6659 * first item in an exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006660 *
6661 * On output, the item is always a fully decoded decimal fraction or
6662 * big float.
6663 *
6664 * This errors out if the input type does not meet the TagSpec.
6665 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07006666static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006667QCBOR_Private_ExpMantissaTypeHandler(QCBORDecodeContext *pMe,
6668 const QCBOR_Private_TagSpec TagSpec,
6669 QCBORItem *pItem)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006670{
6671 QCBORError uErr;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006672
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006673 /* pItem could either be a decoded exponent and mantissa or
6674 * the opening array of an undecoded exponent and mantissa. This
Laurence Lundblade37286c02022-09-03 10:05:02 -07006675 * check will succeed on either, but doesn't say which it was.
6676 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006677 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07006678 if(uErr != QCBOR_SUCCESS) {
6679 goto Done;
6680 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006681
Laurence Lundblade37286c02022-09-03 10:05:02 -07006682 if(pItem->uDataType == QCBOR_TYPE_ARRAY) {
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006683 /* The item is an array, which means is is an undecoded exponent
6684 * and mantissa. This call consumes the items in the array and
6685 * results in a decoded exponent and mantissa in pItem. This is
Laurence Lundblade37286c02022-09-03 10:05:02 -07006686 * the case where there was no tag.
6687 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006688 uErr = QCBORDecode_Private_ExpMantissa(pMe, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006689 if(uErr != QCBOR_SUCCESS) {
6690 goto Done;
6691 }
6692
Laurence Lundblade37286c02022-09-03 10:05:02 -07006693 /* The above decode didn't determine whether it is a decimal
6694 * fraction or big num. Which of these two depends on what the
6695 * caller wants it decoded as since there is no tag, so fish the
6696 * type out of the TagSpec. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006697 pItem->uDataType = QCBOR_Private_ExpMantissaDataType(TagSpec.uTaggedTypes[0], pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07006698
6699 /* No need to check the type again. All that we need to know was
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006700 * that it decoded correctly as a exponent and mantissa. The
Laurence Lundblade37286c02022-09-03 10:05:02 -07006701 * QCBOR type is set out by what was requested.
6702 */
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006703 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07006704
6705 /* If the item was not an array and the check passed, then
6706 * it is a fully decoded big float or decimal fraction and
6707 * matches what is requested.
6708 */
6709
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006710Done:
6711 return uErr;
6712}
6713
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006714
Laurence Lundblade37286c02022-09-03 10:05:02 -07006715/* Some notes from the work to disable tags.
6716 *
6717 * The API for big floats and decimal fractions seems good.
6718 * If there's any issue with it it's that the code size to
6719 * implement is a bit large because of the conversion
6720 * to/from int and bignum that is required. There is no API
6721 * that doesn't do the conversion so dead stripping will never
6722 * leave that code out.
6723 *
6724 * The implementation itself seems correct, but not as clean
6725 * and neat as it could be. It could probably be smaller too.
6726 *
6727 * The implementation has three main parts / functions
6728 * - The decoding of the array of two
6729 * - All the tag and type checking for the various API functions
6730 * - Conversion to/from bignum and int
6731 *
6732 * The type checking seems like it wastes the most code for
6733 * what it needs to do.
6734 *
6735 * The inlining for the conversion is probably making the
6736 * overall code base larger.
6737 *
6738 * The tests cases could be organized a lot better and be
6739 * more thorough.
6740 *
6741 * Seems also like there could be more common code in the
6742 * first tier part of the public API. Some functions only
6743 * vary by a TagSpec.
6744 */
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006745
6746/**
6747 * @brief Common processor for exponent and mantissa.
6748 *
6749 * @param[in] pMe The decode context.
6750 * @param[in] TagSpec The expected/allowed tags.
6751 * @param[in] pItem The data item to process.
6752 * @param[out] pnMantissa The returned mantissa as an int64_t.
6753 * @param[out] pnExponent The returned exponent as an int64_t.
6754 *
6755 * This handles exponent and mantissa for base 2 and 10. This
6756 * is limited to a mantissa that is an int64_t. See also
6757 * QCBORDecode_Private_ProcessExpMantissaBig().
6758 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006759static void
6760QCBOR_Private_ProcessExpMantissa(QCBORDecodeContext *pMe,
6761 const QCBOR_Private_TagSpec TagSpec,
6762 QCBORItem *pItem,
6763 int64_t *pnMantissa,
6764 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006765{
6766 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006767
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006768 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006769 if(uErr != QCBOR_SUCCESS) {
6770 goto Done;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006771 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006772
Laurence Lundblade9b334962020-08-27 10:55:53 -07006773 switch (pItem->uDataType) {
6774
6775 case QCBOR_TYPE_DECIMAL_FRACTION:
6776 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade9b334962020-08-27 10:55:53 -07006777 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006778 *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
Laurence Lundblade9b334962020-08-27 10:55:53 -07006779 break;
6780
Laurence Lundblade37286c02022-09-03 10:05:02 -07006781#ifndef QCBOR_DISABLE_TAGS
6782 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006783 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
6784 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
6785 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006786 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006787 break;
6788
6789 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
6790 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
6791 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006792 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006793 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006794#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006795
6796 default:
6797 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
6798 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006799
6800 Done:
6801 pMe->uLastError = (uint8_t)uErr;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006802}
6803
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006804
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006805/**
6806 * @brief Decode exponent and mantissa into a big number.
6807 *
6808 * @param[in] pMe The decode context.
6809 * @param[in] TagSpec The expected/allowed tags.
6810 * @param[in] pItem Item to decode and convert.
6811 * @param[in] BufferForMantissa Buffer to output mantissa into.
6812 * @param[out] pMantissa The output mantissa.
6813 * @param[out] pbIsNegative The sign of the output.
6814 * @param[out] pnExponent The mantissa of the output.
6815 *
6816 * This is the common processing of a decimal fraction or a big float
6817 * into a big number. This will decode and consume all the CBOR items
6818 * that make up the decimal fraction or big float.
6819 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006820static void
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006821QCBORDecode_Private_ProcessExpMantissaBig(QCBORDecodeContext *pMe,
6822 const QCBOR_Private_TagSpec TagSpec,
6823 QCBORItem *pItem,
6824 const UsefulBuf BufferForMantissa,
6825 UsefulBufC *pMantissa,
6826 bool *pbIsNegative,
6827 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006828{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006829 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006830
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006831 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006832 if(uErr != QCBOR_SUCCESS) {
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006833 goto Done;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006834 }
6835
6836 uint64_t uMantissa;
6837
6838 switch (pItem->uDataType) {
6839
6840 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006841 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006842 /* See comments in ExponentiateNN() on handling INT64_MIN */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006843 if(pItem->val.expAndMantissa.Mantissa.nInt >= 0) {
6844 uMantissa = (uint64_t)pItem->val.expAndMantissa.Mantissa.nInt;
6845 *pbIsNegative = false;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006846 } else if(pItem->val.expAndMantissa.Mantissa.nInt != INT64_MIN) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006847 uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt;
6848 *pbIsNegative = true;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006849 } else {
6850 uMantissa = (uint64_t)INT64_MAX+1;
6851 *pbIsNegative = true;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006852 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006853 *pMantissa = QCBOR_Private_ConvertIntToBigNum(uMantissa,
6854 BufferForMantissa);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006855 *pnExponent = pItem->val.expAndMantissa.nExponent;
6856 break;
6857
Laurence Lundblade37286c02022-09-03 10:05:02 -07006858#ifndef QCBOR_DISABLE_TAGS
6859 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006860 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006861 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006862 *pnExponent = pItem->val.expAndMantissa.nExponent;
6863 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6864 *pbIsNegative = false;
6865 break;
6866
6867 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006868 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006869 *pnExponent = pItem->val.expAndMantissa.nExponent;
6870 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6871 *pbIsNegative = true;
6872 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006873#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006874
6875 default:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006876 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006877 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006878
6879Done:
6880 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006881}
6882
6883
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006884/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006885 * Public function, see header qcbor/qcbor_decode.h file
6886 */
6887void
6888QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe,
6889 const uint8_t uTagRequirement,
6890 int64_t *pnMantissa,
6891 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006892{
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006893 if(pMe->uLastError != QCBOR_SUCCESS) {
6894 return;
6895 }
6896
6897 QCBORItem Item;
6898 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
6899 if(uError) {
6900 pMe->uLastError = (uint8_t)uError;
6901 return;
6902 }
6903
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006904 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006905 {
6906 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006907 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6908 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6909 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006910 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006911
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006912 QCBOR_Private_ProcessExpMantissa(pMe,
6913 TagSpec,
6914 &Item,
6915 pnMantissa,
6916 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006917}
6918
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006919
6920/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006921 * Public function, see header qcbor/qcbor_decode.h file
6922 */
6923void
6924QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe,
6925 const int64_t nLabel,
6926 const uint8_t uTagRequirement,
6927 int64_t *pnMantissa,
6928 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006929{
6930 if(pMe->uLastError != QCBOR_SUCCESS) {
6931 return;
6932 }
6933
6934 QCBORItem Item;
6935 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
6936
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006937 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006938 {
6939 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006940 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6941 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6942 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006943 };
6944
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006945 QCBOR_Private_ProcessExpMantissa(pMe,
6946 TagSpec,
6947 &Item,
6948 pnMantissa,
6949 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006950}
6951
6952
6953/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006954 * Public function, see header qcbor/qcbor_decode.h file
6955 */
6956void
6957QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
6958 const char *szLabel,
6959 const uint8_t uTagRequirement,
6960 int64_t *pnMantissa,
6961 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006962{
6963 if(pMe->uLastError != QCBOR_SUCCESS) {
6964 return;
6965 }
6966
6967 QCBORItem Item;
6968 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
6969
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006970 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006971 {
6972 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006973 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6974 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6975 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006976 };
Laurence Lundblade9b334962020-08-27 10:55:53 -07006977
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006978 QCBOR_Private_ProcessExpMantissa(pMe,
6979 TagSpec,
6980 &Item,
6981 pnMantissa,
6982 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006983}
6984
6985
6986/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006987 * Public function, see header qcbor/qcbor_decode.h file
6988 */
6989void
6990QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe,
6991 const uint8_t uTagRequirement,
6992 const UsefulBuf MantissaBuffer,
6993 UsefulBufC *pMantissa,
6994 bool *pbMantissaIsNegative,
6995 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006996{
6997 if(pMe->uLastError != QCBOR_SUCCESS) {
6998 return;
6999 }
7000
7001 QCBORItem Item;
7002 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
7003 if(uError) {
7004 pMe->uLastError = (uint8_t)uError;
7005 return;
7006 }
7007
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007008 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007009 {
7010 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007011 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7012 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7013 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007014 };
7015
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007016 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7017 TagSpec,
7018 &Item,
7019 MantissaBuffer,
7020 pMantissa,
7021 pbMantissaIsNegative,
7022 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007023}
7024
7025
7026/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007027 * Public function, see header qcbor/qcbor_decode.h file
7028 */
7029void
7030QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe,
7031 const int64_t nLabel,
7032 const uint8_t uTagRequirement,
7033 const UsefulBuf BufferForMantissa,
7034 UsefulBufC *pMantissa,
7035 bool *pbIsNegative,
7036 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007037{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007038 if(pMe->uLastError != QCBOR_SUCCESS) {
7039 return;
7040 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007041
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007042 QCBORItem Item;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007043 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007044 if(pMe->uLastError != QCBOR_SUCCESS) {
7045 return;
7046 }
7047
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007048 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007049 {
7050 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007051 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7052 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7053 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007054 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007055
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007056 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7057 TagSpec,
7058 &Item,
7059 BufferForMantissa,
7060 pMantissa,
7061 pbIsNegative,
7062 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007063}
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007064
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007065
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007066/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007067 * Public function, see header qcbor/qcbor_decode.h file
7068 */
7069void
7070QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe,
7071 const char *szLabel,
7072 const uint8_t uTagRequirement,
7073 const UsefulBuf BufferForMantissa,
7074 UsefulBufC *pMantissa,
7075 bool *pbIsNegative,
7076 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007077{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007078 if(pMe->uLastError != QCBOR_SUCCESS) {
7079 return;
7080 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007081
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007082 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007083 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7084 if(pMe->uLastError != QCBOR_SUCCESS) {
7085 return;
7086 }
7087
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007088 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007089 {
7090 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007091 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7092 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7093 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007094 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007095
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007096 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7097 TagSpec,
7098 &Item,
7099 BufferForMantissa,
7100 pMantissa,
7101 pbIsNegative,
7102 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007103}
7104
7105
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007106/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007107 * Public function, see header qcbor/qcbor_decode.h file
7108 */
7109void
7110QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe,
7111 const uint8_t uTagRequirement,
7112 int64_t *pnMantissa,
7113 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007114{
7115 if(pMe->uLastError != QCBOR_SUCCESS) {
7116 return;
7117 }
7118
7119 QCBORItem Item;
7120 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
7121 if(uError) {
7122 pMe->uLastError = (uint8_t)uError;
7123 return;
7124 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007125 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007126 {
7127 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007128 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7129 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7130 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007131 };
7132
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007133 QCBOR_Private_ProcessExpMantissa(pMe,
7134 TagSpec,
7135 &Item,
7136 pnMantissa,
7137 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007138}
7139
7140
7141/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007142 * Public function, see header qcbor/qcbor_decode.h file
7143 */
7144void
7145QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe,
7146 const int64_t nLabel,
7147 const uint8_t uTagRequirement,
7148 int64_t *pnMantissa,
7149 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007150{
7151 if(pMe->uLastError != QCBOR_SUCCESS) {
7152 return;
7153 }
7154
7155 QCBORItem Item;
7156 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7157 if(pMe->uLastError != QCBOR_SUCCESS) {
7158 return;
7159 }
7160
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007161 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007162 {
7163 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007164 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7165 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7166 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007167 };
7168
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007169 QCBOR_Private_ProcessExpMantissa(pMe,
7170 TagSpec,
7171 &Item,
7172 pnMantissa,
7173 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007174}
7175
7176
7177/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007178 * Public function, see header qcbor/qcbor_decode.h file
7179 */
7180void
7181QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe,
7182 const char *szLabel,
7183 const uint8_t uTagRequirement,
7184 int64_t *pnMantissa,
7185 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007186{
7187 if(pMe->uLastError != QCBOR_SUCCESS) {
7188 return;
7189 }
7190
7191 QCBORItem Item;
7192 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7193 if(pMe->uLastError != QCBOR_SUCCESS) {
7194 return;
7195 }
7196
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007197 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007198 {
7199 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007200 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7201 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7202 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007203 };
7204
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007205 QCBOR_Private_ProcessExpMantissa(pMe,
7206 TagSpec,
7207 &Item,
7208 pnMantissa,
7209 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007210}
7211
7212
7213/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007214 * Public function, see header qcbor/qcbor_decode.h file
7215 */
7216void
7217QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe,
7218 const uint8_t uTagRequirement,
7219 const UsefulBuf MantissaBuffer,
7220 UsefulBufC *pMantissa,
7221 bool *pbMantissaIsNegative,
7222 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007223{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007224 if(pMe->uLastError != QCBOR_SUCCESS) {
7225 return;
7226 }
7227
7228 QCBORItem Item;
7229 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
7230 if(uError) {
7231 pMe->uLastError = (uint8_t)uError;
7232 return;
7233 }
7234
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007235 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007236 {
7237 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007238 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7239 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7240 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007241 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007242
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007243 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7244 TagSpec,
7245 &Item,
7246 MantissaBuffer,
7247 pMantissa,
7248 pbMantissaIsNegative,
7249 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007250}
7251
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007252
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007253/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007254 * Public function, see header qcbor/qcbor_decode.h file
7255 */
7256void
7257QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe,
7258 const int64_t nLabel,
7259 const uint8_t uTagRequirement,
7260 const UsefulBuf BufferForMantissa,
7261 UsefulBufC *pMantissa,
7262 bool *pbIsNegative,
7263 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007264{
7265 if(pMe->uLastError != QCBOR_SUCCESS) {
7266 return;
7267 }
7268
7269 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007270 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7271 if(pMe->uLastError != QCBOR_SUCCESS) {
7272 return;
7273 }
7274
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007275 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007276 {
7277 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007278 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7279 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7280 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007281 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007282
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007283 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7284 TagSpec,
7285 &Item,
7286 BufferForMantissa,
7287 pMantissa,
7288 pbIsNegative,
7289 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007290}
7291
7292
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007293/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007294 * Public function, see header qcbor/qcbor_decode.h file
7295 */
7296void
7297QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe,
7298 const char *szLabel,
7299 const uint8_t uTagRequirement,
7300 const UsefulBuf BufferForMantissa,
7301 UsefulBufC *pMantissa,
7302 bool *pbIsNegative,
7303 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007304{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007305 if(pMe->uLastError != QCBOR_SUCCESS) {
7306 return;
7307 }
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007308
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007309 QCBORItem Item;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007310 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7311 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007312 return;
7313 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007314
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007315 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007316 {
7317 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007318 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7319 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7320 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007321 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007322
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007323 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7324 TagSpec,
7325 &Item,
7326 BufferForMantissa,
7327 pMantissa,
7328 pbIsNegative,
7329 pnExponent);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007330}
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007331
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07007332#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */