blob: 30253c24346112a4efc731231f25724d2053894c [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 *
854 * @param[in] nMajorType The CBOR major type (0 or 1).
855 * @param[in] uArgument The argument from the head.
856 * @param[out] pDecodedItem The filled in decoded item.
857 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -0700858 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800859 *
860 * Must only be called when major type is 0 or 1.
861 *
862 * CBOR doesn't explicitly specify two's compliment for integers but
863 * all CPUs use it these days and the test vectors in the RFC are
864 * so. All integers in the CBOR structure are positive and the major
865 * type indicates positive or negative. CBOR can express positive
866 * integers up to 2^x - 1 where x is the number of bits and negative
867 * integers down to 2^x. Note that negative numbers can be one more
868 * away from zero than positive. Stdint, as far as I can tell, uses
869 * two's compliment to represent negative integers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700870 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700871static QCBORError
872QCBOR_Private_DecodeInteger(const int nMajorType,
873 const uint64_t uArgument,
Laurence Lundblade62cae932024-06-03 13:16:17 -0700874 const int nAdditionalInfo,
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700875 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700876{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800877 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800878
Laurence Lundblade62cae932024-06-03 13:16:17 -0700879 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
880 uReturn = QCBOR_ERR_BAD_INT;
881 goto Done;
882 }
883
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700884 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800885 if (uArgument <= INT64_MAX) {
886 pDecodedItem->val.int64 = (int64_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700887 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800888
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700889 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800890 pDecodedItem->val.uint64 = uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700891 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700892 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800893
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700894 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800895 if(uArgument <= INT64_MAX) {
896 /* CBOR's representation of negative numbers lines up with
897 * the two-compliment representation. A negative integer has
898 * one more in range than a positive integer. INT64_MIN is
899 * equal to (-INT64_MAX) - 1.
900 */
901 pDecodedItem->val.int64 = (-(int64_t)uArgument) - 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700902 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800903
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700904 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800905 /* C can't represent a negative integer in this range so it
906 * is an error.
907 */
908 uReturn = QCBOR_ERR_INT_OVERFLOW;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700909 }
910 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800911
Laurence Lundblade62cae932024-06-03 13:16:17 -0700912Done:
913 return uReturn;
914}
915
916
917static QCBORError
918QCBOR_Private_DecodeTag(const int nAdditionalInfo,
919 const uint64_t uArgument,
920 QCBORItem *pDecodedItem)
921{
922 QCBORError uReturn;
923
924#ifndef QCBOR_DISABLE_TAGS
925 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
926 uReturn = QCBOR_ERR_BAD_INT;
927 } else {
928 pDecodedItem->val.uTagV = uArgument;
929 pDecodedItem->uDataType = QCBOR_TYPE_TAG;
930 uReturn = QCBOR_SUCCESS;
931 }
932#else /* QCBOR_DISABLE_TAGS */
Laurence Lundbladecfd8a2c2024-06-06 21:01:42 -0700933 (void)nAdditionalInfo;
934 (void)uArgument;
935 (void)pDecodedItem;
936 uReturn = QCBOR_ERR_TAGS_DISABLED;
Laurence Lundblade62cae932024-06-03 13:16:17 -0700937#endif /* QCBOR_DISABLE_TAGS */
938
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800939 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700940}
941
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800942
943/* Make sure #define value line up as DecodeSimple counts on this. */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700944#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
945#error QCBOR_TYPE_FALSE macro value wrong
946#endif
947
948#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
949#error QCBOR_TYPE_TRUE macro value wrong
950#endif
951
952#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
953#error QCBOR_TYPE_NULL macro value wrong
954#endif
955
956#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
957#error QCBOR_TYPE_UNDEF macro value wrong
958#endif
959
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700960#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
961#error QCBOR_TYPE_BREAK macro value wrong
962#endif
963
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700964#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
965#error QCBOR_TYPE_DOUBLE macro value wrong
966#endif
967
968#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
969#error QCBOR_TYPE_FLOAT macro value wrong
970#endif
971
Laurence Lundblade9b334962020-08-27 10:55:53 -0700972
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800973/**
974 * @brief Decode major type 7 -- true, false, floating-point, break...
975 *
976 * @param[in] nAdditionalInfo The lower five bits from the initial byte.
977 * @param[in] uArgument The argument from the head.
978 * @param[out] pDecodedItem The filled in decoded item.
979 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -0700980 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
981 * of half-precision disabled
982 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all float
983 * decode is disabled.
984 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of simple
985 * type in input.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700986 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700987static QCBORError
988QCBOR_Private_DecodeType7(const int nAdditionalInfo,
989 const uint64_t uArgument,
990 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800991{
992 QCBORError uReturn = QCBOR_SUCCESS;
993
994 /* uAdditionalInfo is 5 bits from the initial byte. Compile time
995 * checks above make sure uAdditionalInfo values line up with
996 * uDataType values. DecodeHead() never returns an AdditionalInfo
997 * > 0x1f so cast is safe.
998 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800999 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001000
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001001 switch(nAdditionalInfo) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001002 /* No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they
1003 * are caught before this is called.
1004 */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001005
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001006 case HALF_PREC_FLOAT: /* 25 */
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -07001007#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001008 /* Half-precision is returned as a double. The cast to
1009 * uint16_t is safe because the encoded value was 16 bits. It
1010 * was widened to 64 bits to be passed in here.
1011 */
1012 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uArgument);
Laurence Lundblade67bd5512018-11-02 21:44:06 +07001013 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001014#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001015 uReturn = FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001016 break;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001017 case SINGLE_PREC_FLOAT: /* 26 */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001018#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001019 /* Single precision is normally returned as a double since
1020 * double is widely supported, there is no loss of precision,
1021 * it makes it easy for the caller in most cases and it can
1022 * be converted back to single with no loss of precision
1023 *
1024 * The cast to uint32_t is safe because the encoded value was
1025 * 32 bits. It was widened to 64 bits to be passed in here.
1026 */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001027 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001028 const float f = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uArgument);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001029#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001030 /* In the normal case, use HW to convert float to
1031 * double. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001032 pDecodedItem->val.dfnum = (double)f;
1033 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001034#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001035 /* Use of float HW is disabled, return as a float. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001036 pDecodedItem->val.fnum = f;
1037 pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
1038
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001039 /* IEEE754_FloatToDouble() could be used here to return as
1040 * a double, but it adds object code and most likely
1041 * anyone disabling FLOAT HW use doesn't care about floats
1042 * and wants to save object code.
1043 */
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001044#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001045 }
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001046#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1047 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001048 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001049
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001050 case DOUBLE_PREC_FLOAT: /* 27 */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001051#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001052 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uArgument);
Laurence Lundblade67bd5512018-11-02 21:44:06 +07001053 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001054#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1055 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001056 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001057
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001058 case CBOR_SIMPLEV_FALSE: /* 20 */
1059 case CBOR_SIMPLEV_TRUE: /* 21 */
1060 case CBOR_SIMPLEV_NULL: /* 22 */
1061 case CBOR_SIMPLEV_UNDEF: /* 23 */
1062 case CBOR_SIMPLE_BREAK: /* 31 */
1063 break; /* nothing to do */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001064
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001065 case CBOR_SIMPLEV_ONEBYTE: /* 24 */
1066 if(uArgument <= CBOR_SIMPLE_BREAK) {
1067 /* This takes out f8 00 ... f8 1f which should be encoded
1068 * as e0 … f7
1069 */
1070 uReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001071 goto Done;
1072 }
Laurence Lundblade5e390822019-01-06 12:35:01 -08001073 /* FALLTHROUGH */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001074
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001075 default: /* 0-19 */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001076 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001077 /* DecodeHead() will make uArgument equal to
1078 * nAdditionalInfo when nAdditionalInfo is < 24. This cast is
1079 * safe because the 2, 4 and 8 byte lengths of uNumber are in
1080 * the double/float cases above
Laurence Lundbladeee851742020-01-08 08:37:05 -08001081 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001082 pDecodedItem->val.uSimple = (uint8_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001083 break;
1084 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001085
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001086Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001087 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001088}
1089
1090
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001091/**
1092 * @brief Decode text and byte strings
1093 *
Laurence Lundblade78a66132024-06-06 12:19:59 -07001094 * @param[in] pMe Decoder context.
1095 * @param[in] bAllocate Whether to allocate and copy string.
1096 * @param[in] nMajorType Whether it is a byte or text string.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001097 * @param[in] uStrLen The length of the string.
Laurence Lundblade78a66132024-06-06 12:19:59 -07001098 * @param[in] nAdditionalInfo Whether it is an indefinite-length string.
1099 * @param[out] pDecodedItem The filled-in decoded item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001100 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001101 * @retval QCBOR_ERR_HIT_END Unexpected end of input.
1102 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1103 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
Laurence Lundblade78a66132024-06-06 12:19:59 -07001104 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001105 *
Laurence Lundblade78a66132024-06-06 12:19:59 -07001106 * This reads @c uStrlen bytes from the input and fills in @c
1107 * pDecodedItem. If @c bAllocate is true, then memory for the string
1108 * is allocated.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001109 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001110static QCBORError
Laurence Lundblade78a66132024-06-06 12:19:59 -07001111QCBOR_Private_DecodeString(QCBORDecodeContext *pMe,
1112 const bool bAllocate,
1113 const int nMajorType,
1114 const uint64_t uStrLen,
1115 const int nAdditionalInfo,
1116 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001117{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001118 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001119
Laurence Lundblade78a66132024-06-06 12:19:59 -07001120 /* ---- Figure out the major type ---- */
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001121 #if CBOR_MAJOR_TYPE_BYTE_STRING + 4 != QCBOR_TYPE_BYTE_STRING
Laurence Lundblade78a66132024-06-06 12:19:59 -07001122 #error QCBOR_TYPE_BYTE_STRING not lined up with major type
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001123 #endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001124
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001125 #if CBOR_MAJOR_TYPE_TEXT_STRING + 4 != QCBOR_TYPE_TEXT_STRING
Laurence Lundblade78a66132024-06-06 12:19:59 -07001126 #error QCBOR_TYPE_TEXT_STRING not lined up with major type
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001127 #endif
Laurence Lundblade62cae932024-06-03 13:16:17 -07001128 pDecodedItem->uDataType = (uint8_t)(nMajorType + 4);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001129
Laurence Lundblade62cae932024-06-03 13:16:17 -07001130 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundblade78a66132024-06-06 12:19:59 -07001131 /* --- Just the head of an indefinite-length string --- */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001132 pDecodedItem->val.string = (UsefulBufC){NULL, QCBOR_STRING_LENGTH_INDEFINITE};
1133
1134 } else {
Laurence Lundblade78a66132024-06-06 12:19:59 -07001135 /* --- A definite-length string --- */
1136 /* --- (which might be a chunk of an indefinte-length string) --- */
1137
Laurence Lundblade62cae932024-06-03 13:16:17 -07001138 /* CBOR lengths can be 64 bits, but size_t is not 64 bits on all
1139 * CPUs. This check makes the casts to size_t below safe.
1140 *
1141 * The max is 4 bytes less than the largest sizeof() so this can be
1142 * tested by putting a SIZE_MAX length in the CBOR test input (no
1143 * one will care the limit on strings is 4 bytes shorter).
1144 */
1145 if(uStrLen > SIZE_MAX-4) {
1146 uReturn = QCBOR_ERR_STRING_TOO_LONG;
1147 goto Done;
1148 }
1149
Laurence Lundblade78a66132024-06-06 12:19:59 -07001150 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(&(pMe->InBuf), (size_t)uStrLen);
Laurence Lundblade62cae932024-06-03 13:16:17 -07001151 if(UsefulBuf_IsNULLC(Bytes)) {
1152 /* Failed to get the bytes for this string item */
1153 uReturn = QCBOR_ERR_HIT_END;
1154 goto Done;
1155 }
1156
1157#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade78a66132024-06-06 12:19:59 -07001158 if(bAllocate) {
1159 /* --- Put string in allocated memory --- */
1160
1161 /* Note that this is not where allocation to coalesce
1162 * indefinite-length strings is done. This is for when the
1163 * caller has requested all strings be allocated. Disabling
1164 * indefinite length strings also disables this allocate-all
1165 * option.
1166 */
1167
1168 if(pMe->StringAllocator.pfAllocator == NULL) {
1169 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1170 goto Done;
1171 }
1172 UsefulBuf NewMem = StringAllocator_Allocate(&(pMe->StringAllocator), (size_t)uStrLen);
Laurence Lundblade62cae932024-06-03 13:16:17 -07001173 if(UsefulBuf_IsNULL(NewMem)) {
1174 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1175 goto Done;
1176 }
1177 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
1178 pDecodedItem->uDataAlloc = 1;
1179 goto Done;
1180 }
Laurence Lundblade9533c482024-06-06 21:41:10 -07001181#else
1182 (void)bAllocate;
Laurence Lundblade62cae932024-06-03 13:16:17 -07001183#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1184
Laurence Lundblade78a66132024-06-06 12:19:59 -07001185 /* --- Normal case with no string allocator --- */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001186 pDecodedItem->val.string = Bytes;
1187 }
1188
1189Done:
1190 return uReturn;
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001191}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001192
1193
Laurence Lundblade62cae932024-06-03 13:16:17 -07001194
1195
Laurence Lundblade78a66132024-06-06 12:19:59 -07001196/**
1197 * @brief Decode array or map.
1198 *
1199 * @param[in] uMode Decoder mode.
1200 * @param[in] nMajorType Whether it is a byte or text string.
1201 * @param[in] uItemCount The length of the string.
1202 * @param[in] nAdditionalInfo Whether it is an indefinite-length.
1203 * @param[out] pDecodedItem The filled-in decoded item.
1204 *
1205 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinites disabled.
1206 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map.
1207 *
1208 * Not much to do for arrays and maps. Just the type
1209 * item count.
1210 *
1211 * This also does the bulk of the work for QCBOR_DECODE_MODE_MAP_AS_ARRAY,
1212 * a special mode to handle arbitrarily complex map labels. This
1213 * ifdefs out with QCBOR_DISABLE_NON_INTEGER_LABELS.
1214 */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001215static QCBORError
1216QCBOR_Private_DecodeArrayOrMap(const uint8_t uMode,
1217 const int nMajorType,
1218 const uint64_t uItemCount,
1219 const int nAdditionalInfo,
1220 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001221{
Laurence Lundblade62cae932024-06-03 13:16:17 -07001222 QCBORError uReturn;
1223
1224 /* ------ Sort out the data type ------ */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001225 #if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
1226 #error QCBOR_TYPE_ARRAY value not lined up with major type
1227 #endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001228
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001229 #if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
1230 #error QCBOR_TYPE_MAP value not lined up with major type
1231 #endif
Laurence Lundblade62cae932024-06-03 13:16:17 -07001232 pDecodedItem->uDataType = (uint8_t)nMajorType;
1233#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1234 if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
1235 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
1236 }
Laurence Lundbladecfd8a2c2024-06-06 21:01:42 -07001237#else
1238 (void)uMode;
Laurence Lundblade78a66132024-06-06 12:19:59 -07001239#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001240
Laurence Lundblade62cae932024-06-03 13:16:17 -07001241 uReturn = QCBOR_SUCCESS;
1242
1243 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundblade78a66132024-06-06 12:19:59 -07001244 /* ------ Indefinite-length array/map ----- */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001245#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
1246 pDecodedItem->val.uCount = QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH;
1247#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1248 uReturn = QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED;
1249#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1250 } else {
1251
1252#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1253 if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
1254 /* ------ Definite-length map as array ------ */
1255
1256 if(uItemCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
1257 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
1258 } else {
1259 /* cast OK because of check above */
1260 pDecodedItem->val.uCount = (uint16_t)uItemCount*2;
1261 }
1262
1263 } else
Laurence Lundblade78a66132024-06-06 12:19:59 -07001264#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001265 {
1266 /* ------ Definite-length array/map ------ */
1267 if(uItemCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
1268 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
1269 } else {
1270 /* cast OK because of check above */
1271 pDecodedItem->val.uCount = (uint16_t)uItemCount;
1272 }
1273 }
1274 }
1275
1276 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001277}
1278
1279
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001280/**
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001281 * @brief Decode a single primitive data item (decode layer 6).
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001282 *
Laurence Lundblade62cae932024-06-03 13:16:17 -07001283 * param[in] pUInBuf Input buffer to read data item from.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001284 * @param[out] pDecodedItem The filled-in decoded item.
Laurence Lundblade78a66132024-06-06 12:19:59 -07001285 * param[in] pAllocator The allocator to use for strings or NULL.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001286 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001287 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1288 * features
1289 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1290 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1291 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1292 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1293 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1294 * of half-precision disabled
1295 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1296 * float decode is disabled.
1297 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1298 * simple type in input.
1299 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1300 * in input, but indefinite
1301 * lengths disabled.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001302 *
1303 * This decodes the most primitive / atomic data item. It does
1304 * no combing of data items.
1305 */
1306static QCBORError
Laurence Lundblade62cae932024-06-03 13:16:17 -07001307QCBOR_Private_DecodeAtomicDataItem(QCBORDecodeContext *pMe,
Laurence Lundblade78a66132024-06-06 12:19:59 -07001308 const bool bAllocateStrings,
1309 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001310{
1311 QCBORError uReturn;
1312
1313 /* Get the major type and the argument. The argument could be
1314 * length of more bytes or the value depending on the major
1315 * type. nAdditionalInfo is an encoding of the length of the
1316 * uNumber and is needed to decode floats and doubles.
1317 */
1318 int nMajorType = 0;
1319 uint64_t uArgument = 0;
1320 int nAdditionalInfo = 0;
1321
1322 memset(pDecodedItem, 0, sizeof(QCBORItem));
1323
Laurence Lundblade62cae932024-06-03 13:16:17 -07001324 uReturn = QCBOR_Private_DecodeHead(&(pMe->InBuf), &nMajorType, &uArgument, &nAdditionalInfo);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001325 if(uReturn) {
1326 goto Done;
1327 }
1328
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001329 switch (nMajorType) {
1330 case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
1331 case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001332 uReturn = QCBOR_Private_DecodeInteger(nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001333 break;
1334
1335 case CBOR_MAJOR_TYPE_BYTE_STRING: /* Major type 2 */
1336 case CBOR_MAJOR_TYPE_TEXT_STRING: /* Major type 3 */
Laurence Lundblade78a66132024-06-06 12:19:59 -07001337 uReturn = QCBOR_Private_DecodeString(pMe, bAllocateStrings, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001338 break;
1339
1340 case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */
1341 case CBOR_MAJOR_TYPE_MAP: /* Major type 5 */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001342 uReturn = QCBOR_Private_DecodeArrayOrMap(pMe->uDecodeMode, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001343 break;
1344
1345 case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001346 uReturn = QCBOR_Private_DecodeTag(nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001347 break;
1348
1349 case CBOR_MAJOR_TYPE_SIMPLE:
1350 /* Major type 7: float, double, true, false, null... */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001351 uReturn = QCBOR_Private_DecodeType7(nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001352 break;
1353
1354 default:
1355 /* Never happens because DecodeHead() should never return > 7 */
1356 uReturn = QCBOR_ERR_UNSUPPORTED;
1357 break;
1358 }
1359
1360Done:
1361 return uReturn;
1362}
1363
1364
1365/**
1366 * @brief Process indefinite-length strings (decode layer 5).
1367 *
1368 * @param[in] pMe Decoder context
1369 * @param[out] pDecodedItem The decoded item that work is done on.
1370 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001371 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1372 * features
1373 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1374 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1375 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1376 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1377 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1378 * of half-precision disabled
1379 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1380 * float decode is disabled.
1381 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1382 * simple type in input.
1383 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1384 * in input, but indefinite
1385 * lengths disabled.
1386 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1387 * but no string allocator.
1388 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1389 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1390 * input, but indefinite-length
1391 * strings are disabled.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001392 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001393 * If @c pDecodedItem is not an indefinite-length string, this does nothing.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001394 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001395 * If it is, this loops getting the subsequent chunk data items that
1396 * make up the string. The string allocator is used to make a
1397 * contiguous buffer for the chunks. When this completes @c
1398 * pDecodedItem contains the put-together string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001399 *
1400 * Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001401 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001402static QCBORError
1403QCBORDecode_Private_GetNextFullString(QCBORDecodeContext *pMe,
1404 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001405{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001406 /* Aproximate stack usage
1407 * 64-bit 32-bit
1408 * local vars 32 16
1409 * 2 UsefulBufs 32 16
1410 * QCBORItem 56 52
1411 * TOTAL 120 74
1412 */
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001413 QCBORError uReturn;
Laurence Lundblade78a66132024-06-06 12:19:59 -07001414
1415 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, pMe->bStringAllocateAll, pDecodedItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001416 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001417 goto Done;
1418 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001419
Laurence Lundblade78a66132024-06-06 12:19:59 -07001420 /* Skip out if not an indefinite-length string */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001421 const uint8_t uStringType = pDecodedItem->uDataType;
Laurence Lundblade78a66132024-06-06 12:19:59 -07001422 if(uStringType != QCBOR_TYPE_BYTE_STRING &&
1423 uStringType != QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001424 goto Done;
1425 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001426 if(pDecodedItem->val.string.len != QCBOR_STRING_LENGTH_INDEFINITE) {
1427 goto Done;
1428 }
1429
1430#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001431 /* Can't decode indefinite-length strings without a string allocator */
Laurence Lundblade78a66132024-06-06 12:19:59 -07001432 if(!pMe->StringAllocator.pfAllocator) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001433 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1434 goto Done;
1435 }
1436
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001437 /* Loop getting chunks of the indefinite-length string */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001438 UsefulBufC FullString = NULLUsefulBufC;
1439
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001440 for(;;) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001441 /* Get QCBORItem for next chunk */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001442 QCBORItem StringChunkItem;
Laurence Lundblade78a66132024-06-06 12:19:59 -07001443 /* Pass a false to DecodeAtomicDataItem() because the
1444 * individual string chunks in an indefinite-length must not
1445 * be allocated. They are always copied into the allocated contiguous
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001446 * buffer allocated here.
1447 */
Laurence Lundblade78a66132024-06-06 12:19:59 -07001448 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &StringChunkItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001449 if(uReturn) {
1450 break;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001451 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001452
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001453 /* Is item is the marker for end of the indefinite-length string? */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001454 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001455 /* String is complete */
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001456 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301457 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001458 break;
1459 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001460
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001461 /* All chunks must be of the same type, the type of the item
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001462 * that introduces the indefinite-length string. This also
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001463 * catches errors where the chunk is not a string at all and an
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001464 * indefinite-length string inside an indefinite-length string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001465 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001466 if(StringChunkItem.uDataType != uStringType ||
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001467 StringChunkItem.val.string.len == QCBOR_STRING_LENGTH_INDEFINITE) {
1468 uReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001469 break;
1470 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001471
David Navarro9123e5b2022-03-28 16:04:03 +02001472 if (StringChunkItem.val.string.len > 0) {
1473 /* The first time throurgh FullString.ptr is NULL and this is
1474 * equivalent to StringAllocator_Allocate(). Subsequently it is
1475 * not NULL and a reallocation happens.
1476 */
Laurence Lundblade78a66132024-06-06 12:19:59 -07001477 UsefulBuf NewMem = StringAllocator_Reallocate(&(pMe->StringAllocator),
David Navarro9123e5b2022-03-28 16:04:03 +02001478 FullString.ptr,
1479 FullString.len + StringChunkItem.val.string.len);
David Navarro9123e5b2022-03-28 16:04:03 +02001480 if(UsefulBuf_IsNULL(NewMem)) {
1481 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1482 break;
1483 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001484
David Navarro9123e5b2022-03-28 16:04:03 +02001485 /* Copy new string chunk to the end of accumulated string */
1486 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001487 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001488 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001489
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001490 if(uReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
1491 /* Getting the item failed, clean up the allocated memory */
Laurence Lundblade78a66132024-06-06 12:19:59 -07001492 StringAllocator_Free(&(pMe->StringAllocator), FullString.ptr);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001493 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001494#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1495 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1496#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001497
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001498Done:
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001499 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001500}
1501
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001502
Laurence Lundblade37286c02022-09-03 10:05:02 -07001503#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001504/**
1505 * @brief This converts a tag number to a shorter mapped value for storage.
1506 *
1507 * @param[in] pMe The decode context.
1508 * @param[in] uUnMappedTag The tag number to map
1509 * @param[out] puMappedTagNumer The stored tag number.
1510 *
1511 * @return error code.
1512 *
1513 * The main point of mapping tag numbers is make QCBORItem
1514 * smaller. With this mapping storage of 4 tags takes up 8
1515 * bytes. Without, it would take up 32 bytes.
1516 *
1517 * This maps tag numbers greater than QCBOR_LAST_UNMAPPED_TAG.
1518 * QCBOR_LAST_UNMAPPED_TAG is a little smaller than MAX_UINT16.
1519 *
1520 * See also UnMapTagNumber() and @ref QCBORItem.
1521 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001522static QCBORError
1523QCBORDecode_Private_MapTagNumber(QCBORDecodeContext *pMe,
1524 const uint64_t uUnMappedTag,
1525 uint16_t *puMappedTagNumer)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001526{
1527 if(uUnMappedTag > QCBOR_LAST_UNMAPPED_TAG) {
1528 unsigned uTagMapIndex;
1529 /* Is there room in the tag map, or is it in it already? */
1530 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
1531 if(pMe->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID64) {
1532 break;
1533 }
1534 if(pMe->auMappedTags[uTagMapIndex] == uUnMappedTag) {
1535 break;
1536 }
1537 }
1538 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
1539 return QCBOR_ERR_TOO_MANY_TAGS;
1540 }
1541
1542 /* Covers the cases where tag is new and were it is already in the map */
1543 pMe->auMappedTags[uTagMapIndex] = uUnMappedTag;
1544 *puMappedTagNumer = (uint16_t)(uTagMapIndex + QCBOR_LAST_UNMAPPED_TAG + 1);
1545
1546 } else {
1547 *puMappedTagNumer = (uint16_t)uUnMappedTag;
1548 }
1549
1550 return QCBOR_SUCCESS;
1551}
1552
1553
1554/**
1555 * @brief This converts a mapped tag number to the actual tag number.
1556 *
1557 * @param[in] pMe The decode context.
1558 * @param[in] uMappedTagNumber The stored tag number.
1559 *
1560 * @return The actual tag number is returned or
1561 * @ref CBOR_TAG_INVALID64 on error.
1562 *
1563 * This is the reverse of MapTagNumber()
1564 */
1565static uint64_t
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001566QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe,
1567 const uint16_t uMappedTagNumber)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001568{
1569 if(uMappedTagNumber <= QCBOR_LAST_UNMAPPED_TAG) {
1570 return uMappedTagNumber;
1571 } else if(uMappedTagNumber == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07001572 return CBOR_TAG_INVALID64;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001573 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001574 /* This won't be negative because of code below in
1575 * MapTagNumber()
1576 */
1577 const unsigned uIndex = uMappedTagNumber - (QCBOR_LAST_UNMAPPED_TAG + 1);
1578 return pMe->auMappedTags[uIndex];
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001579 }
1580}
Laurence Lundblade37286c02022-09-03 10:05:02 -07001581#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001582
Laurence Lundblade9b334962020-08-27 10:55:53 -07001583
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001584/**
1585 * @brief Aggregate all tags wrapping a data item (decode layer 4).
1586 *
1587 * @param[in] pMe Decoder context
1588 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001589 *
1590 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1591 * features
1592 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1593 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1594 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1595 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1596 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1597 * of half-precision disabled
1598 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1599 * float decode is disabled.
1600 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1601 * simple type in input.
1602 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1603 * in input, but indefinite
1604 * lengths disabled.
1605 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1606 * but no string allocator.
1607 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1608 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1609 * input, but indefinite-length
1610 * strings are disabled.
1611 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001612 *
1613 * This loops getting atomic data items until one is not a tag
1614 * number. Usually this is largely pass-through because most
1615 * item are not tag numbers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001616 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001617static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001618QCBORDecode_Private_GetNextTagNumber(QCBORDecodeContext *pMe,
1619 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001620{
Laurence Lundblade37286c02022-09-03 10:05:02 -07001621#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001622 /* Accummulate the tags from multiple items here and then copy them
1623 * into the last item, the non-tag item.
1624 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001625 uint16_t auItemsTags[QCBOR_MAX_TAGS_PER_ITEM];
1626
1627 /* Initialize to CBOR_TAG_INVALID16 */
1628 #if CBOR_TAG_INVALID16 != 0xffff
1629 /* Be sure the memset does the right thing. */
1630 #err CBOR_TAG_INVALID16 tag not defined as expected
1631 #endif
1632 memset(auItemsTags, 0xff, sizeof(auItemsTags));
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001633
Laurence Lundblade9b334962020-08-27 10:55:53 -07001634 QCBORError uReturn = QCBOR_SUCCESS;
1635
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001636 /* Loop fetching data items until the item fetched is not a tag */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001637 for(;;) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001638 QCBORError uErr = QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07001639 if(uErr != QCBOR_SUCCESS) {
1640 uReturn = uErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001641 goto Done;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001642 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001643
Laurence Lundblade9b334962020-08-27 10:55:53 -07001644 if(pDecodedItem->uDataType != QCBOR_TYPE_TAG) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001645 /* Successful exit from loop; maybe got some tags, maybe not */
1646 memcpy(pDecodedItem->uTags, auItemsTags, sizeof(auItemsTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001647 break;
1648 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001649
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001650 if(auItemsTags[QCBOR_MAX_TAGS_PER_ITEM - 1] != CBOR_TAG_INVALID16) {
1651 /* No room in the tag list */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001652 uReturn = QCBOR_ERR_TOO_MANY_TAGS;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001653 /* Continue on to get all tags wrapping this item even though
1654 * it is erroring out in the end. This allows decoding to
1655 * continue. This is a resource limit error, not a problem
1656 * with being well-formed CBOR.
1657 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001658 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001659 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001660 /* Slide tags over one in the array to make room at index 0.
1661 * Must use memmove because the move source and destination
1662 * overlap.
1663 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001664 memmove(&auItemsTags[1],
1665 auItemsTags,
1666 sizeof(auItemsTags) - sizeof(auItemsTags[0]));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001667
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001668 /* Map the tag */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001669 uint16_t uMappedTagNumber = 0;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001670 uReturn = QCBORDecode_Private_MapTagNumber(pMe, pDecodedItem->val.uTagV, &uMappedTagNumber);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001671 /* Continue even on error so as to consume all tags wrapping
1672 * this data item so decoding can go on. If MapTagNumber()
1673 * errors once it will continue to error.
1674 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001675 auItemsTags[0] = uMappedTagNumber;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001676 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001677
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001678Done:
Laurence Lundblade9b334962020-08-27 10:55:53 -07001679 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001680
Laurence Lundblade37286c02022-09-03 10:05:02 -07001681#else /* QCBOR_DISABLE_TAGS */
1682
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07001683 return QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07001684
1685#endif /* QCBOR_DISABLE_TAGS */
1686}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001687
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001688
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001689/**
1690 * @brief Combine a map entry label and value into one item (decode layer 3).
1691 *
1692 * @param[in] pMe Decoder context
1693 * @param[out] pDecodedItem The decoded item that work is done on.
1694 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001695 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1696 * features
1697 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1698 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1699 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1700 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1701 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1702 * of half-precision disabled
1703 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1704 * float decode is disabled.
1705 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1706 * simple type in input.
1707 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1708 * in input, but indefinite
1709 * lengths disabled.
1710 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1711 * but no string allocator.
1712 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1713 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1714 * input, but indefinite-length
1715 * strings are disabled.
1716 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1717 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1718 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001719 *
Laurence Lundblade62cae932024-06-03 13:16:17 -07001720 * If the current nesting level is a map, then this
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001721 * combines pairs of items into one data item with a label
1722 * and value.
1723 *
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07001724 * This is passthrough if the current nesting level is
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001725 * not a map.
1726 *
1727 * This also implements maps-as-array mode where a map
1728 * is treated like an array to allow caller to do their
1729 * own label processing.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001730 */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001731
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001732static QCBORError
1733QCBORDecode_Private_GetNextMapEntry(QCBORDecodeContext *pMe,
1734 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001735{
Laurence Lundblade62cae932024-06-03 13:16:17 -07001736 QCBORItem LabelItem;
1737 QCBORError uErr;
1738
1739 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1740 if(QCBORDecode_IsUnrecoverableError(uErr)) {
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001741 goto Done;
1742 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001743
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001744 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
1745 /* Break can't be a map entry */
1746 goto Done;
1747 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001748
Laurence Lundblade62cae932024-06-03 13:16:17 -07001749 if(!DecodeNesting_IsCurrentTypeMap(&(pMe->nesting))) {
1750 /* Not decoding a map; nothing to do */
1751 /* This is where maps-as-arrays is effected too */
1752 goto Done;
1753 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001754
Laurence Lundblade62cae932024-06-03 13:16:17 -07001755 /* Decoding a map entry, so the item so far is the label; must get value */
1756 LabelItem = *pDecodedItem;
1757 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1758 if(QCBORDecode_IsUnrecoverableError(uErr)) {
1759 goto Done;
1760 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001761
Laurence Lundblade62cae932024-06-03 13:16:17 -07001762 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
1763 pDecodedItem->uLabelType = LabelItem.uDataType;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001764
Laurence Lundblade62cae932024-06-03 13:16:17 -07001765#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1766 /* QCBOR_DECODE_MODE_MAP_STRINGS_ONLY was a bad idea. Maybe
1767 * get rid of it in QCBOR 2.0
1768 */
1769 if(pMe->uDecodeMode == QCBOR_DECODE_MODE_MAP_STRINGS_ONLY &&
1770 LabelItem.uDataType != QCBOR_TYPE_TEXT_STRING) {
1771 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
1772 goto Done;
1773 }
1774#endif /* !QCBOR_DISABLE_NON_INTEGER_LABELS */
1775
1776 switch(LabelItem.uDataType) {
1777 case QCBOR_TYPE_INT64:
1778 pDecodedItem->label.int64 = LabelItem.val.int64;
1779 break;
1780
1781#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1782 case QCBOR_TYPE_UINT64:
1783 pDecodedItem->label.uint64 = LabelItem.val.uint64;
1784 break;
1785
1786 case QCBOR_TYPE_TEXT_STRING:
1787 case QCBOR_TYPE_BYTE_STRING:
1788 pDecodedItem->label.string = LabelItem.val.string;
1789 break;
1790#endif /* !QCBOR_DISABLE_NON_INTEGER_LABELS */
1791
1792 /* case QCBOR_TYPE_BREAK:
1793 uErr = 99;
1794 goto Done; */
1795
1796 default:
1797 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
1798 goto Done;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001799 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001800
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001801Done:
Laurence Lundblade62cae932024-06-03 13:16:17 -07001802 return uErr;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001803}
1804
1805
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001806#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001807/**
1808 * @brief Peek and see if next data item is a break;
1809 *
Laurence Lundblade62cae932024-06-03 13:16:17 -07001810 * param[in] pUIB UsefulInputBuf to read from.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001811 * @param[out] pbNextIsBreak Indicate if next was a break or not.
1812 *
1813 * @return Any decoding error.
1814 *
1815 * See if next item is a CBOR break. If it is, it is consumed,
1816 * if not it is not consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07001817*/
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001818static QCBORError
Laurence Lundblade62cae932024-06-03 13:16:17 -07001819QCBOR_Private_NextIsBreak(QCBORDecodeContext *pMe, bool *pbNextIsBreak)
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001820{
1821 *pbNextIsBreak = false;
Laurence Lundblade62cae932024-06-03 13:16:17 -07001822 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) != 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001823 QCBORItem Peek;
Laurence Lundblade62cae932024-06-03 13:16:17 -07001824 size_t uPeek = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade78a66132024-06-06 12:19:59 -07001825 QCBORError uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &Peek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001826 if(uReturn != QCBOR_SUCCESS) {
1827 return uReturn;
1828 }
1829 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001830 /* It is not a break, rewind so it can be processed normally. */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001831 UsefulInputBuf_Seek(&(pMe->InBuf), uPeek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001832 } else {
1833 *pbNextIsBreak = true;
1834 }
1835 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001836
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001837 return QCBOR_SUCCESS;
1838}
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001839#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001840
1841
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001842/**
1843 * @brief Ascend up nesting levels if all items in them have been consumed.
1844 *
1845 * @param[in] pMe The decode context.
1846 * @param[in] bMarkEnd If true mark end of maps/arrays with count of zero.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001847 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001848 *
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001849 * An item was just consumed, now figure out if it was the
1850 * end of an array/map map that can be closed out. That
1851 * may in turn close out the above array/map...
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001852 *
1853 * When ascending indefinite-length arrays and maps, this will correctly
1854 * consume the break for the level above. This is a problem for the
1855 * implementation of QCBORDecode_GetArray() that must not return
1856 * that break. @c pbBreak is set to true to indicate that one
1857 * byte should be removed.
1858 *
1859 * Improvement: this could reduced further if indef is disabled
1860 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001861static QCBORError
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001862QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd, bool *pbBreak)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001863{
1864 QCBORError uReturn;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001865
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001866 /* Loop ascending nesting levels as long as there is ascending to do */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001867 while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001868 if(pbBreak) {
1869 *pbBreak = false;
1870 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001871
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001872 if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) {
1873 /* Nesting level is bstr-wrapped CBOR */
1874
1875 /* Ascent for bstr-wrapped CBOR is always by explicit call
1876 * so no further ascending can happen.
1877 */
1878 break;
1879
1880 } else if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
1881 /* Level is a definite-length array/map */
1882
1883 /* Decrement the item count the definite-length array/map */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001884 DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(&(pMe->nesting));
1885 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001886 /* Didn't close out array/map, so all work here is done */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001887 break;
1888 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001889 /* All items in a definite-length array were consumed so it
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001890 * is time to ascend one level. This happens below.
1891 */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001892
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001893#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001894 } else {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001895 /* Level is an indefinite-length array/map. */
1896
1897 /* Check for a break which is what ends indefinite-length arrays/maps */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001898 bool bIsBreak = false;
Laurence Lundblade62cae932024-06-03 13:16:17 -07001899 uReturn = QCBOR_Private_NextIsBreak(pMe, &bIsBreak);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001900 if(uReturn != QCBOR_SUCCESS) {
1901 goto Done;
1902 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001903
1904 if(!bIsBreak) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001905 /* Not a break so array/map does not close out. All work is done */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001906 break;
1907 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001908
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001909 /* It was a break in an indefinitelength map / array so
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001910 * it is time to ascend one level.
1911 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001912 if(pbBreak) {
1913 *pbBreak = true;
1914 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001915
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001916#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001917 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001918
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001919
1920 /* All items in the array/map have been consumed. */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001921
Laurence Lundblade93d89472020-10-03 22:30:50 -07001922 /* But ascent in bounded mode is only by explicit call to
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001923 * QCBORDecode_ExitBoundedMode().
1924 */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07001925 if(DecodeNesting_IsCurrentBounded(&(pMe->nesting))) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001926 /* Set the count to zero for definite-length arrays to indicate
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001927 * cursor is at end of bounded array/map */
Laurence Lundbladed0304932020-06-27 10:59:38 -07001928 if(bMarkEnd) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001929 /* Used for definite and indefinite to signal end */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07001930 DecodeNesting_ZeroMapOrArrayCount(&(pMe->nesting));
Laurence Lundbladed0304932020-06-27 10:59:38 -07001931
Laurence Lundblade2c1faf92020-06-26 22:43:56 -07001932 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001933 break;
1934 }
1935
1936 /* Finally, actually ascend one level. */
1937 DecodeNesting_Ascend(&(pMe->nesting));
1938 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001939
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001940 uReturn = QCBOR_SUCCESS;
1941
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001942#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001943Done:
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001944#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1945
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001946 return uReturn;
1947}
1948
1949
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001950/**
1951 * @brief Ascending & Descending out of nesting levels (decode layer 2).
1952 *
1953 * @param[in] pMe Decoder context
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001954 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001955 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001956
1957 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1958 * features
1959 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1960 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1961 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1962 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1963 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1964 * of half-precision disabled
1965 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1966 * float decode is disabled.
1967 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1968 * simple type in input.
1969 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1970 * in input, but indefinite
1971 * lengths disabled.
1972 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1973 * but no string allocator.
1974 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1975 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1976 * input, but indefinite-length
1977 * strings are disabled.
1978 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1979 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1980 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
1981 * @retval QCBOR_ERR_NO_MORE_ITEMS Need more items for map or array.
1982 * @retval QCBOR_ERR_BAD_BREAK Indefinite-length break in wrong
1983 * place.
1984 * @retval QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP Nesting deeper than QCBOR
1985 * can handle.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001986 *
1987 * This handles the traversal descending into and asecnding out of
1988 * maps, arrays and bstr-wrapped CBOR. It figures out the ends of
1989 * definite- and indefinte-length maps and arrays by looking at the
1990 * item count or finding CBOR breaks. It detects the ends of the
1991 * top-level sequence and of bstr-wrapped CBOR by byte count.
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001992 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001993static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001994QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001995 bool *pbBreak,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001996 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001997{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001998 QCBORError uReturn;
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07001999 /* ==== First: figure out if at the end of a traversal ==== */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002000
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002001 /* If out of bytes to consume, it is either the end of the
2002 * top-level sequence of some bstr-wrapped CBOR that was entered.
2003 *
2004 * In the case of bstr-wrapped CBOR, the length of the
2005 * UsefulInputBuf was set to that of the bstr-wrapped CBOR. When
2006 * the bstr-wrapped CBOR is exited, the length is set back to the
2007 * top-level's length or to the next highest bstr-wrapped CBOR.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002008 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002009 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) == 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002010 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002011 goto Done;
2012 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07002013
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002014 /* Check to see if at the end of a bounded definite-length map or
2015 * array. The check for a break ending indefinite-length array is
2016 * later in QCBORDecode_NestLevelAscender().
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002017 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002018 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002019 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002020 goto Done;
2021 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002022
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002023 /* ==== Next: not at the end, so get another item ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002024 uReturn = QCBORDecode_Private_GetNextMapEntry(pMe, pDecodedItem);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002025 if(QCBORDecode_IsUnrecoverableError(uReturn)) {
2026 /* Error is so bad that traversal is not possible. */
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002027 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002028 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05302029
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002030 /* Breaks ending arrays/maps are processed later in the call to
2031 * QCBORDecode_NestLevelAscender(). They should never show up here.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002032 */
Laurence Lundblade6de37062018-10-15 12:22:42 +05302033 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002034 uReturn = QCBOR_ERR_BAD_BREAK;
Laurence Lundblade6de37062018-10-15 12:22:42 +05302035 goto Done;
Laurence Lundblade5b8c5852018-10-14 21:11:42 +05302036 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002037
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002038 /* Record the nesting level for this data item before processing
2039 * any of decrementing and descending.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002040 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002041 pDecodedItem->uNestingLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002042
Laurence Lundblade642282a2020-06-23 12:00:33 -07002043
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002044 /* ==== Next: Process the item for descent, ascent, decrement... ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002045 if(QCBORItem_IsMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002046 /* If the new item is a map or array, descend.
2047 *
2048 * Empty indefinite-length maps and arrays are descended into,
2049 * but then ascended out of in the next chunk of code.
2050 *
2051 * Maps and arrays do count as items in the map/array that
2052 * encloses them so a decrement needs to be done for them too,
2053 * but that is done only when all the items in them have been
2054 * processed, not when they are opened with the exception of an
2055 * empty map or array.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002056 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002057 QCBORError uDescendErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002058 uDescendErr = DecodeNesting_DescendMapOrArray(&(pMe->nesting),
Laurence Lundblade642282a2020-06-23 12:00:33 -07002059 pDecodedItem->uDataType,
2060 pDecodedItem->val.uCount);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002061 if(uDescendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002062 /* This error is probably a traversal error and it overrides
2063 * the non-traversal error.
2064 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002065 uReturn = uDescendErr;
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002066 goto Done;
2067 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002068 }
2069
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002070 if(!QCBORItem_IsMapOrArray(*pDecodedItem) ||
2071 QCBORItem_IsEmptyDefiniteLengthMapOrArray(*pDecodedItem) ||
2072 QCBORItem_IsIndefiniteLengthMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002073 /* The following cases are handled here:
2074 * - A non-aggregate item like an integer or string
2075 * - An empty definite-length map or array
2076 * - An indefinite-length map or array that might be empty or might not.
2077 *
2078 * QCBORDecode_NestLevelAscender() does the work of decrementing the count
2079 * for an definite-length map/array and break detection for an
2080 * indefinite-0length map/array. If the end of the map/array was
2081 * reached, then it ascends nesting levels, possibly all the way
2082 * to the top level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002083 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002084 QCBORError uAscendErr;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002085 uAscendErr = QCBORDecode_Private_NestLevelAscender(pMe, true, pbBreak);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002086 if(uAscendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002087 /* This error is probably a traversal error and it overrides
2088 * the non-traversal error.
2089 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002090 uReturn = uAscendErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002091 goto Done;
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002092 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05302093 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002094
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002095 /* ==== Last: tell the caller the nest level of the next item ==== */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002096 /* Tell the caller what level is next. This tells them what
2097 * maps/arrays were closed out and makes it possible for them to
2098 * reconstruct the tree with just the information returned in a
2099 * QCBORItem.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002100 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002101 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07002102 /* At end of a bounded map/array; uNextNestLevel 0 to indicate this */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002103 pDecodedItem->uNextNestLevel = 0;
2104 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002105 pDecodedItem->uNextNestLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002106 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002107
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002108Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002109 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002110}
2111
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002112
Laurence Lundblade37286c02022-09-03 10:05:02 -07002113#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002114/**
2115 * @brief Shift 0th tag out of the tag list.
2116 *
2117 * pDecodedItem[in,out] The data item to convert.
2118 *
2119 * The 0th tag is discarded. \ref CBOR_TAG_INVALID16 is
2120 * shifted into empty slot at the end of the tag list.
2121 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002122static void
2123QCBOR_Private_ShiftTags(QCBORItem *pDecodedItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002124{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002125 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM-1; i++) {
2126 pDecodedItem->uTags[i] = pDecodedItem->uTags[i+1];
2127 }
2128 pDecodedItem->uTags[QCBOR_MAX_TAGS_PER_ITEM-1] = CBOR_TAG_INVALID16;
Laurence Lundblade9b334962020-08-27 10:55:53 -07002129}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002130#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002131
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002132
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002133/**
2134 * @brief Convert different epoch date formats in to the QCBOR epoch date format
2135 *
2136 * pDecodedItem[in,out] The data item to convert.
2137 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002138 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2139 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2140 * floating-point date disabled.
2141 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2142 * all floating-point disabled.
2143 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2144 * error decoding date.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002145 *
2146 * The epoch date tag defined in QCBOR allows for floating-point
2147 * dates. It even allows a protocol to flop between date formats when
2148 * ever it wants. Floating-point dates aren't that useful as they are
2149 * only needed for dates beyond the age of the earth.
2150 *
2151 * This converts all the date formats into one format of an unsigned
2152 * integer plus a floating-point fraction.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002153 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002154static QCBORError
2155QCBOR_Private_DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002156{
Laurence Lundbladec7114722020-08-13 05:11:40 -07002157 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002158
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002159#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade59289e52019-12-30 13:44:37 -08002160 pDecodedItem->val.epochDate.fSecondsFraction = 0;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002161#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002162
2163 switch (pDecodedItem->uDataType) {
2164
2165 case QCBOR_TYPE_INT64:
2166 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
2167 break;
2168
2169 case QCBOR_TYPE_UINT64:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002170 /* This only happens for CBOR type 0 > INT64_MAX so it is
2171 * always an overflow.
2172 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07002173 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2174 goto Done;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002175 break;
2176
2177 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade9682a532020-06-06 18:33:04 -07002178 case QCBOR_TYPE_FLOAT:
2179#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade59289e52019-12-30 13:44:37 -08002180 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002181 /* Convert working value to double if input was a float */
Laurence Lundblade3ed0bca2020-07-14 22:50:10 -07002182 const double d = pDecodedItem->uDataType == QCBOR_TYPE_DOUBLE ?
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002183 pDecodedItem->val.dfnum :
2184 (double)pDecodedItem->val.fnum;
2185
2186 /* The conversion from float to integer requires overflow
2187 * detection since floats can be much larger than integers.
2188 * This implementation errors out on these large float values
2189 * since they are beyond the age of the earth.
2190 *
2191 * These constants for the overflow check are computed by the
2192 * compiler. They are not computed at run time.
2193 *
2194 * The factor of 0x7ff is added/subtracted to avoid a
2195 * rounding error in the wrong direction when the compiler
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002196 * computes these constants. There is rounding because a
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002197 * 64-bit integer has 63 bits of precision where a double
2198 * only has 53 bits. Without the 0x7ff factor, the compiler
2199 * may round up and produce a double for the bounds check
2200 * that is larger than can be stored in a 64-bit integer. The
2201 * amount of 0x7ff is picked because it has 11 bits set.
2202 *
2203 * Without the 0x7ff there is a ~30 minute range of time
2204 * values 10 billion years in the past and in the future
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002205 * where this code could go wrong. Some compilers
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002206 * generate a warning or error without the 0x7ff.
2207 */
2208 const double dDateMax = (double)(INT64_MAX - 0x7ff);
2209 const double dDateMin = (double)(INT64_MIN + 0x7ff);
2210
2211 if(isnan(d) || d > dDateMax || d < dDateMin) {
Laurence Lundbladec7114722020-08-13 05:11:40 -07002212 uReturn = QCBOR_ERR_DATE_OVERFLOW;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002213 goto Done;
2214 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002215
2216 /* The actual conversion */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002217 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
Laurence Lundblade2feb1e12020-07-15 03:50:45 -07002218 pDecodedItem->val.epochDate.fSecondsFraction =
2219 d - (double)pDecodedItem->val.epochDate.nSeconds;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002220 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002221#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade4b270642020-08-14 12:53:07 -07002222
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002223 uReturn = QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundblade4b270642020-08-14 12:53:07 -07002224 goto Done;
2225
Laurence Lundblade9682a532020-06-06 18:33:04 -07002226#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002227 break;
2228
2229 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002230 /* It's the arrays and maps that are unrecoverable because
2231 * they are not consumed here. Since this is just an error
2232 * condition, no extra code is added here to make the error
2233 * recoverable for non-arrays and maps like strings. */
2234 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002235 goto Done;
2236 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002237
Laurence Lundblade59289e52019-12-30 13:44:37 -08002238 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
2239
2240Done:
Laurence Lundbladec7114722020-08-13 05:11:40 -07002241 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002242}
2243
2244
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002245/**
2246 * @brief Convert the days epoch date.
2247 *
2248 * pDecodedItem[in,out] The data item to convert.
2249 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002250 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2251 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2252 * floating-point date disabled.
2253 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2254 * all floating-point disabled.
2255 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2256 * error decoding date.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002257 *
2258 * This is much simpler than the other epoch date format because
2259 * floating-porint is not allowed. This is mostly a simple type check.
2260 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002261static QCBORError
2262QCBOR_Private_DecodeDaysEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002263{
2264 QCBORError uReturn = QCBOR_SUCCESS;
2265
2266 switch (pDecodedItem->uDataType) {
2267
2268 case QCBOR_TYPE_INT64:
2269 pDecodedItem->val.epochDays = pDecodedItem->val.int64;
2270 break;
2271
2272 case QCBOR_TYPE_UINT64:
2273 /* This only happens for CBOR type 0 > INT64_MAX so it is
2274 * always an overflow.
2275 */
2276 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2277 goto Done;
2278 break;
2279
2280 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002281 /* It's the arrays and maps that are unrecoverable because
2282 * they are not consumed here. Since this is just an error
2283 * condition, no extra code is added here to make the error
2284 * recoverable for non-arrays and maps like strings. */
2285 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002286 goto Done;
2287 break;
2288 }
2289
2290 pDecodedItem->uDataType = QCBOR_TYPE_DAYS_EPOCH;
2291
2292Done:
2293 return uReturn;
2294}
2295
2296
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002297#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade37286c02022-09-03 10:05:02 -07002298
2299/* Forward declaration is necessary for
2300 * QCBORDecode_MantissaAndExponent(). to be able to decode bignum
2301 * tags in the mantissa. If the mantissa is a decimal fraction or big
2302 * float in error, this will result in a recurive call to
2303 * QCBORDecode_MantissaAndExponent(), but the recursion will unwined
2304 * correctly and the correct error is returned.
2305 */
2306static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002307QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2308 QCBORItem *pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002309
2310
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002311/**
2312 * @brief Decode decimal fractions and big floats.
2313 *
2314 * @param[in] pMe The decode context.
2315 * @param[in,out] pDecodedItem On input the array data item that
2316 * holds the mantissa and exponent. On
2317 * output the decoded mantissa and
2318 * exponent.
2319 *
2320 * @returns Decoding errors from getting primitive data items or
2321 * \ref QCBOR_ERR_BAD_EXP_AND_MANTISSA.
2322 *
Laurence Lundblade37286c02022-09-03 10:05:02 -07002323 * When called pDecodedItem must be the array with two members, the
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002324 * exponent and mantissa.
2325 *
2326 * This will fetch and decode the exponent and mantissa and put the
2327 * result back into pDecodedItem.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002328 *
2329 * This does no checking or processing of tag numbers. That is to be
2330 * done by the code that calls this.
2331 *
2332 * This stuffs the type of the mantissa into pDecodedItem with the expectation
2333 * the caller will process it.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002334 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002335static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002336QCBORDecode_Private_ExpMantissa(QCBORDecodeContext *pMe,
2337 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002338{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002339 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002340
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002341 /* --- Make sure it is an array; track nesting level of members --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002342 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002343 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002344 goto Done;
2345 }
2346
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002347 /* A check for pDecodedItem->val.uCount == 2 would work for
Laurence Lundblade37286c02022-09-03 10:05:02 -07002348 * definite-length arrays, but not for indefinite. Instead remember
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002349 * the nesting level the two integers must be at, which is one
2350 * deeper than that of the array.
2351 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002352 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
2353
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002354 /* --- Get the exponent --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002355 QCBORItem exponentItem;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002356 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, &exponentItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002357 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002358 goto Done;
2359 }
2360 if(exponentItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002361 /* Array is empty or a map/array encountered when expecting an int */
2362 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002363 goto Done;
2364 }
2365 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002366 /* Data arriving as an unsigned int < INT64_MAX has been
2367 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2368 * also means that the only data arriving here of type
2369 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2370 * and thus an error that will get handled in the next else.
2371 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002372 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
2373 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002374 /* Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX */
2375 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002376 goto Done;
2377 }
2378
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002379 /* --- Get the mantissa --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002380 QCBORItem mantissaItem;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002381 uReturn = QCBORDecode_Private_GetNextTagContent(pMe, &mantissaItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002382 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002383 goto Done;
2384 }
2385 if(mantissaItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002386 /* Mantissa missing or map/array encountered when expecting number */
2387 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002388 goto Done;
2389 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002390 /* Stuff the mantissa data type into the item to send it up to the
2391 * the next level. */
2392 pDecodedItem->uDataType = mantissaItem.uDataType;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002393 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002394 /* Data arriving as an unsigned int < INT64_MAX has been
2395 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2396 * also means that the only data arriving here of type
2397 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2398 * and thus an error that will get handled in an else below.
2399 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002400 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002401#ifndef QCBOR_DISABLE_TAGS
2402 /* With tags fully disabled a big number mantissa will error out
2403 * in the call to QCBORDecode_GetNextWithTags() because it has
2404 * a tag number.
2405 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07002406 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM ||
2407 mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002408 /* Got a good big num mantissa */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002409 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002410#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002411 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002412 /* Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX */
2413 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002414 goto Done;
2415 }
2416
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002417 /* --- Check that array only has the two numbers --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002418 if(mantissaItem.uNextNestLevel == nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002419 /* Extra items in the decimal fraction / big float */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002420 /* Improvement: this should probably be an unrecoverable error. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002421 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002422 goto Done;
2423 }
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002424 pDecodedItem->uNextNestLevel = mantissaItem.uNextNestLevel;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002425
2426Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002427 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002428}
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002429#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002430
2431
Laurence Lundblade37286c02022-09-03 10:05:02 -07002432#ifndef QCBOR_DISABLE_TAGS
2433
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002434#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002435/**
2436 * @brief Decode the MIME type tag
2437 *
2438 * @param[in,out] pDecodedItem The item to decode.
2439 *
2440 * Handle the text and binary MIME type tags. Slightly too complicated
2441 * f or ProcessTaggedString() because the RFC 7049 MIME type was
2442 * incorreclty text-only.
2443 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002444static QCBORError
2445QCBOR_Private_DecodeMIME(QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002446{
2447 if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) {
2448 pDecodedItem->uDataType = QCBOR_TYPE_MIME;
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07002449 } else if(pDecodedItem->uDataType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002450 pDecodedItem->uDataType = QCBOR_TYPE_BINARY_MIME;
2451 } else {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002452 /* It's the arrays and maps that are unrecoverable because
2453 * they are not consumed here. Since this is just an error
2454 * condition, no extra code is added here to make the error
2455 * recoverable for non-arrays and maps like strings. */
2456 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002457 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002458
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002459 return QCBOR_SUCCESS;
2460}
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002461#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002462
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002463/**
Laurence Lundblade99615302020-11-29 11:19:47 -08002464 * Table of CBOR tags whose content is either a text string or a byte
2465 * string. The table maps the CBOR tag to the QCBOR type. The high-bit
2466 * of uQCBORtype indicates the content should be a byte string rather
2467 * than a text string
2468 */
2469struct StringTagMapEntry {
2470 uint16_t uTagNumber;
2471 uint8_t uQCBORtype;
2472};
2473
2474#define IS_BYTE_STRING_BIT 0x80
2475#define QCBOR_TYPE_MASK ~IS_BYTE_STRING_BIT
2476
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002477static const struct StringTagMapEntry QCBOR_Private_StringTagMap[] = {
Laurence Lundblade99615302020-11-29 11:19:47 -08002478 {CBOR_TAG_DATE_STRING, QCBOR_TYPE_DATE_STRING},
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002479 {CBOR_TAG_DAYS_STRING, QCBOR_TYPE_DAYS_STRING},
Laurence Lundblade99615302020-11-29 11:19:47 -08002480 {CBOR_TAG_POS_BIGNUM, QCBOR_TYPE_POSBIGNUM | IS_BYTE_STRING_BIT},
2481 {CBOR_TAG_NEG_BIGNUM, QCBOR_TYPE_NEGBIGNUM | IS_BYTE_STRING_BIT},
2482 {CBOR_TAG_CBOR, QBCOR_TYPE_WRAPPED_CBOR | IS_BYTE_STRING_BIT},
2483 {CBOR_TAG_URI, QCBOR_TYPE_URI},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002484#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002485 {CBOR_TAG_B64URL, QCBOR_TYPE_BASE64URL},
2486 {CBOR_TAG_B64, QCBOR_TYPE_BASE64},
2487 {CBOR_TAG_REGEX, QCBOR_TYPE_REGEX},
2488 {CBOR_TAG_BIN_UUID, QCBOR_TYPE_UUID | IS_BYTE_STRING_BIT},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002489#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade99615302020-11-29 11:19:47 -08002490 {CBOR_TAG_CBOR_SEQUENCE, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE | IS_BYTE_STRING_BIT},
2491 {CBOR_TAG_INVALID16, QCBOR_TYPE_NONE}
2492};
2493
2494
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002495/**
2496 * @brief Process standard CBOR tags whose content is a string
2497 *
2498 * @param[in] uTag The tag.
2499 * @param[in,out] pDecodedItem The data item.
2500 *
2501 * @returns This returns QCBOR_SUCCESS if the tag was procssed,
2502 * \ref QCBOR_ERR_UNSUPPORTED if the tag was not processed and
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002503 * \ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT if the content type was wrong for the tag.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002504 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002505 * Process the CBOR tags that whose content is a byte string or a text
2506 * string and for which the string is just passed on to the caller.
2507 *
2508 * This maps the CBOR tag to the QCBOR type and checks the content
2509 * type. Nothing more. It may not be the most important
Laurence Lundbladec02e13e2020-12-06 05:45:41 -08002510 * functionality, but it part of implementing as much of RFC 8949 as
Laurence Lundblade99615302020-11-29 11:19:47 -08002511 * possible.
Laurence Lundblade99615302020-11-29 11:19:47 -08002512 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002513static QCBORError
2514QCBOR_Private_ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002515{
Laurence Lundblade99615302020-11-29 11:19:47 -08002516 /* This only works on tags that were not mapped; no need for other yet */
2517 if(uTag > QCBOR_LAST_UNMAPPED_TAG) {
2518 return QCBOR_ERR_UNSUPPORTED;
2519 }
2520
2521 unsigned uIndex;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002522 for(uIndex = 0; QCBOR_Private_StringTagMap[uIndex].uTagNumber != CBOR_TAG_INVALID16; uIndex++) {
2523 if(QCBOR_Private_StringTagMap[uIndex].uTagNumber == uTag) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002524 break;
2525 }
2526 }
2527
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002528 const uint8_t uQCBORType = QCBOR_Private_StringTagMap[uIndex].uQCBORtype;
Laurence Lundblade99615302020-11-29 11:19:47 -08002529 if(uQCBORType == QCBOR_TYPE_NONE) {
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002530 /* repurpose this error to mean not handled here */
Laurence Lundblade99615302020-11-29 11:19:47 -08002531 return QCBOR_ERR_UNSUPPORTED;
2532 }
2533
2534 uint8_t uExpectedType = QCBOR_TYPE_TEXT_STRING;
2535 if(uQCBORType & IS_BYTE_STRING_BIT) {
2536 uExpectedType = QCBOR_TYPE_BYTE_STRING;
2537 }
2538
2539 if(pDecodedItem->uDataType != uExpectedType) {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002540 /* It's the arrays and maps that are unrecoverable because
2541 * they are not consumed here. Since this is just an error
2542 * condition, no extra code is added here to make the error
2543 * recoverable for non-arrays and maps like strings. */
2544 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002545 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002546
Laurence Lundblade99615302020-11-29 11:19:47 -08002547 pDecodedItem->uDataType = (uint8_t)(uQCBORType & QCBOR_TYPE_MASK);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002548 return QCBOR_SUCCESS;
2549}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002550#endif /* QCBOR_DISABLE_TAGS */
2551
2552
2553#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002554/**
2555 * @brief Figures out data type for exponent mantissa tags.
2556 *
2557 * @param[in] uTagToProcess Either @ref CBOR_TAG_DECIMAL_FRACTION or
2558 * @ref CBOR_TAG_BIG_FLOAT.
2559 * @param[in] pDecodedItem Item being decoded.
2560 *
2561 * @returns One of the 6 values between \ref QCBOR_TYPE_DECIMAL_FRACTION
2562 * and @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM.
2563 *
2564 * Does mapping between a CBOR tag number and a QCBOR type. with a
2565 * little bit of logic and arithmatic.
2566 *
2567 * Used in serveral contexts. Does the work where sometimes the data
2568 * item is explicitly tagged and sometimes not.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002569 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002570static uint8_t
2571QCBOR_Private_ExpMantissaDataType(const uint16_t uTagToProcess,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002572 const QCBORItem *pDecodedItem)
Laurence Lundblade37286c02022-09-03 10:05:02 -07002573{
2574 uint8_t uBase = uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ?
2575 QCBOR_TYPE_DECIMAL_FRACTION :
2576 QCBOR_TYPE_BIGFLOAT;
2577 if(pDecodedItem->uDataType != QCBOR_TYPE_INT64) {
2578 uBase = (uint8_t)(uBase + pDecodedItem->uDataType - QCBOR_TYPE_POSBIGNUM + 1);
2579 }
2580 return uBase;
2581}
2582#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002583
2584
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002585/**
2586 * @brief Decode tag content for select tags (decoding layer 1).
2587 *
2588 * @param[in] pMe The decode context.
2589 * @param[out] pDecodedItem The decoded item.
2590 *
2591 * @return Decoding error code.
2592 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002593 * CBOR tag numbers for the item were decoded in GetNext_TaggedItem(),
2594 * but the whole tag was not decoded. Here, the whole tags (tag number
2595 * and tag content) that are supported by QCBOR are decoded. This is a
2596 * quick pass through for items that are not tags.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002597 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002598static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002599QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2600 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002601{
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002602 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002603
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002604 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pDecodedItem);
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002605 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002606 goto Done;
2607 }
2608
Laurence Lundblade37286c02022-09-03 10:05:02 -07002609#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002610 /* When there are no tag numbers for the item, this exits first
2611 * thing and effectively does nothing.
2612 *
2613 * This loops over all the tag numbers accumulated for this item
2614 * trying to decode and interpret them. This stops at the end of
2615 * the list or at the first tag number that can't be interpreted by
2616 * this code. This is effectively a recursive processing of the
2617 * tags number list that handles nested tags.
2618 */
2619 while(1) {
2620 /* Don't bother to unmap tags via QCBORITem.uTags since this
2621 * code only works on tags less than QCBOR_LAST_UNMAPPED_TAG.
2622 */
2623 const uint16_t uTagToProcess = pDecodedItem->uTags[0];
Laurence Lundblade59289e52019-12-30 13:44:37 -08002624
Laurence Lundblade99615302020-11-29 11:19:47 -08002625 if(uTagToProcess == CBOR_TAG_INVALID16) {
2626 /* Hit the end of the tag list. A successful exit. */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002627 break;
2628
Laurence Lundblade99615302020-11-29 11:19:47 -08002629 } else if(uTagToProcess == CBOR_TAG_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002630 uReturn = QCBOR_Private_DecodeDateEpoch(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002631
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002632 } else if(uTagToProcess == CBOR_TAG_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002633 uReturn = QCBOR_Private_DecodeDaysEpoch(pDecodedItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002634
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002635#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade99615302020-11-29 11:19:47 -08002636 } else if(uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ||
2637 uTagToProcess == CBOR_TAG_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002638 uReturn = QCBORDecode_Private_ExpMantissa(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002639 /* --- Which is it, decimal fraction or a bigfloat? --- */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002640 pDecodedItem->uDataType = QCBOR_Private_ExpMantissaDataType(uTagToProcess, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002641
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002642#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002643#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002644 } else if(uTagToProcess == CBOR_TAG_MIME ||
2645 uTagToProcess == CBOR_TAG_BINARY_MIME) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002646 uReturn = QCBOR_Private_DecodeMIME(pDecodedItem);
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002647#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002648
Laurence Lundblade99615302020-11-29 11:19:47 -08002649 } else {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002650 /* See if it is a passthrough byte/text string tag; process if so */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002651 uReturn = QCBOR_Private_ProcessTaggedString(pDecodedItem->uTags[0], pDecodedItem);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002652
Laurence Lundblade99615302020-11-29 11:19:47 -08002653 if(uReturn == QCBOR_ERR_UNSUPPORTED) {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002654 /* It wasn't a passthrough byte/text string tag so it is
Laurence Lundblade99615302020-11-29 11:19:47 -08002655 * an unknown tag. This is the exit from the loop on the
2656 * first unknown tag. It is a successful exit.
2657 */
2658 uReturn = QCBOR_SUCCESS;
2659 break;
2660 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002661 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002662
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002663 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002664 /* Error exit from the loop */
2665 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002666 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002667
2668 /* A tag was successfully processed, shift it out of the list of
2669 * tags returned. This is the loop increment.
2670 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002671 QCBOR_Private_ShiftTags(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002672 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002673#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002674
2675Done:
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002676 return uReturn;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002677}
2678
2679
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002680/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002681 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002682 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002683QCBORError
2684QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2685{
2686 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002687 uErr = QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002688 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002689 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2690 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
2691 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002692 return uErr;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002693}
2694
2695
2696/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002697 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08002698 */
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002699QCBORError
2700QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2701{
2702 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2703 const UsefulInputBuf Save = pMe->InBuf;
2704
2705 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
2706
2707 pMe->nesting = SaveNesting;
2708 pMe->InBuf = Save;
2709
2710 return uErr;
2711}
2712
2713
2714/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002715 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002716 */
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002717void
2718QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2719{
2720 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002721 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2722 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002723 return;
2724 }
2725
2726 pMe->uLastError = (uint8_t)QCBORDecode_PeekNext(pMe, pDecodedItem);
2727}
2728
2729
2730/*
2731 * Public function, see header qcbor/qcbor_decode.h file
2732 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002733void
2734QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002735{
2736 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002737 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2738 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002739 return;
2740 }
2741
2742 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem);
2743}
2744
2745
2746/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002747 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002748 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002749QCBORError
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002750QCBORDecode_GetNextWithTags(QCBORDecodeContext *pMe,
2751 QCBORItem *pDecodedItem,
2752 QCBORTagListOut *pTags)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002753{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002754#ifndef QCBOR_DISABLE_TAGS
2755
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002756 QCBORError uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002757
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002758 uReturn = QCBORDecode_GetNext(pMe, pDecodedItem);
2759 if(uReturn != QCBOR_SUCCESS) {
2760 return uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002761 }
2762
2763 if(pTags != NULL) {
2764 pTags->uNumUsed = 0;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002765 /* Reverse the order because pTags is reverse of QCBORItem.uTags. */
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002766 for(int nTagIndex = QCBOR_MAX_TAGS_PER_ITEM-1; nTagIndex >=0; nTagIndex--) {
2767 if(pDecodedItem->uTags[nTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07002768 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002769 }
2770 if(pTags->uNumUsed >= pTags->uNumAllocated) {
2771 return QCBOR_ERR_TOO_MANY_TAGS;
2772 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002773 pTags->puTags[pTags->uNumUsed] = QCBORDecode_Private_UnMapTagNumber(pMe,pDecodedItem->uTags[nTagIndex]);
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002774 pTags->uNumUsed++;
2775 }
2776 }
2777
2778 return QCBOR_SUCCESS;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002779
2780#else /* QCBOR_DISABLE_TAGS */
2781 (void)pMe;
2782 (void)pDecodedItem;
2783 (void)pTags;
2784 return QCBOR_ERR_TAGS_DISABLED;
2785#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002786}
2787
2788
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002789/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002790 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05302791 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002792bool
2793QCBORDecode_IsTagged(QCBORDecodeContext *pMe,
2794 const QCBORItem *pItem,
2795 uint64_t uTag)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002796{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002797#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002798 for(unsigned uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) {
2799 if(pItem->uTags[uTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002800 break;
2801 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002802 if(QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uTagIndex]) == uTag) {
Laurence Lundbladef71e1622020-08-06 18:52:13 -07002803 return true;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002804 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002805 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002806#else /* QCBOR_TAGS_DISABLED */
2807 (void)pMe;
2808 (void)pItem;
2809 (void)uTag;
2810#endif /* QCBOR_TAGS_DISABLED */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002811
Laurence Lundbladef71e1622020-08-06 18:52:13 -07002812 return false;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002813}
2814
2815
2816/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002817 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002818 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002819QCBORError
2820QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002821{
Laurence Lundblade87495732021-02-26 10:05:55 -07002822 if(puConsumed != NULL) {
2823 *puConsumed = pMe->InBuf.cursor;
2824 }
2825
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002826 QCBORError uReturn = pMe->uLastError;
Laurence Lundblade085d7952020-07-24 10:26:30 -07002827
2828 if(uReturn != QCBOR_SUCCESS) {
2829 goto Done;
2830 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002831
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002832 /* Error out if all the maps/arrays are not closed out */
2833 if(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002834 uReturn = QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002835 goto Done;
2836 }
2837
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002838 /* Error out if not all the bytes are consumed */
2839 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf))) {
Laurence Lundblade085d7952020-07-24 10:26:30 -07002840 uReturn = QCBOR_ERR_EXTRA_BYTES;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002841 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002842
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002843Done:
Laurence Lundblade87495732021-02-26 10:05:55 -07002844 return uReturn;
2845}
2846
2847
2848/*
2849 * Public function, see header qcbor/qcbor_decode.h file
2850 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002851QCBORError
2852QCBORDecode_Finish(QCBORDecodeContext *pMe)
Laurence Lundblade87495732021-02-26 10:05:55 -07002853{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002854#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002855 /* Call the destructor for the string allocator if there is one.
2856 * Always called, even if there are errors; always have to clean up.
2857 */
2858 StringAllocator_Destruct(&(pMe->StringAllocator));
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002859#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002860
Laurence Lundblade87495732021-02-26 10:05:55 -07002861 return QCBORDecode_PartialFinish(pMe, NULL);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002862}
2863
2864
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002865/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002866 * Public function, see header qcbor/qcbor_decode.h file
2867 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002868uint64_t
2869QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
2870 const QCBORItem *pItem,
2871 uint32_t uIndex)
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002872{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002873#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002874 if(pItem->uDataType == QCBOR_TYPE_NONE) {
2875 return CBOR_TAG_INVALID64;
2876 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002877 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2878 return CBOR_TAG_INVALID64;
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002879 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002880 return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uIndex]);
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002881 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002882#else /* QCBOR_DISABLE_TAGS */
2883 (void)pMe;
2884 (void)pItem;
2885 (void)uIndex;
2886
2887 return CBOR_TAG_INVALID64;
2888#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002889}
2890
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002891
Laurence Lundblade9b334962020-08-27 10:55:53 -07002892/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002893 * Public function, see header qcbor/qcbor_decode.h file
2894 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002895uint64_t
2896QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe,
2897 uint32_t uIndex)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002898{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002899#ifndef QCBOR_DISABLE_TAGS
2900
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002901 if(pMe->uLastError != QCBOR_SUCCESS) {
2902 return CBOR_TAG_INVALID64;
2903 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002904 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2905 return CBOR_TAG_INVALID64;
2906 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002907 return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->uLastTags[uIndex]);
Laurence Lundblade9b334962020-08-27 10:55:53 -07002908 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002909#else /* QCBOR_DISABLE_TAGS */
2910 (void)pMe;
2911 (void)uIndex;
2912
2913 return CBOR_TAG_INVALID64;
2914#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07002915}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002916
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002917
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002918
2919
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002920#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladef6531662018-12-04 10:42:22 +09002921
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002922/* ===========================================================================
2923 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002924
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002925 This implements a simple sting allocator for indefinite-length
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002926 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
2927 implements the function type QCBORStringAllocate and allows easy
2928 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09002929
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002930 This particular allocator is built-in for convenience. The caller
2931 can implement their own. All of this following code will get
2932 dead-stripped if QCBORDecode_SetMemPool() is not called.
2933
2934 This is a very primitive memory allocator. It does not track
2935 individual allocations, only a high-water mark. A free or
2936 reallocation must be of the last chunk allocated.
2937
2938 The size of the pool and offset to free memory are packed into the
2939 first 8 bytes of the memory pool so we don't have to keep them in
2940 the decode context. Since the address of the pool may not be
2941 aligned, they have to be packed and unpacked as if they were
2942 serialized data of the wire or such.
2943
2944 The sizes packed in are uint32_t to be the same on all CPU types
2945 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08002946 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002947
2948
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002949static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08002950MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002951{
2952 // Use of UsefulInputBuf is overkill, but it is convenient.
2953 UsefulInputBuf UIB;
2954
Laurence Lundbladeee851742020-01-08 08:37:05 -08002955 // Just assume the size here. It was checked during SetUp so
2956 // the assumption is safe.
Laurence Lundblade93d89472020-10-03 22:30:50 -07002957 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem,QCBOR_DECODE_MIN_MEM_POOL_SIZE});
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002958 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
2959 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
2960 return UsefulInputBuf_GetError(&UIB);
2961}
2962
2963
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002964static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08002965MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002966{
2967 // Use of UsefulOutBuf is overkill, but convenient. The
2968 // length check performed here is useful.
2969 UsefulOutBuf UOB;
2970
2971 UsefulOutBuf_Init(&UOB, Pool);
2972 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
2973 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
2974 return UsefulOutBuf_GetError(&UOB);
2975}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002976
2977
2978/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002979 Internal function for an allocation, reallocation free and destuct.
2980
2981 Having only one function rather than one each per mode saves space in
2982 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002983
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002984 Code Reviewers: THIS FUNCTION DOES POINTER MATH
2985 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08002986static UsefulBuf
2987MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002988{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002989 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002990
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002991 uint32_t uPoolSize;
2992 uint32_t uFreeOffset;
2993
2994 if(uNewSize > UINT32_MAX) {
2995 // This allocator is only good up to 4GB. This check should
2996 // optimize out if sizeof(size_t) == sizeof(uint32_t)
2997 goto Done;
2998 }
2999 const uint32_t uNewSize32 = (uint32_t)uNewSize;
3000
3001 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
3002 goto Done;
3003 }
3004
3005 if(uNewSize) {
3006 if(pMem) {
3007 // REALLOCATION MODE
3008 // Calculate pointer to the end of the memory pool. It is
3009 // assumed that pPool + uPoolSize won't wrap around by
3010 // assuming the caller won't pass a pool buffer in that is
3011 // not in legitimate memory space.
3012 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
3013
3014 // Check that the pointer for reallocation is in the range of the
3015 // pool. This also makes sure that pointer math further down
3016 // doesn't wrap under or over.
3017 if(pMem >= pPool && pMem < pPoolEnd) {
3018 // Offset to start of chunk for reallocation. This won't
3019 // wrap under because of check that pMem >= pPool. Cast
3020 // is safe because the pool is always less than UINT32_MAX
3021 // because of check in QCBORDecode_SetMemPool().
3022 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3023
3024 // Check to see if the allocation will fit. uPoolSize -
3025 // uMemOffset will not wrap under because of check that
3026 // pMem is in the range of the uPoolSize by check above.
3027 if(uNewSize <= uPoolSize - uMemOffset) {
3028 ReturnValue.ptr = pMem;
3029 ReturnValue.len = uNewSize;
3030
3031 // Addition won't wrap around over because uNewSize was
3032 // checked to be sure it is less than the pool size.
3033 uFreeOffset = uMemOffset + uNewSize32;
3034 }
3035 }
3036 } else {
3037 // ALLOCATION MODE
3038 // uPoolSize - uFreeOffset will not underflow because this
3039 // pool implementation makes sure uFreeOffset is always
3040 // smaller than uPoolSize through this check here and
3041 // reallocation case.
3042 if(uNewSize <= uPoolSize - uFreeOffset) {
3043 ReturnValue.len = uNewSize;
3044 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08003045 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003046 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003047 }
3048 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003049 if(pMem) {
3050 // FREE MODE
3051 // Cast is safe because of limit on pool size in
3052 // QCBORDecode_SetMemPool()
3053 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3054 } else {
3055 // DESTRUCT MODE
3056 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003057 }
3058 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003059
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003060 UsefulBuf Pool = {pPool, uPoolSize};
3061 MemPool_Pack(Pool, uFreeOffset);
3062
3063Done:
3064 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003065}
3066
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003067
Laurence Lundbladef6531662018-12-04 10:42:22 +09003068/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003069 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09003070 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003071QCBORError
3072QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
3073 UsefulBuf Pool,
3074 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003075{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003076 // The pool size and free mem offset are packed into the beginning
Dave Thaler93c01182022-08-06 15:08:35 -04003077 // of the pool memory. This compile time check makes sure the
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003078 // constant in the header is correct. This check should optimize
3079 // down to nothing.
Dave Thaler93c01182022-08-06 15:08:35 -04003080#ifdef _MSC_VER
3081#pragma warning(push)
3082#pragma warning(disable:4127) // conditional expression is constant
3083#endif
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003084 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003085 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003086 }
Dave Thaler93c01182022-08-06 15:08:35 -04003087#ifdef _MSC_VER
3088#pragma warning(pop)
3089#endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003090
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003091 // The pool size and free offset packed in to the beginning of pool
3092 // memory are only 32-bits. This check will optimize out on 32-bit
3093 // machines.
3094 if(Pool.len > UINT32_MAX) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003095 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003096 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003097
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003098 // This checks that the pool buffer given is big enough.
3099 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003100 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003101 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003102
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003103 QCBORDecode_SetUpAllocator(pMe, MemPool_Function, Pool.ptr, bAllStrings);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003104
Laurence Lundblade30816f22018-11-10 13:40:22 +07003105 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003106}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003107#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003108
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003109
3110
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003111static void
3112QCBORDecode_Private_CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07003113{
Laurence Lundblade37286c02022-09-03 10:05:02 -07003114#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade9b334962020-08-27 10:55:53 -07003115 memcpy(pMe->uLastTags, pItem->uTags, sizeof(pItem->uTags));
Laurence Lundblade37286c02022-09-03 10:05:02 -07003116#else
3117 (void)pMe;
3118 (void)pItem;
3119#endif
Laurence Lundblade9b334962020-08-27 10:55:53 -07003120}
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003121
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003122
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003123/**
3124 * @brief Consume an entire map or array including its contents.
3125 *
3126 * @param[in] pMe The decoder context.
3127 * @param[in] pItemToConsume The array/map whose contents are to be
3128 * consumed.
3129 * @param[out] puNextNestLevel The next nesting level after the item was
3130 * fully consumed.
3131 *
3132 * This may be called when @c pItemToConsume is not an array or
3133 * map. In that case, this is just a pass through for @c puNextNestLevel
3134 * since there is nothing to do.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003135 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003136static QCBORError
3137QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
3138 const QCBORItem *pItemToConsume,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003139 bool *pbBreak,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003140 uint8_t *puNextNestLevel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003141{
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003142 QCBORError uReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003143 QCBORItem Item;
Laurence Lundblade9b334962020-08-27 10:55:53 -07003144
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003145 /* If it is a map or array, this will tell if it is empty. */
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003146 const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel);
3147
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003148 if(QCBORItem_IsMapOrArray(*pItemToConsume) && !bIsEmpty) {
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003149 /* There is only real work to do for non-empty maps and arrays */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003150
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003151 /* This works for definite- and indefinite-length maps and
3152 * arrays by using the nesting level
Laurence Lundblade1341c592020-04-11 14:19:05 -07003153 */
3154 do {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003155 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pbBreak, &Item);
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003156 if(QCBORDecode_IsUnrecoverableError(uReturn) ||
3157 uReturn == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003158 goto Done;
3159 }
3160 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003161
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003162 *puNextNestLevel = Item.uNextNestLevel;
3163
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003164 uReturn = QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003165
Laurence Lundblade1341c592020-04-11 14:19:05 -07003166 } else {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003167 /* pItemToConsume is not a map or array. Just pass the nesting
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003168 * level through. */
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003169 *puNextNestLevel = pItemToConsume->uNextNestLevel;
3170
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003171 uReturn = QCBOR_SUCCESS;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003172 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003173
3174Done:
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003175 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003176}
3177
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003178
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003179/*
3180 * Public function, see header qcbor/qcbor_decode.h file
3181 */
3182void
3183QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003184{
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003185 QCBORDecode_VGetNext(pMe, pDecodedItem);
3186
3187 if(pMe->uLastError == QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003188 pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL,
Máté Tóth-Pálc6d59682021-05-26 18:55:30 +02003189 &pDecodedItem->uNextNestLevel);
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003190 }
3191}
3192
3193
Laurence Lundblade11654912024-05-09 11:49:24 -07003194/*
3195 * Public function, see header qcbor/qcbor_decode.h file
3196 */
3197uint32_t
3198QCBORDecode_Tell(QCBORDecodeContext *pMe)
3199{
3200 size_t uCursorOffset;
3201
3202 if(pMe->uLastError != QCBOR_SUCCESS) {
3203 return UINT32_MAX;
3204 }
3205
3206 uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
3207
3208 if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
3209 return UINT32_MAX;
3210 } else {
3211 /* Cast is safe because decoder input size is restricted. */
3212 return (uint32_t)uCursorOffset;
3213 }
3214}
3215
3216
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003217/**
3218 * @brief Rewind cursor to start as if map or array were just entered.
3219 *
3220 * @param[in] pMe The decoding context
3221 *
3222 * This affects the nesting tracking and the UsefulInputBuf.
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003223 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003224static void
3225QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003226{
3227 /* Reset nesting tracking to the deepest bounded level */
3228 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3229
3230 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3231
3232 /* Reposition traversal cursor to the start of the map/array */
3233 UsefulInputBuf_Seek(&(pMe->InBuf),
3234 DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
3235}
3236
3237
3238/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003239 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003240 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003241void
3242QCBORDecode_Rewind(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003243{
3244 if(pMe->nesting.pCurrentBounded != NULL) {
3245 /* In a bounded map, array or bstr-wrapped CBOR */
3246
3247 if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
3248 /* In bstr-wrapped CBOR. */
3249
3250 /* Reposition traversal cursor to start of wrapping byte string */
3251 UsefulInputBuf_Seek(&(pMe->InBuf),
3252 pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
3253 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3254
3255 } else {
3256 /* In a map or array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003257 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003258 }
3259
3260 } else {
3261 /* Not in anything bounded */
3262
3263 /* Reposition traversal cursor to the start of input CBOR */
3264 UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
3265
3266 /* Reset nesting tracking to beginning of input. */
3267 DecodeNesting_Init(&(pMe->nesting));
3268 }
3269
3270 pMe->uLastError = QCBOR_SUCCESS;
3271}
3272
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003273
Laurence Lundblade9b334962020-08-27 10:55:53 -07003274
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003275
3276
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003277typedef struct {
3278 void *pCBContext;
3279 QCBORItemCallback pfCallback;
3280} MapSearchCallBack;
3281
3282typedef struct {
3283 size_t uStartOffset;
3284 uint16_t uItemCount;
3285} MapSearchInfo;
3286
3287
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003288/**
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003289 * @brief Search a map for a set of items.
3290 *
3291 * @param[in] pMe The decode context to search.
3292 * @param[in,out] pItemArray The items to search for and the items found.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003293 * @param[out] pInfo Several bits of meta-info returned by search.
3294 * @param[in] pCallBack Callback object or @c NULL.
3295 * TODO: fix params
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003296 *
3297 * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map.
3298 *
3299 * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label)
3300 * were found for one of the labels being
3301 * search for. This duplicate detection is
3302 * only performed for items in pItemArray,
3303 * not every item in the map.
3304 *
3305 * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was
3306 * wrong for the matchd label.
3307 *
3308 * @retval Also errors returned by QCBORDecode_GetNext().
3309 *
3310 * On input, \c pItemArray contains a list of labels and data types of
3311 * items to be found.
3312 *
3313 * On output, the fully retrieved items are filled in with values and
3314 * such. The label was matched, so it never changes.
3315 *
3316 * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE.
3317 *
3318 * This also finds the ends of maps and arrays when they are exited.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003319 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003320static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003321QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
3322 QCBORItem *pItemArray,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003323 MapSearchInfo *pInfo,
3324 MapSearchCallBack *pCallBack)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003325{
Laurence Lundbladee6f15112020-07-23 18:44:16 -07003326 QCBORError uReturn;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003327 uint64_t uFoundItemBitMap = 0;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07003328
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003329 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003330 uReturn = pMe->uLastError;
3331 goto Done2;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003332 }
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003333
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003334 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) &&
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003335 pItemArray->uLabelType != QCBOR_TYPE_NONE) {
3336 /* QCBOR_TYPE_NONE as first item indicates just looking
3337 for the end of an array, so don't give error. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003338 uReturn = QCBOR_ERR_MAP_NOT_ENTERED;
3339 goto Done2;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003340 }
3341
Laurence Lundblade085d7952020-07-24 10:26:30 -07003342 if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) {
3343 // It is an empty bounded array or map
3344 if(pItemArray->uLabelType == QCBOR_TYPE_NONE) {
3345 // Just trying to find the end of the map or array
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003346 pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003347 uReturn = QCBOR_SUCCESS;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003348 } else {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003349 // Nothing is ever found in an empty array or map. All items
3350 // are marked as not found below.
Laurence Lundblade085d7952020-07-24 10:26:30 -07003351 uReturn = QCBOR_SUCCESS;
3352 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003353 goto Done2;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003354 }
3355
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003356 QCBORDecodeNesting SaveNesting;
Laurence Lundblade11654912024-05-09 11:49:24 -07003357 size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003358 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3359
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003360 /* Reposition to search from the start of the map / array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003361 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundblade1341c592020-04-11 14:19:05 -07003362
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003363 /*
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003364 Loop over all the items in the map or array. Each item
3365 could be a map or array, but label matching is only at
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003366 the main level. This handles definite- and indefinite-
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003367 length maps and arrays. The only reason this is ever
3368 called on arrays is to find their end position.
3369
3370 This will always run over all items in order to do
3371 duplicate detection.
3372
3373 This will exit with failure if it encounters an
3374 unrecoverable error, but continue on for recoverable
3375 errors.
3376
3377 If a recoverable error occurs on a matched item, then
3378 that error code is returned.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003379 */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07003380 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003381 if(pInfo) {
3382 pInfo->uItemCount = 0;
3383 }
Máté Tóth-Pál2f2aa5f2021-05-17 21:35:09 +02003384 uint8_t uNextNestLevel;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003385 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003386 /* Remember offset of the item because sometimes it has to be returned */
Laurence Lundblade1341c592020-04-11 14:19:05 -07003387 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003388
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003389 /* Get the item */
3390 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003391 QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003392 if(QCBORDecode_IsUnrecoverableError(uResult)) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003393 /* The map/array can't be decoded when unrecoverable errors occur */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003394 uReturn = uResult;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003395 goto Done;
3396 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003397 if(uResult == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003398 /* Unexpected end of map or array. */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003399 uReturn = uResult;
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003400 goto Done;
3401 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003402
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003403 /* See if item has one of the labels that are of interest */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003404 bool bMatched = false;
3405 for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003406 if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003407 /* A label match has been found */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003408 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
3409 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003410 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003411 }
Laurence Lundblade63926052021-03-29 16:05:51 -07003412 if(uResult != QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003413 /* The label matches, but the data item is in error.
3414 * It is OK to have recoverable errors on items that are not
3415 * matched. */
Laurence Lundblade63926052021-03-29 16:05:51 -07003416 uReturn = uResult;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003417 goto Done;
3418 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003419 if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) {
Laurence Lundblade63926052021-03-29 16:05:51 -07003420 /* The data item is not of the type(s) requested */
3421 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003422 goto Done;
3423 }
3424
Laurence Lundblade1341c592020-04-11 14:19:05 -07003425 /* Successful match. Return the item. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003426 pItemArray[nIndex] = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003427 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003428 if(pInfo) {
3429 pInfo->uStartOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003430 }
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003431 bMatched = true;
3432 }
3433 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003434
3435
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003436 if(!bMatched && pCallBack != NULL) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003437 /*
3438 Call the callback on unmatched labels.
3439 (It is tempting to do duplicate detection here, but that would
3440 require dynamic memory allocation because the number of labels
3441 that might be encountered is unbounded.)
3442 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003443 uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item);
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003444 if(uReturn != QCBOR_SUCCESS) {
3445 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003446 }
3447 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003448
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003449 /*
3450 Consume the item whether matched or not. This
3451 does the work of traversing maps and array and
3452 everything in them. In this loop only the
3453 items at the current nesting level are examined
3454 to match the labels.
3455 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003456 uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel);
Laurence Lundbladec7114722020-08-13 05:11:40 -07003457 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003458 goto Done;
3459 }
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003460
3461 if(pInfo) {
3462 pInfo->uItemCount++;
3463 }
3464
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003465 } while (uNextNestLevel >= uMapNestLevel);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003466
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003467 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003468
3469 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003470
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003471 // Check here makes sure that this won't accidentally be
3472 // QCBOR_MAP_OFFSET_CACHE_INVALID which is larger than
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003473 // QCBOR_MAX_DECODE_INPUT_SIZE.
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -08003474 // Cast to uint32_t to possibly address cases where SIZE_MAX < UINT32_MAX
3475 if((uint32_t)uEndOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003476 uReturn = QCBOR_ERR_INPUT_TOO_LARGE;
3477 goto Done;
3478 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003479 /* Cast OK because encoded CBOR is limited to UINT32_MAX */
3480 pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003481
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003482 Done:
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003483 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade11654912024-05-09 11:49:24 -07003484 UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos);
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003485
3486 Done2:
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003487 /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */
Laurence Lundbladec7114722020-08-13 05:11:40 -07003488 for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003489 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003490 pItemArray[i].uDataType = QCBOR_TYPE_NONE;
3491 pItemArray[i].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003492 }
3493 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003494
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003495 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003496}
3497
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003498
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003499/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003500 * Public function, see header qcbor/qcbor_decode.h file
3501 */
3502void
3503QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
3504 int64_t nLabel,
3505 uint8_t uQcborType,
3506 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003507{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003508 if(pMe->uLastError != QCBOR_SUCCESS) {
3509 return;
3510 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003511
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003512 QCBORItem OneItemSeach[2];
3513 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3514 OneItemSeach[0].label.int64 = nLabel;
3515 OneItemSeach[0].uDataType = uQcborType;
3516 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003517
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003518 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003519
3520 *pItem = OneItemSeach[0];
3521
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003522 if(uReturn != QCBOR_SUCCESS) {
3523 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003524 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003525 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003526 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003527 }
3528
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003529 Done:
3530 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003531}
3532
3533
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003534/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003535 * Public function, see header qcbor/qcbor_decode.h file
3536 */
3537void
3538QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
3539 const char *szLabel,
3540 uint8_t uQcborType,
3541 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003542{
Laurence Lundbladeda095972020-06-06 18:35:33 -07003543 if(pMe->uLastError != QCBOR_SUCCESS) {
3544 return;
3545 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003546
Laurence Lundblade78a66132024-06-06 12:19:59 -07003547#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003548 QCBORItem OneItemSeach[2];
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003549 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3550 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3551 OneItemSeach[0].uDataType = uQcborType;
3552 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003553
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003554 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
3555
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003556 if(uReturn != QCBOR_SUCCESS) {
3557 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003558 }
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003559 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003560 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003561 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003562 }
3563
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003564 *pItem = OneItemSeach[0];
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003565Done:
Laurence Lundblade78a66132024-06-06 12:19:59 -07003566
3567#else
Laurence Lundblade9533c482024-06-06 21:41:10 -07003568 (void)pMe;
3569 (void)szLabel;
3570 (void)uQcborType;
3571 (void)pItem;
Laurence Lundblade78a66132024-06-06 12:19:59 -07003572 QCBORError uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
3573#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
3574
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003575 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003576}
3577
3578
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003579
3580/**
3581 * @brief Semi-private. Get pointer, length and item for an array or map.
3582 *
3583 * @param[in] pMe The decode context.
3584 * @param[in] uType CBOR major type, either array/map.
3585 * @param[out] pItem The item for the array/map.
3586 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3587 *
3588 * The next item to be decoded must be a map or array as specified by \c uType.
3589 *
3590 * \c pItem will be filled in with the label and tags of the array or map
3591 * in addition to \c pEncodedCBOR giving the pointer and length of the
3592 * encoded CBOR.
3593 *
3594 * When this is complete, the traversal cursor is at the end of the array or
3595 * map that was retrieved.
3596 */
3597void
3598QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe,
3599 const uint8_t uType,
3600 QCBORItem *pItem,
3601 UsefulBufC *pEncodedCBOR)
3602{
3603 QCBORError uErr;
3604 uint8_t uNestLevel;
3605 size_t uStartingCursor;
3606 size_t uStartOfReturned;
3607 size_t uEndOfReturned;
3608 size_t uTempSaveCursor;
3609 bool bInMap;
3610 QCBORItem LabelItem;
3611 bool EndedByBreak;
3612
3613 uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3614 bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting));
3615
3616 /* Could call GetNext here, but don't need to because this
3617 * is only interested in arrays and maps. */
3618 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem);
3619 if(uErr != QCBOR_SUCCESS) {
3620 pMe->uLastError = (uint8_t)uErr;
3621 return;
3622 }
3623
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003624 uint8_t uItemDataType = pItem->uDataType;
Laurence Lundblade62cae932024-06-03 13:16:17 -07003625#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003626 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
3627 uItemDataType = QCBOR_TYPE_ARRAY;
3628 }
Laurence Lundblade78a66132024-06-06 12:19:59 -07003629#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003630
3631 if(uItemDataType != uType) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003632 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
3633 return;
3634 }
3635
3636 if(bInMap) {
3637 /* If the item is in a map, the start of the array/map
3638 * itself, not the label, must be found. Do this by
3639 * rewinding to the starting position and fetching
3640 * just the label data item. QCBORDecode_Private_GetNextTagNumber()
3641 * doesn't do any of the array/map item counting or nesting
3642 * level tracking. Used here it will just fetech the label
3643 * data item.
3644 *
3645 * Have to save the cursor and put it back to the position
3646 * after the full item once the label as been fetched by
3647 * itself.
3648 */
3649 uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3650 UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor);
3651
3652 /* Item has been fetched once so safe to ignore error */
3653 (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem);
3654
3655 uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3656 UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor);
3657 } else {
3658 uStartOfReturned = uStartingCursor;
3659 }
3660
3661 /* Consume the entire array/map to find the end */
3662 uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel);
3663 if(uErr != QCBOR_SUCCESS) {
3664 pMe->uLastError = (uint8_t)uErr;
3665 goto Done;
3666 }
3667
3668 /* Fill in returned values */
3669 uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3670 if(EndedByBreak) {
3671 /* When ascending nesting levels, a break for the level above
3672 * was consumed. That break is not a part of what is consumed here. */
3673 uEndOfReturned--;
3674 }
3675 pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned);
3676 pEncodedCBOR->len = uEndOfReturned - uStartOfReturned;
3677
3678Done:
3679 return;
3680}
3681
3682
3683/**
3684 * @brief Semi-private. Get pointer, length and item count of an array or map.
3685 *
3686 * @param[in] pMe The decode context.
3687 * @param[in] pTarget The label and type of the array or map to retrieve.
3688 * @param[out] pItem The item for the array/map.
3689 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3690 *
3691 * The next item to be decoded must be a map or array as specified by \c uType.
3692 *
3693 * When this is complete, the traversal cursor is unchanged.
3694 */void
3695QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe,
3696 QCBORItem *pTarget,
3697 QCBORItem *pItem,
3698 UsefulBufC *pEncodedCBOR)
3699{
3700 MapSearchInfo Info;
3701 QCBORDecodeNesting SaveNesting;
3702 size_t uSaveCursor;
3703
3704 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL);
3705 if(pMe->uLastError != QCBOR_SUCCESS) {
3706 return;
3707 }
3708
3709 /* Save the whole position of things so they can be restored.
3710 * so the cursor position is unchanged by this operation, like
3711 * all the other GetXxxxInMap() operations. */
3712 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3713 uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3714
3715 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3716 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
3717 QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR);
3718
3719 UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor);
3720 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
3721}
3722
3723
3724
3725
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003726/**
3727 * @brief Is a QCBOR_TYPE in the type list?
3728 *
3729 * @param[in] uDataType Type to check for.
3730 * @param[in] puTypeList List to check.
3731 *
3732 * @retval QCBOR_SUCCESS If in the list.
3733 * @retval QCBOR_ERR_UNEXPECTED_TYPE Not in the list.
3734 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07003735static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003736QCBOR_Private_CheckTypeList(const int uDataType,
3737 const uint8_t puTypeList[QCBOR_TAGSPEC_NUM_TYPES])
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003738{
3739 for(size_t i = 0; i < QCBOR_TAGSPEC_NUM_TYPES; i++) {
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003740 if(uDataType == puTypeList[i]) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003741 return QCBOR_SUCCESS;
3742 }
3743 }
3744 return QCBOR_ERR_UNEXPECTED_TYPE;
3745}
3746
Laurence Lundblade67257dc2020-07-27 03:33:37 -07003747
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003748/**
Laurence Lundblade37286c02022-09-03 10:05:02 -07003749 * Match a tag/type specification against the type of the item.
3750 *
3751 * @param[in] TagSpec Specification for matching tags.
3752 * @param[in] pItem The item to check.
3753 *
3754 * @retval QCBOR_SUCCESS \c uDataType is allowed by @c TagSpec
3755 * @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec
3756 *
3757 * This checks the item data type of untagged items as well as of
3758 * tagged items against a specification to see if decoding should
3759 * proceed.
3760 *
3761 * This relies on the automatic tag decoding done by QCBOR that turns
3762 * tag numbers into particular QCBOR_TYPEs so there is no actual
3763 * comparsion of tag numbers, just of QCBOR_TYPEs.
3764 *
3765 * This checks the data item type as possibly representing the tag
3766 * number or as the tag content type.
3767 *
3768 * If QCBOR_DISABLE_TAGS is #defined, this primarily checks the item
3769 * data type against the allowed tag content types. It will also error out
3770 * if the caller tries to require a tag because there is no way that can
3771 * ever be fulfilled.
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003772 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07003773static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003774QCBOR_Private_CheckTagRequirement(const QCBOR_Private_TagSpec TagSpec,
3775 const QCBORItem *pItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07003776{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003777 const int nItemType = pItem->uDataType; /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade37286c02022-09-03 10:05:02 -07003778 const int nTagReq = TagSpec.uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
3779
3780#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003781 /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003782 if(!(TagSpec.uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS) &&
3783 pItem->uTags[0] != CBOR_TAG_INVALID16) {
3784 /* There are tags that QCBOR couldn't process on this item and
Laurence Lundblade37286c02022-09-03 10:05:02 -07003785 * the caller has told us there should not be.
3786 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003787 return QCBOR_ERR_UNEXPECTED_TYPE;
3788 }
3789
Laurence Lundblade9b334962020-08-27 10:55:53 -07003790 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
Laurence Lundblade37286c02022-09-03 10:05:02 -07003791 /* Must match the tag number and only the tag */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003792 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003793 }
3794
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003795 QCBORError uReturn = QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003796 if(uReturn == QCBOR_SUCCESS) {
3797 return QCBOR_SUCCESS;
3798 }
3799
3800 if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
3801 /* Must match the content type and only the content type.
Laurence Lundblade37286c02022-09-03 10:05:02 -07003802 * There was no match just above so it is a fail. */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003803 return QCBOR_ERR_UNEXPECTED_TYPE;
3804 }
3805
Laurence Lundblade37286c02022-09-03 10:05:02 -07003806 /* QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG: If here it can match either the tag or the content
3807 * and it hasn't matched the content, so the end
3808 * result is whether it matches the tag. This is
3809 * the tag optional case that the CBOR standard discourages.
3810 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003811
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003812 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003813
Laurence Lundblade37286c02022-09-03 10:05:02 -07003814#else /* QCBOR_DISABLE_TAGS */
3815 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
3816 return QCBOR_ERR_UNEXPECTED_TYPE;
3817 }
3818
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07003819 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade37286c02022-09-03 10:05:02 -07003820
3821#endif /* QCBOR_DISABLE_TAGS */
3822}
Laurence Lundblade9b334962020-08-27 10:55:53 -07003823
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003824
3825/**
3826 * @brief Get an item by label to match a tag specification.
3827 *
3828 * @param[in] pMe The decode context.
3829 * @param[in] nLabel The label to search map for.
3830 * @param[in] TagSpec The tag number specification to match.
3831 * @param[out] pItem The item found.
3832 *
3833 * This finds the item with the given label in currently open
3834 * map. Then checks that its tag number and types matches the tag
3835 * specification. If not, an error is set in the decode context.
3836 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003837static void
3838QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
3839 const int64_t nLabel,
3840 const QCBOR_Private_TagSpec TagSpec,
3841 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003842{
3843 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
3844 if(pMe->uLastError != QCBOR_SUCCESS) {
3845 return;
3846 }
3847
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003848 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003849}
3850
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07003851
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003852/**
3853 * @brief Get an item by label to match a tag specification.
3854 *
3855 * @param[in] pMe The decode context.
3856 * @param[in] szLabel The label to search map for.
3857 * @param[in] TagSpec The tag number specification to match.
3858 * @param[out] pItem The item found.
3859 *
3860 * This finds the item with the given label in currently open
3861 * map. Then checks that its tag number and types matches the tag
3862 * specification. If not, an error is set in the decode context.
3863 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003864static void
3865QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
3866 const char *szLabel,
3867 const QCBOR_Private_TagSpec TagSpec,
3868 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003869{
3870 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
3871 if(pMe->uLastError != QCBOR_SUCCESS) {
3872 return;
3873 }
3874
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003875 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003876}
3877
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003878
3879/**
3880 * @brief Semi-private to get an string by label to match a tag specification.
3881 *
3882 * @param[in] pMe The decode context.
3883 * @param[in] nLabel The label to search map for.
3884 * @param[in] TagSpec The tag number specification to match.
3885 * @param[out] pString The string found.
3886 *
3887 * This finds the string with the given label in currently open
3888 * map. Then checks that its tag number and types matches the tag
3889 * specification. If not, an error is set in the decode context.
3890 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003891void
3892QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
3893 const int64_t nLabel,
3894 const QCBOR_Private_TagSpec TagSpec,
3895 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003896{
3897 QCBORItem Item;
3898 QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
3899 if(pMe->uLastError == QCBOR_SUCCESS) {
3900 *pString = Item.val.string;
3901 }
3902}
3903
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003904
3905/**
3906 * @brief Semi-private to get an string by label to match a tag specification.
3907 *
3908 * @param[in] pMe The decode context.
3909 * @param[in] szLabel The label to search map for.
3910 * @param[in] TagSpec The tag number specification to match.
3911 * @param[out] pString The string found.
3912 *
3913 * This finds the string with the given label in currently open
3914 * map. Then checks that its tag number and types matches the tag
3915 * specification. If not, an error is set in the decode context.
3916 */void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003917QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
3918 const char * szLabel,
3919 const QCBOR_Private_TagSpec TagSpec,
3920 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003921{
3922 QCBORItem Item;
3923 QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
3924 if(pMe->uLastError == QCBOR_SUCCESS) {
3925 *pString = Item.val.string;
3926 }
3927}
Laurence Lundblade1341c592020-04-11 14:19:05 -07003928
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003929
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003930/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003931 * Public function, see header qcbor/qcbor_decode.h file
3932 */
3933void
3934QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003935{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003936 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL);
Laurence Lundblade5f53f832020-09-03 12:00:14 -07003937 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003938}
3939
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003940/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003941 * Public function, see header qcbor/qcbor_decode.h file
3942 */
3943void
3944QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe,
3945 QCBORItem *pItemList,
3946 void *pCallbackCtx,
3947 QCBORItemCallback pfCB)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003948{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003949 MapSearchCallBack CallBack;
3950 CallBack.pCBContext = pCallbackCtx;
3951 CallBack.pfCallback = pfCB;
3952
3953 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack);
3954
Laurence Lundblade5f53f832020-09-03 12:00:14 -07003955 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003956}
3957
3958
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08003959/**
3960 * @brief Search for a map/array by label and enter it
3961 *
3962 * @param[in] pMe The decode context.
3963 * @param[in] pSearch The map/array to search for.
3964 *
3965 * @c pSearch is expected to contain one item of type map or array
3966 * with the label specified. The current bounded map will be searched for
3967 * this and if found will be entered.
3968 *
3969 * If the label is not found, or the item found is not a map or array,
3970 * the error state is set.
3971 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003972static void
3973QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07003974{
Laurence Lundblade323f8a92020-09-06 19:43:09 -07003975 // The first item in pSearch is the one that is to be
3976 // entered. It should be the only one filled in. Any other
3977 // will be ignored unless it causes an error.
Laurence Lundblade34691b92020-05-18 22:25:25 -07003978 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07003979 return;
3980 }
3981
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003982 MapSearchInfo Info;
3983 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pSearch, &Info, NULL);
Laurence Lundblade34691b92020-05-18 22:25:25 -07003984 if(pMe->uLastError != QCBOR_SUCCESS) {
3985 return;
3986 }
3987
Laurence Lundblade9b334962020-08-27 10:55:53 -07003988 if(pSearch->uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003989 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade9b334962020-08-27 10:55:53 -07003990 return;
3991 }
3992
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003993
3994 /* The map or array was found. Now enter it.
3995 *
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08003996 * QCBORDecode_EnterBoundedMapOrArray() used here, requires the
3997 * next item for the pre-order traversal cursor to be the map/array
3998 * found by MapSearch(). The next few lines of code force the
3999 * cursor to that.
4000 *
4001 * There is no need to retain the old cursor because
4002 * QCBORDecode_EnterBoundedMapOrArray() will set it to the
4003 * beginning of the map/array being entered.
4004 *
4005 * The cursor is forced by: 1) setting the input buffer position to
4006 * the item offset found by MapSearch(), 2) setting the map/array
4007 * counter to the total in the map/array, 3) setting the nesting
4008 * level. Setting the map/array counter to the total is not
4009 * strictly correct, but this is OK because this cursor only needs
4010 * to be used to get one item and MapSearch() has already found it
4011 * confirming it exists.
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004012 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004013 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004014
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004015 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
4016
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004017 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07004018
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004019 QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004020}
4021
4022
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004023/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004024 * Public function, see header qcbor/qcbor_decode.h file
4025 */
4026void
4027QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004028{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004029 QCBORItem OneItemSeach[2];
4030 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4031 OneItemSeach[0].label.int64 = nLabel;
4032 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4033 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004034
Laurence Lundblade9b334962020-08-27 10:55:53 -07004035 /* The map to enter was found, now finish off entering it. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004036 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004037}
4038
4039
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004040/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004041 * Public function, see header qcbor/qcbor_decode.h file
4042 */
4043void
4044QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004045{
Laurence Lundblade78a66132024-06-06 12:19:59 -07004046#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004047 QCBORItem OneItemSeach[2];
4048 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4049 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4050 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4051 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004052
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004053 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade78a66132024-06-06 12:19:59 -07004054#else
Laurence Lundblade9533c482024-06-06 21:41:10 -07004055 (void)szLabel;
4056 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade78a66132024-06-06 12:19:59 -07004057#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004058}
4059
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004060/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004061 * Public function, see header qcbor/qcbor_decode.h file
4062 */
4063void
4064QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07004065{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004066 QCBORItem OneItemSeach[2];
4067 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4068 OneItemSeach[0].label.int64 = nLabel;
4069 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4070 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004071
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004072 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07004073}
4074
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004075/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004076 * Public function, see header qcbor/qcbor_decode.h file
4077 */
4078void
4079QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundblade34691b92020-05-18 22:25:25 -07004080{
Laurence Lundblade78a66132024-06-06 12:19:59 -07004081#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004082 QCBORItem OneItemSeach[2];
4083 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4084 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4085 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4086 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004087
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004088 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade78a66132024-06-06 12:19:59 -07004089#else
Laurence Lundblade9533c482024-06-06 21:41:10 -07004090 (void)szLabel;
4091 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade78a66132024-06-06 12:19:59 -07004092#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade1341c592020-04-11 14:19:05 -07004093}
4094
4095
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004096/**
4097 * @brief Semi-private to do the the work for EnterMap() and EnterArray().
4098 *
4099 * @param[in] pMe The decode context
4100 * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY.
4101 * @param[out] pItem The data item for the map or array entered.
4102 *
4103 * The next item in the traversal must be a map or array. This
4104 * consumes that item and does the book keeping to enter the map or
4105 * array.
4106 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004107void
4108QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe,
4109 const uint8_t uType,
4110 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004111{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004112 QCBORError uErr;
4113
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004114 /* Must only be called on maps and arrays. */
Laurence Lundblade34691b92020-05-18 22:25:25 -07004115 if(pMe->uLastError != QCBOR_SUCCESS) {
4116 // Already in error state; do nothing.
4117 return;
4118 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07004119
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004120 /* Get the data item that is the map or array being entered. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004121 QCBORItem Item;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004122 uErr = QCBORDecode_GetNext(pMe, &Item);
4123 if(uErr != QCBOR_SUCCESS) {
4124 goto Done;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07004125 }
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004126
4127 uint8_t uItemDataType = Item.uDataType;
Laurence Lundblade78a66132024-06-06 12:19:59 -07004128
Laurence Lundblade62cae932024-06-03 13:16:17 -07004129#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004130 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) {
4131 uItemDataType = QCBOR_TYPE_ARRAY;
4132 }
Laurence Lundblade78a66132024-06-06 12:19:59 -07004133#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
4134
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004135 if(uItemDataType != uType) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004136 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
4137 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004138 }
4139
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004140 QCBORDecode_Private_CopyTags(pMe, &Item);
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004141
4142
Laurence Lundbladef0499502020-08-01 11:55:57 -07004143 const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
Laurence Lundblade085d7952020-07-24 10:26:30 -07004144 if(bIsEmpty) {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004145 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
4146 // Undo decrement done by QCBORDecode_GetNext() so the the
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004147 // the decrement when exiting the map/array works correctly
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004148 pMe->nesting.pCurrent->u.ma.uCountCursor++;
4149 }
Laurence Lundblade93d89472020-10-03 22:30:50 -07004150 // Special case to increment nesting level for zero-length maps
4151 // and arrays entered in bounded mode.
Laurence Lundbladee6f15112020-07-23 18:44:16 -07004152 DecodeNesting_Descend(&(pMe->nesting), uType);
4153 }
4154
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004155 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004156
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004157 uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty,
4158 UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004159
Laurence Lundblade6545d1b2020-10-14 11:13:13 -07004160 if(pItem != NULL) {
4161 *pItem = Item;
4162 }
4163
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004164Done:
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004165 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004166}
4167
Laurence Lundblade02625d42020-06-25 14:41:41 -07004168
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004169/**
4170 * @brief Exit a bounded map, array or bstr (semi-private).
4171 *
4172 * @param[in] pMe Decode context.
4173 * @param[in] uEndOffset The input buffer offset of the end of item exited.
4174 *
4175 * @returns QCBOR_SUCCESS or an error code.
4176 *
4177 * This is the common work for exiting a level that is a bounded map,
4178 * array or bstr wrapped CBOR.
4179 *
4180 * One chunk of work is to set up the pre-order traversal so it is at
4181 * the item just after the bounded map, array or bstr that is being
4182 * exited. This is somewhat complex.
4183 *
4184 * The other work is to level-up the bounded mode to next higest
4185 * bounded mode or the top level if there isn't one.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004186 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004187static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004188QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
4189 const uint32_t uEndOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004190{
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004191 QCBORError uErr;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004192
Laurence Lundblade02625d42020-06-25 14:41:41 -07004193 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004194 * First the pre-order-traversal byte offset is positioned to the
4195 * item just after the bounded mode item that was just consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004196 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004197 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
4198
Laurence Lundblade02625d42020-06-25 14:41:41 -07004199 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004200 * Next, set the current nesting level to one above the bounded
4201 * level that was just exited.
4202 *
4203 * DecodeNesting_CheckBoundedType() is always called before this
4204 * and makes sure pCurrentBounded is valid.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004205 */
4206 DecodeNesting_LevelUpCurrent(&(pMe->nesting));
4207
4208 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004209 * This does the complex work of leveling up the pre-order
4210 * traversal when the end of a map or array or another bounded
4211 * level is reached. It may do nothing, or ascend all the way to
4212 * the top level.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004213 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004214 uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004215 if(uErr != QCBOR_SUCCESS) {
4216 goto Done;
4217 }
4218
Laurence Lundblade02625d42020-06-25 14:41:41 -07004219 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004220 * This makes the next highest bounded level the current bounded
4221 * level. If there is no next highest level, then no bounded mode
4222 * is in effect.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004223 */
4224 DecodeNesting_LevelUpBounded(&(pMe->nesting));
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004225
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004226 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004227
4228Done:
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004229 return uErr;
4230}
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004231
Laurence Lundblade02625d42020-06-25 14:41:41 -07004232
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004233/**
4234 * @brief Get started exiting a map or array (semi-private)
4235 *
4236 * @param[in] pMe The decode context
4237 * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP
4238 *
4239 * This does some work for map and array exiting (but not
4240 * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel()
4241 * is called to do the rest.
4242 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004243void
4244QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe,
4245 const uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004246{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004247 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07004248 /* Already in error state; do nothing. */
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004249 return;
4250 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004251
Laurence Lundblade02625d42020-06-25 14:41:41 -07004252 QCBORError uErr;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004253
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004254 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004255 uErr = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004256 goto Done;
4257 }
4258
Laurence Lundblade02625d42020-06-25 14:41:41 -07004259 /*
4260 Have to set the offset to the end of the map/array
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004261 that is being exited. If there is no cached value,
Laurence Lundblade02625d42020-06-25 14:41:41 -07004262 from previous map search, then do a dummy search.
4263 */
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004264 if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004265 QCBORItem Dummy;
4266 Dummy.uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004267 uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL);
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004268 if(uErr != QCBOR_SUCCESS) {
4269 goto Done;
4270 }
4271 }
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004272
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004273 uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004274
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004275Done:
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004276 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004277}
4278
4279
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004280/**
4281 * @brief The main work of entering some byte-string wrapped CBOR.
4282 *
4283 * @param[in] pMe The decode context.
4284 * @param[in] pItem The byte string item.
4285 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX
4286 * @param[out] pBstr Pointer and length of byte string entered.
4287 *
4288 * This is called once the byte string item has been decoded to do all
4289 * the book keeping work for descending a nesting level into the
4290 * nested CBOR.
4291 *
4292 * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement.
4293 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004294static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004295QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe,
4296 const QCBORItem *pItem,
4297 const uint8_t uTagRequirement,
4298 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004299{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004300 if(pBstr) {
4301 *pBstr = NULLUsefulBufC;
4302 }
4303
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004304 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004305 /* Already in error state; do nothing. */
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004306 return pMe->uLastError;
4307 }
4308
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004309 QCBORError uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004310
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004311 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004312 {
4313 uTagRequirement,
4314 {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE},
4315 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4316 };
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004317
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004318 uError = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004319 if(uError != QCBOR_SUCCESS) {
4320 goto Done;
4321 }
4322
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004323 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004324 /* Reverse the decrement done by GetNext() for the bstr so the
4325 * increment in QCBORDecode_NestLevelAscender() called by
4326 * ExitBoundedLevel() will work right.
4327 */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004328 DecodeNesting_ReverseDecrement(&(pMe->nesting));
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07004329 }
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004330
4331 if(pBstr) {
4332 *pBstr = pItem->val.string;
4333 }
4334
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004335 /* This saves the current length of the UsefulInputBuf and then
4336 * narrows the UsefulInputBuf to start and length of the wrapped
4337 * CBOR that is being entered.
4338 *
4339 * Most of these calls are simple inline accessors so this doesn't
4340 * amount to much code.
4341 */
4342
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004343 const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004344 /* This check makes the cast of uPreviousLength to uint32_t below safe. */
4345 if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004346 uError = QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladef76a2622020-08-06 19:51:03 -07004347 goto Done;
4348 }
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004349
4350 const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
4351 pItem->val.string.ptr);
4352 /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
4353 if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
4354 /* This should never happen because pItem->val.string.ptr should
4355 * always be valid since it was just returned.
4356 */
4357 uError = QCBOR_ERR_INPUT_TOO_LARGE;
4358 goto Done;
4359 }
4360
4361 const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
4362
4363 UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004364 UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004365
Laurence Lundblade02625d42020-06-25 14:41:41 -07004366 uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004367 (uint32_t)uPreviousLength,
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004368 (uint32_t)uStartOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004369Done:
4370 return uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004371}
4372
4373
Laurence Lundblade02625d42020-06-25 14:41:41 -07004374/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004375 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004376 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004377void
4378QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe,
4379 const uint8_t uTagRequirement,
4380 UsefulBufC *pBstr)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004381{
4382 if(pMe->uLastError != QCBOR_SUCCESS) {
4383 // Already in error state; do nothing.
4384 return;
4385 }
4386
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004387 /* Get the data item that is the byte string being entered */
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004388 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004389 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4390 if(pMe->uLastError != QCBOR_SUCCESS) {
4391 return;
4392 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004393
Laurence Lundblade31fddb72024-05-13 13:03:35 -07004394 if(Item.uDataAlloc) {
4395 pMe->uLastError = QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
4396 return;
4397 }
4398
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004399 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4400 &Item,
4401 uTagRequirement,
4402 pBstr);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004403}
4404
4405
Laurence Lundblade02625d42020-06-25 14:41:41 -07004406/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004407 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004408 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004409void
4410QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe,
4411 const int64_t nLabel,
4412 const uint8_t uTagRequirement,
4413 UsefulBufC *pBstr)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004414{
4415 QCBORItem Item;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004416 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004417
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004418 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4419 &Item,
4420 uTagRequirement,
4421 pBstr);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004422}
4423
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004424
Laurence Lundblade02625d42020-06-25 14:41:41 -07004425/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004426 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004427 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004428void
4429QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe,
4430 const char *szLabel,
4431 const uint8_t uTagRequirement,
4432 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004433{
4434 QCBORItem Item;
4435 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4436
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004437 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4438 &Item,
4439 uTagRequirement,
4440 pBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004441}
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004442
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004443
Laurence Lundblade02625d42020-06-25 14:41:41 -07004444/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004445 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004446 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004447void
4448QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004449{
Laurence Lundblade02625d42020-06-25 14:41:41 -07004450 if(pMe->uLastError != QCBOR_SUCCESS) {
4451 // Already in error state; do nothing.
4452 return;
4453 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004454
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004455 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004456 pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade02625d42020-06-25 14:41:41 -07004457 return;
4458 }
4459
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004460 const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
4461
Laurence Lundblade02625d42020-06-25 14:41:41 -07004462 /*
4463 Reset the length of the UsefulInputBuf to what it was before
4464 the bstr wrapped CBOR was entered.
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004465 */
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004466 UsefulInputBuf_SetBufferLength(&(pMe->InBuf),
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004467 DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004468
4469
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004470 QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004471 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004472}
4473
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004474
Laurence Lundbladee6430642020-03-14 21:15:44 -07004475
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004476/**
4477 * @brief Process simple type true and false, a boolean
4478 *
4479 * @param[in] pMe The decode context.
4480 * @param[in] pItem The item with either true or false.
4481 * @param[out] pBool The boolean value output.
4482 *
4483 * Sets the internal error if the item isn't a true or a false. Also
4484 * records any tag numbers as the tag numbers of the last item.
4485 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004486static void
4487QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe,
4488 const QCBORItem *pItem,
4489 bool *pBool)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004490{
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004491 if(pMe->uLastError != QCBOR_SUCCESS) {
4492 /* Already in error state, do nothing */
4493 return;
4494 }
4495
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004496 switch(pItem->uDataType) {
4497 case QCBOR_TYPE_TRUE:
4498 *pBool = true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004499 break;
4500
4501 case QCBOR_TYPE_FALSE:
4502 *pBool = false;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004503 break;
4504
4505 default:
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004506 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004507 break;
4508 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004509 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004510}
Laurence Lundbladee6430642020-03-14 21:15:44 -07004511
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004512
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004513/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004514 * Public function, see header qcbor/qcbor_decode.h file
4515 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004516void
4517QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004518{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004519 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004520 /* Already in error state, do nothing */
Laurence Lundbladee6430642020-03-14 21:15:44 -07004521 return;
4522 }
4523
Laurence Lundbladec4537442020-04-14 18:53:22 -07004524 QCBORItem Item;
4525
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004526 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4527
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004528 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004529}
4530
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004531
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004532/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004533 * Public function, see header qcbor/qcbor_decode.h file
4534 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004535void
4536QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe,
4537 const int64_t nLabel,
4538 bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004539{
4540 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004541 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004542
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004543 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004544}
4545
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004546
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004547/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004548 * Public function, see header qcbor/qcbor_decode.h file
4549 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004550void
4551QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe,
4552 const char *szLabel,
4553 bool *pValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004554{
4555 QCBORItem Item;
4556 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4557
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004558 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004559}
4560
4561
4562
Laurence Lundbladec7114722020-08-13 05:11:40 -07004563
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004564/**
4565 * @brief Common processing for an epoch date.
4566 *
4567 * @param[in] pMe The decode context.
4568 * @param[in] pItem The item with the date.
4569 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4570 * @param[out] pnTime The returned date.
4571 *
4572 * Common processing for the date tag. Mostly make sure the tag
4573 * content is correct and copy forward any further other tag numbers.
4574 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004575static void
4576QCBORDecode_Private_ProcessEpochDate(QCBORDecodeContext *pMe,
4577 QCBORItem *pItem,
4578 const uint8_t uTagRequirement,
4579 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004580{
4581 if(pMe->uLastError != QCBOR_SUCCESS) {
4582 // Already in error state, do nothing
4583 return;
4584 }
4585
4586 QCBORError uErr;
4587
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004588 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladec7114722020-08-13 05:11:40 -07004589 {
4590 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004591 {QCBOR_TYPE_DATE_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4592 {QCBOR_TYPE_INT64, QCBOR_TYPE_DOUBLE, QCBOR_TYPE_FLOAT, QCBOR_TYPE_UINT64}
Laurence Lundbladec7114722020-08-13 05:11:40 -07004593 };
4594
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004595 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004596 if(uErr != QCBOR_SUCCESS) {
4597 goto Done;
4598 }
4599
4600 if(pItem->uDataType != QCBOR_TYPE_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004601 uErr = QCBOR_Private_DecodeDateEpoch(pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004602 if(uErr != QCBOR_SUCCESS) {
4603 goto Done;
4604 }
4605 }
4606
Laurence Lundblade9b334962020-08-27 10:55:53 -07004607 // Save the tags in the last item's tags in the decode context
4608 // for QCBORDecode_GetNthTagOfLast()
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004609 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07004610
Laurence Lundbladec7114722020-08-13 05:11:40 -07004611 *pnTime = pItem->val.epochDate.nSeconds;
4612
4613Done:
4614 pMe->uLastError = (uint8_t)uErr;
4615}
4616
4617
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004618
4619/*
4620 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4621 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004622void
4623QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
4624 uint8_t uTagRequirement,
4625 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004626{
4627 if(pMe->uLastError != QCBOR_SUCCESS) {
4628 // Already in error state, do nothing
4629 return;
4630 }
4631
4632 QCBORItem Item;
4633 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4634
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004635 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004636}
4637
4638
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004639/*
4640 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4641 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07004642void
4643QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
4644 int64_t nLabel,
4645 uint8_t uTagRequirement,
4646 int64_t *pnTime)
4647{
4648 QCBORItem Item;
4649 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004650 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004651}
4652
4653
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004654/*
4655 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4656 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07004657void
4658QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
4659 const char *szLabel,
4660 uint8_t uTagRequirement,
4661 int64_t *pnTime)
4662{
4663 QCBORItem Item;
4664 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004665 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004666}
4667
4668
4669
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004670/**
4671 * @brief Common processing for an epoch date.
4672 *
4673 * @param[in] pMe The decode context.
4674 * @param[in] pItem The item with the date.
4675 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4676 * @param[out] pnDays The returned day count.
4677 *
4678 * Common processing for the RFC 8943 day-count tag. Mostly make sure
4679 * the tag content is correct and copy forward any further other tag
4680 * numbers.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004681 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004682static void
4683QCBORDecode_Private_ProcessEpochDays(QCBORDecodeContext *pMe,
4684 QCBORItem *pItem,
4685 uint8_t uTagRequirement,
4686 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004687{
4688 if(pMe->uLastError != QCBOR_SUCCESS) {
4689 /* Already in error state, do nothing */
4690 return;
4691 }
4692
4693 QCBORError uErr;
4694
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004695 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004696 {
4697 uTagRequirement,
4698 {QCBOR_TYPE_DAYS_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4699 {QCBOR_TYPE_INT64, QCBOR_TYPE_UINT64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4700 };
4701
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004702 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004703 if(uErr != QCBOR_SUCCESS) {
4704 goto Done;
4705 }
4706
4707 if(pItem->uDataType != QCBOR_TYPE_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004708 uErr = QCBOR_Private_DecodeDaysEpoch(pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004709 if(uErr != QCBOR_SUCCESS) {
4710 goto Done;
4711 }
4712 }
4713
4714 /* Save the tags in the last item's tags in the decode context
4715 * for QCBORDecode_GetNthTagOfLast()
4716 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004717 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004718
4719 *pnDays = pItem->val.epochDays;
4720
4721Done:
4722 pMe->uLastError = (uint8_t)uErr;
4723}
4724
4725
4726/*
4727 * Public function, see header qcbor/qcbor_decode.h
4728 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004729void
4730QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe,
4731 uint8_t uTagRequirement,
4732 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004733{
4734 if(pMe->uLastError != QCBOR_SUCCESS) {
4735 /* Already in error state, do nothing */
4736 return;
4737 }
4738
4739 QCBORItem Item;
4740 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4741
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004742 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004743}
4744
4745
4746/*
4747 * Public function, see header qcbor/qcbor_decode.h
4748 */
4749void
4750QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe,
4751 int64_t nLabel,
4752 uint8_t uTagRequirement,
4753 int64_t *pnDays)
4754{
4755 QCBORItem Item;
4756 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004757 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004758}
4759
4760
4761/*
4762 * Public function, see header qcbor/qcbor_decode.h
4763 */
4764void
4765QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe,
4766 const char *szLabel,
4767 uint8_t uTagRequirement,
4768 int64_t *pnDays)
4769{
4770 QCBORItem Item;
4771 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004772 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004773}
4774
4775
4776
Laurence Lundblade37286c02022-09-03 10:05:02 -07004777/*
4778 * @brief Get a string that matches the type/tag specification.
4779 */
4780void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004781QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
4782 const QCBOR_Private_TagSpec TagSpec,
4783 UsefulBufC *pBstr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004784{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004785 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade37286c02022-09-03 10:05:02 -07004786 /* Already in error state, do nothing */
Laurence Lundbladec4537442020-04-14 18:53:22 -07004787 return;
4788 }
4789
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004790 QCBORError uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004791 QCBORItem Item;
4792
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004793 uError = QCBORDecode_GetNext(pMe, &Item);
4794 if(uError != QCBOR_SUCCESS) {
4795 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004796 return;
4797 }
4798
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004799 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004800
4801 if(pMe->uLastError == QCBOR_SUCCESS) {
4802 *pBstr = Item.val.string;
Laurence Lundbladeab40c6f2020-08-28 11:24:58 -07004803 } else {
4804 *pBstr = NULLUsefulBufC;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004805 }
4806}
4807
Laurence Lundbladec4537442020-04-14 18:53:22 -07004808
4809
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004810
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004811/**
4812 * @brief Common processing for a big number tag.
4813 *
4814 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4815 * @param[in] pItem The item with the date.
4816 * @param[out] pValue The returned big number
4817 * @param[out] pbIsNegative The returned sign of the big number.
4818 *
4819 * Common processing for the big number tag. Mostly make sure
4820 * the tag content is correct and copy forward any further other tag
4821 * numbers.
4822 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004823static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004824QCBOR_Private_ProcessBigNum(const uint8_t uTagRequirement,
4825 const QCBORItem *pItem,
4826 UsefulBufC *pValue,
4827 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004828{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004829 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004830 {
4831 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004832 {QCBOR_TYPE_POSBIGNUM, QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4833 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004834 };
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004835
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004836 QCBORError uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004837 if(uErr != QCBOR_SUCCESS) {
4838 return uErr;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004839 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004840
4841 *pValue = pItem->val.string;
4842
4843 if(pItem->uDataType == QCBOR_TYPE_POSBIGNUM) {
4844 *pbIsNegative = false;
4845 } else if(pItem->uDataType == QCBOR_TYPE_NEGBIGNUM) {
4846 *pbIsNegative = true;
4847 }
4848
4849 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004850}
4851
4852
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004853/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004854 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004855 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004856void
4857QCBORDecode_GetBignum(QCBORDecodeContext *pMe,
4858 const uint8_t uTagRequirement,
4859 UsefulBufC *pValue,
4860 bool *pbIsNegative)
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004861{
4862 if(pMe->uLastError != QCBOR_SUCCESS) {
4863 // Already in error state, do nothing
4864 return;
4865 }
4866
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004867 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004868 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
4869 if(uError != QCBOR_SUCCESS) {
4870 pMe->uLastError = (uint8_t)uError;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004871 return;
4872 }
4873
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004874 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4875 &Item,
4876 pValue,
4877 pbIsNegative);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004878}
4879
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004880
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004881/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004882 * Public function, see header qcbor/qcbor_spiffy_decode.h
4883 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004884void
4885QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe,
4886 const int64_t nLabel,
4887 const uint8_t uTagRequirement,
4888 UsefulBufC *pValue,
4889 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004890{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004891 QCBORItem Item;
4892 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004893 if(pMe->uLastError != QCBOR_SUCCESS) {
4894 return;
4895 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004896
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004897 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4898 &Item,
4899 pValue,
4900 pbIsNegative);
Laurence Lundbladec4537442020-04-14 18:53:22 -07004901}
4902
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004903
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004904/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004905 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004906 */
4907void
4908QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe,
4909 const char *szLabel,
4910 const uint8_t uTagRequirement,
4911 UsefulBufC *pValue,
4912 bool *pbIsNegative)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004913{
4914 QCBORItem Item;
4915 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004916 if(pMe->uLastError != QCBOR_SUCCESS) {
4917 return;
4918 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004919
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004920 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4921 &Item,
4922 pValue,
4923 pbIsNegative);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004924}
4925
4926
4927
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004928/**
4929 * @brief Common processing for MIME tag (semi-private).
4930 *
4931 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4932 * @param[in] pItem The item with the date.
4933 * @param[out] pMessage The returned MIME message.
4934 * @param[out] pbIsTag257 If true, binary MIME, if not, text MIME.
4935 *
4936 * Common processing for the MIME tag. Mostly make sure the tag
4937 * content is correct and copy forward any further other tag
4938 * numbers. See QCBORDecode_GetMIMEMessage().
4939 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004940QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004941QCBORDecode_Private_GetMIME(const uint8_t uTagRequirement,
Laurence Lundblade37286c02022-09-03 10:05:02 -07004942 const QCBORItem *pItem,
4943 UsefulBufC *pMessage,
4944 bool *pbIsTag257)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004945{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004946 const QCBOR_Private_TagSpec TagSpecText =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004947 {
4948 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004949 {QCBOR_TYPE_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4950 {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004951 };
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004952 const QCBOR_Private_TagSpec TagSpecBinary =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004953 {
4954 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004955 {QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4956 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004957 };
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004958
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004959 QCBORError uReturn;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004960
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004961 if(QCBOR_Private_CheckTagRequirement(TagSpecText, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004962 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07004963 if(pbIsTag257 != NULL) {
4964 *pbIsTag257 = false;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004965 }
4966 uReturn = QCBOR_SUCCESS;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004967 } else if(QCBOR_Private_CheckTagRequirement(TagSpecBinary, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004968 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07004969 if(pbIsTag257 != NULL) {
4970 *pbIsTag257 = true;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004971 }
4972 uReturn = QCBOR_SUCCESS;
4973
4974 } else {
4975 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
4976 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07004977
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004978 return uReturn;
4979}
4980
Laurence Lundblade93d89472020-10-03 22:30:50 -07004981// Improvement: add methods for wrapped CBOR, a simple alternate
4982// to EnterBstrWrapped
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004983
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004984
4985
4986
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07004987#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundbladee6430642020-03-14 21:15:44 -07004988
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004989/**
4990 * @brief Prototype for conversion of exponent and mantissa to unsigned integer.
4991 *
4992 * @param[in] uMantissa The mantissa.
4993 * @param[in] nExponent The exponent.
4994 * @param[out] puResult The resulting integer.
4995 *
4996 * Concrete implementations of this are for exponent base 10 and 2 supporting
4997 * decimal fractions and big floats.
4998 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004999typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005000
5001
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005002/**
5003 * @brief Base 10 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5004 *
5005 * @param[in] uMantissa The unsigned integer mantissa.
5006 * @param[in] nExponent The signed integer exponent.
5007 * @param[out] puResult Place to return the unsigned integer result.
5008 *
5009 * This computes: mantissa * 10 ^^ exponent as for a decimal fraction. The output is a 64-bit
5010 * unsigned integer.
5011 *
5012 * There are many inputs for which the result will not fit in the
5013 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5014 * be returned.
5015 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005016static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005017QCBOR_Private_Exponentitate10(const uint64_t uMantissa,
5018 int64_t nExponent,
5019 uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005020{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005021 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005022
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005023 if(uResult != 0) {
5024 /* This loop will run a maximum of 19 times because
5025 * UINT64_MAX < 10 ^^ 19. More than that will cause
5026 * exit with the overflow error
5027 */
5028 for(; nExponent > 0; nExponent--) {
5029 if(uResult > UINT64_MAX / 10) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005030 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005031 }
5032 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005033 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005034
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005035 for(; nExponent < 0; nExponent++) {
5036 uResult = uResult / 10;
5037 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005038 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005039 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005040 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005041 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005042 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07005043
5044 *puResult = uResult;
5045
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005046 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005047}
5048
5049
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005050/**
5051 * @brief Base 2 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5052 *
5053 * @param[in] uMantissa The unsigned integer mantissa.
5054 * @param[in] nExponent The signed integer exponent.
5055 * @param[out] puResult Place to return the unsigned integer result.
5056 *
5057 * This computes: mantissa * 2 ^^ exponent as for a big float. The
5058 * output is a 64-bit unsigned integer.
5059 *
5060 * There are many inputs for which the result will not fit in the
5061 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5062 * be returned.
5063 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005064static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005065QCBOR_Private_Exponentitate2(const uint64_t uMantissa,
5066 int64_t nExponent,
5067 uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005068{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005069 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005070
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005071 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005072
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005073 /* This loop will run a maximum of 64 times because INT64_MAX <
5074 * 2^31. More than that will cause exit with the overflow error
Laurence Lundbladee6430642020-03-14 21:15:44 -07005075 */
5076 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005077 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005078 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005079 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005080 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005081 nExponent--;
5082 }
5083
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005084 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005085 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005086 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005087 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005088 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005089 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005090 }
5091
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005092 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005093
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005094 return QCBOR_SUCCESS;
5095}
5096
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005097
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005098/**
5099 * @brief Exponentiate a signed mantissa and signed exponent to produce a signed result.
5100 *
5101 * @param[in] nMantissa Signed integer mantissa.
5102 * @param[in] nExponent Signed integer exponent.
5103 * @param[out] pnResult Place to put the signed integer result.
5104 * @param[in] pfExp Exponentiation function.
5105 *
5106 * @returns Error code
5107 *
5108 * \c pfExp performs exponentiation on and unsigned mantissa and
5109 * produces an unsigned result. This converts the mantissa from signed
5110 * and converts the result to signed. The exponentiation function is
5111 * either for base 2 or base 10 (and could be other if needed).
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005112 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005113static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005114QCBOR_Private_ExponentiateNN(const int64_t nMantissa,
5115 const int64_t nExponent,
5116 int64_t *pnResult,
5117 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005118{
5119 uint64_t uResult;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005120 uint64_t uMantissa;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005121
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005122 /* Take the absolute value and put it into an unsigned. */
5123 if(nMantissa >= 0) {
5124 /* Positive case is straightforward */
5125 uMantissa = (uint64_t)nMantissa;
5126 } else if(nMantissa != INT64_MIN) {
5127 /* The common negative case. See next. */
5128 uMantissa = (uint64_t)-nMantissa;
5129 } else {
5130 /* int64_t and uint64_t are always two's complement per the
5131 * C standard (and since QCBOR uses these it only works with
5132 * two's complement, which is pretty much universal these
5133 * days). The range of a negative two's complement integer is
5134 * one more that than a positive, so the simple code above might
5135 * not work all the time because you can't simply negate the
5136 * value INT64_MIN because it can't be represented in an
5137 * int64_t. -INT64_MIN can however be represented in a
5138 * uint64_t. Some compilers seem to recognize this case for the
5139 * above code and put the correct value in uMantissa, however
5140 * they are not required to do this by the C standard. This next
5141 * line does however work for all compilers.
5142 *
5143 * This does assume two's complement where -INT64_MIN ==
5144 * INT64_MAX + 1 (which wouldn't be true for one's complement or
5145 * sign and magnitude (but we know we're using two's complement
5146 * because int64_t requires it)).
5147 *
5148 * See these, particularly the detailed commentary:
5149 * https://stackoverflow.com/questions/54915742/does-c99-mandate-a-int64-t-type-be-available-always
5150 * https://stackoverflow.com/questions/37301078/is-negating-int-min-undefined-behaviour
5151 */
5152 uMantissa = (uint64_t)INT64_MAX+1;
5153 }
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005154
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005155 /* Call the exponentiator passed for either base 2 or base 10.
5156 * Here is where most of the overflow errors are caught. */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005157 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
5158 if(uReturn) {
5159 return uReturn;
5160 }
5161
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005162 /* Convert back to the sign of the original mantissa */
5163 if(nMantissa >= 0) {
5164 if(uResult > INT64_MAX) {
5165 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5166 }
5167 *pnResult = (int64_t)uResult;
5168 } else {
5169 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
5170 * of INT64_MIN. This assumes two's compliment representation
5171 * where INT64_MIN is one increment farther from 0 than
5172 * INT64_MAX. Trying to write -INT64_MIN doesn't work to get
5173 * this because the compiler makes it an int64_t which can't
5174 * represent -INT64_MIN. Also see above.
5175 */
5176 if(uResult > (uint64_t)INT64_MAX+1) {
5177 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5178 }
5179 *pnResult = -(int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005180 }
5181
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005182 return QCBOR_SUCCESS;
5183}
5184
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005185
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005186/**
5187 * @brief Exponentiate an unsigned mantissa and signed exponent to produce an unsigned result.
5188 *
5189 * @param[in] nMantissa Signed integer mantissa.
5190 * @param[in] nExponent Signed integer exponent.
5191 * @param[out] puResult Place to put the signed integer result.
5192 * @param[in] pfExp Exponentiation function.
5193 *
5194 * @returns Error code
5195 *
5196 * \c pfExp performs exponentiation on and unsigned mantissa and
5197 * produces an unsigned result. This errors out if the mantissa
5198 * is negative because the output is unsigned.
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005199 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005200static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005201QCBOR_Private_ExponentitateNU(const int64_t nMantissa,
5202 const int64_t nExponent,
5203 uint64_t *puResult,
5204 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005205{
5206 if(nMantissa < 0) {
5207 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5208 }
5209
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005210 /* Cast to unsigned is OK because of check for negative.
5211 * Cast to unsigned is OK because UINT64_MAX > INT64_MAX.
5212 * Exponentiation is straight forward
5213 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005214 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
5215}
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005216
5217
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005218/**
5219 * @brief Exponentiate an usnigned mantissa and unsigned exponent to produce an unsigned result.
5220 *
5221 * @param[in] uMantissa Unsigned integer mantissa.
5222 * @param[in] nExponent Unsigned integer exponent.
5223 * @param[out] puResult Place to put the unsigned integer result.
5224 * @param[in] pfExp Exponentiation function.
5225 *
5226 * @returns Error code
5227 *
5228 * \c pfExp performs exponentiation on and unsigned mantissa and
5229 * produces an unsigned result so this is just a wrapper that does
5230 * nothing (and is likely inlined).
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005231 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005232static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005233QCBOR_Private_ExponentitateUU(const uint64_t uMantissa,
5234 const int64_t nExponent,
5235 uint64_t *puResult,
5236 fExponentiator pfExp)
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005237{
5238 return (*pfExp)(uMantissa, nExponent, puResult);
5239}
5240
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005241#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005242
5243
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005244
5245
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005246/**
5247 * @brief Convert a CBOR big number to a uint64_t.
5248 *
5249 * @param[in] BigNum Bytes of the big number to convert.
5250 * @param[in] uMax Maximum value allowed for the result.
5251 * @param[out] pResult Place to put the unsigned integer result.
5252 *
5253 * @returns Error code
5254 *
5255 * Many values will overflow because a big num can represent a much
5256 * larger range than uint64_t.
5257 */
5258static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005259QCBOR_Private_ConvertBigNumToUnsigned(const UsefulBufC BigNum,
5260 const uint64_t uMax,
5261 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005262{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005263 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005264
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005265 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005266 const uint8_t *pByte = BigNum.ptr;
5267 size_t uLen = BigNum.len;
5268 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07005269 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005270 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005271 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07005272 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005273 }
5274
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005275 *pResult = uResult;
5276 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005277}
5278
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005279
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005280/**
5281 * @brief Convert a CBOR postive big number to a uint64_t.
5282 *
5283 * @param[in] BigNum Bytes of the big number to convert.
5284 * @param[out] pResult Place to put the unsigned integer result.
5285 *
5286 * @returns Error code
5287 *
5288 * Many values will overflow because a big num can represent a much
5289 * larger range than uint64_t.
5290 */
5291static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005292QCBOR_Private_ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum,
5293 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005294{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005295 return QCBOR_Private_ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005296}
5297
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005298
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005299/**
5300 * @brief Convert a CBOR positive big number to an int64_t.
5301 *
5302 * @param[in] BigNum Bytes of the big number to convert.
5303 * @param[out] pResult Place to put the signed integer result.
5304 *
5305 * @returns Error code
5306 *
5307 * Many values will overflow because a big num can represent a much
5308 * larger range than int64_t.
5309 */
5310static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005311QCBOR_Private_ConvertPositiveBigNumToSigned(const UsefulBufC BigNum,
5312 int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005313{
5314 uint64_t uResult;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005315 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5316 INT64_MAX,
5317 &uResult);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005318 if(uError) {
5319 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005320 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005321 /* Cast is safe because ConvertBigNumToUnsigned limits to INT64_MAX */
Laurence Lundbladee6430642020-03-14 21:15:44 -07005322 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005323 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005324}
5325
5326
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005327/**
5328 * @brief Convert a CBOR negative big number to an int64_t.
5329 *
5330 * @param[in] BigNum Bytes of the big number to convert.
5331 * @param[out] pnResult Place to put the signed integer result.
5332 *
5333 * @returns Error code
5334 *
5335 * Many values will overflow because a big num can represent a much
5336 * larger range than int64_t.
5337 */
5338static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005339QCBOR_Private_ConvertNegativeBigNumToSigned(const UsefulBufC BigNum,
5340 int64_t *pnResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005341{
5342 uint64_t uResult;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005343 /* The negative integer furthest from zero for a C int64_t is
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005344 * INT64_MIN which is expressed as -INT64_MAX - 1. The value of a
5345 * negative number in CBOR is computed as -n - 1 where n is the
5346 * encoded integer, where n is what is in the variable BigNum. When
5347 * converting BigNum to a uint64_t, the maximum value is thus
5348 * INT64_MAX, so that when it -n - 1 is applied to it the result
5349 * will never be further from 0 than INT64_MIN.
5350 *
5351 * -n - 1 <= INT64_MIN.
5352 * -n - 1 <= -INT64_MAX - 1
5353 * n <= INT64_MAX.
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005354 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005355 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5356 INT64_MAX,
5357 &uResult);
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005358 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005359 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005360 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005361
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005362 /* Now apply -n - 1. The cast is safe because
5363 * ConvertBigNumToUnsigned() is limited to INT64_MAX which does fit
5364 * is the largest positive integer that an int64_t can
5365 * represent. */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005366 *pnResult = -(int64_t)uResult - 1;
5367
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005368 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005369}
5370
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005371
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005372
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005373
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005374/**
5375 * @brief Convert integers and floats to an int64_t.
5376 *
5377 * @param[in] pItem The item to convert.
5378 * @param[in] uConvertTypes Bit mask list of conversion options.
5379 * @param[out] pnValue The resulting converted value.
5380 *
5381 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5382 * in uConvertTypes.
5383 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5384 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5385 * or too small.
5386 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005387static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005388QCBOR_Private_ConvertInt64(const QCBORItem *pItem,
5389 const uint32_t uConvertTypes,
5390 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005391{
5392 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005393 case QCBOR_TYPE_FLOAT:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005394 case QCBOR_TYPE_DOUBLE:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005395#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005396 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005397 /* https://pubs.opengroup.org/onlinepubs/009695399/functions/llround.html
5398 http://www.cplusplus.com/reference/cmath/llround/
5399 */
5400 // Not interested in FE_INEXACT
5401 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005402 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5403 *pnValue = llround(pItem->val.dfnum);
5404 } else {
5405 *pnValue = lroundf(pItem->val.fnum);
5406 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005407 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5408 // llround() shouldn't result in divide by zero, but catch
5409 // it here in case it unexpectedly does. Don't try to
5410 // distinguish between the various exceptions because it seems
5411 // they vary by CPU, compiler and OS.
5412 return QCBOR_ERR_FLOAT_EXCEPTION;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005413 }
5414 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005415 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005416 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005417#else
5418 return QCBOR_ERR_HW_FLOAT_DISABLED;
5419#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005420 break;
5421
5422 case QCBOR_TYPE_INT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005423 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005424 *pnValue = pItem->val.int64;
5425 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005426 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005427 }
5428 break;
5429
5430 case QCBOR_TYPE_UINT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005431 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005432 if(pItem->val.uint64 < INT64_MAX) {
5433 *pnValue = pItem->val.int64;
5434 } else {
5435 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5436 }
5437 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005438 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005439 }
5440 break;
5441
5442 default:
5443 return QCBOR_ERR_UNEXPECTED_TYPE;
5444 }
5445 return QCBOR_SUCCESS;
5446}
5447
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005448
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005449/**
5450 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5451 *
5452 * @param[in] pMe The decode context.
5453 * @param[in] uConvertTypes Bit mask list of conversion options.
5454 * @param[out] pnValue Result of the conversion.
5455 * @param[in,out] pItem Temporary space to store Item, returned item.
5456 *
5457 * See QCBORDecode_GetInt64Convert().
5458 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005459void
5460QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pMe,
5461 uint32_t uConvertTypes,
5462 int64_t *pnValue,
5463 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005464{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07005465 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005466 return;
5467 }
5468
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005469 QCBORError uError = QCBORDecode_GetNext(pMe, pItem);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005470 if(uError) {
5471 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005472 return;
5473 }
5474
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005475 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005476 uConvertTypes,
5477 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005478}
5479
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005480/**
5481 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5482 *
5483 * @param[in] pMe The decode context.
5484 * @param[in] nLabel Label to find in map.
5485 * @param[in] uConvertTypes Bit mask list of conversion options.
5486 * @param[out] pnValue Result of the conversion.
5487 * @param[in,out] pItem Temporary space to store Item, returned item.
5488 *
5489 * See QCBORDecode_GetInt64ConvertInMapN().
5490 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005491void
5492QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pMe,
5493 int64_t nLabel,
5494 uint32_t uConvertTypes,
5495 int64_t *pnValue,
5496 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005497{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005498 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005499 if(pMe->uLastError != QCBOR_SUCCESS) {
5500 return;
5501 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005502
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005503 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5504 uConvertTypes,
5505 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005506}
5507
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005508/**
5509 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5510 *
5511 * @param[in] pMe The decode context.
5512 * @param[in] szLabel Label to find in map.
5513 * @param[in] uConvertTypes Bit mask list of conversion options.
5514 * @param[out] pnValue Result of the conversion.
5515 * @param[in,out] pItem Temporary space to store Item, returned item.
5516 *
5517 * See QCBORDecode_GetInt64ConvertInMapSZ().
5518 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005519void
5520QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5521 const char * szLabel,
5522 uint32_t uConvertTypes,
5523 int64_t *pnValue,
5524 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005525{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005526 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005527 if(pMe->uLastError != QCBOR_SUCCESS) {
5528 return;
5529 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005530
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005531 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5532 uConvertTypes,
5533 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005534}
5535
5536
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005537/**
5538 * @brief Convert many number types to an int64_t.
5539 *
5540 * @param[in] pItem The item to convert.
5541 * @param[in] uConvertTypes Bit mask list of conversion options.
5542 * @param[out] pnValue The resulting converted value.
5543 *
5544 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5545 * in uConvertTypes.
5546 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5547 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5548 * or too small.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005549 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005550static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005551QCBOR_Private_Int64ConvertAll(const QCBORItem *pItem,
5552 const uint32_t uConvertTypes,
5553 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005554{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005555 switch(pItem->uDataType) {
5556
5557 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005558 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005559 return QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005560 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005561 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005562 }
5563 break;
5564
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005565 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005566 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005567 return QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005568 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005569 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005570 }
5571 break;
5572
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005573#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005574 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005575 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005576 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005577 pItem->val.expAndMantissa.nExponent,
5578 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005579 &QCBOR_Private_Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005580 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005581 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005582 }
5583 break;
5584
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005585 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005586 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005587 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005588 pItem->val.expAndMantissa.nExponent,
5589 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005590 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005591 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005592 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005593 }
5594 break;
5595
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005596 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005597 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005598 int64_t nMantissa;
5599 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005600 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005601 if(uErr) {
5602 return uErr;
5603 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005604 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005605 pItem->val.expAndMantissa.nExponent,
5606 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005607 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005608 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005609 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005610 }
5611 break;
5612
5613 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005614 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005615 int64_t nMantissa;
5616 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005617 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005618 if(uErr) {
5619 return uErr;
5620 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005621 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005622 pItem->val.expAndMantissa.nExponent,
5623 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005624 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005625 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005626 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005627 }
5628 break;
5629
5630 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005631 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005632 int64_t nMantissa;
5633 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005634 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005635 if(uErr) {
5636 return uErr;
5637 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005638 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005639 pItem->val.expAndMantissa.nExponent,
5640 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005641 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005642 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005643 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005644 }
5645 break;
5646
5647 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005648 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005649 int64_t nMantissa;
5650 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005651 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005652 if(uErr) {
5653 return uErr;
5654 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005655 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005656 pItem->val.expAndMantissa.nExponent,
5657 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005658 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005659 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005660 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005661 }
5662 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005663#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005664
Laurence Lundbladee6430642020-03-14 21:15:44 -07005665
Laurence Lundbladec4537442020-04-14 18:53:22 -07005666 default:
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005667 return QCBOR_ERR_UNEXPECTED_TYPE; }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005668}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005669
5670
Laurence Lundbladec4537442020-04-14 18:53:22 -07005671/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005672 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005673 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005674void
5675QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe,
5676 const uint32_t uConvertTypes,
5677 int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005678{
5679 QCBORItem Item;
5680
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005681 QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005682
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005683 if(pMe->uLastError == QCBOR_SUCCESS) {
5684 // The above conversion succeeded
5685 return;
5686 }
5687
Laurence Lundbladef6c86662020-05-12 02:08:00 -07005688 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005689 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07005690 return;
5691 }
5692
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005693 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5694 uConvertTypes,
5695 pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005696}
5697
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005698
5699/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005700 * Public function, see header qcbor/qcbor_decode.h file
5701 */
5702void
5703QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
5704 const int64_t nLabel,
5705 const uint32_t uConvertTypes,
5706 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005707{
5708 QCBORItem Item;
5709
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005710 QCBORDecode_Private_GetInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07005711 nLabel,
5712 uConvertTypes,
5713 pnValue,
5714 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005715
5716 if(pMe->uLastError == QCBOR_SUCCESS) {
5717 // The above conversion succeeded
5718 return;
5719 }
5720
5721 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5722 // The above conversion failed in a way that code below can't correct
5723 return;
5724 }
5725
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005726 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5727 uConvertTypes,
5728 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005729}
5730
5731
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005732/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005733 * Public function, see header qcbor/qcbor_decode.h file
5734 */
5735void
5736QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
5737 const char *szLabel,
5738 const uint32_t uConvertTypes,
5739 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005740{
5741 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005742 QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07005743 szLabel,
5744 uConvertTypes,
5745 pnValue,
5746 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005747
5748 if(pMe->uLastError == QCBOR_SUCCESS) {
5749 // The above conversion succeeded
5750 return;
5751 }
5752
5753 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5754 // The above conversion failed in a way that code below can't correct
5755 return;
5756 }
5757
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005758 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5759 uConvertTypes,
5760 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005761}
5762
5763
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005764/**
5765 * @brief Convert many number types to an uint64_t.
5766 *
5767 * @param[in] pItem The item to convert.
5768 * @param[in] uConvertTypes Bit mask list of conversion options.
5769 * @param[out] puValue The resulting converted value.
5770 *
5771 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5772 * in uConvertTypes.
5773 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5774 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5775 * or too small.
5776 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005777static QCBORError
5778QCBOR_Private_ConvertUInt64(const QCBORItem *pItem,
5779 const uint32_t uConvertTypes,
5780 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005781{
5782 switch(pItem->uDataType) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005783 case QCBOR_TYPE_DOUBLE:
5784 case QCBOR_TYPE_FLOAT:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005785#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005786 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005787 // Can't use llround here because it will not convert values
5788 // greater than INT64_MAX and less than UINT64_MAX that
5789 // need to be converted so it is more complicated.
5790 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
5791 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5792 if(isnan(pItem->val.dfnum)) {
5793 return QCBOR_ERR_FLOAT_EXCEPTION;
5794 } else if(pItem->val.dfnum < 0) {
5795 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5796 } else {
5797 double dRounded = round(pItem->val.dfnum);
5798 // See discussion in DecodeDateEpoch() for
5799 // explanation of - 0x7ff
5800 if(dRounded > (double)(UINT64_MAX- 0x7ff)) {
5801 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5802 }
5803 *puValue = (uint64_t)dRounded;
5804 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005805 } else {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005806 if(isnan(pItem->val.fnum)) {
5807 return QCBOR_ERR_FLOAT_EXCEPTION;
5808 } else if(pItem->val.fnum < 0) {
5809 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5810 } else {
5811 float fRounded = roundf(pItem->val.fnum);
5812 // See discussion in DecodeDateEpoch() for
5813 // explanation of - 0x7ff
5814 if(fRounded > (float)(UINT64_MAX- 0x7ff)) {
5815 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5816 }
5817 *puValue = (uint64_t)fRounded;
5818 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005819 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005820 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5821 // round() and roundf() shouldn't result in exceptions here, but
5822 // catch them to be robust and thorough. Don't try to
5823 // distinguish between the various exceptions because it seems
5824 // they vary by CPU, compiler and OS.
5825 return QCBOR_ERR_FLOAT_EXCEPTION;
5826 }
5827
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005828 } else {
5829 return QCBOR_ERR_UNEXPECTED_TYPE;
5830 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005831#else
5832 return QCBOR_ERR_HW_FLOAT_DISABLED;
5833#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005834 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005835
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005836 case QCBOR_TYPE_INT64:
5837 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
5838 if(pItem->val.int64 >= 0) {
5839 *puValue = (uint64_t)pItem->val.int64;
5840 } else {
5841 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5842 }
5843 } else {
5844 return QCBOR_ERR_UNEXPECTED_TYPE;
5845 }
5846 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005847
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005848 case QCBOR_TYPE_UINT64:
5849 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
5850 *puValue = pItem->val.uint64;
5851 } else {
5852 return QCBOR_ERR_UNEXPECTED_TYPE;
5853 }
5854 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005855
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005856 default:
5857 return QCBOR_ERR_UNEXPECTED_TYPE;
5858 }
5859
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005860 return QCBOR_SUCCESS;
5861}
Laurence Lundbladec4537442020-04-14 18:53:22 -07005862
5863
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005864/**
5865 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5866 *
5867 * @param[in] pMe The decode context.
5868 * @param[in] uConvertTypes Bit mask list of conversion options.
5869 * @param[out] puValue Result of the conversion.
5870 * @param[in,out] pItem Temporary space to store Item, returned item.
5871 *
5872 * See QCBORDecode_GetUInt64Convert().
5873 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005874void
5875QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pMe,
5876 const uint32_t uConvertTypes,
5877 uint64_t *puValue,
5878 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005879{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005880 if(pMe->uLastError != QCBOR_SUCCESS) {
5881 return;
5882 }
5883
Laurence Lundbladec4537442020-04-14 18:53:22 -07005884 QCBORItem Item;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005885
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005886 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
5887 if(uError) {
5888 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005889 return;
5890 }
5891
Laurence Lundbladea826c502020-05-10 21:07:00 -07005892 if(pItem) {
5893 *pItem = Item;
5894 }
5895
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005896 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(&Item,
5897 uConvertTypes,
5898 puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005899}
5900
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005901
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005902/**
5903 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5904 *
5905 * @param[in] pMe The decode context.
5906 * @param[in] nLabel Label to find in map.
5907 * @param[in] uConvertTypes Bit mask list of conversion options.
5908 * @param[out] puValue Result of the conversion.
5909 * @param[in,out] pItem Temporary space to store Item, returned item.
5910 *
5911 * See QCBORDecode_GetUInt64ConvertInMapN().
5912 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005913void
5914QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe,
5915 const int64_t nLabel,
5916 const uint32_t uConvertTypes,
5917 uint64_t *puValue,
5918 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005919{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005920 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005921 if(pMe->uLastError != QCBOR_SUCCESS) {
5922 return;
5923 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005924
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005925 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
5926 uConvertTypes,
5927 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005928}
5929
5930
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005931/**
5932 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5933 *
5934 * @param[in] pMe The decode context.
5935 * @param[in] szLabel Label to find in map.
5936 * @param[in] uConvertTypes Bit mask list of conversion options.
5937 * @param[out] puValue Result of the conversion.
5938 * @param[in,out] pItem Temporary space to store Item, returned item.
5939 *
5940 * See QCBORDecode_GetUInt64ConvertInMapSZ().
5941 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005942void
5943QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5944 const char *szLabel,
5945 const uint32_t uConvertTypes,
5946 uint64_t *puValue,
5947 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005948{
5949 if(pMe->uLastError != QCBOR_SUCCESS) {
5950 return;
5951 }
5952
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005953 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005954 if(pMe->uLastError != QCBOR_SUCCESS) {
5955 return;
5956 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005957
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005958 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
5959 uConvertTypes,
5960 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005961}
5962
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005963
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005964/**
5965 * @brief Convert many number types to an unt64_t.
5966 *
5967 * @param[in] pItem The item to convert.
5968 * @param[in] uConvertTypes Bit mask list of conversion options.
5969 * @param[out] puValue The resulting converted value.
5970 *
5971 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5972 * in uConvertTypes.
5973 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5974 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5975 * or too small.
5976 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005977static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005978QCBOR_Private_UInt64ConvertAll(const QCBORItem *pItem,
5979 const uint32_t uConvertTypes,
5980 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005981{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08005982 switch(pItem->uDataType) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005983
5984 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005985 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005986 return QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005987 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005988 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005989 }
5990 break;
5991
5992 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005993 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005994 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5995 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005996 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005997 }
5998 break;
5999
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006000#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006001
6002 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006003 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006004 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006005 pItem->val.expAndMantissa.nExponent,
6006 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006007 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006008 } 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
6013 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006014 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006015 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006016 pItem->val.expAndMantissa.nExponent,
6017 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006018 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006019 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006020 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006021 }
6022 break;
6023
6024 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006025 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006026 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006027 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006028 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006029 if(uErr != QCBOR_SUCCESS) {
6030 return uErr;
6031 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006032 return QCBOR_Private_ExponentitateUU(uMantissa,
6033 pItem->val.expAndMantissa.nExponent,
6034 puValue,
6035 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006036 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006037 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006038 }
6039 break;
6040
6041 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006042 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006043 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6044 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006045 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006046 }
6047 break;
6048
6049 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006050 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006051 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006052 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006053 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum,
6054 &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006055 if(uErr != QCBOR_SUCCESS) {
6056 return uErr;
6057 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006058 return QCBOR_Private_ExponentitateUU(uMantissa,
6059 pItem->val.expAndMantissa.nExponent,
6060 puValue,
6061 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006062 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006063 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006064 }
6065 break;
6066
6067 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006068 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006069 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6070 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006071 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006072 }
6073 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006074#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006075 default:
6076 return QCBOR_ERR_UNEXPECTED_TYPE;
6077 }
6078}
6079
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006080
Laurence Lundblade4e2da002020-06-13 23:08:31 -07006081/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006082 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006083 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006084void
6085QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe,
6086 const uint32_t uConvertTypes,
6087 uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006088{
6089 QCBORItem Item;
6090
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006091 QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006092
Laurence Lundbladef6c86662020-05-12 02:08:00 -07006093 if(pMe->uLastError == QCBOR_SUCCESS) {
6094 // The above conversion succeeded
6095 return;
6096 }
6097
6098 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6099 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07006100 return;
6101 }
6102
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006103 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6104 uConvertTypes,
6105 puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006106}
6107
Laurence Lundbladec4537442020-04-14 18:53:22 -07006108
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006109/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006110 * Public function, see header qcbor/qcbor_decode.h file
6111 */
6112void
6113QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
6114 const int64_t nLabel,
6115 const uint32_t uConvertTypes,
6116 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006117{
6118 QCBORItem Item;
6119
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006120 QCBORDecode_Private_GetUInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006121 nLabel,
6122 uConvertTypes,
6123 puValue,
6124 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006125
6126 if(pMe->uLastError == QCBOR_SUCCESS) {
6127 // The above conversion succeeded
6128 return;
6129 }
6130
6131 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6132 // The above conversion failed in a way that code below can't correct
6133 return;
6134 }
6135
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006136 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6137 uConvertTypes,
6138 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006139}
6140
6141
6142/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006143 * Public function, see header qcbor/qcbor_decode.h file
6144 */
6145void
6146QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
6147 const char *szLabel,
6148 const uint32_t uConvertTypes,
6149 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006150{
6151 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006152 QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006153 szLabel,
6154 uConvertTypes,
6155 puValue,
6156 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006157
6158 if(pMe->uLastError == QCBOR_SUCCESS) {
6159 // The above conversion succeeded
6160 return;
6161 }
6162
6163 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6164 // The above conversion failed in a way that code below can't correct
6165 return;
6166 }
6167
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006168 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6169 uConvertTypes,
6170 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006171}
6172
6173
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006174
6175
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006176#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006177/**
6178 * @brief Basic conversions to a double.
6179 *
6180 * @param[in] pItem The item to convert
6181 * @param[in] uConvertTypes Bit flags indicating source types for conversion
6182 * @param[out] pdValue The value converted to a double
6183 *
6184 * This does the conversions that don't need much object code,
6185 * the conversions from int, uint and float to double.
6186 *
6187 * See QCBOR_Private_DoubleConvertAll() for the full set
6188 * of conversions.
6189 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006190static QCBORError
6191QCBOR_Private_ConvertDouble(const QCBORItem *pItem,
6192 const uint32_t uConvertTypes,
6193 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006194{
6195 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006196 case QCBOR_TYPE_FLOAT:
6197#ifndef QCBOR_DISABLE_FLOAT_HW_USE
6198 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6199 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006200 // Simple cast does the job.
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006201 *pdValue = (double)pItem->val.fnum;
6202 } else {
6203 return QCBOR_ERR_UNEXPECTED_TYPE;
6204 }
6205 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006206#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006207 return QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006208#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006209 break;
6210
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006211 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006212 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6213 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006214 *pdValue = pItem->val.dfnum;
6215 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006216 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006217 }
6218 }
6219 break;
6220
6221 case QCBOR_TYPE_INT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006222#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006223 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006224 // A simple cast seems to do the job with no worry of exceptions.
6225 // There will be precision loss for some values.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006226 *pdValue = (double)pItem->val.int64;
6227
6228 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006229 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006230 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006231#else
6232 return QCBOR_ERR_HW_FLOAT_DISABLED;
6233#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006234 break;
6235
6236 case QCBOR_TYPE_UINT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006237#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006238 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006239 // A simple cast seems to do the job with no worry of exceptions.
6240 // There will be precision loss for some values.
6241 *pdValue = (double)pItem->val.uint64;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006242 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006243 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006244 }
6245 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006246#else
6247 return QCBOR_ERR_HW_FLOAT_DISABLED;
6248#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006249
6250 default:
6251 return QCBOR_ERR_UNEXPECTED_TYPE;
6252 }
6253
6254 return QCBOR_SUCCESS;
6255}
6256
6257
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006258/**
6259 * @brief Almost-public method to decode a number and convert to double (semi-private).
6260 *
6261 * @param[in] pMe The decode context.
6262 * @param[in] uConvertTypes Bit mask list of conversion options
6263 * @param[out] pdValue The output of the conversion.
6264 * @param[in,out] pItem Temporary space to store Item, returned item.
6265 *
6266 * See QCBORDecode_GetDoubleConvert().
6267 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006268void
6269QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pMe,
6270 const uint32_t uConvertTypes,
6271 double *pdValue,
6272 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07006273{
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006274 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07006275 return;
6276 }
6277
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006278 QCBORError uError = QCBORDecode_GetNext(pMe, pItem);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006279 if(uError) {
6280 pMe->uLastError = (uint8_t)uError;
6281 return;
6282 }
6283
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006284 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006285 uConvertTypes,
6286 pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006287}
Laurence Lundbladec4537442020-04-14 18:53:22 -07006288
Laurence Lundbladec4537442020-04-14 18:53:22 -07006289
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006290/**
6291 * @brief Almost-public method to decode a number and convert to double (semi-private).
6292 *
6293 * @param[in] pMe The decode context.
6294 * @param[in] nLabel Label to find in map.
6295 * @param[in] uConvertTypes Bit mask list of conversion options
6296 * @param[out] pdValue The output of the conversion.
6297 * @param[in,out] pItem Temporary space to store Item, returned item.
6298 *
6299 * See QCBORDecode_GetDoubleConvertInMapN().
6300 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006301void
6302QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pMe,
6303 const int64_t nLabel,
6304 const uint32_t uConvertTypes,
6305 double *pdValue,
6306 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006307{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006308 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006309 if(pMe->uLastError != QCBOR_SUCCESS) {
6310 return;
6311 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006312
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006313 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6314 uConvertTypes,
6315 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006316}
6317
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006318
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006319/**
6320 * @brief Almost-public method to decode a number and convert to double (semi-private).
6321 *
6322 * @param[in] pMe The decode context.
6323 * @param[in] szLabel Label to find in map.
6324 * @param[in] uConvertTypes Bit mask list of conversion options
6325 * @param[out] pdValue The output of the conversion.
6326 * @param[in,out] pItem Temporary space to store Item, returned item.
6327 *
6328 * See QCBORDecode_GetDoubleConvertInMapSZ().
6329 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006330void
6331QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe,
6332 const char *szLabel,
6333 const uint32_t uConvertTypes,
6334 double *pdValue,
6335 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006336{
6337 if(pMe->uLastError != QCBOR_SUCCESS) {
6338 return;
6339 }
6340
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006341 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006342 if(pMe->uLastError != QCBOR_SUCCESS) {
6343 return;
6344 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006345
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006346 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6347 uConvertTypes,
6348 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006349}
6350
6351
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006352#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006353/**
6354 * @brief Convert a big number to double-precision float.
6355 *
6356 * @param[in] BigNum The big number to convert
6357 *
6358 * @returns The double value.
6359 *
6360 * This will always succeed. It will lose precision for larger
6361 * numbers. If the big number is too large to fit (more than
6362 * 1.7976931348623157E+308) infinity will be returned. NaN is never
6363 * returned.
6364 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006365static double
6366QCBOR_Private_ConvertBigNumToDouble(const UsefulBufC BigNum)
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006367{
6368 double dResult;
6369
6370 dResult = 0.0;
6371 const uint8_t *pByte = BigNum.ptr;
6372 size_t uLen = BigNum.len;
6373 /* This will overflow and become the float value INFINITY if the number
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006374 * is too large to fit. */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006375 while(uLen--) {
6376 dResult = (dResult * 256.0) + (double)*pByte++;
6377 }
6378
6379 return dResult;
6380}
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006381#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6382
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006383
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006384
6385
6386/**
6387 * @brief Convert many number types to a double.
6388 *
6389 * @param[in] pItem The item to convert.
6390 * @param[in] uConvertTypes Bit mask list of conversion options.
6391 * @param[out] pdValue The resulting converted value.
6392 *
6393 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6394 * in uConvertTypes.
6395 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6396 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6397 * or too small.
6398 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006399static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006400QCBOR_Private_DoubleConvertAll(const QCBORItem *pItem,
6401 const uint32_t uConvertTypes,
6402 double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006403{
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006404#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07006405 /*
Laurence Lundblade16a207a2021-09-18 17:22:46 -07006406 * What Every Computer Scientist Should Know About Floating-Point Arithmetic
6407 * https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
6408 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006409 switch(pItem->uDataType) {
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006410
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006411#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006412 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006413 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006414 // Underflow gives 0, overflow gives infinity
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006415 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6416 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
6417 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006418 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006419 }
6420 break;
6421
6422 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006423 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006424 // Underflow gives 0, overflow gives infinity
6425 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6426 exp2((double)pItem->val.expAndMantissa.nExponent);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006427 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006428 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006429 }
6430 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006431#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006432
6433 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006434 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006435 *pdValue = QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006436 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006437 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006438 }
6439 break;
6440
6441 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006442 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006443 *pdValue = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006444 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006445 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006446 }
6447 break;
6448
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006449#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006450 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006451 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006452 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006453 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6454 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006455 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006456 }
6457 break;
6458
6459 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006460 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006461 double dMantissa = -QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006462 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6463 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006464 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006465 }
6466 break;
6467
6468 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006469 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006470 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006471 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6472 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006473 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006474 }
6475 break;
6476
6477 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006478 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006479 double dMantissa = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006480 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6481 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006482 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006483 }
6484 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006485#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006486
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006487 default:
6488 return QCBOR_ERR_UNEXPECTED_TYPE;
6489 }
6490
6491 return QCBOR_SUCCESS;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006492
6493#else
6494 (void)pItem;
6495 (void)uConvertTypes;
6496 (void)pdValue;
6497 return QCBOR_ERR_HW_FLOAT_DISABLED;
6498#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6499
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006500}
6501
6502
6503/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006504 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006505 */
6506void
6507QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe,
6508 const uint32_t uConvertTypes,
6509 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006510{
6511
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006512 QCBORItem Item;
6513
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006514 QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006515
6516 if(pMe->uLastError == QCBOR_SUCCESS) {
6517 // The above conversion succeeded
6518 return;
6519 }
6520
6521 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6522 // The above conversion failed in a way that code below can't correct
6523 return;
6524 }
6525
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006526 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6527 uConvertTypes,
6528 pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006529}
6530
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006531
6532/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006533 * Public function, see header qcbor/qcbor_decode.h file
6534 */
6535void
6536QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe,
6537 const int64_t nLabel,
6538 const uint32_t uConvertTypes,
6539 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006540{
6541 QCBORItem Item;
6542
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006543 QCBORDecode_Private_GetDoubleConvertInMapN(pMe,
6544 nLabel,
6545 uConvertTypes,
6546 pdValue,
6547 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006548
6549 if(pMe->uLastError == QCBOR_SUCCESS) {
6550 // The above conversion succeeded
6551 return;
6552 }
6553
6554 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6555 // The above conversion failed in a way that code below can't correct
6556 return;
6557 }
6558
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006559 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6560 uConvertTypes,
6561 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006562}
6563
6564
6565/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006566 * Public function, see header qcbor/qcbor_decode.h file
6567 */
6568void
6569QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe,
6570 const char *szLabel,
6571 const uint32_t uConvertTypes,
6572 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006573{
6574 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006575 QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe,
6576 szLabel,
6577 uConvertTypes,
6578 pdValue,
6579 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006580
6581 if(pMe->uLastError == QCBOR_SUCCESS) {
6582 // The above conversion succeeded
6583 return;
6584 }
6585
6586 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6587 // The above conversion failed in a way that code below can't correct
6588 return;
6589 }
6590
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006591 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6592 uConvertTypes,
6593 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006594}
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006595#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006596
6597
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006598
6599
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006600#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006601/**
6602 * @brief Convert an integer to a big number
6603 *
6604 * @param[in] uInt The integer to convert.
6605 * @param[in] Buffer The buffer to output the big number to.
6606 *
6607 * @returns The big number or NULLUsefulBufC is the buffer is to small.
6608 *
6609 * This always succeeds unless the buffer is too small.
6610 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006611static UsefulBufC
6612QCBOR_Private_ConvertIntToBigNum(uint64_t uInt, const UsefulBuf Buffer)
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006613{
6614 while((uInt & 0xff00000000000000UL) == 0) {
6615 uInt = uInt << 8;
6616 };
6617
6618 UsefulOutBuf UOB;
6619
6620 UsefulOutBuf_Init(&UOB, Buffer);
6621
6622 while(uInt) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006623 UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff00000000000000UL) >> 56));
6624 uInt = uInt << 8;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006625 }
6626
6627 return UsefulOutBuf_OutUBuf(&UOB);
6628}
6629
6630
Laurence Lundblade37286c02022-09-03 10:05:02 -07006631/**
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006632 * @brief Check and/or complete exponent and mantissa item.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006633 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006634 * @param[in] pMe The decoder context.
6635 * @param[in] TagSpec Expected type(s).
6636 * @param[in,out] pItem See below.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006637 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006638 * This is for decimal fractions and big floats, both of which are an
6639 * exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006640 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006641 * If the item item had a tag number indicating it was a
6642 * decimal fraction or big float, then the input @c pItem will
6643 * have been decoded as exponent and mantissa. If there was
6644 * no tag number, the caller is asking this be decoded as a
6645 * big float or decimal fraction and @c pItem just has the
6646 * first item in an exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006647 *
6648 * On output, the item is always a fully decoded decimal fraction or
6649 * big float.
6650 *
6651 * This errors out if the input type does not meet the TagSpec.
6652 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07006653static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006654QCBOR_Private_ExpMantissaTypeHandler(QCBORDecodeContext *pMe,
6655 const QCBOR_Private_TagSpec TagSpec,
6656 QCBORItem *pItem)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006657{
6658 QCBORError uErr;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006659
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006660 /* pItem could either be a decoded exponent and mantissa or
6661 * the opening array of an undecoded exponent and mantissa. This
Laurence Lundblade37286c02022-09-03 10:05:02 -07006662 * check will succeed on either, but doesn't say which it was.
6663 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006664 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07006665 if(uErr != QCBOR_SUCCESS) {
6666 goto Done;
6667 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006668
Laurence Lundblade37286c02022-09-03 10:05:02 -07006669 if(pItem->uDataType == QCBOR_TYPE_ARRAY) {
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006670 /* The item is an array, which means is is an undecoded exponent
6671 * and mantissa. This call consumes the items in the array and
6672 * results in a decoded exponent and mantissa in pItem. This is
Laurence Lundblade37286c02022-09-03 10:05:02 -07006673 * the case where there was no tag.
6674 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006675 uErr = QCBORDecode_Private_ExpMantissa(pMe, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006676 if(uErr != QCBOR_SUCCESS) {
6677 goto Done;
6678 }
6679
Laurence Lundblade37286c02022-09-03 10:05:02 -07006680 /* The above decode didn't determine whether it is a decimal
6681 * fraction or big num. Which of these two depends on what the
6682 * caller wants it decoded as since there is no tag, so fish the
6683 * type out of the TagSpec. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006684 pItem->uDataType = QCBOR_Private_ExpMantissaDataType(TagSpec.uTaggedTypes[0], pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07006685
6686 /* No need to check the type again. All that we need to know was
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006687 * that it decoded correctly as a exponent and mantissa. The
Laurence Lundblade37286c02022-09-03 10:05:02 -07006688 * QCBOR type is set out by what was requested.
6689 */
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006690 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07006691
6692 /* If the item was not an array and the check passed, then
6693 * it is a fully decoded big float or decimal fraction and
6694 * matches what is requested.
6695 */
6696
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006697Done:
6698 return uErr;
6699}
6700
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006701
Laurence Lundblade37286c02022-09-03 10:05:02 -07006702/* Some notes from the work to disable tags.
6703 *
6704 * The API for big floats and decimal fractions seems good.
6705 * If there's any issue with it it's that the code size to
6706 * implement is a bit large because of the conversion
6707 * to/from int and bignum that is required. There is no API
6708 * that doesn't do the conversion so dead stripping will never
6709 * leave that code out.
6710 *
6711 * The implementation itself seems correct, but not as clean
6712 * and neat as it could be. It could probably be smaller too.
6713 *
6714 * The implementation has three main parts / functions
6715 * - The decoding of the array of two
6716 * - All the tag and type checking for the various API functions
6717 * - Conversion to/from bignum and int
6718 *
6719 * The type checking seems like it wastes the most code for
6720 * what it needs to do.
6721 *
6722 * The inlining for the conversion is probably making the
6723 * overall code base larger.
6724 *
6725 * The tests cases could be organized a lot better and be
6726 * more thorough.
6727 *
6728 * Seems also like there could be more common code in the
6729 * first tier part of the public API. Some functions only
6730 * vary by a TagSpec.
6731 */
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006732
6733/**
6734 * @brief Common processor for exponent and mantissa.
6735 *
6736 * @param[in] pMe The decode context.
6737 * @param[in] TagSpec The expected/allowed tags.
6738 * @param[in] pItem The data item to process.
6739 * @param[out] pnMantissa The returned mantissa as an int64_t.
6740 * @param[out] pnExponent The returned exponent as an int64_t.
6741 *
6742 * This handles exponent and mantissa for base 2 and 10. This
6743 * is limited to a mantissa that is an int64_t. See also
6744 * QCBORDecode_Private_ProcessExpMantissaBig().
6745 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006746static void
6747QCBOR_Private_ProcessExpMantissa(QCBORDecodeContext *pMe,
6748 const QCBOR_Private_TagSpec TagSpec,
6749 QCBORItem *pItem,
6750 int64_t *pnMantissa,
6751 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006752{
6753 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006754
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006755 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006756 if(uErr != QCBOR_SUCCESS) {
6757 goto Done;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006758 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006759
Laurence Lundblade9b334962020-08-27 10:55:53 -07006760 switch (pItem->uDataType) {
6761
6762 case QCBOR_TYPE_DECIMAL_FRACTION:
6763 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade9b334962020-08-27 10:55:53 -07006764 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006765 *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
Laurence Lundblade9b334962020-08-27 10:55:53 -07006766 break;
6767
Laurence Lundblade37286c02022-09-03 10:05:02 -07006768#ifndef QCBOR_DISABLE_TAGS
6769 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006770 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
6771 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
6772 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006773 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006774 break;
6775
6776 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
6777 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
6778 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006779 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006780 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006781#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006782
6783 default:
6784 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
6785 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006786
6787 Done:
6788 pMe->uLastError = (uint8_t)uErr;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006789}
6790
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006791
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006792/**
6793 * @brief Decode exponent and mantissa into a big number.
6794 *
6795 * @param[in] pMe The decode context.
6796 * @param[in] TagSpec The expected/allowed tags.
6797 * @param[in] pItem Item to decode and convert.
6798 * @param[in] BufferForMantissa Buffer to output mantissa into.
6799 * @param[out] pMantissa The output mantissa.
6800 * @param[out] pbIsNegative The sign of the output.
6801 * @param[out] pnExponent The mantissa of the output.
6802 *
6803 * This is the common processing of a decimal fraction or a big float
6804 * into a big number. This will decode and consume all the CBOR items
6805 * that make up the decimal fraction or big float.
6806 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006807static void
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006808QCBORDecode_Private_ProcessExpMantissaBig(QCBORDecodeContext *pMe,
6809 const QCBOR_Private_TagSpec TagSpec,
6810 QCBORItem *pItem,
6811 const UsefulBuf BufferForMantissa,
6812 UsefulBufC *pMantissa,
6813 bool *pbIsNegative,
6814 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006815{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006816 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006817
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006818 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006819 if(uErr != QCBOR_SUCCESS) {
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006820 goto Done;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006821 }
6822
6823 uint64_t uMantissa;
6824
6825 switch (pItem->uDataType) {
6826
6827 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006828 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006829 /* See comments in ExponentiateNN() on handling INT64_MIN */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006830 if(pItem->val.expAndMantissa.Mantissa.nInt >= 0) {
6831 uMantissa = (uint64_t)pItem->val.expAndMantissa.Mantissa.nInt;
6832 *pbIsNegative = false;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006833 } else if(pItem->val.expAndMantissa.Mantissa.nInt != INT64_MIN) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006834 uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt;
6835 *pbIsNegative = true;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006836 } else {
6837 uMantissa = (uint64_t)INT64_MAX+1;
6838 *pbIsNegative = true;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006839 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006840 *pMantissa = QCBOR_Private_ConvertIntToBigNum(uMantissa,
6841 BufferForMantissa);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006842 *pnExponent = pItem->val.expAndMantissa.nExponent;
6843 break;
6844
Laurence Lundblade37286c02022-09-03 10:05:02 -07006845#ifndef QCBOR_DISABLE_TAGS
6846 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006847 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006848 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006849 *pnExponent = pItem->val.expAndMantissa.nExponent;
6850 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6851 *pbIsNegative = false;
6852 break;
6853
6854 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006855 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006856 *pnExponent = pItem->val.expAndMantissa.nExponent;
6857 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6858 *pbIsNegative = true;
6859 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006860#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006861
6862 default:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006863 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006864 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006865
6866Done:
6867 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006868}
6869
6870
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006871/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006872 * Public function, see header qcbor/qcbor_decode.h file
6873 */
6874void
6875QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe,
6876 const uint8_t uTagRequirement,
6877 int64_t *pnMantissa,
6878 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006879{
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006880 if(pMe->uLastError != QCBOR_SUCCESS) {
6881 return;
6882 }
6883
6884 QCBORItem Item;
6885 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
6886 if(uError) {
6887 pMe->uLastError = (uint8_t)uError;
6888 return;
6889 }
6890
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006891 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006892 {
6893 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006894 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6895 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6896 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006897 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006898
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006899 QCBOR_Private_ProcessExpMantissa(pMe,
6900 TagSpec,
6901 &Item,
6902 pnMantissa,
6903 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006904}
6905
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006906
6907/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006908 * Public function, see header qcbor/qcbor_decode.h file
6909 */
6910void
6911QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe,
6912 const int64_t nLabel,
6913 const uint8_t uTagRequirement,
6914 int64_t *pnMantissa,
6915 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006916{
6917 if(pMe->uLastError != QCBOR_SUCCESS) {
6918 return;
6919 }
6920
6921 QCBORItem Item;
6922 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
6923
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006924 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006925 {
6926 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006927 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6928 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6929 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006930 };
6931
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006932 QCBOR_Private_ProcessExpMantissa(pMe,
6933 TagSpec,
6934 &Item,
6935 pnMantissa,
6936 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006937}
6938
6939
6940/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006941 * Public function, see header qcbor/qcbor_decode.h file
6942 */
6943void
6944QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
6945 const char *szLabel,
6946 const uint8_t uTagRequirement,
6947 int64_t *pnMantissa,
6948 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006949{
6950 if(pMe->uLastError != QCBOR_SUCCESS) {
6951 return;
6952 }
6953
6954 QCBORItem Item;
6955 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
6956
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006957 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006958 {
6959 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006960 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6961 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6962 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006963 };
Laurence Lundblade9b334962020-08-27 10:55:53 -07006964
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006965 QCBOR_Private_ProcessExpMantissa(pMe,
6966 TagSpec,
6967 &Item,
6968 pnMantissa,
6969 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006970}
6971
6972
6973/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006974 * Public function, see header qcbor/qcbor_decode.h file
6975 */
6976void
6977QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe,
6978 const uint8_t uTagRequirement,
6979 const UsefulBuf MantissaBuffer,
6980 UsefulBufC *pMantissa,
6981 bool *pbMantissaIsNegative,
6982 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006983{
6984 if(pMe->uLastError != QCBOR_SUCCESS) {
6985 return;
6986 }
6987
6988 QCBORItem Item;
6989 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
6990 if(uError) {
6991 pMe->uLastError = (uint8_t)uError;
6992 return;
6993 }
6994
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006995 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006996 {
6997 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006998 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6999 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7000 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007001 };
7002
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007003 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7004 TagSpec,
7005 &Item,
7006 MantissaBuffer,
7007 pMantissa,
7008 pbMantissaIsNegative,
7009 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007010}
7011
7012
7013/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007014 * Public function, see header qcbor/qcbor_decode.h file
7015 */
7016void
7017QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe,
7018 const int64_t nLabel,
7019 const uint8_t uTagRequirement,
7020 const UsefulBuf BufferForMantissa,
7021 UsefulBufC *pMantissa,
7022 bool *pbIsNegative,
7023 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007024{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007025 if(pMe->uLastError != QCBOR_SUCCESS) {
7026 return;
7027 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007028
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007029 QCBORItem Item;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007030 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007031 if(pMe->uLastError != QCBOR_SUCCESS) {
7032 return;
7033 }
7034
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007035 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007036 {
7037 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007038 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7039 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7040 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007041 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007042
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007043 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7044 TagSpec,
7045 &Item,
7046 BufferForMantissa,
7047 pMantissa,
7048 pbIsNegative,
7049 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007050}
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007051
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007052
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007053/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007054 * Public function, see header qcbor/qcbor_decode.h file
7055 */
7056void
7057QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe,
7058 const char *szLabel,
7059 const uint8_t uTagRequirement,
7060 const UsefulBuf BufferForMantissa,
7061 UsefulBufC *pMantissa,
7062 bool *pbIsNegative,
7063 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007064{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007065 if(pMe->uLastError != QCBOR_SUCCESS) {
7066 return;
7067 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007068
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007069 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007070 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7071 if(pMe->uLastError != QCBOR_SUCCESS) {
7072 return;
7073 }
7074
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007075 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007076 {
7077 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007078 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7079 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7080 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007081 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007082
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007083 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7084 TagSpec,
7085 &Item,
7086 BufferForMantissa,
7087 pMantissa,
7088 pbIsNegative,
7089 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007090}
7091
7092
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007093/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007094 * Public function, see header qcbor/qcbor_decode.h file
7095 */
7096void
7097QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe,
7098 const uint8_t uTagRequirement,
7099 int64_t *pnMantissa,
7100 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007101{
7102 if(pMe->uLastError != QCBOR_SUCCESS) {
7103 return;
7104 }
7105
7106 QCBORItem Item;
7107 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
7108 if(uError) {
7109 pMe->uLastError = (uint8_t)uError;
7110 return;
7111 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007112 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007113 {
7114 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007115 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7116 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7117 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007118 };
7119
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007120 QCBOR_Private_ProcessExpMantissa(pMe,
7121 TagSpec,
7122 &Item,
7123 pnMantissa,
7124 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007125}
7126
7127
7128/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007129 * Public function, see header qcbor/qcbor_decode.h file
7130 */
7131void
7132QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe,
7133 const int64_t nLabel,
7134 const uint8_t uTagRequirement,
7135 int64_t *pnMantissa,
7136 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007137{
7138 if(pMe->uLastError != QCBOR_SUCCESS) {
7139 return;
7140 }
7141
7142 QCBORItem Item;
7143 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7144 if(pMe->uLastError != QCBOR_SUCCESS) {
7145 return;
7146 }
7147
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007148 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007149 {
7150 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007151 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7152 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7153 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007154 };
7155
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007156 QCBOR_Private_ProcessExpMantissa(pMe,
7157 TagSpec,
7158 &Item,
7159 pnMantissa,
7160 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007161}
7162
7163
7164/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007165 * Public function, see header qcbor/qcbor_decode.h file
7166 */
7167void
7168QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe,
7169 const char *szLabel,
7170 const uint8_t uTagRequirement,
7171 int64_t *pnMantissa,
7172 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007173{
7174 if(pMe->uLastError != QCBOR_SUCCESS) {
7175 return;
7176 }
7177
7178 QCBORItem Item;
7179 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7180 if(pMe->uLastError != QCBOR_SUCCESS) {
7181 return;
7182 }
7183
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007184 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007185 {
7186 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007187 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7188 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7189 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007190 };
7191
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007192 QCBOR_Private_ProcessExpMantissa(pMe,
7193 TagSpec,
7194 &Item,
7195 pnMantissa,
7196 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007197}
7198
7199
7200/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007201 * Public function, see header qcbor/qcbor_decode.h file
7202 */
7203void
7204QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe,
7205 const uint8_t uTagRequirement,
7206 const UsefulBuf MantissaBuffer,
7207 UsefulBufC *pMantissa,
7208 bool *pbMantissaIsNegative,
7209 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007210{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007211 if(pMe->uLastError != QCBOR_SUCCESS) {
7212 return;
7213 }
7214
7215 QCBORItem Item;
7216 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
7217 if(uError) {
7218 pMe->uLastError = (uint8_t)uError;
7219 return;
7220 }
7221
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007222 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007223 {
7224 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007225 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7226 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7227 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007228 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007229
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007230 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7231 TagSpec,
7232 &Item,
7233 MantissaBuffer,
7234 pMantissa,
7235 pbMantissaIsNegative,
7236 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007237}
7238
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007239
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007240/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007241 * Public function, see header qcbor/qcbor_decode.h file
7242 */
7243void
7244QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe,
7245 const int64_t nLabel,
7246 const uint8_t uTagRequirement,
7247 const UsefulBuf BufferForMantissa,
7248 UsefulBufC *pMantissa,
7249 bool *pbIsNegative,
7250 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007251{
7252 if(pMe->uLastError != QCBOR_SUCCESS) {
7253 return;
7254 }
7255
7256 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007257 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7258 if(pMe->uLastError != QCBOR_SUCCESS) {
7259 return;
7260 }
7261
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007262 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007263 {
7264 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007265 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7266 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7267 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007268 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007269
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007270 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7271 TagSpec,
7272 &Item,
7273 BufferForMantissa,
7274 pMantissa,
7275 pbIsNegative,
7276 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007277}
7278
7279
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007280/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007281 * Public function, see header qcbor/qcbor_decode.h file
7282 */
7283void
7284QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe,
7285 const char *szLabel,
7286 const uint8_t uTagRequirement,
7287 const UsefulBuf BufferForMantissa,
7288 UsefulBufC *pMantissa,
7289 bool *pbIsNegative,
7290 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007291{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007292 if(pMe->uLastError != QCBOR_SUCCESS) {
7293 return;
7294 }
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007295
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007296 QCBORItem Item;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007297 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7298 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007299 return;
7300 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007301
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007302 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007303 {
7304 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007305 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7306 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7307 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007308 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007309
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007310 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7311 TagSpec,
7312 &Item,
7313 BufferForMantissa,
7314 pMantissa,
7315 pbIsNegative,
7316 pnExponent);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007317}
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007318
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07007319#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */