blob: 9c5d2d229cb90e970e97a9754788442646f2875f [file] [log] [blame]
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001/*==============================================================================
Laurence Lundbladed92a6162018-11-01 11:38:35 +07002 Copyright (c) 2016-2018, The Linux Foundation.
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003 Copyright (c) 2018-2024, Laurence Lundblade.
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02004 Copyright (c) 2021, Arm Limited.
Laurence Lundbladed92a6162018-11-01 11:38:35 +07005 All rights reserved.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08006
Laurence Lundblade0dbc9172018-11-01 14:17:21 +07007Redistribution and use in source and binary forms, with or without
8modification, are permitted provided that the following conditions are
9met:
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above
13 copyright notice, this list of conditions and the following
14 disclaimer in the documentation and/or other materials provided
15 with the distribution.
16 * Neither the name of The Linux Foundation nor the names of its
17 contributors, nor the name "Laurence Lundblade" may be used to
18 endorse or promote products derived from this software without
19 specific prior written permission.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080020
Laurence Lundblade0dbc9172018-11-01 14:17:21 +070021THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
22WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
24ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
25BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
30OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Laurence Lundbladeee851742020-01-08 08:37:05 -080032 =============================================================================*/
Laurence Lundblade624405d2018-09-18 20:10:47 -070033
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080034
Laurence Lundblade844bb5c2020-03-01 17:27:25 -080035#include "qcbor/qcbor_decode.h"
Laurence Lundblade67257dc2020-07-27 03:33:37 -070036#include "qcbor/qcbor_spiffy_decode.h"
Laurence Lundblade3f1318a2021-01-04 18:26:44 -080037#include "ieee754.h" /* Does not use math.h */
Laurence Lundbladec7114722020-08-13 05:11:40 -070038
39#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade3f1318a2021-01-04 18:26:44 -080040
41#include <math.h> /* For isnan(), llround(), llroudf(), round(), roundf(),
42 * pow(), exp2()
43 */
44#include <fenv.h> /* feclearexcept(), fetestexcept() */
45
Laurence Lundbladee2c893c2020-12-26 17:41:53 -080046#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070047
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070048
Laurence Lundblade68cb61c2023-02-12 13:21:44 -080049#if (defined(__GNUC__) && !defined(__clang__))
Laurence Lundblade8e36f812024-01-26 10:59:29 -070050/*
Laurence Lundblade68cb61c2023-02-12 13:21:44 -080051 * This is how the -Wmaybe-uninitialized compiler warning is
52 * handled. It can’t be ignored because some version of gcc enable it
53 * with -Wall which is a common and useful gcc warning option. It also
54 * can’t be ignored because it is the goal of QCBOR to compile clean
55 * out of the box in all environments.
56 *
57 * The big problem with -Wmaybe-uninitialized is that it generates
58 * false positives. It complains things are uninitialized when they
59 * are not. This is because it is not a thorough static analyzer. This
60 * is why “maybe” is in its name. The problem is it is just not
61 * thorough enough to understand all the code (and someone saw fit to
62 * put it in gcc and worse to enable it with -Wall).
63 *
64 * One solution would be to change the code so -Wmaybe-uninitialized
65 * doesn’t get confused, for example adding an unnecessary extra
66 * initialization to zero. (If variables were truly uninitialized, the
67 * correct path is to understand the code thoroughly and set them to
68 * the correct value at the correct time; in essence this is already
69 * done; -Wmaybe-uninitialized just can’t tell). This path is not
70 * taken because it makes the code bigger and is kind of the tail
71 * wagging the dog.
72 *
73 * The solution here is to just use a pragma to disable it for the
74 * whole file. Disabling it for each line makes the code fairly ugly
75 * requiring #pragma to push, pop and ignore. Another reason is the
76 * warnings issues vary by version of gcc and which optimization
77 * optimizations are selected. Another reason is that compilers other
78 * than gcc don’t have -Wmaybe-uninitialized.
79 *
80 * One may ask how to be sure these warnings are false positives and
81 * not real issues. 1) The code has been read carefully to check. 2)
82 * Testing is pretty thorough. 3) This code has been run through
83 * thorough high-quality static analyzers.
84 *
85 * In particularly, most of the warnings are about
86 * Item.Item->uDataType being uninitialized. QCBORDecode_GetNext()
87 * *always* sets this value and test case confirm
88 * this. -Wmaybe-uninitialized just can't tell.
89 *
90 * https://stackoverflow.com/questions/5080848/disable-gcc-may-be-used-uninitialized-on-a-particular-variable
91 */
92#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
Laurence Lundblade8e36f812024-01-26 10:59:29 -070093#endif
Laurence Lundblade68cb61c2023-02-12 13:21:44 -080094
95
96
Laurence Lundblade3f1318a2021-01-04 18:26:44 -080097
Laurence Lundbladea9489f82020-09-12 13:50:56 -070098#define SIZEOF_C_ARRAY(array,type) (sizeof(array)/sizeof(type))
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070099
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700100
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800101
102
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700103static bool
104QCBORItem_IsMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700105{
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700106 const uint8_t uDataType = Item.uDataType;
Laurence Lundblade02625d42020-06-25 14:41:41 -0700107 return uDataType == QCBOR_TYPE_MAP ||
Laurence Lundblade62cae932024-06-03 13:16:17 -0700108#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
109 uDataType == QCBOR_TYPE_MAP_AS_ARRAY ||
Laurence Lundblade78a66132024-06-06 12:19:59 -0700110#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade62cae932024-06-03 13:16:17 -0700111 uDataType == QCBOR_TYPE_ARRAY;
Laurence Lundblade02625d42020-06-25 14:41:41 -0700112}
113
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700114static bool
115QCBORItem_IsEmptyDefiniteLengthMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700116{
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700117 if(!QCBORItem_IsMapOrArray(Item)){
Laurence Lundblade02625d42020-06-25 14:41:41 -0700118 return false;
119 }
120
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700121 if(Item.val.uCount != 0) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700122 return false;
123 }
124 return true;
125}
126
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700127static bool
128QCBORItem_IsIndefiniteLengthMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700129{
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800130#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700131 if(!QCBORItem_IsMapOrArray(Item)){
Laurence Lundblade02625d42020-06-25 14:41:41 -0700132 return false;
133 }
134
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700135 if(Item.val.uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700136 return false;
137 }
138 return true;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800139#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700140 (void)Item;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800141 return false;
142#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700143}
144
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700145/* Return true if the labels in Item1 and Item2 are the same.
146 Works only for integer and string labels. Returns false
147 for any other type. */
148static bool
149QCBORItem_MatchLabel(const QCBORItem Item1, const QCBORItem Item2)
150{
151 if(Item1.uLabelType == QCBOR_TYPE_INT64) {
152 if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
153 return true;
154 }
Laurence Lundblade78a66132024-06-06 12:19:59 -0700155#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700156 } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
157 if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
158 return true;
159 }
160 } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
161 if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
162 return true;
163 }
164 } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
165 if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
166 return true;
167 }
Laurence Lundblade78a66132024-06-06 12:19:59 -0700168#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700169 }
170
171 /* Other label types are never matched */
172 return false;
173}
174
175
176/*
177 Returns true if Item1 and Item2 are the same type
178 or if either are of QCBOR_TYPE_ANY.
179 */
180static bool
181QCBORItem_MatchType(const QCBORItem Item1, const QCBORItem Item2)
182{
183 if(Item1.uDataType == Item2.uDataType) {
184 return true;
185 } else if(Item1.uDataType == QCBOR_TYPE_ANY) {
186 return true;
187 } else if(Item2.uDataType == QCBOR_TYPE_ANY) {
188 return true;
189 }
190 return false;
191}
192
Laurence Lundblade02625d42020-06-25 14:41:41 -0700193
Laurence Lundbladeee851742020-01-08 08:37:05 -0800194/*===========================================================================
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700195 DecodeNesting -- Tracking array/map/sequence/bstr-wrapped nesting
Laurence Lundbladeee851742020-01-08 08:37:05 -0800196 ===========================================================================*/
197
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700198/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800199 * See comments about and typedef of QCBORDecodeNesting in qcbor_private.h,
200 * the data structure all these functions work on.
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700201 */
202
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700203
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700204static uint8_t
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700205DecodeNesting_GetCurrentLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700206{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700207 const ptrdiff_t nLevel = pNesting->pCurrent - &(pNesting->pLevels[0]);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800208 /* Limit in DecodeNesting_Descend against more than
209 * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
Laurence Lundblade02625d42020-06-25 14:41:41 -0700210 */
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700211 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700212}
213
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700214
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700215static uint8_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700216DecodeNesting_GetBoundedModeLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700217{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700218 const ptrdiff_t nLevel = pNesting->pCurrentBounded - &(pNesting->pLevels[0]);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800219 /* Limit in DecodeNesting_Descend against more than
220 * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
Laurence Lundblade02625d42020-06-25 14:41:41 -0700221 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700222 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700223}
224
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700225
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700226static uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700227DecodeNesting_GetMapOrArrayStart(const QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700228{
229 return pNesting->pCurrentBounded->u.ma.uStartOffset;
230}
231
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700232
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700233static bool
Laurence Lundblade085d7952020-07-24 10:26:30 -0700234DecodeNesting_IsBoundedEmpty(const QCBORDecodeNesting *pNesting)
235{
236 if(pNesting->pCurrentBounded->u.ma.uCountCursor == QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
237 return true;
238 } else {
239 return false;
240 }
241}
242
243
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700244static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700245DecodeNesting_IsCurrentAtTop(const QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700246{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700247 if(pNesting->pCurrent == &(pNesting->pLevels[0])) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700248 return true;
249 } else {
250 return false;
251 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700252}
253
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700254
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700255static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700256DecodeNesting_IsCurrentDefiniteLength(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700257{
258 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800259 /* Not a map or array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700260 return false;
261 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800262
263#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700264 if(pNesting->pCurrent->u.ma.uCountTotal == QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800265 /* Is indefinite */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700266 return false;
267 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800268
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800269#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
270
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800271 /* All checks passed; is a definte length map or array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700272 return true;
273}
274
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700275static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700276DecodeNesting_IsCurrentBstrWrapped(const QCBORDecodeNesting *pNesting)
Laurence Lundblade642282a2020-06-23 12:00:33 -0700277{
278 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800279 /* is a byte string */
Laurence Lundblade642282a2020-06-23 12:00:33 -0700280 return true;
281 }
282 return false;
283}
284
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700285
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700286static bool
287DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700288{
289 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
290 return true;
291 }
Laurence Lundblade02625d42020-06-25 14:41:41 -0700292 if(pNesting->pCurrent->u.ma.uStartOffset != QCBOR_NON_BOUNDED_OFFSET) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700293 return true;
294 }
295 return false;
296}
297
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700298
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700299static void
300DecodeNesting_SetMapOrArrayBoundedMode(QCBORDecodeNesting *pNesting, bool bIsEmpty, size_t uStart)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700301{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800302 /* Should be only called on maps and arrays */
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700303 /*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800304 * DecodeNesting_EnterBoundedMode() checks to be sure uStart is not
305 * larger than DecodeNesting_EnterBoundedMode which keeps it less than
306 * uin32_t so the cast is safe.
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700307 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700308 pNesting->pCurrent->u.ma.uStartOffset = (uint32_t)uStart;
Laurence Lundblade085d7952020-07-24 10:26:30 -0700309
310 if(bIsEmpty) {
311 pNesting->pCurrent->u.ma.uCountCursor = QCBOR_COUNT_INDICATES_ZERO_LENGTH;
312 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700313}
314
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700315
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700316static void
317DecodeNesting_ClearBoundedMode(QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700318{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700319 pNesting->pCurrent->u.ma.uStartOffset = QCBOR_NON_BOUNDED_OFFSET;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700320}
321
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700322
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700323static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700324DecodeNesting_IsAtEndOfBoundedLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700325{
326 if(pNesting->pCurrentBounded == NULL) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800327 /* No bounded map or array set up */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700328 return false;
329 }
330 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800331 /* Not a map or array; end of those is by byte count */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700332 return false;
333 }
Laurence Lundblade6ab01fb2020-10-01 13:04:49 -0700334 if(!DecodeNesting_IsCurrentBounded(pNesting)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800335 /* In a traveral at a level deeper than the bounded level */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700336 return false;
337 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800338 /* Works for both definite- and indefinitelength maps/arrays */
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800339 if(pNesting->pCurrentBounded->u.ma.uCountCursor != 0 &&
340 pNesting->pCurrentBounded->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800341 /* Count is not zero, still unconsumed item */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700342 return false;
343 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800344 /* All checks passed, got to the end of an array or map*/
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700345 return true;
346}
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700347
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700348
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700349static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700350DecodeNesting_IsEndOfDefiniteLengthMapOrArray(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700351{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800352 /* Must only be called on map / array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700353 if(pNesting->pCurrent->u.ma.uCountCursor == 0) {
354 return true;
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700355 } else {
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700356 return false;
357 }
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700358}
359
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700360
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700361static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700362DecodeNesting_IsCurrentTypeMap(const QCBORDecodeNesting *pNesting)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700363{
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700364 if(pNesting->pCurrent->uLevelType == CBOR_MAJOR_TYPE_MAP) {
365 return true;
366 } else {
367 return false;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700368 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700369}
370
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700371
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700372static bool
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700373DecodeNesting_IsBoundedType(const QCBORDecodeNesting *pNesting, uint8_t uType)
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700374{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700375 if(pNesting->pCurrentBounded == NULL) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700376 return false;
377 }
Laurence Lundblade02625d42020-06-25 14:41:41 -0700378
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700379 uint8_t uItemDataType = pNesting->pCurrentBounded->uLevelType;
Laurence Lundblade62cae932024-06-03 13:16:17 -0700380#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700381 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
382 uItemDataType = QCBOR_TYPE_ARRAY;
383 }
Laurence Lundblade78a66132024-06-06 12:19:59 -0700384#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700385
386 if(uItemDataType != uType) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700387 return false;
388 }
389
390 return true;
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700391}
392
Laurence Lundblade02625d42020-06-25 14:41:41 -0700393
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700394static void
Laurence Lundblade6c8a4442020-06-22 22:16:11 -0700395DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700396{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800397 /* Only call on a definite-length array / map */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700398 pNesting->pCurrent->u.ma.uCountCursor--;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700399}
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700400
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700401
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700402static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700403DecodeNesting_ReverseDecrement(QCBORDecodeNesting *pNesting)
404{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800405 /* Only call on a definite-length array / map */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700406 pNesting->pCurrent->u.ma.uCountCursor++;
407}
408
409
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700410static void
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700411DecodeNesting_Ascend(QCBORDecodeNesting *pNesting)
412{
413 pNesting->pCurrent--;
414}
415
Laurence Lundblade02625d42020-06-25 14:41:41 -0700416
417static QCBORError
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700418DecodeNesting_Descend(QCBORDecodeNesting *pNesting, uint8_t uType)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700419{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800420 /* Error out if nesting is too deep */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700421 if(pNesting->pCurrent >= &(pNesting->pLevels[QCBOR_MAX_ARRAY_NESTING])) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700422 return QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP;
Laurence Lundblade02625d42020-06-25 14:41:41 -0700423 }
424
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800425 /* The actual descend */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700426 pNesting->pCurrent++;
427
428 pNesting->pCurrent->uLevelType = uType;
429
430 return QCBOR_SUCCESS;
431}
432
433
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700434static QCBORError
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800435DecodeNesting_EnterBoundedMapOrArray(QCBORDecodeNesting *pNesting,
436 bool bIsEmpty,
437 size_t uOffset)
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700438{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700439 /*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800440 * Should only be called on map/array.
441 *
442 * Have descended into this before this is called. The job here is
443 * just to mark it in bounded mode.
444 *
445 * Check against QCBOR_MAX_DECODE_INPUT_SIZE make sure that
446 * uOffset doesn't collide with QCBOR_NON_BOUNDED_OFFSET.
447 *
448 * Cast of uOffset to uint32_t for cases where SIZE_MAX < UINT32_MAX.
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700449 */
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -0800450 if((uint32_t)uOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700451 return QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700452 }
453
Laurence Lundblade0750fc42020-06-20 21:02:34 -0700454 pNesting->pCurrentBounded = pNesting->pCurrent;
Laurence Lundblade085d7952020-07-24 10:26:30 -0700455
456 DecodeNesting_SetMapOrArrayBoundedMode(pNesting, bIsEmpty, uOffset);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700457
458 return QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700459}
460
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700461
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700462static QCBORError
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700463DecodeNesting_DescendMapOrArray(QCBORDecodeNesting *pNesting,
Laurence Lundblade02625d42020-06-25 14:41:41 -0700464 uint8_t uQCBORType,
465 uint64_t uCount)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700466{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700467 QCBORError uError = QCBOR_SUCCESS;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700468
469 if(uCount == 0) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800470 /* Nothing to do for empty definite-length arrays. They are just are
471 * effectively the same as an item that is not a map or array.
472 */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700473 goto Done;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800474 /* Empty indefinite-length maps and arrays are handled elsewhere */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700475 }
476
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800477 /* Error out if arrays is too long to handle */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700478 if(uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH &&
479 uCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700480 uError = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700481 goto Done;
482 }
483
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700484 uError = DecodeNesting_Descend(pNesting, uQCBORType);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700485 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700486 goto Done;
487 }
488
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800489 /* Fill in the new map/array level. Check above makes casts OK. */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -0700490 pNesting->pCurrent->u.ma.uCountCursor = (uint16_t)uCount;
491 pNesting->pCurrent->u.ma.uCountTotal = (uint16_t)uCount;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700492
493 DecodeNesting_ClearBoundedMode(pNesting);
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700494
495Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700496 return uError;;
497}
498
499
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700500static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700501DecodeNesting_LevelUpCurrent(QCBORDecodeNesting *pNesting)
502{
503 pNesting->pCurrent = pNesting->pCurrentBounded - 1;
504}
505
506
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700507static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700508DecodeNesting_LevelUpBounded(QCBORDecodeNesting *pNesting)
509{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700510 while(pNesting->pCurrentBounded != &(pNesting->pLevels[0])) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700511 pNesting->pCurrentBounded--;
512 if(DecodeNesting_IsCurrentBounded(pNesting)) {
513 break;
514 }
515 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700516}
517
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800518
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700519static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700520DecodeNesting_SetCurrentToBoundedLevel(QCBORDecodeNesting *pNesting)
521{
522 pNesting->pCurrent = pNesting->pCurrentBounded;
523}
524
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700525
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700526static QCBORError
Laurence Lundblade02625d42020-06-25 14:41:41 -0700527DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting,
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700528 uint32_t uEndOffset,
529 uint32_t uStartOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700530{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700531 QCBORError uError;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700532
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700533 uError = DecodeNesting_Descend(pNesting, QCBOR_TYPE_BYTE_STRING);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700534 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700535 goto Done;
536 }
537
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800538 /* Fill in the new byte string level */
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700539 pNesting->pCurrent->u.bs.uSavedEndOffset = uEndOffset;
540 pNesting->pCurrent->u.bs.uBstrStartOffset = uStartOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700541
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800542 /* Bstr wrapped levels are always bounded */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700543 pNesting->pCurrentBounded = pNesting->pCurrent;
544
545Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700546 return uError;;
547}
548
Laurence Lundbladed0304932020-06-27 10:59:38 -0700549
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700550static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700551DecodeNesting_ZeroMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700552{
553 pNesting->pCurrent->u.ma.uCountCursor = 0;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700554}
555
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700556
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700557static void
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800558DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting)
559{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700560 if(pNesting->pCurrent->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
561 pNesting->pCurrentBounded->u.ma.uCountCursor = pNesting->pCurrentBounded->u.ma.uCountTotal;
562 }
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800563}
564
565
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700566static void
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700567DecodeNesting_Init(QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700568{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700569 /* Assumes that *pNesting has been zero'd before this call. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700570 pNesting->pLevels[0].uLevelType = QCBOR_TYPE_BYTE_STRING;
571 pNesting->pCurrent = &(pNesting->pLevels[0]);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700572}
573
574
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700575static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800576DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting,
577 QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700578{
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700579 *pSave = *pNesting;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700580}
581
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700582
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700583static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800584DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting,
585 const QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700586{
587 *pNesting = *pSave;
588}
589
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700590
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700591static uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700592DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700593{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700594 return pMe->pCurrentBounded->u.bs.uSavedEndOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700595}
596
597
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800598
599
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800600#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladeee851742020-01-08 08:37:05 -0800601/*===========================================================================
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800602 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
603
604 The following four functions are pretty wrappers for invocation of
605 the string allocator supplied by the caller.
606
Laurence Lundbladeee851742020-01-08 08:37:05 -0800607 ===========================================================================*/
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800608
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700609static void
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800610StringAllocator_Free(const QCBORInternalAllocator *pMe, const void *pMem)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800611{
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300612 /* This cast to uintptr_t suppresses the "-Wcast-qual" warnings.
613 * This is the one place where the const needs to be cast away so const can
614 * be use in the rest of the code.
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800615 */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300616 (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, 0);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800617}
618
Laurence Lundbladeee851742020-01-08 08:37:05 -0800619// StringAllocator_Reallocate called with pMem NULL is
620// equal to StringAllocator_Allocate()
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700621static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800622StringAllocator_Reallocate(const QCBORInternalAllocator *pMe,
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800623 const void *pMem,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800624 size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800625{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800626 /* See comment in StringAllocator_Free() */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300627 return (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, uSize);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800628}
629
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700630static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800631StringAllocator_Allocate(const QCBORInternalAllocator *pMe, size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800632{
633 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
634}
635
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700636static void
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800637StringAllocator_Destruct(const QCBORInternalAllocator *pMe)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800638{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800639 /* See comment in StringAllocator_Free() */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800640 if(pMe->pfAllocator) {
641 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
642 }
643}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800644#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800645
646
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800647
648
Laurence Lundbladeee851742020-01-08 08:37:05 -0800649/*===========================================================================
650 QCBORDecode -- The main implementation of CBOR decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700651
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800652 See qcbor/qcbor_decode.h for definition of the object
653 used here: QCBORDecodeContext
Laurence Lundbladeee851742020-01-08 08:37:05 -0800654 ===========================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700655/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800656 * Public function, see header file
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700657 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700658void
659QCBORDecode_Init(QCBORDecodeContext *pMe,
660 UsefulBufC EncodedCBOR,
661 QCBORDecodeMode nDecodeMode)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700662{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800663 memset(pMe, 0, sizeof(QCBORDecodeContext));
664 UsefulInputBuf_Init(&(pMe->InBuf), EncodedCBOR);
665 /* Don't bother with error check on decode mode. If a bad value is
666 * passed it will just act as if the default normal mode of 0 was set.
667 */
668 pMe->uDecodeMode = (uint8_t)nDecodeMode;
669 DecodeNesting_Init(&(pMe->nesting));
670
671 /* Inialize me->auMappedTags to CBOR_TAG_INVALID16. See
672 * GetNext_TaggedItem() and MapTagNumber(). */
673 memset(pMe->auMappedTags, 0xff, sizeof(pMe->auMappedTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700674}
675
676
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800677#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
678
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700679/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800680 * Public function, see header file
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700681 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700682void
683QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
684 QCBORStringAllocate pfAllocateFunction,
685 void *pAllocateContext,
686 bool bAllStrings)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700687{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800688 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
689 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
690 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700691}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800692#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700693
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800694
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800695
696
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800697/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800698 * Deprecated public function, see header file
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800699 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700700void
701QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pMe,
702 const QCBORTagListIn *pTagList)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700703{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800704 /* This does nothing now. It is retained for backwards compatibility */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700705 (void)pMe;
706 (void)pTagList;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700707}
708
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700709
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800710
711
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700712/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800713 * Decoding items is done in six layers, one calling the next one
714 * down. If a layer has no work to do for a particular item, it
715 * returns quickly.
716 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700717 * 1. QCBORDecode_Private_GetNextTagContent - The top layer processes
718 * tagged data items, turning them into the local C representation.
719 * For the most simple it is just associating a QCBOR_TYPE with the
720 * data. For the complex ones that an aggregate of data items, there
721 * is some further decoding and some limited recursion.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800722 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700723 * 2. QCBORDecode_Private_GetNextMapOrArray - This manages the
724 * beginnings and ends of maps and arrays. It tracks descending into
725 * and ascending out of maps/arrays. It processes breaks that
726 * terminate indefinite-length maps and arrays.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800727 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700728 * 3. QCBORDecode_Private_GetNextMapEntry - This handles the combining
729 * of two items, the label and the data, that make up a map entry. It
730 * only does work on maps. It combines the label and data items into
731 * one labeled item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800732 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700733 * 4. QCBORDecode_Private_GetNextTagNumber - This decodes type 6 tag
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800734 * numbers. It turns the tag numbers into bit flags associated with
735 * the data item. No actual decoding of the contents of the tag is
736 * performed here.
737 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700738 * 5. QCBORDecode_Private_GetNextFullString - This assembles the
739 * sub-items that make up an indefinite-length string into one string
740 * item. It uses the string allocator to create contiguous space for
741 * the item. It processes all breaks that are part of
742 * indefinite-length strings.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800743 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700744 * 6. QCBOR_Private_DecodeAtomicDataItem - This decodes the atomic
745 * data items in CBOR. Each atomic data item has a "major type", an
746 * integer "argument" and optionally some content. For text and byte
747 * strings, the content is the bytes that make up the string. These
748 * are the smallest data items that are considered to be well-formed.
749 * The content may also be other data items in the case of aggregate
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800750 * types. They are not handled in this layer.
751 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700752 * This uses about 350 bytes of stack. This number comes from
753 * instrumenting (printf address of stack variables) the code on x86
754 * compiled for size optimization.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700755 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800756
757
758/*
759 * Note about use of int and unsigned variables.
760 *
761 * See http://www.unix.org/whitepapers/64bit.html for reasons int is
762 * used carefully here, and in particular why it isn't used in the
763 * public interface. Also see
764 * https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers
765 *
766 * Int is used for values that need less than 16-bits and would be
767 * subject to integer promotion and result in complaining from static
768 * analyzers.
769 */
770
771
772/**
773 * @brief Decode the CBOR head, the type and argument.
774 *
775 * @param[in] pUInBuf The input buffer to read from.
776 * @param[out] pnMajorType The decoded major type.
777 * @param[out] puArgument The decoded argument.
778 * @param[out] pnAdditionalInfo The decoded Lower 5 bits of initial byte.
779 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -0700780 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved features
781 * @retval QCBOR_ERR_HIT_END Unexpected end of input
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800782 *
783 * This decodes the CBOR "head" that every CBOR data item has. See
784 * longer explaination of the head in documentation for
785 * QCBOREncode_EncodeHead().
786 *
787 * This does the network->host byte order conversion. The conversion
788 * here also results in the conversion for floats in addition to that
789 * for lengths, tags and integer values.
790 *
791 * The int type is preferred to uint8_t for some variables as this
792 * avoids integer promotions, can reduce code size and makes static
793 * analyzers happier.
794 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700795static QCBORError
796QCBOR_Private_DecodeHead(UsefulInputBuf *pUInBuf,
797 int *pnMajorType,
798 uint64_t *puArgument,
799 int *pnAdditionalInfo)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700800{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800801 QCBORError uReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800802
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800803 /* Get the initial byte that every CBOR data item has and break it
804 * down. */
805 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800806 const int nTmpMajorType = nInitialByte >> 5;
807 const int nAdditionalInfo = nInitialByte & 0x1f;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800808
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800809 /* Where the argument accumulates */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800810 uint64_t uArgument;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800811
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800812 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800813 /* Need to get 1,2,4 or 8 additional argument bytes. Map
814 * LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length.
815 */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800816 static const uint8_t aIterate[] = {1,2,4,8};
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800817
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800818 /* Loop getting all the bytes in the argument */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800819 uArgument = 0;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800820 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800821 /* This shift and add gives the endian conversion. */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800822 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
823 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800824 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800825 /* The reserved and thus-far unused additional info values */
826 uReturn = QCBOR_ERR_UNSUPPORTED;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800827 goto Done;
828 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800829 /* Less than 24, additional info is argument or 31, an
830 * indefinite-length. No more bytes to get.
831 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800832 uArgument = (uint64_t)nAdditionalInfo;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700833 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800834
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700835 if(UsefulInputBuf_GetError(pUInBuf)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800836 uReturn = QCBOR_ERR_HIT_END;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700837 goto Done;
838 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800839
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800840 /* All successful if arrived here. */
841 uReturn = QCBOR_SUCCESS;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800842 *pnMajorType = nTmpMajorType;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800843 *puArgument = uArgument;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800844 *pnAdditionalInfo = nAdditionalInfo;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800845
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700846Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800847 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700848}
849
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800850
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800851/**
852 * @brief Decode integer types, major types 0 and 1.
853 *
Laurence Lundblade95606972024-06-07 11:32:12 -0700854 * @param[in] nMajorType The CBOR major type (0 or 1).
855 * @param[in] uArgument The argument from the head.
856 * @param[in] nAdditionalInfo So it can be error-checked.
857 * @param[out] pDecodedItem The filled in decoded item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800858 *
Laurence Lundblade95606972024-06-07 11:32:12 -0700859 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered.
860 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800861 *
862 * Must only be called when major type is 0 or 1.
863 *
864 * CBOR doesn't explicitly specify two's compliment for integers but
865 * all CPUs use it these days and the test vectors in the RFC are
866 * so. All integers in the CBOR structure are positive and the major
867 * type indicates positive or negative. CBOR can express positive
868 * integers up to 2^x - 1 where x is the number of bits and negative
869 * integers down to 2^x. Note that negative numbers can be one more
870 * away from zero than positive. Stdint, as far as I can tell, uses
871 * two's compliment to represent negative integers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700872 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700873static QCBORError
874QCBOR_Private_DecodeInteger(const int nMajorType,
875 const uint64_t uArgument,
Laurence Lundblade62cae932024-06-03 13:16:17 -0700876 const int nAdditionalInfo,
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700877 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700878{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800879 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800880
Laurence Lundblade62cae932024-06-03 13:16:17 -0700881 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
882 uReturn = QCBOR_ERR_BAD_INT;
883 goto Done;
884 }
885
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700886 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800887 if (uArgument <= INT64_MAX) {
888 pDecodedItem->val.int64 = (int64_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700889 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800890
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700891 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800892 pDecodedItem->val.uint64 = uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700893 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700894 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800895
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700896 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800897 if(uArgument <= INT64_MAX) {
898 /* CBOR's representation of negative numbers lines up with
899 * the two-compliment representation. A negative integer has
900 * one more in range than a positive integer. INT64_MIN is
901 * equal to (-INT64_MAX) - 1.
902 */
903 pDecodedItem->val.int64 = (-(int64_t)uArgument) - 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700904 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800905
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700906 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800907 /* C can't represent a negative integer in this range so it
908 * is an error.
909 */
910 uReturn = QCBOR_ERR_INT_OVERFLOW;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700911 }
912 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800913
Laurence Lundblade62cae932024-06-03 13:16:17 -0700914Done:
915 return uReturn;
916}
917
918
Laurence Lundblade95606972024-06-07 11:32:12 -0700919/**
920 * @brief Decode text and byte strings
921 *
922 * @param[in] pMe Decoder context.
923 * @param[in] bAllocate Whether to allocate and copy string.
924 * @param[in] nMajorType Whether it is a byte or text string.
925 * @param[in] uStrLen The length of the string.
926 * @param[in] nAdditionalInfo Whether it is an indefinite-length string.
927 * @param[out] pDecodedItem The filled-in decoded item.
928 *
929 * @retval QCBOR_ERR_HIT_END Unexpected end of input.
930 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
931 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
932 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator
933 *
934 * This reads @c uStrlen bytes from the input and fills in @c
935 * pDecodedItem. If @c bAllocate is true, then memory for the string
936 * is allocated.
937 */
Laurence Lundblade62cae932024-06-03 13:16:17 -0700938static QCBORError
Laurence Lundblade95606972024-06-07 11:32:12 -0700939QCBOR_Private_DecodeString(QCBORDecodeContext *pMe,
940 const bool bAllocate,
941 const int nMajorType,
942 const uint64_t uStrLen,
943 const int nAdditionalInfo,
944 QCBORItem *pDecodedItem)
945{
946 QCBORError uReturn = QCBOR_SUCCESS;
947
948 /* ---- Figure out the major type ---- */
949 #if CBOR_MAJOR_TYPE_BYTE_STRING + 4 != QCBOR_TYPE_BYTE_STRING
950 #error QCBOR_TYPE_BYTE_STRING not lined up with major type
951 #endif
952
953 #if CBOR_MAJOR_TYPE_TEXT_STRING + 4 != QCBOR_TYPE_TEXT_STRING
954 #error QCBOR_TYPE_TEXT_STRING not lined up with major type
955 #endif
956 pDecodedItem->uDataType = (uint8_t)(nMajorType + 4);
957
958 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
959 /* --- Just the head of an indefinite-length string --- */
960 pDecodedItem->val.string = (UsefulBufC){NULL, QCBOR_STRING_LENGTH_INDEFINITE};
961
962 } else {
963 /* --- A definite-length string --- */
964 /* --- (which might be a chunk of an indefinte-length string) --- */
965
966 /* CBOR lengths can be 64 bits, but size_t is not 64 bits on all
967 * CPUs. This check makes the casts to size_t below safe.
968 *
969 * The max is 4 bytes less than the largest sizeof() so this can be
970 * tested by putting a SIZE_MAX length in the CBOR test input (no
971 * one will care the limit on strings is 4 bytes shorter).
972 */
973 if(uStrLen > SIZE_MAX-4) {
974 uReturn = QCBOR_ERR_STRING_TOO_LONG;
975 goto Done;
976 }
977
978 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(&(pMe->InBuf), (size_t)uStrLen);
979 if(UsefulBuf_IsNULLC(Bytes)) {
980 /* Failed to get the bytes for this string item */
981 uReturn = QCBOR_ERR_HIT_END;
982 goto Done;
983 }
984
985#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
986 if(bAllocate) {
987 /* --- Put string in allocated memory --- */
988
989 /* Note that this is not where allocation to coalesce
990 * indefinite-length strings is done. This is for when the
991 * caller has requested all strings be allocated. Disabling
992 * indefinite length strings also disables this allocate-all
993 * option.
994 */
995
996 if(pMe->StringAllocator.pfAllocator == NULL) {
997 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
998 goto Done;
999 }
1000 UsefulBuf NewMem = StringAllocator_Allocate(&(pMe->StringAllocator), (size_t)uStrLen);
1001 if(UsefulBuf_IsNULL(NewMem)) {
1002 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1003 goto Done;
1004 }
1005 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
1006 pDecodedItem->uDataAlloc = 1;
1007 goto Done;
1008 }
1009#else
1010 (void)bAllocate;
1011#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1012
1013 /* --- Normal case with no string allocator --- */
1014 pDecodedItem->val.string = Bytes;
1015 }
1016
1017Done:
1018 return uReturn;
1019}
1020
1021
1022/**
1023 * @brief Decode array or map.
1024 *
1025 * @param[in] uMode Decoder mode.
1026 * @param[in] nMajorType Whether it is a byte or text string.
1027 * @param[in] uItemCount The length of the string.
1028 * @param[in] nAdditionalInfo Whether it is an indefinite-length.
1029 * @param[out] pDecodedItem The filled-in decoded item.
1030 *
1031 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinites disabled.
1032 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map.
1033 *
1034 * Not much to do for arrays and maps. Just the type item count (but a
1035 * little messy because of ifdefs for indefinite-lengths and
1036 * map-as-array decoding).
1037 *
1038 * This also does the bulk of the work for @ref
1039 * QCBOR_DECODE_MODE_MAP_AS_ARRAY, a special mode to handle
1040 * arbitrarily complex map labels. This ifdefs out with
1041 * QCBOR_DISABLE_NON_INTEGER_LABELS.
1042 */
1043static QCBORError
1044QCBOR_Private_DecodeArrayOrMap(const uint8_t uMode,
1045 const int nMajorType,
1046 const uint64_t uItemCount,
1047 const int nAdditionalInfo,
1048 QCBORItem *pDecodedItem)
Laurence Lundblade62cae932024-06-03 13:16:17 -07001049{
1050 QCBORError uReturn;
1051
Laurence Lundblade95606972024-06-07 11:32:12 -07001052 /* ------ Sort out the data type ------ */
1053 #if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
1054 #error QCBOR_TYPE_ARRAY value not lined up with major type
1055 #endif
1056
1057 #if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
1058 #error QCBOR_TYPE_MAP value not lined up with major type
1059 #endif
1060 pDecodedItem->uDataType = (uint8_t)nMajorType;
1061#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1062 if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
1063 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
1064 }
1065#else
1066 (void)uMode;
1067#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
1068
1069 uReturn = QCBOR_SUCCESS;
1070
1071 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1072 /* ------ Indefinite-length array/map ----- */
1073#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
1074 pDecodedItem->val.uCount = QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH;
1075#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1076 uReturn = QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED;
1077#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1078 } else {
1079
1080#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1081 if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
1082 /* ------ Definite-length map as array ------ */
1083
1084 if(uItemCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
1085 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
1086 } else {
1087 /* cast OK because of check above */
1088 pDecodedItem->val.uCount = (uint16_t)uItemCount*2;
1089 }
1090
1091 } else
1092#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
1093 {
1094 /* ------ Definite-length array/map ------ */
1095 if(uItemCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
1096 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
1097 } else {
1098 /* cast OK because of check above */
1099 pDecodedItem->val.uCount = (uint16_t)uItemCount;
1100 }
Laurence Lundblade62cae932024-06-03 13:16:17 -07001101 }
Laurence Lundblade95606972024-06-07 11:32:12 -07001102 }
1103
1104 return uReturn;
1105}
1106
1107
1108/**
1109 * @brief Decode a tag number.
1110 *
1111 * @param[in] uTagNumber The length of the string.
1112 * @param[in] nAdditionalInfo So this can be error-checked.
1113 * @param[out] pDecodedItem The filled-in decoded item.
1114 *
1115 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo is LEN_IS_INDEFINITE.
1116 * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined.
1117 *
1118 * Not much to do for tags, but fill in pDecodedItem and check for
1119 * error in nAdditionalInfo.
1120 */
1121static QCBORError
1122QCBOR_Private_DecodeTag(const uint64_t uTagNumber,
1123 const int nAdditionalInfo,
1124 QCBORItem *pDecodedItem)
1125{
1126#ifndef QCBOR_DISABLE_TAGS
1127 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1128 return QCBOR_ERR_BAD_INT;
1129 } else {
1130 pDecodedItem->val.uTagV = uTagNumber;
1131 pDecodedItem->uDataType = QCBOR_TYPE_TAG;
1132 return QCBOR_SUCCESS;
1133 }
Laurence Lundblade62cae932024-06-03 13:16:17 -07001134#else /* QCBOR_DISABLE_TAGS */
Laurence Lundbladecfd8a2c2024-06-06 21:01:42 -07001135 (void)nAdditionalInfo;
1136 (void)uArgument;
1137 (void)pDecodedItem;
Laurence Lundblade95606972024-06-07 11:32:12 -07001138 return QCBOR_ERR_TAGS_DISABLED;
Laurence Lundblade62cae932024-06-03 13:16:17 -07001139#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001140}
1141
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001142
1143/* Make sure #define value line up as DecodeSimple counts on this. */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001144#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
1145#error QCBOR_TYPE_FALSE macro value wrong
1146#endif
1147
1148#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
1149#error QCBOR_TYPE_TRUE macro value wrong
1150#endif
1151
1152#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
1153#error QCBOR_TYPE_NULL macro value wrong
1154#endif
1155
1156#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
1157#error QCBOR_TYPE_UNDEF macro value wrong
1158#endif
1159
Laurence Lundblade0f99d692018-09-26 14:39:28 -07001160#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
1161#error QCBOR_TYPE_BREAK macro value wrong
1162#endif
1163
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001164#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
1165#error QCBOR_TYPE_DOUBLE macro value wrong
1166#endif
1167
1168#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
1169#error QCBOR_TYPE_FLOAT macro value wrong
1170#endif
1171
Laurence Lundblade9b334962020-08-27 10:55:53 -07001172
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001173/**
1174 * @brief Decode major type 7 -- true, false, floating-point, break...
1175 *
1176 * @param[in] nAdditionalInfo The lower five bits from the initial byte.
1177 * @param[in] uArgument The argument from the head.
1178 * @param[out] pDecodedItem The filled in decoded item.
1179 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001180 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1181 * of half-precision disabled
1182 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all float
1183 * decode is disabled.
1184 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of simple
1185 * type in input.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001186 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001187static QCBORError
1188QCBOR_Private_DecodeType7(const int nAdditionalInfo,
1189 const uint64_t uArgument,
1190 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001191{
1192 QCBORError uReturn = QCBOR_SUCCESS;
1193
1194 /* uAdditionalInfo is 5 bits from the initial byte. Compile time
1195 * checks above make sure uAdditionalInfo values line up with
1196 * uDataType values. DecodeHead() never returns an AdditionalInfo
1197 * > 0x1f so cast is safe.
1198 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001199 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001200
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001201 switch(nAdditionalInfo) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001202 /* No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they
1203 * are caught before this is called.
1204 */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001205
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001206 case HALF_PREC_FLOAT: /* 25 */
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -07001207#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001208 /* Half-precision is returned as a double. The cast to
1209 * uint16_t is safe because the encoded value was 16 bits. It
1210 * was widened to 64 bits to be passed in here.
1211 */
1212 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uArgument);
Laurence Lundblade67bd5512018-11-02 21:44:06 +07001213 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001214#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001215 uReturn = FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001216 break;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001217 case SINGLE_PREC_FLOAT: /* 26 */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001218#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001219 /* Single precision is normally returned as a double since
1220 * double is widely supported, there is no loss of precision,
1221 * it makes it easy for the caller in most cases and it can
1222 * be converted back to single with no loss of precision
1223 *
1224 * The cast to uint32_t is safe because the encoded value was
1225 * 32 bits. It was widened to 64 bits to be passed in here.
1226 */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001227 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001228 const float f = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uArgument);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001229#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001230 /* In the normal case, use HW to convert float to
1231 * double. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001232 pDecodedItem->val.dfnum = (double)f;
1233 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001234#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001235 /* Use of float HW is disabled, return as a float. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001236 pDecodedItem->val.fnum = f;
1237 pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
1238
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001239 /* IEEE754_FloatToDouble() could be used here to return as
1240 * a double, but it adds object code and most likely
1241 * anyone disabling FLOAT HW use doesn't care about floats
1242 * and wants to save object code.
1243 */
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001244#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001245 }
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001246#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1247 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001248 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001249
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001250 case DOUBLE_PREC_FLOAT: /* 27 */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001251#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001252 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uArgument);
Laurence Lundblade67bd5512018-11-02 21:44:06 +07001253 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001254#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1255 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001256 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001257
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001258 case CBOR_SIMPLEV_FALSE: /* 20 */
1259 case CBOR_SIMPLEV_TRUE: /* 21 */
1260 case CBOR_SIMPLEV_NULL: /* 22 */
1261 case CBOR_SIMPLEV_UNDEF: /* 23 */
1262 case CBOR_SIMPLE_BREAK: /* 31 */
1263 break; /* nothing to do */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001264
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001265 case CBOR_SIMPLEV_ONEBYTE: /* 24 */
1266 if(uArgument <= CBOR_SIMPLE_BREAK) {
1267 /* This takes out f8 00 ... f8 1f which should be encoded
1268 * as e0 … f7
1269 */
1270 uReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001271 goto Done;
1272 }
Laurence Lundblade5e390822019-01-06 12:35:01 -08001273 /* FALLTHROUGH */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001274
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001275 default: /* 0-19 */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001276 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001277 /* DecodeHead() will make uArgument equal to
1278 * nAdditionalInfo when nAdditionalInfo is < 24. This cast is
1279 * safe because the 2, 4 and 8 byte lengths of uNumber are in
1280 * the double/float cases above
Laurence Lundbladeee851742020-01-08 08:37:05 -08001281 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001282 pDecodedItem->val.uSimple = (uint8_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001283 break;
1284 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001285
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001286Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001287 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001288}
1289
1290
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001291/**
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001292 * @brief Decode a single primitive data item (decode layer 6).
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001293 *
Laurence Lundblade95606972024-06-07 11:32:12 -07001294 * @param[in] pMe Decoder context.
1295 * @param[in] bAllocateStrings If true, use allocator for strings.
1296 * @param[out] pDecodedItem The filled-in decoded item.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001297 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001298 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1299 * features
1300 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1301 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1302 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1303 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
Laurence Lundblade95606972024-06-07 11:32:12 -07001304 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001305 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1306 * of half-precision disabled
1307 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1308 * float decode is disabled.
1309 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1310 * simple type in input.
1311 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1312 * in input, but indefinite
1313 * lengths disabled.
Laurence Lundblade95606972024-06-07 11:32:12 -07001314 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte.
1315 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map.
1316 * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001317 *
Laurence Lundblade95606972024-06-07 11:32:12 -07001318 * This decodes the most primitive / atomic data item. It does no
1319 * combining of data items.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001320 */
1321static QCBORError
Laurence Lundblade95606972024-06-07 11:32:12 -07001322QCBOR_Private_DecodeAtomicDataItem(QCBORDecodeContext *pMe,
1323 const bool bAllocateStrings,
1324 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001325{
1326 QCBORError uReturn;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001327 int nMajorType = 0;
1328 uint64_t uArgument = 0;
1329 int nAdditionalInfo = 0;
1330
Laurence Lundblade95606972024-06-07 11:32:12 -07001331 /* Decode the "head" that every CBOR item has into the major type,
1332 * length and the additional info.
1333 */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001334 uReturn = QCBOR_Private_DecodeHead(&(pMe->InBuf), &nMajorType, &uArgument, &nAdditionalInfo);
Laurence Lundblade95606972024-06-07 11:32:12 -07001335 if(uReturn != QCBOR_SUCCESS) {
1336 return uReturn;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001337 }
1338
Laurence Lundblade95606972024-06-07 11:32:12 -07001339 memset(pDecodedItem, 0, sizeof(QCBORItem));
1340
1341 /* All the functions below get inlined by the optimizer. This code
1342 * is easier to read with them all being similar functions, even if
1343 * some functions don't do much.
1344 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001345 switch (nMajorType) {
1346 case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
1347 case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
Laurence Lundblade95606972024-06-07 11:32:12 -07001348 return QCBOR_Private_DecodeInteger(nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001349 break;
1350
1351 case CBOR_MAJOR_TYPE_BYTE_STRING: /* Major type 2 */
1352 case CBOR_MAJOR_TYPE_TEXT_STRING: /* Major type 3 */
Laurence Lundblade95606972024-06-07 11:32:12 -07001353 return QCBOR_Private_DecodeString(pMe, bAllocateStrings, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001354 break;
1355
1356 case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */
1357 case CBOR_MAJOR_TYPE_MAP: /* Major type 5 */
Laurence Lundblade95606972024-06-07 11:32:12 -07001358 return QCBOR_Private_DecodeArrayOrMap(pMe->uDecodeMode, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001359 break;
1360
1361 case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */
Laurence Lundblade95606972024-06-07 11:32:12 -07001362 return QCBOR_Private_DecodeTag(uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001363 break;
1364
1365 case CBOR_MAJOR_TYPE_SIMPLE:
1366 /* Major type 7: float, double, true, false, null... */
Laurence Lundblade95606972024-06-07 11:32:12 -07001367 return QCBOR_Private_DecodeType7(nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001368 break;
1369
1370 default:
1371 /* Never happens because DecodeHead() should never return > 7 */
Laurence Lundblade95606972024-06-07 11:32:12 -07001372 return QCBOR_ERR_UNSUPPORTED;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001373 break;
1374 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001375}
1376
1377
1378/**
1379 * @brief Process indefinite-length strings (decode layer 5).
1380 *
1381 * @param[in] pMe Decoder context
1382 * @param[out] pDecodedItem The decoded item that work is done on.
1383 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001384 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1385 * features
1386 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1387 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1388 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1389 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1390 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1391 * of half-precision disabled
1392 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1393 * float decode is disabled.
1394 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1395 * simple type in input.
1396 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1397 * in input, but indefinite
1398 * lengths disabled.
1399 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1400 * but no string allocator.
1401 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1402 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1403 * input, but indefinite-length
1404 * strings are disabled.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001405 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001406 * If @c pDecodedItem is not an indefinite-length string, this does nothing.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001407 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001408 * If it is, this loops getting the subsequent chunk data items that
1409 * make up the string. The string allocator is used to make a
1410 * contiguous buffer for the chunks. When this completes @c
1411 * pDecodedItem contains the put-together string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001412 *
1413 * Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001414 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001415static QCBORError
1416QCBORDecode_Private_GetNextFullString(QCBORDecodeContext *pMe,
1417 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001418{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001419 /* Aproximate stack usage
1420 * 64-bit 32-bit
1421 * local vars 32 16
1422 * 2 UsefulBufs 32 16
1423 * QCBORItem 56 52
1424 * TOTAL 120 74
1425 */
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001426 QCBORError uReturn;
Laurence Lundblade78a66132024-06-06 12:19:59 -07001427
Laurence Lundblade38964bd2024-06-08 11:49:35 -07001428 /* A note about string allocation -- Memory for strings is
1429 * allocated either because 1) indefinte-length string chunks are
1430 * being coalecsed or 2) caller has requested all strings be
1431 * allocated. The first case is handed below here. The second case
1432 * is handled in DecodeString if the bAllocate is true. That
1433 * boolean originates here with pMe->bStringAllocateAll immediately
1434 * below. That is, QCBOR_Private_DecodeAtomicDataItem() is called
1435 * in two different contexts here 1) main-line processing which is
1436 * where definite-length strings need to be allocated if
1437 * bStringAllocateAll is true and 2) processing chunks of
1438 * indefinite-lengths strings in in which case there must be no
1439 * allocation.
1440 */
1441
1442
Laurence Lundblade78a66132024-06-06 12:19:59 -07001443 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, pMe->bStringAllocateAll, pDecodedItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001444 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001445 goto Done;
1446 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001447
Laurence Lundblade38964bd2024-06-08 11:49:35 -07001448
1449 /* This is where out-of-place break is detected for the whole
1450 * decoding stack. Break is an error for everything that calls
1451 * QCBORDecode_Private_GetNextFullString(), so the check is
1452 * centralized here.
1453 */
1454 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
1455 uReturn = QCBOR_ERR_BAD_BREAK;
1456 goto Done;
1457 }
1458
1459
Laurence Lundblade78a66132024-06-06 12:19:59 -07001460 /* Skip out if not an indefinite-length string */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001461 const uint8_t uStringType = pDecodedItem->uDataType;
Laurence Lundblade78a66132024-06-06 12:19:59 -07001462 if(uStringType != QCBOR_TYPE_BYTE_STRING &&
1463 uStringType != QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001464 goto Done;
1465 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001466 if(pDecodedItem->val.string.len != QCBOR_STRING_LENGTH_INDEFINITE) {
1467 goto Done;
1468 }
1469
1470#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001471 /* Can't decode indefinite-length strings without a string allocator */
Laurence Lundblade78a66132024-06-06 12:19:59 -07001472 if(!pMe->StringAllocator.pfAllocator) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001473 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1474 goto Done;
1475 }
1476
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001477 /* Loop getting chunks of the indefinite-length string */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001478 UsefulBufC FullString = NULLUsefulBufC;
1479
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001480 for(;;) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001481 /* Get QCBORItem for next chunk */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001482 QCBORItem StringChunkItem;
Laurence Lundblade38964bd2024-06-08 11:49:35 -07001483 /* Pass false to DecodeAtomicDataItem() because the individual
1484 * string chunks in an indefinite-length must not be
1485 * allocated. They are always copied into the allocated
1486 * contiguous buffer allocated here.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001487 */
Laurence Lundblade78a66132024-06-06 12:19:59 -07001488 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &StringChunkItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001489 if(uReturn) {
1490 break;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001491 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001492
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001493 /* Is item is the marker for end of the indefinite-length string? */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001494 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001495 /* String is complete */
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001496 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301497 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001498 break;
1499 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001500
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001501 /* All chunks must be of the same type, the type of the item
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001502 * that introduces the indefinite-length string. This also
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001503 * catches errors where the chunk is not a string at all and an
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001504 * indefinite-length string inside an indefinite-length string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001505 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001506 if(StringChunkItem.uDataType != uStringType ||
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001507 StringChunkItem.val.string.len == QCBOR_STRING_LENGTH_INDEFINITE) {
1508 uReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001509 break;
1510 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001511
David Navarro9123e5b2022-03-28 16:04:03 +02001512 if (StringChunkItem.val.string.len > 0) {
1513 /* The first time throurgh FullString.ptr is NULL and this is
1514 * equivalent to StringAllocator_Allocate(). Subsequently it is
1515 * not NULL and a reallocation happens.
1516 */
Laurence Lundblade78a66132024-06-06 12:19:59 -07001517 UsefulBuf NewMem = StringAllocator_Reallocate(&(pMe->StringAllocator),
David Navarro9123e5b2022-03-28 16:04:03 +02001518 FullString.ptr,
1519 FullString.len + StringChunkItem.val.string.len);
David Navarro9123e5b2022-03-28 16:04:03 +02001520 if(UsefulBuf_IsNULL(NewMem)) {
1521 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1522 break;
1523 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001524
David Navarro9123e5b2022-03-28 16:04:03 +02001525 /* Copy new string chunk to the end of accumulated string */
1526 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001527 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001528 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001529
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001530 if(uReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
1531 /* Getting the item failed, clean up the allocated memory */
Laurence Lundblade78a66132024-06-06 12:19:59 -07001532 StringAllocator_Free(&(pMe->StringAllocator), FullString.ptr);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001533 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001534#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1535 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1536#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001537
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001538Done:
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001539 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001540}
1541
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001542
Laurence Lundblade37286c02022-09-03 10:05:02 -07001543#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001544/**
1545 * @brief This converts a tag number to a shorter mapped value for storage.
1546 *
1547 * @param[in] pMe The decode context.
1548 * @param[in] uUnMappedTag The tag number to map
1549 * @param[out] puMappedTagNumer The stored tag number.
1550 *
1551 * @return error code.
1552 *
1553 * The main point of mapping tag numbers is make QCBORItem
1554 * smaller. With this mapping storage of 4 tags takes up 8
1555 * bytes. Without, it would take up 32 bytes.
1556 *
1557 * This maps tag numbers greater than QCBOR_LAST_UNMAPPED_TAG.
1558 * QCBOR_LAST_UNMAPPED_TAG is a little smaller than MAX_UINT16.
1559 *
1560 * See also UnMapTagNumber() and @ref QCBORItem.
1561 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001562static QCBORError
1563QCBORDecode_Private_MapTagNumber(QCBORDecodeContext *pMe,
1564 const uint64_t uUnMappedTag,
1565 uint16_t *puMappedTagNumer)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001566{
1567 if(uUnMappedTag > QCBOR_LAST_UNMAPPED_TAG) {
1568 unsigned uTagMapIndex;
1569 /* Is there room in the tag map, or is it in it already? */
1570 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
1571 if(pMe->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID64) {
1572 break;
1573 }
1574 if(pMe->auMappedTags[uTagMapIndex] == uUnMappedTag) {
1575 break;
1576 }
1577 }
1578 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
1579 return QCBOR_ERR_TOO_MANY_TAGS;
1580 }
1581
1582 /* Covers the cases where tag is new and were it is already in the map */
1583 pMe->auMappedTags[uTagMapIndex] = uUnMappedTag;
1584 *puMappedTagNumer = (uint16_t)(uTagMapIndex + QCBOR_LAST_UNMAPPED_TAG + 1);
1585
1586 } else {
1587 *puMappedTagNumer = (uint16_t)uUnMappedTag;
1588 }
1589
1590 return QCBOR_SUCCESS;
1591}
1592
1593
1594/**
1595 * @brief This converts a mapped tag number to the actual tag number.
1596 *
1597 * @param[in] pMe The decode context.
1598 * @param[in] uMappedTagNumber The stored tag number.
1599 *
1600 * @return The actual tag number is returned or
1601 * @ref CBOR_TAG_INVALID64 on error.
1602 *
1603 * This is the reverse of MapTagNumber()
1604 */
1605static uint64_t
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001606QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe,
1607 const uint16_t uMappedTagNumber)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001608{
1609 if(uMappedTagNumber <= QCBOR_LAST_UNMAPPED_TAG) {
1610 return uMappedTagNumber;
1611 } else if(uMappedTagNumber == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07001612 return CBOR_TAG_INVALID64;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001613 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001614 /* This won't be negative because of code below in
1615 * MapTagNumber()
1616 */
1617 const unsigned uIndex = uMappedTagNumber - (QCBOR_LAST_UNMAPPED_TAG + 1);
1618 return pMe->auMappedTags[uIndex];
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001619 }
1620}
Laurence Lundblade37286c02022-09-03 10:05:02 -07001621#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001622
Laurence Lundblade9b334962020-08-27 10:55:53 -07001623
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001624/**
1625 * @brief Aggregate all tags wrapping a data item (decode layer 4).
1626 *
1627 * @param[in] pMe Decoder context
1628 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001629 *
1630 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1631 * features
1632 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1633 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1634 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1635 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1636 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1637 * of half-precision disabled
1638 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1639 * float decode is disabled.
1640 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1641 * simple type in input.
1642 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1643 * in input, but indefinite
1644 * lengths disabled.
1645 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1646 * but no string allocator.
1647 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1648 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1649 * input, but indefinite-length
1650 * strings are disabled.
1651 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001652 *
1653 * This loops getting atomic data items until one is not a tag
1654 * number. Usually this is largely pass-through because most
1655 * item are not tag numbers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001656 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001657static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001658QCBORDecode_Private_GetNextTagNumber(QCBORDecodeContext *pMe,
1659 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001660{
Laurence Lundblade37286c02022-09-03 10:05:02 -07001661#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001662 /* Accummulate the tags from multiple items here and then copy them
1663 * into the last item, the non-tag item.
1664 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001665 uint16_t auItemsTags[QCBOR_MAX_TAGS_PER_ITEM];
1666
1667 /* Initialize to CBOR_TAG_INVALID16 */
1668 #if CBOR_TAG_INVALID16 != 0xffff
1669 /* Be sure the memset does the right thing. */
1670 #err CBOR_TAG_INVALID16 tag not defined as expected
1671 #endif
1672 memset(auItemsTags, 0xff, sizeof(auItemsTags));
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001673
Laurence Lundblade9b334962020-08-27 10:55:53 -07001674 QCBORError uReturn = QCBOR_SUCCESS;
1675
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001676 /* Loop fetching data items until the item fetched is not a tag */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001677 for(;;) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001678 QCBORError uErr = QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07001679 if(uErr != QCBOR_SUCCESS) {
1680 uReturn = uErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001681 goto Done;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001682 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001683
Laurence Lundblade9b334962020-08-27 10:55:53 -07001684 if(pDecodedItem->uDataType != QCBOR_TYPE_TAG) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001685 /* Successful exit from loop; maybe got some tags, maybe not */
1686 memcpy(pDecodedItem->uTags, auItemsTags, sizeof(auItemsTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001687 break;
1688 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001689
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001690 if(auItemsTags[QCBOR_MAX_TAGS_PER_ITEM - 1] != CBOR_TAG_INVALID16) {
1691 /* No room in the tag list */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001692 uReturn = QCBOR_ERR_TOO_MANY_TAGS;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001693 /* Continue on to get all tags wrapping this item even though
1694 * it is erroring out in the end. This allows decoding to
1695 * continue. This is a resource limit error, not a problem
1696 * with being well-formed CBOR.
1697 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001698 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001699 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001700 /* Slide tags over one in the array to make room at index 0.
1701 * Must use memmove because the move source and destination
1702 * overlap.
1703 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001704 memmove(&auItemsTags[1],
1705 auItemsTags,
1706 sizeof(auItemsTags) - sizeof(auItemsTags[0]));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001707
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001708 /* Map the tag */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001709 uint16_t uMappedTagNumber = 0;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001710 uReturn = QCBORDecode_Private_MapTagNumber(pMe, pDecodedItem->val.uTagV, &uMappedTagNumber);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001711 /* Continue even on error so as to consume all tags wrapping
1712 * this data item so decoding can go on. If MapTagNumber()
1713 * errors once it will continue to error.
1714 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001715 auItemsTags[0] = uMappedTagNumber;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001716 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001717
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001718Done:
Laurence Lundblade9b334962020-08-27 10:55:53 -07001719 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001720
Laurence Lundblade37286c02022-09-03 10:05:02 -07001721#else /* QCBOR_DISABLE_TAGS */
1722
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07001723 return QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07001724
1725#endif /* QCBOR_DISABLE_TAGS */
1726}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001727
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001728
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001729/**
1730 * @brief Combine a map entry label and value into one item (decode layer 3).
1731 *
1732 * @param[in] pMe Decoder context
1733 * @param[out] pDecodedItem The decoded item that work is done on.
1734 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001735 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1736 * features
1737 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1738 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1739 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1740 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1741 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1742 * of half-precision disabled
1743 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1744 * float decode is disabled.
1745 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1746 * simple type in input.
1747 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1748 * in input, but indefinite
1749 * lengths disabled.
1750 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1751 * but no string allocator.
1752 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1753 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1754 * input, but indefinite-length
1755 * strings are disabled.
1756 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1757 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1758 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001759 *
Laurence Lundblade38964bd2024-06-08 11:49:35 -07001760 * If the current nesting level is a map, then this combines pairs of
1761 * items into one data item with a label and value.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001762 *
Laurence Lundblade38964bd2024-06-08 11:49:35 -07001763 * This is passthrough if the current nesting level is not a map.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001764 *
Laurence Lundblade38964bd2024-06-08 11:49:35 -07001765 * This also implements maps-as-array mode where a map is treated like
1766 * an array to allow caller to do their own label processing.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001767 */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001768
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001769static QCBORError
1770QCBORDecode_Private_GetNextMapEntry(QCBORDecodeContext *pMe,
1771 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001772{
Laurence Lundblade62cae932024-06-03 13:16:17 -07001773 QCBORItem LabelItem;
1774 QCBORError uErr;
1775
1776 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1777 if(QCBORDecode_IsUnrecoverableError(uErr)) {
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001778 goto Done;
1779 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001780
Laurence Lundblade62cae932024-06-03 13:16:17 -07001781 if(!DecodeNesting_IsCurrentTypeMap(&(pMe->nesting))) {
Laurence Lundblade38964bd2024-06-08 11:49:35 -07001782 /* Not decoding a map. Nothing to do. */
1783 /* When decoding maps-as-arrays, the type will be
1784 * QCBOR_TYPE_MAP_AS_ARRAY and this function will exit
1785 * here. This is now map processing for maps-as-arrays is not
1786 * done. */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001787 goto Done;
1788 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001789
Laurence Lundblade38964bd2024-06-08 11:49:35 -07001790 /* Decoding a map entry, so the item decoded above was the label */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001791 LabelItem = *pDecodedItem;
Laurence Lundblade38964bd2024-06-08 11:49:35 -07001792
1793 /* Get the value of the map item */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001794 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1795 if(QCBORDecode_IsUnrecoverableError(uErr)) {
1796 goto Done;
1797 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001798
Laurence Lundblade38964bd2024-06-08 11:49:35 -07001799 /* Combine the label item and value item into one */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001800 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
1801 pDecodedItem->uLabelType = LabelItem.uDataType;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001802
Laurence Lundblade62cae932024-06-03 13:16:17 -07001803#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade38964bd2024-06-08 11:49:35 -07001804 /* QCBOR_DECODE_MODE_MAP_STRINGS_ONLY might have been a bad idea. Maybe
Laurence Lundblade62cae932024-06-03 13:16:17 -07001805 * get rid of it in QCBOR 2.0
1806 */
1807 if(pMe->uDecodeMode == QCBOR_DECODE_MODE_MAP_STRINGS_ONLY &&
1808 LabelItem.uDataType != QCBOR_TYPE_TEXT_STRING) {
1809 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
1810 goto Done;
1811 }
Laurence Lundblade38964bd2024-06-08 11:49:35 -07001812#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001813
1814 switch(LabelItem.uDataType) {
1815 case QCBOR_TYPE_INT64:
1816 pDecodedItem->label.int64 = LabelItem.val.int64;
1817 break;
1818
1819#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1820 case QCBOR_TYPE_UINT64:
1821 pDecodedItem->label.uint64 = LabelItem.val.uint64;
1822 break;
1823
1824 case QCBOR_TYPE_TEXT_STRING:
1825 case QCBOR_TYPE_BYTE_STRING:
1826 pDecodedItem->label.string = LabelItem.val.string;
1827 break;
Laurence Lundblade38964bd2024-06-08 11:49:35 -07001828#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001829
1830 default:
1831 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
1832 goto Done;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001833 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001834
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001835Done:
Laurence Lundblade62cae932024-06-03 13:16:17 -07001836 return uErr;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001837}
1838
1839
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001840#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001841/**
1842 * @brief Peek and see if next data item is a break;
1843 *
Laurence Lundblade62cae932024-06-03 13:16:17 -07001844 * param[in] pUIB UsefulInputBuf to read from.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001845 * @param[out] pbNextIsBreak Indicate if next was a break or not.
1846 *
1847 * @return Any decoding error.
1848 *
1849 * See if next item is a CBOR break. If it is, it is consumed,
1850 * if not it is not consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07001851*/
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001852static QCBORError
Laurence Lundblade62cae932024-06-03 13:16:17 -07001853QCBOR_Private_NextIsBreak(QCBORDecodeContext *pMe, bool *pbNextIsBreak)
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001854{
1855 *pbNextIsBreak = false;
Laurence Lundblade62cae932024-06-03 13:16:17 -07001856 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) != 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001857 QCBORItem Peek;
Laurence Lundblade62cae932024-06-03 13:16:17 -07001858 size_t uPeek = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade78a66132024-06-06 12:19:59 -07001859 QCBORError uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &Peek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001860 if(uReturn != QCBOR_SUCCESS) {
1861 return uReturn;
1862 }
1863 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001864 /* It is not a break, rewind so it can be processed normally. */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001865 UsefulInputBuf_Seek(&(pMe->InBuf), uPeek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001866 } else {
1867 *pbNextIsBreak = true;
1868 }
1869 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001870
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001871 return QCBOR_SUCCESS;
1872}
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001873#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001874
1875
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001876/**
1877 * @brief Ascend up nesting levels if all items in them have been consumed.
1878 *
1879 * @param[in] pMe The decode context.
1880 * @param[in] bMarkEnd If true mark end of maps/arrays with count of zero.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001881 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001882 *
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001883 * An item was just consumed, now figure out if it was the
1884 * end of an array/map map that can be closed out. That
1885 * may in turn close out the above array/map...
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001886 *
1887 * When ascending indefinite-length arrays and maps, this will correctly
1888 * consume the break for the level above. This is a problem for the
1889 * implementation of QCBORDecode_GetArray() that must not return
1890 * that break. @c pbBreak is set to true to indicate that one
1891 * byte should be removed.
1892 *
1893 * Improvement: this could reduced further if indef is disabled
1894 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001895static QCBORError
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001896QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd, bool *pbBreak)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001897{
1898 QCBORError uReturn;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001899
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001900 /* Loop ascending nesting levels as long as there is ascending to do */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001901 while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001902 if(pbBreak) {
1903 *pbBreak = false;
1904 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001905
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001906 if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) {
1907 /* Nesting level is bstr-wrapped CBOR */
1908
1909 /* Ascent for bstr-wrapped CBOR is always by explicit call
1910 * so no further ascending can happen.
1911 */
1912 break;
1913
1914 } else if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
1915 /* Level is a definite-length array/map */
1916
1917 /* Decrement the item count the definite-length array/map */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001918 DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(&(pMe->nesting));
1919 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001920 /* Didn't close out array/map, so all work here is done */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001921 break;
1922 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001923 /* All items in a definite-length array were consumed so it
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001924 * is time to ascend one level. This happens below.
1925 */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001926
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001927#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001928 } else {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001929 /* Level is an indefinite-length array/map. */
1930
1931 /* Check for a break which is what ends indefinite-length arrays/maps */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001932 bool bIsBreak = false;
Laurence Lundblade62cae932024-06-03 13:16:17 -07001933 uReturn = QCBOR_Private_NextIsBreak(pMe, &bIsBreak);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001934 if(uReturn != QCBOR_SUCCESS) {
1935 goto Done;
1936 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001937
1938 if(!bIsBreak) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001939 /* Not a break so array/map does not close out. All work is done */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001940 break;
1941 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001942
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001943 /* It was a break in an indefinitelength map / array so
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001944 * it is time to ascend one level.
1945 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001946 if(pbBreak) {
1947 *pbBreak = true;
1948 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001949
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001950#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001951 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001952
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001953
1954 /* All items in the array/map have been consumed. */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001955
Laurence Lundblade93d89472020-10-03 22:30:50 -07001956 /* But ascent in bounded mode is only by explicit call to
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001957 * QCBORDecode_ExitBoundedMode().
1958 */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07001959 if(DecodeNesting_IsCurrentBounded(&(pMe->nesting))) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001960 /* Set the count to zero for definite-length arrays to indicate
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001961 * cursor is at end of bounded array/map */
Laurence Lundbladed0304932020-06-27 10:59:38 -07001962 if(bMarkEnd) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001963 /* Used for definite and indefinite to signal end */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07001964 DecodeNesting_ZeroMapOrArrayCount(&(pMe->nesting));
Laurence Lundbladed0304932020-06-27 10:59:38 -07001965
Laurence Lundblade2c1faf92020-06-26 22:43:56 -07001966 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001967 break;
1968 }
1969
1970 /* Finally, actually ascend one level. */
1971 DecodeNesting_Ascend(&(pMe->nesting));
1972 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001973
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001974 uReturn = QCBOR_SUCCESS;
1975
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001976#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001977Done:
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001978#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1979
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001980 return uReturn;
1981}
1982
1983
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001984/**
1985 * @brief Ascending & Descending out of nesting levels (decode layer 2).
1986 *
1987 * @param[in] pMe Decoder context
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001988 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001989 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001990
1991 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1992 * features
1993 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1994 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1995 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1996 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1997 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1998 * of half-precision disabled
1999 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
2000 * float decode is disabled.
2001 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
2002 * simple type in input.
2003 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
2004 * in input, but indefinite
2005 * lengths disabled.
2006 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
2007 * but no string allocator.
2008 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
2009 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
2010 * input, but indefinite-length
2011 * strings are disabled.
2012 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
2013 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
2014 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
2015 * @retval QCBOR_ERR_NO_MORE_ITEMS Need more items for map or array.
2016 * @retval QCBOR_ERR_BAD_BREAK Indefinite-length break in wrong
2017 * place.
2018 * @retval QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP Nesting deeper than QCBOR
2019 * can handle.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002020 *
2021 * This handles the traversal descending into and asecnding out of
2022 * maps, arrays and bstr-wrapped CBOR. It figures out the ends of
2023 * definite- and indefinte-length maps and arrays by looking at the
2024 * item count or finding CBOR breaks. It detects the ends of the
2025 * top-level sequence and of bstr-wrapped CBOR by byte count.
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002026 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002027static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002028QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002029 bool *pbBreak,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002030 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002031{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002032 QCBORError uReturn;
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002033 /* ==== First: figure out if at the end of a traversal ==== */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002034
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002035 /* If out of bytes to consume, it is either the end of the
2036 * top-level sequence of some bstr-wrapped CBOR that was entered.
2037 *
2038 * In the case of bstr-wrapped CBOR, the length of the
2039 * UsefulInputBuf was set to that of the bstr-wrapped CBOR. When
2040 * the bstr-wrapped CBOR is exited, the length is set back to the
2041 * top-level's length or to the next highest bstr-wrapped CBOR.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002042 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002043 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) == 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002044 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002045 goto Done;
2046 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07002047
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002048 /* Check to see if at the end of a bounded definite-length map or
2049 * array. The check for a break ending indefinite-length array is
2050 * later in QCBORDecode_NestLevelAscender().
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002051 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002052 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002053 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002054 goto Done;
2055 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002056
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002057 /* ==== Next: not at the end, so get another item ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002058 uReturn = QCBORDecode_Private_GetNextMapEntry(pMe, pDecodedItem);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002059 if(QCBORDecode_IsUnrecoverableError(uReturn)) {
2060 /* Error is so bad that traversal is not possible. */
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002061 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002062 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05302063
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002064 /* Record the nesting level for this data item before processing
2065 * any of decrementing and descending.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002066 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002067 pDecodedItem->uNestingLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002068
Laurence Lundblade642282a2020-06-23 12:00:33 -07002069
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002070 /* ==== Next: Process the item for descent, ascent, decrement... ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002071 if(QCBORItem_IsMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002072 /* If the new item is a map or array, descend.
2073 *
2074 * Empty indefinite-length maps and arrays are descended into,
2075 * but then ascended out of in the next chunk of code.
2076 *
2077 * Maps and arrays do count as items in the map/array that
2078 * encloses them so a decrement needs to be done for them too,
2079 * but that is done only when all the items in them have been
2080 * processed, not when they are opened with the exception of an
2081 * empty map or array.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002082 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002083 QCBORError uDescendErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002084 uDescendErr = DecodeNesting_DescendMapOrArray(&(pMe->nesting),
Laurence Lundblade642282a2020-06-23 12:00:33 -07002085 pDecodedItem->uDataType,
2086 pDecodedItem->val.uCount);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002087 if(uDescendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002088 /* This error is probably a traversal error and it overrides
2089 * the non-traversal error.
2090 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002091 uReturn = uDescendErr;
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002092 goto Done;
2093 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002094 }
2095
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002096 if(!QCBORItem_IsMapOrArray(*pDecodedItem) ||
2097 QCBORItem_IsEmptyDefiniteLengthMapOrArray(*pDecodedItem) ||
2098 QCBORItem_IsIndefiniteLengthMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002099 /* The following cases are handled here:
2100 * - A non-aggregate item like an integer or string
2101 * - An empty definite-length map or array
2102 * - An indefinite-length map or array that might be empty or might not.
2103 *
2104 * QCBORDecode_NestLevelAscender() does the work of decrementing the count
2105 * for an definite-length map/array and break detection for an
2106 * indefinite-0length map/array. If the end of the map/array was
2107 * reached, then it ascends nesting levels, possibly all the way
2108 * to the top level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002109 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002110 QCBORError uAscendErr;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002111 uAscendErr = QCBORDecode_Private_NestLevelAscender(pMe, true, pbBreak);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002112 if(uAscendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002113 /* This error is probably a traversal error and it overrides
2114 * the non-traversal error.
2115 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002116 uReturn = uAscendErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002117 goto Done;
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002118 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05302119 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002120
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002121 /* ==== Last: tell the caller the nest level of the next item ==== */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002122 /* Tell the caller what level is next. This tells them what
2123 * maps/arrays were closed out and makes it possible for them to
2124 * reconstruct the tree with just the information returned in a
2125 * QCBORItem.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002126 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002127 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07002128 /* At end of a bounded map/array; uNextNestLevel 0 to indicate this */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002129 pDecodedItem->uNextNestLevel = 0;
2130 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002131 pDecodedItem->uNextNestLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002132 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002133
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002134Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002135 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002136}
2137
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002138
Laurence Lundblade37286c02022-09-03 10:05:02 -07002139#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002140/**
2141 * @brief Shift 0th tag out of the tag list.
2142 *
2143 * pDecodedItem[in,out] The data item to convert.
2144 *
2145 * The 0th tag is discarded. \ref CBOR_TAG_INVALID16 is
2146 * shifted into empty slot at the end of the tag list.
2147 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002148static void
2149QCBOR_Private_ShiftTags(QCBORItem *pDecodedItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002150{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002151 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM-1; i++) {
2152 pDecodedItem->uTags[i] = pDecodedItem->uTags[i+1];
2153 }
2154 pDecodedItem->uTags[QCBOR_MAX_TAGS_PER_ITEM-1] = CBOR_TAG_INVALID16;
Laurence Lundblade9b334962020-08-27 10:55:53 -07002155}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002156#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002157
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002158
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002159/**
2160 * @brief Convert different epoch date formats in to the QCBOR epoch date format
2161 *
2162 * pDecodedItem[in,out] The data item to convert.
2163 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002164 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2165 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2166 * floating-point date disabled.
2167 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2168 * all floating-point disabled.
2169 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2170 * error decoding date.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002171 *
2172 * The epoch date tag defined in QCBOR allows for floating-point
2173 * dates. It even allows a protocol to flop between date formats when
2174 * ever it wants. Floating-point dates aren't that useful as they are
2175 * only needed for dates beyond the age of the earth.
2176 *
2177 * This converts all the date formats into one format of an unsigned
2178 * integer plus a floating-point fraction.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002179 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002180static QCBORError
2181QCBOR_Private_DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002182{
Laurence Lundbladec7114722020-08-13 05:11:40 -07002183 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002184
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002185#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade59289e52019-12-30 13:44:37 -08002186 pDecodedItem->val.epochDate.fSecondsFraction = 0;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002187#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002188
2189 switch (pDecodedItem->uDataType) {
2190
2191 case QCBOR_TYPE_INT64:
2192 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
2193 break;
2194
2195 case QCBOR_TYPE_UINT64:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002196 /* This only happens for CBOR type 0 > INT64_MAX so it is
2197 * always an overflow.
2198 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07002199 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2200 goto Done;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002201 break;
2202
2203 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade9682a532020-06-06 18:33:04 -07002204 case QCBOR_TYPE_FLOAT:
2205#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade59289e52019-12-30 13:44:37 -08002206 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002207 /* Convert working value to double if input was a float */
Laurence Lundblade3ed0bca2020-07-14 22:50:10 -07002208 const double d = pDecodedItem->uDataType == QCBOR_TYPE_DOUBLE ?
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002209 pDecodedItem->val.dfnum :
2210 (double)pDecodedItem->val.fnum;
2211
2212 /* The conversion from float to integer requires overflow
2213 * detection since floats can be much larger than integers.
2214 * This implementation errors out on these large float values
2215 * since they are beyond the age of the earth.
2216 *
2217 * These constants for the overflow check are computed by the
2218 * compiler. They are not computed at run time.
2219 *
2220 * The factor of 0x7ff is added/subtracted to avoid a
2221 * rounding error in the wrong direction when the compiler
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002222 * computes these constants. There is rounding because a
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002223 * 64-bit integer has 63 bits of precision where a double
2224 * only has 53 bits. Without the 0x7ff factor, the compiler
2225 * may round up and produce a double for the bounds check
2226 * that is larger than can be stored in a 64-bit integer. The
2227 * amount of 0x7ff is picked because it has 11 bits set.
2228 *
2229 * Without the 0x7ff there is a ~30 minute range of time
2230 * values 10 billion years in the past and in the future
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002231 * where this code could go wrong. Some compilers
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002232 * generate a warning or error without the 0x7ff.
2233 */
2234 const double dDateMax = (double)(INT64_MAX - 0x7ff);
2235 const double dDateMin = (double)(INT64_MIN + 0x7ff);
2236
2237 if(isnan(d) || d > dDateMax || d < dDateMin) {
Laurence Lundbladec7114722020-08-13 05:11:40 -07002238 uReturn = QCBOR_ERR_DATE_OVERFLOW;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002239 goto Done;
2240 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002241
2242 /* The actual conversion */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002243 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
Laurence Lundblade2feb1e12020-07-15 03:50:45 -07002244 pDecodedItem->val.epochDate.fSecondsFraction =
2245 d - (double)pDecodedItem->val.epochDate.nSeconds;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002246 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002247#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade4b270642020-08-14 12:53:07 -07002248
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002249 uReturn = QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundblade4b270642020-08-14 12:53:07 -07002250 goto Done;
2251
Laurence Lundblade9682a532020-06-06 18:33:04 -07002252#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002253 break;
2254
2255 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002256 /* It's the arrays and maps that are unrecoverable because
2257 * they are not consumed here. Since this is just an error
2258 * condition, no extra code is added here to make the error
2259 * recoverable for non-arrays and maps like strings. */
2260 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002261 goto Done;
2262 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002263
Laurence Lundblade59289e52019-12-30 13:44:37 -08002264 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
2265
2266Done:
Laurence Lundbladec7114722020-08-13 05:11:40 -07002267 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002268}
2269
2270
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002271/**
2272 * @brief Convert the days epoch date.
2273 *
2274 * pDecodedItem[in,out] The data item to convert.
2275 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002276 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2277 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2278 * floating-point date disabled.
2279 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2280 * all floating-point disabled.
2281 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2282 * error decoding date.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002283 *
2284 * This is much simpler than the other epoch date format because
2285 * floating-porint is not allowed. This is mostly a simple type check.
2286 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002287static QCBORError
2288QCBOR_Private_DecodeDaysEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002289{
2290 QCBORError uReturn = QCBOR_SUCCESS;
2291
2292 switch (pDecodedItem->uDataType) {
2293
2294 case QCBOR_TYPE_INT64:
2295 pDecodedItem->val.epochDays = pDecodedItem->val.int64;
2296 break;
2297
2298 case QCBOR_TYPE_UINT64:
2299 /* This only happens for CBOR type 0 > INT64_MAX so it is
2300 * always an overflow.
2301 */
2302 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2303 goto Done;
2304 break;
2305
2306 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002307 /* It's the arrays and maps that are unrecoverable because
2308 * they are not consumed here. Since this is just an error
2309 * condition, no extra code is added here to make the error
2310 * recoverable for non-arrays and maps like strings. */
2311 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002312 goto Done;
2313 break;
2314 }
2315
2316 pDecodedItem->uDataType = QCBOR_TYPE_DAYS_EPOCH;
2317
2318Done:
2319 return uReturn;
2320}
2321
2322
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002323#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade37286c02022-09-03 10:05:02 -07002324
2325/* Forward declaration is necessary for
2326 * QCBORDecode_MantissaAndExponent(). to be able to decode bignum
2327 * tags in the mantissa. If the mantissa is a decimal fraction or big
2328 * float in error, this will result in a recurive call to
2329 * QCBORDecode_MantissaAndExponent(), but the recursion will unwined
2330 * correctly and the correct error is returned.
2331 */
2332static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002333QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2334 QCBORItem *pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002335
2336
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002337/**
2338 * @brief Decode decimal fractions and big floats.
2339 *
2340 * @param[in] pMe The decode context.
2341 * @param[in,out] pDecodedItem On input the array data item that
2342 * holds the mantissa and exponent. On
2343 * output the decoded mantissa and
2344 * exponent.
2345 *
2346 * @returns Decoding errors from getting primitive data items or
2347 * \ref QCBOR_ERR_BAD_EXP_AND_MANTISSA.
2348 *
Laurence Lundblade37286c02022-09-03 10:05:02 -07002349 * When called pDecodedItem must be the array with two members, the
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002350 * exponent and mantissa.
2351 *
2352 * This will fetch and decode the exponent and mantissa and put the
2353 * result back into pDecodedItem.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002354 *
2355 * This does no checking or processing of tag numbers. That is to be
2356 * done by the code that calls this.
2357 *
2358 * This stuffs the type of the mantissa into pDecodedItem with the expectation
2359 * the caller will process it.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002360 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002361static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002362QCBORDecode_Private_ExpMantissa(QCBORDecodeContext *pMe,
2363 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002364{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002365 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002366
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002367 /* --- Make sure it is an array; track nesting level of members --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002368 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002369 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002370 goto Done;
2371 }
2372
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002373 /* A check for pDecodedItem->val.uCount == 2 would work for
Laurence Lundblade37286c02022-09-03 10:05:02 -07002374 * definite-length arrays, but not for indefinite. Instead remember
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002375 * the nesting level the two integers must be at, which is one
2376 * deeper than that of the array.
2377 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002378 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
2379
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002380 /* --- Get the exponent --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002381 QCBORItem exponentItem;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002382 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, &exponentItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002383 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002384 goto Done;
2385 }
2386 if(exponentItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002387 /* Array is empty or a map/array encountered when expecting an int */
2388 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002389 goto Done;
2390 }
2391 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002392 /* Data arriving as an unsigned int < INT64_MAX has been
2393 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2394 * also means that the only data arriving here of type
2395 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2396 * and thus an error that will get handled in the next else.
2397 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002398 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
2399 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002400 /* Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX */
2401 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002402 goto Done;
2403 }
2404
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002405 /* --- Get the mantissa --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002406 QCBORItem mantissaItem;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002407 uReturn = QCBORDecode_Private_GetNextTagContent(pMe, &mantissaItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002408 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002409 goto Done;
2410 }
2411 if(mantissaItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002412 /* Mantissa missing or map/array encountered when expecting number */
2413 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002414 goto Done;
2415 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002416 /* Stuff the mantissa data type into the item to send it up to the
2417 * the next level. */
2418 pDecodedItem->uDataType = mantissaItem.uDataType;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002419 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002420 /* Data arriving as an unsigned int < INT64_MAX has been
2421 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2422 * also means that the only data arriving here of type
2423 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2424 * and thus an error that will get handled in an else below.
2425 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002426 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002427#ifndef QCBOR_DISABLE_TAGS
2428 /* With tags fully disabled a big number mantissa will error out
2429 * in the call to QCBORDecode_GetNextWithTags() because it has
2430 * a tag number.
2431 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07002432 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM ||
2433 mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002434 /* Got a good big num mantissa */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002435 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002436#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002437 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002438 /* Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX */
2439 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002440 goto Done;
2441 }
2442
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002443 /* --- Check that array only has the two numbers --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002444 if(mantissaItem.uNextNestLevel == nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002445 /* Extra items in the decimal fraction / big float */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002446 /* Improvement: this should probably be an unrecoverable error. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002447 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002448 goto Done;
2449 }
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002450 pDecodedItem->uNextNestLevel = mantissaItem.uNextNestLevel;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002451
2452Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002453 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002454}
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002455#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002456
2457
Laurence Lundblade37286c02022-09-03 10:05:02 -07002458#ifndef QCBOR_DISABLE_TAGS
2459
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002460#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002461/**
2462 * @brief Decode the MIME type tag
2463 *
2464 * @param[in,out] pDecodedItem The item to decode.
2465 *
2466 * Handle the text and binary MIME type tags. Slightly too complicated
2467 * f or ProcessTaggedString() because the RFC 7049 MIME type was
2468 * incorreclty text-only.
2469 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002470static QCBORError
2471QCBOR_Private_DecodeMIME(QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002472{
2473 if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) {
2474 pDecodedItem->uDataType = QCBOR_TYPE_MIME;
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07002475 } else if(pDecodedItem->uDataType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002476 pDecodedItem->uDataType = QCBOR_TYPE_BINARY_MIME;
2477 } else {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002478 /* It's the arrays and maps that are unrecoverable because
2479 * they are not consumed here. Since this is just an error
2480 * condition, no extra code is added here to make the error
2481 * recoverable for non-arrays and maps like strings. */
2482 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002483 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002484
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002485 return QCBOR_SUCCESS;
2486}
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002487#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002488
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002489/**
Laurence Lundblade99615302020-11-29 11:19:47 -08002490 * Table of CBOR tags whose content is either a text string or a byte
2491 * string. The table maps the CBOR tag to the QCBOR type. The high-bit
2492 * of uQCBORtype indicates the content should be a byte string rather
2493 * than a text string
2494 */
2495struct StringTagMapEntry {
2496 uint16_t uTagNumber;
2497 uint8_t uQCBORtype;
2498};
2499
2500#define IS_BYTE_STRING_BIT 0x80
2501#define QCBOR_TYPE_MASK ~IS_BYTE_STRING_BIT
2502
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002503static const struct StringTagMapEntry QCBOR_Private_StringTagMap[] = {
Laurence Lundblade99615302020-11-29 11:19:47 -08002504 {CBOR_TAG_DATE_STRING, QCBOR_TYPE_DATE_STRING},
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002505 {CBOR_TAG_DAYS_STRING, QCBOR_TYPE_DAYS_STRING},
Laurence Lundblade99615302020-11-29 11:19:47 -08002506 {CBOR_TAG_POS_BIGNUM, QCBOR_TYPE_POSBIGNUM | IS_BYTE_STRING_BIT},
2507 {CBOR_TAG_NEG_BIGNUM, QCBOR_TYPE_NEGBIGNUM | IS_BYTE_STRING_BIT},
2508 {CBOR_TAG_CBOR, QBCOR_TYPE_WRAPPED_CBOR | IS_BYTE_STRING_BIT},
2509 {CBOR_TAG_URI, QCBOR_TYPE_URI},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002510#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002511 {CBOR_TAG_B64URL, QCBOR_TYPE_BASE64URL},
2512 {CBOR_TAG_B64, QCBOR_TYPE_BASE64},
2513 {CBOR_TAG_REGEX, QCBOR_TYPE_REGEX},
2514 {CBOR_TAG_BIN_UUID, QCBOR_TYPE_UUID | IS_BYTE_STRING_BIT},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002515#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade99615302020-11-29 11:19:47 -08002516 {CBOR_TAG_CBOR_SEQUENCE, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE | IS_BYTE_STRING_BIT},
2517 {CBOR_TAG_INVALID16, QCBOR_TYPE_NONE}
2518};
2519
2520
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002521/**
2522 * @brief Process standard CBOR tags whose content is a string
2523 *
2524 * @param[in] uTag The tag.
2525 * @param[in,out] pDecodedItem The data item.
2526 *
2527 * @returns This returns QCBOR_SUCCESS if the tag was procssed,
2528 * \ref QCBOR_ERR_UNSUPPORTED if the tag was not processed and
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002529 * \ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT if the content type was wrong for the tag.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002530 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002531 * Process the CBOR tags that whose content is a byte string or a text
2532 * string and for which the string is just passed on to the caller.
2533 *
2534 * This maps the CBOR tag to the QCBOR type and checks the content
2535 * type. Nothing more. It may not be the most important
Laurence Lundbladec02e13e2020-12-06 05:45:41 -08002536 * functionality, but it part of implementing as much of RFC 8949 as
Laurence Lundblade99615302020-11-29 11:19:47 -08002537 * possible.
Laurence Lundblade99615302020-11-29 11:19:47 -08002538 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002539static QCBORError
2540QCBOR_Private_ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002541{
Laurence Lundblade99615302020-11-29 11:19:47 -08002542 /* This only works on tags that were not mapped; no need for other yet */
2543 if(uTag > QCBOR_LAST_UNMAPPED_TAG) {
2544 return QCBOR_ERR_UNSUPPORTED;
2545 }
2546
2547 unsigned uIndex;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002548 for(uIndex = 0; QCBOR_Private_StringTagMap[uIndex].uTagNumber != CBOR_TAG_INVALID16; uIndex++) {
2549 if(QCBOR_Private_StringTagMap[uIndex].uTagNumber == uTag) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002550 break;
2551 }
2552 }
2553
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002554 const uint8_t uQCBORType = QCBOR_Private_StringTagMap[uIndex].uQCBORtype;
Laurence Lundblade99615302020-11-29 11:19:47 -08002555 if(uQCBORType == QCBOR_TYPE_NONE) {
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002556 /* repurpose this error to mean not handled here */
Laurence Lundblade99615302020-11-29 11:19:47 -08002557 return QCBOR_ERR_UNSUPPORTED;
2558 }
2559
2560 uint8_t uExpectedType = QCBOR_TYPE_TEXT_STRING;
2561 if(uQCBORType & IS_BYTE_STRING_BIT) {
2562 uExpectedType = QCBOR_TYPE_BYTE_STRING;
2563 }
2564
2565 if(pDecodedItem->uDataType != uExpectedType) {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002566 /* It's the arrays and maps that are unrecoverable because
2567 * they are not consumed here. Since this is just an error
2568 * condition, no extra code is added here to make the error
2569 * recoverable for non-arrays and maps like strings. */
2570 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002571 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002572
Laurence Lundblade99615302020-11-29 11:19:47 -08002573 pDecodedItem->uDataType = (uint8_t)(uQCBORType & QCBOR_TYPE_MASK);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002574 return QCBOR_SUCCESS;
2575}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002576#endif /* QCBOR_DISABLE_TAGS */
2577
2578
2579#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002580/**
2581 * @brief Figures out data type for exponent mantissa tags.
2582 *
2583 * @param[in] uTagToProcess Either @ref CBOR_TAG_DECIMAL_FRACTION or
2584 * @ref CBOR_TAG_BIG_FLOAT.
2585 * @param[in] pDecodedItem Item being decoded.
2586 *
2587 * @returns One of the 6 values between \ref QCBOR_TYPE_DECIMAL_FRACTION
2588 * and @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM.
2589 *
2590 * Does mapping between a CBOR tag number and a QCBOR type. with a
2591 * little bit of logic and arithmatic.
2592 *
2593 * Used in serveral contexts. Does the work where sometimes the data
2594 * item is explicitly tagged and sometimes not.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002595 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002596static uint8_t
2597QCBOR_Private_ExpMantissaDataType(const uint16_t uTagToProcess,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002598 const QCBORItem *pDecodedItem)
Laurence Lundblade37286c02022-09-03 10:05:02 -07002599{
2600 uint8_t uBase = uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ?
2601 QCBOR_TYPE_DECIMAL_FRACTION :
2602 QCBOR_TYPE_BIGFLOAT;
2603 if(pDecodedItem->uDataType != QCBOR_TYPE_INT64) {
2604 uBase = (uint8_t)(uBase + pDecodedItem->uDataType - QCBOR_TYPE_POSBIGNUM + 1);
2605 }
2606 return uBase;
2607}
2608#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002609
2610
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002611/**
2612 * @brief Decode tag content for select tags (decoding layer 1).
2613 *
2614 * @param[in] pMe The decode context.
2615 * @param[out] pDecodedItem The decoded item.
2616 *
2617 * @return Decoding error code.
2618 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002619 * CBOR tag numbers for the item were decoded in GetNext_TaggedItem(),
2620 * but the whole tag was not decoded. Here, the whole tags (tag number
2621 * and tag content) that are supported by QCBOR are decoded. This is a
2622 * quick pass through for items that are not tags.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002623 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002624static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002625QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2626 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002627{
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002628 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002629
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002630 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pDecodedItem);
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002631 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002632 goto Done;
2633 }
2634
Laurence Lundblade37286c02022-09-03 10:05:02 -07002635#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002636 /* When there are no tag numbers for the item, this exits first
2637 * thing and effectively does nothing.
2638 *
2639 * This loops over all the tag numbers accumulated for this item
2640 * trying to decode and interpret them. This stops at the end of
2641 * the list or at the first tag number that can't be interpreted by
2642 * this code. This is effectively a recursive processing of the
2643 * tags number list that handles nested tags.
2644 */
2645 while(1) {
2646 /* Don't bother to unmap tags via QCBORITem.uTags since this
2647 * code only works on tags less than QCBOR_LAST_UNMAPPED_TAG.
2648 */
2649 const uint16_t uTagToProcess = pDecodedItem->uTags[0];
Laurence Lundblade59289e52019-12-30 13:44:37 -08002650
Laurence Lundblade99615302020-11-29 11:19:47 -08002651 if(uTagToProcess == CBOR_TAG_INVALID16) {
2652 /* Hit the end of the tag list. A successful exit. */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002653 break;
2654
Laurence Lundblade99615302020-11-29 11:19:47 -08002655 } else if(uTagToProcess == CBOR_TAG_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002656 uReturn = QCBOR_Private_DecodeDateEpoch(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002657
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002658 } else if(uTagToProcess == CBOR_TAG_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002659 uReturn = QCBOR_Private_DecodeDaysEpoch(pDecodedItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002660
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002661#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade99615302020-11-29 11:19:47 -08002662 } else if(uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ||
2663 uTagToProcess == CBOR_TAG_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002664 uReturn = QCBORDecode_Private_ExpMantissa(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002665 /* --- Which is it, decimal fraction or a bigfloat? --- */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002666 pDecodedItem->uDataType = QCBOR_Private_ExpMantissaDataType(uTagToProcess, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002667
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002668#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002669#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002670 } else if(uTagToProcess == CBOR_TAG_MIME ||
2671 uTagToProcess == CBOR_TAG_BINARY_MIME) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002672 uReturn = QCBOR_Private_DecodeMIME(pDecodedItem);
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002673#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002674
Laurence Lundblade99615302020-11-29 11:19:47 -08002675 } else {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002676 /* See if it is a passthrough byte/text string tag; process if so */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002677 uReturn = QCBOR_Private_ProcessTaggedString(pDecodedItem->uTags[0], pDecodedItem);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002678
Laurence Lundblade99615302020-11-29 11:19:47 -08002679 if(uReturn == QCBOR_ERR_UNSUPPORTED) {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002680 /* It wasn't a passthrough byte/text string tag so it is
Laurence Lundblade99615302020-11-29 11:19:47 -08002681 * an unknown tag. This is the exit from the loop on the
2682 * first unknown tag. It is a successful exit.
2683 */
2684 uReturn = QCBOR_SUCCESS;
2685 break;
2686 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002687 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002688
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002689 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002690 /* Error exit from the loop */
2691 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002692 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002693
2694 /* A tag was successfully processed, shift it out of the list of
2695 * tags returned. This is the loop increment.
2696 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002697 QCBOR_Private_ShiftTags(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002698 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002699#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002700
2701Done:
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002702 return uReturn;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002703}
2704
2705
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002706/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002707 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002708 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002709QCBORError
2710QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2711{
2712 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002713 uErr = QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002714 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002715 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2716 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
2717 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002718 return uErr;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002719}
2720
2721
2722/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002723 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08002724 */
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002725QCBORError
2726QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2727{
2728 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2729 const UsefulInputBuf Save = pMe->InBuf;
2730
2731 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
2732
2733 pMe->nesting = SaveNesting;
2734 pMe->InBuf = Save;
2735
2736 return uErr;
2737}
2738
2739
2740/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002741 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002742 */
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002743void
2744QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2745{
2746 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002747 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2748 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002749 return;
2750 }
2751
2752 pMe->uLastError = (uint8_t)QCBORDecode_PeekNext(pMe, pDecodedItem);
2753}
2754
2755
2756/*
2757 * Public function, see header qcbor/qcbor_decode.h file
2758 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002759void
2760QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002761{
2762 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002763 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2764 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002765 return;
2766 }
2767
2768 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem);
2769}
2770
2771
2772/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002773 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002774 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002775QCBORError
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002776QCBORDecode_GetNextWithTags(QCBORDecodeContext *pMe,
2777 QCBORItem *pDecodedItem,
2778 QCBORTagListOut *pTags)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002779{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002780#ifndef QCBOR_DISABLE_TAGS
2781
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002782 QCBORError uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002783
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002784 uReturn = QCBORDecode_GetNext(pMe, pDecodedItem);
2785 if(uReturn != QCBOR_SUCCESS) {
2786 return uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002787 }
2788
2789 if(pTags != NULL) {
2790 pTags->uNumUsed = 0;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002791 /* Reverse the order because pTags is reverse of QCBORItem.uTags. */
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002792 for(int nTagIndex = QCBOR_MAX_TAGS_PER_ITEM-1; nTagIndex >=0; nTagIndex--) {
2793 if(pDecodedItem->uTags[nTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07002794 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002795 }
2796 if(pTags->uNumUsed >= pTags->uNumAllocated) {
2797 return QCBOR_ERR_TOO_MANY_TAGS;
2798 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002799 pTags->puTags[pTags->uNumUsed] = QCBORDecode_Private_UnMapTagNumber(pMe,pDecodedItem->uTags[nTagIndex]);
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002800 pTags->uNumUsed++;
2801 }
2802 }
2803
2804 return QCBOR_SUCCESS;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002805
2806#else /* QCBOR_DISABLE_TAGS */
2807 (void)pMe;
2808 (void)pDecodedItem;
2809 (void)pTags;
2810 return QCBOR_ERR_TAGS_DISABLED;
2811#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002812}
2813
2814
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002815/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002816 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05302817 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002818bool
2819QCBORDecode_IsTagged(QCBORDecodeContext *pMe,
2820 const QCBORItem *pItem,
2821 uint64_t uTag)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002822{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002823#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002824 for(unsigned uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) {
2825 if(pItem->uTags[uTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002826 break;
2827 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002828 if(QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uTagIndex]) == uTag) {
Laurence Lundbladef71e1622020-08-06 18:52:13 -07002829 return true;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002830 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002831 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002832#else /* QCBOR_TAGS_DISABLED */
2833 (void)pMe;
2834 (void)pItem;
2835 (void)uTag;
2836#endif /* QCBOR_TAGS_DISABLED */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002837
Laurence Lundbladef71e1622020-08-06 18:52:13 -07002838 return false;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002839}
2840
2841
2842/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002843 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002844 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002845QCBORError
2846QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002847{
Laurence Lundblade87495732021-02-26 10:05:55 -07002848 if(puConsumed != NULL) {
2849 *puConsumed = pMe->InBuf.cursor;
2850 }
2851
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002852 QCBORError uReturn = pMe->uLastError;
Laurence Lundblade085d7952020-07-24 10:26:30 -07002853
2854 if(uReturn != QCBOR_SUCCESS) {
2855 goto Done;
2856 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002857
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002858 /* Error out if all the maps/arrays are not closed out */
2859 if(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002860 uReturn = QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002861 goto Done;
2862 }
2863
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002864 /* Error out if not all the bytes are consumed */
2865 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf))) {
Laurence Lundblade085d7952020-07-24 10:26:30 -07002866 uReturn = QCBOR_ERR_EXTRA_BYTES;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002867 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002868
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002869Done:
Laurence Lundblade87495732021-02-26 10:05:55 -07002870 return uReturn;
2871}
2872
2873
2874/*
2875 * Public function, see header qcbor/qcbor_decode.h file
2876 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002877QCBORError
2878QCBORDecode_Finish(QCBORDecodeContext *pMe)
Laurence Lundblade87495732021-02-26 10:05:55 -07002879{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002880#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002881 /* Call the destructor for the string allocator if there is one.
2882 * Always called, even if there are errors; always have to clean up.
2883 */
2884 StringAllocator_Destruct(&(pMe->StringAllocator));
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002885#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002886
Laurence Lundblade87495732021-02-26 10:05:55 -07002887 return QCBORDecode_PartialFinish(pMe, NULL);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002888}
2889
2890
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002891/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002892 * Public function, see header qcbor/qcbor_decode.h file
2893 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002894uint64_t
2895QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
2896 const QCBORItem *pItem,
2897 uint32_t uIndex)
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002898{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002899#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002900 if(pItem->uDataType == QCBOR_TYPE_NONE) {
2901 return CBOR_TAG_INVALID64;
2902 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002903 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2904 return CBOR_TAG_INVALID64;
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002905 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002906 return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uIndex]);
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002907 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002908#else /* QCBOR_DISABLE_TAGS */
2909 (void)pMe;
2910 (void)pItem;
2911 (void)uIndex;
2912
2913 return CBOR_TAG_INVALID64;
2914#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002915}
2916
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002917
Laurence Lundblade9b334962020-08-27 10:55:53 -07002918/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002919 * Public function, see header qcbor/qcbor_decode.h file
2920 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002921uint64_t
2922QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe,
2923 uint32_t uIndex)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002924{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002925#ifndef QCBOR_DISABLE_TAGS
2926
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002927 if(pMe->uLastError != QCBOR_SUCCESS) {
2928 return CBOR_TAG_INVALID64;
2929 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002930 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2931 return CBOR_TAG_INVALID64;
2932 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002933 return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->uLastTags[uIndex]);
Laurence Lundblade9b334962020-08-27 10:55:53 -07002934 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002935#else /* QCBOR_DISABLE_TAGS */
2936 (void)pMe;
2937 (void)uIndex;
2938
2939 return CBOR_TAG_INVALID64;
2940#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07002941}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002942
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002943
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002944
2945
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002946#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladef6531662018-12-04 10:42:22 +09002947
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002948/* ===========================================================================
2949 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002950
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002951 This implements a simple sting allocator for indefinite-length
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002952 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
2953 implements the function type QCBORStringAllocate and allows easy
2954 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09002955
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002956 This particular allocator is built-in for convenience. The caller
2957 can implement their own. All of this following code will get
2958 dead-stripped if QCBORDecode_SetMemPool() is not called.
2959
2960 This is a very primitive memory allocator. It does not track
2961 individual allocations, only a high-water mark. A free or
2962 reallocation must be of the last chunk allocated.
2963
2964 The size of the pool and offset to free memory are packed into the
2965 first 8 bytes of the memory pool so we don't have to keep them in
2966 the decode context. Since the address of the pool may not be
2967 aligned, they have to be packed and unpacked as if they were
2968 serialized data of the wire or such.
2969
2970 The sizes packed in are uint32_t to be the same on all CPU types
2971 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08002972 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002973
2974
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002975static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08002976MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002977{
2978 // Use of UsefulInputBuf is overkill, but it is convenient.
2979 UsefulInputBuf UIB;
2980
Laurence Lundbladeee851742020-01-08 08:37:05 -08002981 // Just assume the size here. It was checked during SetUp so
2982 // the assumption is safe.
Laurence Lundblade93d89472020-10-03 22:30:50 -07002983 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem,QCBOR_DECODE_MIN_MEM_POOL_SIZE});
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002984 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
2985 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
2986 return UsefulInputBuf_GetError(&UIB);
2987}
2988
2989
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002990static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08002991MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002992{
2993 // Use of UsefulOutBuf is overkill, but convenient. The
2994 // length check performed here is useful.
2995 UsefulOutBuf UOB;
2996
2997 UsefulOutBuf_Init(&UOB, Pool);
2998 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
2999 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
3000 return UsefulOutBuf_GetError(&UOB);
3001}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003002
3003
3004/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003005 Internal function for an allocation, reallocation free and destuct.
3006
3007 Having only one function rather than one each per mode saves space in
3008 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003009
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003010 Code Reviewers: THIS FUNCTION DOES POINTER MATH
3011 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08003012static UsefulBuf
3013MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003014{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003015 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003016
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003017 uint32_t uPoolSize;
3018 uint32_t uFreeOffset;
3019
3020 if(uNewSize > UINT32_MAX) {
3021 // This allocator is only good up to 4GB. This check should
3022 // optimize out if sizeof(size_t) == sizeof(uint32_t)
3023 goto Done;
3024 }
3025 const uint32_t uNewSize32 = (uint32_t)uNewSize;
3026
3027 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
3028 goto Done;
3029 }
3030
3031 if(uNewSize) {
3032 if(pMem) {
3033 // REALLOCATION MODE
3034 // Calculate pointer to the end of the memory pool. It is
3035 // assumed that pPool + uPoolSize won't wrap around by
3036 // assuming the caller won't pass a pool buffer in that is
3037 // not in legitimate memory space.
3038 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
3039
3040 // Check that the pointer for reallocation is in the range of the
3041 // pool. This also makes sure that pointer math further down
3042 // doesn't wrap under or over.
3043 if(pMem >= pPool && pMem < pPoolEnd) {
3044 // Offset to start of chunk for reallocation. This won't
3045 // wrap under because of check that pMem >= pPool. Cast
3046 // is safe because the pool is always less than UINT32_MAX
3047 // because of check in QCBORDecode_SetMemPool().
3048 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3049
3050 // Check to see if the allocation will fit. uPoolSize -
3051 // uMemOffset will not wrap under because of check that
3052 // pMem is in the range of the uPoolSize by check above.
3053 if(uNewSize <= uPoolSize - uMemOffset) {
3054 ReturnValue.ptr = pMem;
3055 ReturnValue.len = uNewSize;
3056
3057 // Addition won't wrap around over because uNewSize was
3058 // checked to be sure it is less than the pool size.
3059 uFreeOffset = uMemOffset + uNewSize32;
3060 }
3061 }
3062 } else {
3063 // ALLOCATION MODE
3064 // uPoolSize - uFreeOffset will not underflow because this
3065 // pool implementation makes sure uFreeOffset is always
3066 // smaller than uPoolSize through this check here and
3067 // reallocation case.
3068 if(uNewSize <= uPoolSize - uFreeOffset) {
3069 ReturnValue.len = uNewSize;
3070 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08003071 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003072 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003073 }
3074 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003075 if(pMem) {
3076 // FREE MODE
3077 // Cast is safe because of limit on pool size in
3078 // QCBORDecode_SetMemPool()
3079 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3080 } else {
3081 // DESTRUCT MODE
3082 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003083 }
3084 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003085
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003086 UsefulBuf Pool = {pPool, uPoolSize};
3087 MemPool_Pack(Pool, uFreeOffset);
3088
3089Done:
3090 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003091}
3092
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003093
Laurence Lundbladef6531662018-12-04 10:42:22 +09003094/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003095 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09003096 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003097QCBORError
3098QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
3099 UsefulBuf Pool,
3100 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003101{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003102 // The pool size and free mem offset are packed into the beginning
Dave Thaler93c01182022-08-06 15:08:35 -04003103 // of the pool memory. This compile time check makes sure the
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003104 // constant in the header is correct. This check should optimize
3105 // down to nothing.
Dave Thaler93c01182022-08-06 15:08:35 -04003106#ifdef _MSC_VER
3107#pragma warning(push)
3108#pragma warning(disable:4127) // conditional expression is constant
3109#endif
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003110 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003111 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003112 }
Dave Thaler93c01182022-08-06 15:08:35 -04003113#ifdef _MSC_VER
3114#pragma warning(pop)
3115#endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003116
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003117 // The pool size and free offset packed in to the beginning of pool
3118 // memory are only 32-bits. This check will optimize out on 32-bit
3119 // machines.
3120 if(Pool.len > UINT32_MAX) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003121 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003122 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003123
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003124 // This checks that the pool buffer given is big enough.
3125 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003126 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003127 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003128
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003129 QCBORDecode_SetUpAllocator(pMe, MemPool_Function, Pool.ptr, bAllStrings);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003130
Laurence Lundblade30816f22018-11-10 13:40:22 +07003131 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003132}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003133#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003134
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003135
3136
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003137static void
3138QCBORDecode_Private_CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07003139{
Laurence Lundblade37286c02022-09-03 10:05:02 -07003140#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade9b334962020-08-27 10:55:53 -07003141 memcpy(pMe->uLastTags, pItem->uTags, sizeof(pItem->uTags));
Laurence Lundblade37286c02022-09-03 10:05:02 -07003142#else
3143 (void)pMe;
3144 (void)pItem;
3145#endif
Laurence Lundblade9b334962020-08-27 10:55:53 -07003146}
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003147
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003148
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003149/**
3150 * @brief Consume an entire map or array including its contents.
3151 *
3152 * @param[in] pMe The decoder context.
3153 * @param[in] pItemToConsume The array/map whose contents are to be
3154 * consumed.
3155 * @param[out] puNextNestLevel The next nesting level after the item was
3156 * fully consumed.
3157 *
3158 * This may be called when @c pItemToConsume is not an array or
3159 * map. In that case, this is just a pass through for @c puNextNestLevel
3160 * since there is nothing to do.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003161 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003162static QCBORError
3163QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
3164 const QCBORItem *pItemToConsume,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003165 bool *pbBreak,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003166 uint8_t *puNextNestLevel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003167{
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003168 QCBORError uReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003169 QCBORItem Item;
Laurence Lundblade9b334962020-08-27 10:55:53 -07003170
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003171 /* If it is a map or array, this will tell if it is empty. */
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003172 const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel);
3173
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003174 if(QCBORItem_IsMapOrArray(*pItemToConsume) && !bIsEmpty) {
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003175 /* There is only real work to do for non-empty maps and arrays */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003176
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003177 /* This works for definite- and indefinite-length maps and
3178 * arrays by using the nesting level
Laurence Lundblade1341c592020-04-11 14:19:05 -07003179 */
3180 do {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003181 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pbBreak, &Item);
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003182 if(QCBORDecode_IsUnrecoverableError(uReturn) ||
3183 uReturn == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003184 goto Done;
3185 }
3186 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003187
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003188 *puNextNestLevel = Item.uNextNestLevel;
3189
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003190 uReturn = QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003191
Laurence Lundblade1341c592020-04-11 14:19:05 -07003192 } else {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003193 /* pItemToConsume is not a map or array. Just pass the nesting
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003194 * level through. */
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003195 *puNextNestLevel = pItemToConsume->uNextNestLevel;
3196
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003197 uReturn = QCBOR_SUCCESS;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003198 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003199
3200Done:
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003201 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003202}
3203
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003204
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003205/*
3206 * Public function, see header qcbor/qcbor_decode.h file
3207 */
3208void
3209QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003210{
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003211 QCBORDecode_VGetNext(pMe, pDecodedItem);
3212
3213 if(pMe->uLastError == QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003214 pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL,
Máté Tóth-Pálc6d59682021-05-26 18:55:30 +02003215 &pDecodedItem->uNextNestLevel);
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003216 }
3217}
3218
3219
Laurence Lundblade11654912024-05-09 11:49:24 -07003220/*
3221 * Public function, see header qcbor/qcbor_decode.h file
3222 */
3223uint32_t
3224QCBORDecode_Tell(QCBORDecodeContext *pMe)
3225{
3226 size_t uCursorOffset;
3227
3228 if(pMe->uLastError != QCBOR_SUCCESS) {
3229 return UINT32_MAX;
3230 }
3231
3232 uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
3233
3234 if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
3235 return UINT32_MAX;
3236 } else {
3237 /* Cast is safe because decoder input size is restricted. */
3238 return (uint32_t)uCursorOffset;
3239 }
3240}
3241
3242
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003243/**
3244 * @brief Rewind cursor to start as if map or array were just entered.
3245 *
3246 * @param[in] pMe The decoding context
3247 *
3248 * This affects the nesting tracking and the UsefulInputBuf.
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003249 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003250static void
3251QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003252{
3253 /* Reset nesting tracking to the deepest bounded level */
3254 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3255
3256 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3257
3258 /* Reposition traversal cursor to the start of the map/array */
3259 UsefulInputBuf_Seek(&(pMe->InBuf),
3260 DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
3261}
3262
3263
3264/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003265 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003266 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003267void
3268QCBORDecode_Rewind(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003269{
3270 if(pMe->nesting.pCurrentBounded != NULL) {
3271 /* In a bounded map, array or bstr-wrapped CBOR */
3272
3273 if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
3274 /* In bstr-wrapped CBOR. */
3275
3276 /* Reposition traversal cursor to start of wrapping byte string */
3277 UsefulInputBuf_Seek(&(pMe->InBuf),
3278 pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
3279 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3280
3281 } else {
3282 /* In a map or array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003283 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003284 }
3285
3286 } else {
3287 /* Not in anything bounded */
3288
3289 /* Reposition traversal cursor to the start of input CBOR */
3290 UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
3291
3292 /* Reset nesting tracking to beginning of input. */
3293 DecodeNesting_Init(&(pMe->nesting));
3294 }
3295
3296 pMe->uLastError = QCBOR_SUCCESS;
3297}
3298
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003299
Laurence Lundblade9b334962020-08-27 10:55:53 -07003300
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003301
3302
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003303typedef struct {
3304 void *pCBContext;
3305 QCBORItemCallback pfCallback;
3306} MapSearchCallBack;
3307
3308typedef struct {
3309 size_t uStartOffset;
3310 uint16_t uItemCount;
3311} MapSearchInfo;
3312
3313
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003314/**
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003315 * @brief Search a map for a set of items.
3316 *
3317 * @param[in] pMe The decode context to search.
3318 * @param[in,out] pItemArray The items to search for and the items found.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003319 * @param[out] pInfo Several bits of meta-info returned by search.
3320 * @param[in] pCallBack Callback object or @c NULL.
3321 * TODO: fix params
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003322 *
3323 * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map.
3324 *
3325 * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label)
3326 * were found for one of the labels being
3327 * search for. This duplicate detection is
3328 * only performed for items in pItemArray,
3329 * not every item in the map.
3330 *
3331 * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was
3332 * wrong for the matchd label.
3333 *
3334 * @retval Also errors returned by QCBORDecode_GetNext().
3335 *
3336 * On input, \c pItemArray contains a list of labels and data types of
3337 * items to be found.
3338 *
3339 * On output, the fully retrieved items are filled in with values and
3340 * such. The label was matched, so it never changes.
3341 *
3342 * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE.
3343 *
3344 * This also finds the ends of maps and arrays when they are exited.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003345 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003346static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003347QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
3348 QCBORItem *pItemArray,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003349 MapSearchInfo *pInfo,
3350 MapSearchCallBack *pCallBack)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003351{
Laurence Lundbladee6f15112020-07-23 18:44:16 -07003352 QCBORError uReturn;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003353 uint64_t uFoundItemBitMap = 0;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07003354
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003355 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003356 uReturn = pMe->uLastError;
3357 goto Done2;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003358 }
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003359
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003360 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) &&
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003361 pItemArray->uLabelType != QCBOR_TYPE_NONE) {
3362 /* QCBOR_TYPE_NONE as first item indicates just looking
3363 for the end of an array, so don't give error. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003364 uReturn = QCBOR_ERR_MAP_NOT_ENTERED;
3365 goto Done2;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003366 }
3367
Laurence Lundblade085d7952020-07-24 10:26:30 -07003368 if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) {
3369 // It is an empty bounded array or map
3370 if(pItemArray->uLabelType == QCBOR_TYPE_NONE) {
3371 // Just trying to find the end of the map or array
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003372 pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003373 uReturn = QCBOR_SUCCESS;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003374 } else {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003375 // Nothing is ever found in an empty array or map. All items
3376 // are marked as not found below.
Laurence Lundblade085d7952020-07-24 10:26:30 -07003377 uReturn = QCBOR_SUCCESS;
3378 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003379 goto Done2;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003380 }
3381
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003382 QCBORDecodeNesting SaveNesting;
Laurence Lundblade11654912024-05-09 11:49:24 -07003383 size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003384 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3385
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003386 /* Reposition to search from the start of the map / array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003387 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundblade1341c592020-04-11 14:19:05 -07003388
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003389 /*
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003390 Loop over all the items in the map or array. Each item
3391 could be a map or array, but label matching is only at
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003392 the main level. This handles definite- and indefinite-
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003393 length maps and arrays. The only reason this is ever
3394 called on arrays is to find their end position.
3395
3396 This will always run over all items in order to do
3397 duplicate detection.
3398
3399 This will exit with failure if it encounters an
3400 unrecoverable error, but continue on for recoverable
3401 errors.
3402
3403 If a recoverable error occurs on a matched item, then
3404 that error code is returned.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003405 */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07003406 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003407 if(pInfo) {
3408 pInfo->uItemCount = 0;
3409 }
Máté Tóth-Pál2f2aa5f2021-05-17 21:35:09 +02003410 uint8_t uNextNestLevel;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003411 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003412 /* Remember offset of the item because sometimes it has to be returned */
Laurence Lundblade1341c592020-04-11 14:19:05 -07003413 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003414
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003415 /* Get the item */
3416 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003417 QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003418 if(QCBORDecode_IsUnrecoverableError(uResult)) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003419 /* The map/array can't be decoded when unrecoverable errors occur */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003420 uReturn = uResult;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003421 goto Done;
3422 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003423 if(uResult == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003424 /* Unexpected end of map or array. */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003425 uReturn = uResult;
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003426 goto Done;
3427 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003428
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003429 /* See if item has one of the labels that are of interest */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003430 bool bMatched = false;
3431 for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003432 if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003433 /* A label match has been found */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003434 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
3435 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003436 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003437 }
Laurence Lundblade63926052021-03-29 16:05:51 -07003438 if(uResult != QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003439 /* The label matches, but the data item is in error.
3440 * It is OK to have recoverable errors on items that are not
3441 * matched. */
Laurence Lundblade63926052021-03-29 16:05:51 -07003442 uReturn = uResult;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003443 goto Done;
3444 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003445 if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) {
Laurence Lundblade63926052021-03-29 16:05:51 -07003446 /* The data item is not of the type(s) requested */
3447 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003448 goto Done;
3449 }
3450
Laurence Lundblade1341c592020-04-11 14:19:05 -07003451 /* Successful match. Return the item. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003452 pItemArray[nIndex] = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003453 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003454 if(pInfo) {
3455 pInfo->uStartOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003456 }
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003457 bMatched = true;
3458 }
3459 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003460
3461
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003462 if(!bMatched && pCallBack != NULL) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003463 /*
3464 Call the callback on unmatched labels.
3465 (It is tempting to do duplicate detection here, but that would
3466 require dynamic memory allocation because the number of labels
3467 that might be encountered is unbounded.)
3468 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003469 uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item);
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003470 if(uReturn != QCBOR_SUCCESS) {
3471 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003472 }
3473 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003474
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003475 /*
3476 Consume the item whether matched or not. This
3477 does the work of traversing maps and array and
3478 everything in them. In this loop only the
3479 items at the current nesting level are examined
3480 to match the labels.
3481 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003482 uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel);
Laurence Lundbladec7114722020-08-13 05:11:40 -07003483 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003484 goto Done;
3485 }
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003486
3487 if(pInfo) {
3488 pInfo->uItemCount++;
3489 }
3490
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003491 } while (uNextNestLevel >= uMapNestLevel);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003492
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003493 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003494
3495 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003496
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003497 // Check here makes sure that this won't accidentally be
3498 // QCBOR_MAP_OFFSET_CACHE_INVALID which is larger than
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003499 // QCBOR_MAX_DECODE_INPUT_SIZE.
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -08003500 // Cast to uint32_t to possibly address cases where SIZE_MAX < UINT32_MAX
3501 if((uint32_t)uEndOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003502 uReturn = QCBOR_ERR_INPUT_TOO_LARGE;
3503 goto Done;
3504 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003505 /* Cast OK because encoded CBOR is limited to UINT32_MAX */
3506 pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003507
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003508 Done:
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003509 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade11654912024-05-09 11:49:24 -07003510 UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos);
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003511
3512 Done2:
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003513 /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */
Laurence Lundbladec7114722020-08-13 05:11:40 -07003514 for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003515 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003516 pItemArray[i].uDataType = QCBOR_TYPE_NONE;
3517 pItemArray[i].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003518 }
3519 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003520
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003521 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003522}
3523
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003524
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003525/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003526 * Public function, see header qcbor/qcbor_decode.h file
3527 */
3528void
3529QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
3530 int64_t nLabel,
3531 uint8_t uQcborType,
3532 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003533{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003534 if(pMe->uLastError != QCBOR_SUCCESS) {
3535 return;
3536 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003537
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003538 QCBORItem OneItemSeach[2];
3539 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3540 OneItemSeach[0].label.int64 = nLabel;
3541 OneItemSeach[0].uDataType = uQcborType;
3542 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003543
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003544 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003545
3546 *pItem = OneItemSeach[0];
3547
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003548 if(uReturn != QCBOR_SUCCESS) {
3549 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003550 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003551 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003552 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003553 }
3554
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003555 Done:
3556 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003557}
3558
3559
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003560/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003561 * Public function, see header qcbor/qcbor_decode.h file
3562 */
3563void
3564QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
3565 const char *szLabel,
3566 uint8_t uQcborType,
3567 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003568{
Laurence Lundbladeda095972020-06-06 18:35:33 -07003569 if(pMe->uLastError != QCBOR_SUCCESS) {
3570 return;
3571 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003572
Laurence Lundblade78a66132024-06-06 12:19:59 -07003573#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003574 QCBORItem OneItemSeach[2];
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003575 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3576 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3577 OneItemSeach[0].uDataType = uQcborType;
3578 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003579
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003580 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
3581
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003582 if(uReturn != QCBOR_SUCCESS) {
3583 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003584 }
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003585 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003586 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003587 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003588 }
3589
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003590 *pItem = OneItemSeach[0];
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003591Done:
Laurence Lundblade78a66132024-06-06 12:19:59 -07003592
3593#else
Laurence Lundblade9533c482024-06-06 21:41:10 -07003594 (void)pMe;
3595 (void)szLabel;
3596 (void)uQcborType;
3597 (void)pItem;
Laurence Lundblade78a66132024-06-06 12:19:59 -07003598 QCBORError uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
3599#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
3600
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003601 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003602}
3603
3604
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003605
3606/**
3607 * @brief Semi-private. Get pointer, length and item for an array or map.
3608 *
3609 * @param[in] pMe The decode context.
3610 * @param[in] uType CBOR major type, either array/map.
3611 * @param[out] pItem The item for the array/map.
3612 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3613 *
3614 * The next item to be decoded must be a map or array as specified by \c uType.
3615 *
3616 * \c pItem will be filled in with the label and tags of the array or map
3617 * in addition to \c pEncodedCBOR giving the pointer and length of the
3618 * encoded CBOR.
3619 *
3620 * When this is complete, the traversal cursor is at the end of the array or
3621 * map that was retrieved.
3622 */
3623void
3624QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe,
3625 const uint8_t uType,
3626 QCBORItem *pItem,
3627 UsefulBufC *pEncodedCBOR)
3628{
3629 QCBORError uErr;
3630 uint8_t uNestLevel;
3631 size_t uStartingCursor;
3632 size_t uStartOfReturned;
3633 size_t uEndOfReturned;
3634 size_t uTempSaveCursor;
3635 bool bInMap;
3636 QCBORItem LabelItem;
3637 bool EndedByBreak;
3638
3639 uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3640 bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting));
3641
3642 /* Could call GetNext here, but don't need to because this
3643 * is only interested in arrays and maps. */
3644 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem);
3645 if(uErr != QCBOR_SUCCESS) {
3646 pMe->uLastError = (uint8_t)uErr;
3647 return;
3648 }
3649
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003650 uint8_t uItemDataType = pItem->uDataType;
Laurence Lundblade62cae932024-06-03 13:16:17 -07003651#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003652 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
3653 uItemDataType = QCBOR_TYPE_ARRAY;
3654 }
Laurence Lundblade78a66132024-06-06 12:19:59 -07003655#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003656
3657 if(uItemDataType != uType) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003658 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
3659 return;
3660 }
3661
3662 if(bInMap) {
3663 /* If the item is in a map, the start of the array/map
3664 * itself, not the label, must be found. Do this by
3665 * rewinding to the starting position and fetching
3666 * just the label data item. QCBORDecode_Private_GetNextTagNumber()
3667 * doesn't do any of the array/map item counting or nesting
3668 * level tracking. Used here it will just fetech the label
3669 * data item.
3670 *
3671 * Have to save the cursor and put it back to the position
3672 * after the full item once the label as been fetched by
3673 * itself.
3674 */
3675 uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3676 UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor);
3677
3678 /* Item has been fetched once so safe to ignore error */
3679 (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem);
3680
3681 uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3682 UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor);
3683 } else {
3684 uStartOfReturned = uStartingCursor;
3685 }
3686
3687 /* Consume the entire array/map to find the end */
3688 uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel);
3689 if(uErr != QCBOR_SUCCESS) {
3690 pMe->uLastError = (uint8_t)uErr;
3691 goto Done;
3692 }
3693
3694 /* Fill in returned values */
3695 uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3696 if(EndedByBreak) {
3697 /* When ascending nesting levels, a break for the level above
3698 * was consumed. That break is not a part of what is consumed here. */
3699 uEndOfReturned--;
3700 }
3701 pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned);
3702 pEncodedCBOR->len = uEndOfReturned - uStartOfReturned;
3703
3704Done:
3705 return;
3706}
3707
3708
3709/**
3710 * @brief Semi-private. Get pointer, length and item count of an array or map.
3711 *
3712 * @param[in] pMe The decode context.
3713 * @param[in] pTarget The label and type of the array or map to retrieve.
3714 * @param[out] pItem The item for the array/map.
3715 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3716 *
3717 * The next item to be decoded must be a map or array as specified by \c uType.
3718 *
3719 * When this is complete, the traversal cursor is unchanged.
3720 */void
3721QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe,
3722 QCBORItem *pTarget,
3723 QCBORItem *pItem,
3724 UsefulBufC *pEncodedCBOR)
3725{
3726 MapSearchInfo Info;
3727 QCBORDecodeNesting SaveNesting;
3728 size_t uSaveCursor;
3729
3730 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL);
3731 if(pMe->uLastError != QCBOR_SUCCESS) {
3732 return;
3733 }
3734
3735 /* Save the whole position of things so they can be restored.
3736 * so the cursor position is unchanged by this operation, like
3737 * all the other GetXxxxInMap() operations. */
3738 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3739 uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3740
3741 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3742 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
3743 QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR);
3744
3745 UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor);
3746 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
3747}
3748
3749
3750
3751
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003752/**
3753 * @brief Is a QCBOR_TYPE in the type list?
3754 *
3755 * @param[in] uDataType Type to check for.
3756 * @param[in] puTypeList List to check.
3757 *
3758 * @retval QCBOR_SUCCESS If in the list.
3759 * @retval QCBOR_ERR_UNEXPECTED_TYPE Not in the list.
3760 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07003761static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003762QCBOR_Private_CheckTypeList(const int uDataType,
3763 const uint8_t puTypeList[QCBOR_TAGSPEC_NUM_TYPES])
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003764{
3765 for(size_t i = 0; i < QCBOR_TAGSPEC_NUM_TYPES; i++) {
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003766 if(uDataType == puTypeList[i]) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003767 return QCBOR_SUCCESS;
3768 }
3769 }
3770 return QCBOR_ERR_UNEXPECTED_TYPE;
3771}
3772
Laurence Lundblade67257dc2020-07-27 03:33:37 -07003773
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003774/**
Laurence Lundblade37286c02022-09-03 10:05:02 -07003775 * Match a tag/type specification against the type of the item.
3776 *
3777 * @param[in] TagSpec Specification for matching tags.
3778 * @param[in] pItem The item to check.
3779 *
3780 * @retval QCBOR_SUCCESS \c uDataType is allowed by @c TagSpec
3781 * @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec
3782 *
3783 * This checks the item data type of untagged items as well as of
3784 * tagged items against a specification to see if decoding should
3785 * proceed.
3786 *
3787 * This relies on the automatic tag decoding done by QCBOR that turns
3788 * tag numbers into particular QCBOR_TYPEs so there is no actual
3789 * comparsion of tag numbers, just of QCBOR_TYPEs.
3790 *
3791 * This checks the data item type as possibly representing the tag
3792 * number or as the tag content type.
3793 *
3794 * If QCBOR_DISABLE_TAGS is #defined, this primarily checks the item
3795 * data type against the allowed tag content types. It will also error out
3796 * if the caller tries to require a tag because there is no way that can
3797 * ever be fulfilled.
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003798 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07003799static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003800QCBOR_Private_CheckTagRequirement(const QCBOR_Private_TagSpec TagSpec,
3801 const QCBORItem *pItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07003802{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003803 const int nItemType = pItem->uDataType; /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade37286c02022-09-03 10:05:02 -07003804 const int nTagReq = TagSpec.uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
3805
3806#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003807 /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003808 if(!(TagSpec.uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS) &&
3809 pItem->uTags[0] != CBOR_TAG_INVALID16) {
3810 /* There are tags that QCBOR couldn't process on this item and
Laurence Lundblade37286c02022-09-03 10:05:02 -07003811 * the caller has told us there should not be.
3812 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003813 return QCBOR_ERR_UNEXPECTED_TYPE;
3814 }
3815
Laurence Lundblade9b334962020-08-27 10:55:53 -07003816 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
Laurence Lundblade37286c02022-09-03 10:05:02 -07003817 /* Must match the tag number and only the tag */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003818 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003819 }
3820
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003821 QCBORError uReturn = QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003822 if(uReturn == QCBOR_SUCCESS) {
3823 return QCBOR_SUCCESS;
3824 }
3825
3826 if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
3827 /* Must match the content type and only the content type.
Laurence Lundblade37286c02022-09-03 10:05:02 -07003828 * There was no match just above so it is a fail. */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003829 return QCBOR_ERR_UNEXPECTED_TYPE;
3830 }
3831
Laurence Lundblade37286c02022-09-03 10:05:02 -07003832 /* QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG: If here it can match either the tag or the content
3833 * and it hasn't matched the content, so the end
3834 * result is whether it matches the tag. This is
3835 * the tag optional case that the CBOR standard discourages.
3836 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003837
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003838 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003839
Laurence Lundblade37286c02022-09-03 10:05:02 -07003840#else /* QCBOR_DISABLE_TAGS */
3841 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
3842 return QCBOR_ERR_UNEXPECTED_TYPE;
3843 }
3844
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07003845 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade37286c02022-09-03 10:05:02 -07003846
3847#endif /* QCBOR_DISABLE_TAGS */
3848}
Laurence Lundblade9b334962020-08-27 10:55:53 -07003849
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003850
3851/**
3852 * @brief Get an item by label to match a tag specification.
3853 *
3854 * @param[in] pMe The decode context.
3855 * @param[in] nLabel The label to search map for.
3856 * @param[in] TagSpec The tag number specification to match.
3857 * @param[out] pItem The item found.
3858 *
3859 * This finds the item with the given label in currently open
3860 * map. Then checks that its tag number and types matches the tag
3861 * specification. If not, an error is set in the decode context.
3862 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003863static void
3864QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
3865 const int64_t nLabel,
3866 const QCBOR_Private_TagSpec TagSpec,
3867 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003868{
3869 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
3870 if(pMe->uLastError != QCBOR_SUCCESS) {
3871 return;
3872 }
3873
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003874 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003875}
3876
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07003877
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003878/**
3879 * @brief Get an item by label to match a tag specification.
3880 *
3881 * @param[in] pMe The decode context.
3882 * @param[in] szLabel The label to search map for.
3883 * @param[in] TagSpec The tag number specification to match.
3884 * @param[out] pItem The item found.
3885 *
3886 * This finds the item with the given label in currently open
3887 * map. Then checks that its tag number and types matches the tag
3888 * specification. If not, an error is set in the decode context.
3889 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003890static void
3891QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
3892 const char *szLabel,
3893 const QCBOR_Private_TagSpec TagSpec,
3894 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003895{
3896 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
3897 if(pMe->uLastError != QCBOR_SUCCESS) {
3898 return;
3899 }
3900
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003901 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003902}
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] nLabel 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 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003917void
3918QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
3919 const int64_t nLabel,
3920 const QCBOR_Private_TagSpec TagSpec,
3921 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003922{
3923 QCBORItem Item;
3924 QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
3925 if(pMe->uLastError == QCBOR_SUCCESS) {
3926 *pString = Item.val.string;
3927 }
3928}
3929
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003930
3931/**
3932 * @brief Semi-private to get an string by label to match a tag specification.
3933 *
3934 * @param[in] pMe The decode context.
3935 * @param[in] szLabel The label to search map for.
3936 * @param[in] TagSpec The tag number specification to match.
3937 * @param[out] pString The string found.
3938 *
3939 * This finds the string with the given label in currently open
3940 * map. Then checks that its tag number and types matches the tag
3941 * specification. If not, an error is set in the decode context.
3942 */void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003943QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
3944 const char * szLabel,
3945 const QCBOR_Private_TagSpec TagSpec,
3946 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003947{
3948 QCBORItem Item;
3949 QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
3950 if(pMe->uLastError == QCBOR_SUCCESS) {
3951 *pString = Item.val.string;
3952 }
3953}
Laurence Lundblade1341c592020-04-11 14:19:05 -07003954
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003955
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003956/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003957 * Public function, see header qcbor/qcbor_decode.h file
3958 */
3959void
3960QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003961{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003962 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL);
Laurence Lundblade5f53f832020-09-03 12:00:14 -07003963 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003964}
3965
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003966/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003967 * Public function, see header qcbor/qcbor_decode.h file
3968 */
3969void
3970QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe,
3971 QCBORItem *pItemList,
3972 void *pCallbackCtx,
3973 QCBORItemCallback pfCB)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003974{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003975 MapSearchCallBack CallBack;
3976 CallBack.pCBContext = pCallbackCtx;
3977 CallBack.pfCallback = pfCB;
3978
3979 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack);
3980
Laurence Lundblade5f53f832020-09-03 12:00:14 -07003981 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003982}
3983
3984
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08003985/**
3986 * @brief Search for a map/array by label and enter it
3987 *
3988 * @param[in] pMe The decode context.
3989 * @param[in] pSearch The map/array to search for.
3990 *
3991 * @c pSearch is expected to contain one item of type map or array
3992 * with the label specified. The current bounded map will be searched for
3993 * this and if found will be entered.
3994 *
3995 * If the label is not found, or the item found is not a map or array,
3996 * the error state is set.
3997 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003998static void
3999QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07004000{
Laurence Lundblade323f8a92020-09-06 19:43:09 -07004001 // The first item in pSearch is the one that is to be
4002 // entered. It should be the only one filled in. Any other
4003 // will be ignored unless it causes an error.
Laurence Lundblade34691b92020-05-18 22:25:25 -07004004 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07004005 return;
4006 }
4007
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004008 MapSearchInfo Info;
4009 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pSearch, &Info, NULL);
Laurence Lundblade34691b92020-05-18 22:25:25 -07004010 if(pMe->uLastError != QCBOR_SUCCESS) {
4011 return;
4012 }
4013
Laurence Lundblade9b334962020-08-27 10:55:53 -07004014 if(pSearch->uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004015 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004016 return;
4017 }
4018
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004019
4020 /* The map or array was found. Now enter it.
4021 *
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004022 * QCBORDecode_EnterBoundedMapOrArray() used here, requires the
4023 * next item for the pre-order traversal cursor to be the map/array
4024 * found by MapSearch(). The next few lines of code force the
4025 * cursor to that.
4026 *
4027 * There is no need to retain the old cursor because
4028 * QCBORDecode_EnterBoundedMapOrArray() will set it to the
4029 * beginning of the map/array being entered.
4030 *
4031 * The cursor is forced by: 1) setting the input buffer position to
4032 * the item offset found by MapSearch(), 2) setting the map/array
4033 * counter to the total in the map/array, 3) setting the nesting
4034 * level. Setting the map/array counter to the total is not
4035 * strictly correct, but this is OK because this cursor only needs
4036 * to be used to get one item and MapSearch() has already found it
4037 * confirming it exists.
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004038 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004039 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004040
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004041 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
4042
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004043 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07004044
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004045 QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004046}
4047
4048
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004049/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004050 * Public function, see header qcbor/qcbor_decode.h file
4051 */
4052void
4053QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004054{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004055 QCBORItem OneItemSeach[2];
4056 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4057 OneItemSeach[0].label.int64 = nLabel;
4058 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4059 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004060
Laurence Lundblade9b334962020-08-27 10:55:53 -07004061 /* The map to enter was found, now finish off entering it. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004062 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004063}
4064
4065
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004066/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004067 * Public function, see header qcbor/qcbor_decode.h file
4068 */
4069void
4070QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004071{
Laurence Lundblade78a66132024-06-06 12:19:59 -07004072#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004073 QCBORItem OneItemSeach[2];
4074 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4075 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4076 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4077 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004078
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004079 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade78a66132024-06-06 12:19:59 -07004080#else
Laurence Lundblade9533c482024-06-06 21:41:10 -07004081 (void)szLabel;
4082 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade78a66132024-06-06 12:19:59 -07004083#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004084}
4085
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004086/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004087 * Public function, see header qcbor/qcbor_decode.h file
4088 */
4089void
4090QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07004091{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004092 QCBORItem OneItemSeach[2];
4093 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4094 OneItemSeach[0].label.int64 = nLabel;
4095 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4096 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004097
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004098 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07004099}
4100
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004101/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004102 * Public function, see header qcbor/qcbor_decode.h file
4103 */
4104void
4105QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundblade34691b92020-05-18 22:25:25 -07004106{
Laurence Lundblade78a66132024-06-06 12:19:59 -07004107#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004108 QCBORItem OneItemSeach[2];
4109 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4110 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4111 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4112 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004113
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004114 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade78a66132024-06-06 12:19:59 -07004115#else
Laurence Lundblade9533c482024-06-06 21:41:10 -07004116 (void)szLabel;
4117 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade78a66132024-06-06 12:19:59 -07004118#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade1341c592020-04-11 14:19:05 -07004119}
4120
4121
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004122/**
4123 * @brief Semi-private to do the the work for EnterMap() and EnterArray().
4124 *
4125 * @param[in] pMe The decode context
4126 * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY.
4127 * @param[out] pItem The data item for the map or array entered.
4128 *
4129 * The next item in the traversal must be a map or array. This
4130 * consumes that item and does the book keeping to enter the map or
4131 * array.
4132 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004133void
4134QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe,
4135 const uint8_t uType,
4136 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004137{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004138 QCBORError uErr;
4139
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004140 /* Must only be called on maps and arrays. */
Laurence Lundblade34691b92020-05-18 22:25:25 -07004141 if(pMe->uLastError != QCBOR_SUCCESS) {
4142 // Already in error state; do nothing.
4143 return;
4144 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07004145
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004146 /* Get the data item that is the map or array being entered. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004147 QCBORItem Item;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004148 uErr = QCBORDecode_GetNext(pMe, &Item);
4149 if(uErr != QCBOR_SUCCESS) {
4150 goto Done;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07004151 }
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004152
4153 uint8_t uItemDataType = Item.uDataType;
Laurence Lundblade78a66132024-06-06 12:19:59 -07004154
Laurence Lundblade62cae932024-06-03 13:16:17 -07004155#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004156 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) {
4157 uItemDataType = QCBOR_TYPE_ARRAY;
4158 }
Laurence Lundblade78a66132024-06-06 12:19:59 -07004159#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade95606972024-06-07 11:32:12 -07004160
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004161 if(uItemDataType != uType) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004162 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
4163 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004164 }
4165
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004166 QCBORDecode_Private_CopyTags(pMe, &Item);
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004167
4168
Laurence Lundbladef0499502020-08-01 11:55:57 -07004169 const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
Laurence Lundblade085d7952020-07-24 10:26:30 -07004170 if(bIsEmpty) {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004171 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
4172 // Undo decrement done by QCBORDecode_GetNext() so the the
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004173 // the decrement when exiting the map/array works correctly
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004174 pMe->nesting.pCurrent->u.ma.uCountCursor++;
4175 }
Laurence Lundblade93d89472020-10-03 22:30:50 -07004176 // Special case to increment nesting level for zero-length maps
4177 // and arrays entered in bounded mode.
Laurence Lundbladee6f15112020-07-23 18:44:16 -07004178 DecodeNesting_Descend(&(pMe->nesting), uType);
4179 }
4180
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004181 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004182
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004183 uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty,
4184 UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004185
Laurence Lundblade6545d1b2020-10-14 11:13:13 -07004186 if(pItem != NULL) {
4187 *pItem = Item;
4188 }
4189
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004190Done:
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004191 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004192}
4193
Laurence Lundblade02625d42020-06-25 14:41:41 -07004194
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004195/**
4196 * @brief Exit a bounded map, array or bstr (semi-private).
4197 *
4198 * @param[in] pMe Decode context.
4199 * @param[in] uEndOffset The input buffer offset of the end of item exited.
4200 *
4201 * @returns QCBOR_SUCCESS or an error code.
4202 *
4203 * This is the common work for exiting a level that is a bounded map,
4204 * array or bstr wrapped CBOR.
4205 *
4206 * One chunk of work is to set up the pre-order traversal so it is at
4207 * the item just after the bounded map, array or bstr that is being
4208 * exited. This is somewhat complex.
4209 *
4210 * The other work is to level-up the bounded mode to next higest
4211 * bounded mode or the top level if there isn't one.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004212 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004213static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004214QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
4215 const uint32_t uEndOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004216{
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004217 QCBORError uErr;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004218
Laurence Lundblade02625d42020-06-25 14:41:41 -07004219 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004220 * First the pre-order-traversal byte offset is positioned to the
4221 * item just after the bounded mode item that was just consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004222 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004223 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
4224
Laurence Lundblade02625d42020-06-25 14:41:41 -07004225 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004226 * Next, set the current nesting level to one above the bounded
4227 * level that was just exited.
4228 *
4229 * DecodeNesting_CheckBoundedType() is always called before this
4230 * and makes sure pCurrentBounded is valid.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004231 */
4232 DecodeNesting_LevelUpCurrent(&(pMe->nesting));
4233
4234 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004235 * This does the complex work of leveling up the pre-order
4236 * traversal when the end of a map or array or another bounded
4237 * level is reached. It may do nothing, or ascend all the way to
4238 * the top level.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004239 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004240 uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004241 if(uErr != QCBOR_SUCCESS) {
4242 goto Done;
4243 }
4244
Laurence Lundblade02625d42020-06-25 14:41:41 -07004245 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004246 * This makes the next highest bounded level the current bounded
4247 * level. If there is no next highest level, then no bounded mode
4248 * is in effect.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004249 */
4250 DecodeNesting_LevelUpBounded(&(pMe->nesting));
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004251
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004252 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004253
4254Done:
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004255 return uErr;
4256}
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004257
Laurence Lundblade02625d42020-06-25 14:41:41 -07004258
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004259/**
4260 * @brief Get started exiting a map or array (semi-private)
4261 *
4262 * @param[in] pMe The decode context
4263 * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP
4264 *
4265 * This does some work for map and array exiting (but not
4266 * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel()
4267 * is called to do the rest.
4268 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004269void
4270QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe,
4271 const uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004272{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004273 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07004274 /* Already in error state; do nothing. */
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004275 return;
4276 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004277
Laurence Lundblade02625d42020-06-25 14:41:41 -07004278 QCBORError uErr;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004279
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004280 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004281 uErr = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004282 goto Done;
4283 }
4284
Laurence Lundblade02625d42020-06-25 14:41:41 -07004285 /*
4286 Have to set the offset to the end of the map/array
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004287 that is being exited. If there is no cached value,
Laurence Lundblade02625d42020-06-25 14:41:41 -07004288 from previous map search, then do a dummy search.
4289 */
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004290 if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004291 QCBORItem Dummy;
4292 Dummy.uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004293 uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL);
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004294 if(uErr != QCBOR_SUCCESS) {
4295 goto Done;
4296 }
4297 }
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004298
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004299 uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004300
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004301Done:
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004302 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004303}
4304
4305
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004306/**
4307 * @brief The main work of entering some byte-string wrapped CBOR.
4308 *
4309 * @param[in] pMe The decode context.
4310 * @param[in] pItem The byte string item.
4311 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX
4312 * @param[out] pBstr Pointer and length of byte string entered.
4313 *
4314 * This is called once the byte string item has been decoded to do all
4315 * the book keeping work for descending a nesting level into the
4316 * nested CBOR.
4317 *
4318 * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement.
4319 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004320static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004321QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe,
4322 const QCBORItem *pItem,
4323 const uint8_t uTagRequirement,
4324 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004325{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004326 if(pBstr) {
4327 *pBstr = NULLUsefulBufC;
4328 }
4329
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004330 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004331 /* Already in error state; do nothing. */
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004332 return pMe->uLastError;
4333 }
4334
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004335 QCBORError uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004336
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004337 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004338 {
4339 uTagRequirement,
4340 {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE},
4341 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4342 };
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004343
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004344 uError = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004345 if(uError != QCBOR_SUCCESS) {
4346 goto Done;
4347 }
4348
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004349 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004350 /* Reverse the decrement done by GetNext() for the bstr so the
4351 * increment in QCBORDecode_NestLevelAscender() called by
4352 * ExitBoundedLevel() will work right.
4353 */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004354 DecodeNesting_ReverseDecrement(&(pMe->nesting));
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07004355 }
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004356
4357 if(pBstr) {
4358 *pBstr = pItem->val.string;
4359 }
4360
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004361 /* This saves the current length of the UsefulInputBuf and then
4362 * narrows the UsefulInputBuf to start and length of the wrapped
4363 * CBOR that is being entered.
4364 *
4365 * Most of these calls are simple inline accessors so this doesn't
4366 * amount to much code.
4367 */
4368
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004369 const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004370 /* This check makes the cast of uPreviousLength to uint32_t below safe. */
4371 if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004372 uError = QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladef76a2622020-08-06 19:51:03 -07004373 goto Done;
4374 }
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004375
4376 const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
4377 pItem->val.string.ptr);
4378 /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
4379 if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
4380 /* This should never happen because pItem->val.string.ptr should
4381 * always be valid since it was just returned.
4382 */
4383 uError = QCBOR_ERR_INPUT_TOO_LARGE;
4384 goto Done;
4385 }
4386
4387 const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
4388
4389 UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004390 UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004391
Laurence Lundblade02625d42020-06-25 14:41:41 -07004392 uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004393 (uint32_t)uPreviousLength,
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004394 (uint32_t)uStartOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004395Done:
4396 return uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004397}
4398
4399
Laurence Lundblade02625d42020-06-25 14:41:41 -07004400/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004401 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004402 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004403void
4404QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe,
4405 const uint8_t uTagRequirement,
4406 UsefulBufC *pBstr)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004407{
4408 if(pMe->uLastError != QCBOR_SUCCESS) {
4409 // Already in error state; do nothing.
4410 return;
4411 }
4412
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004413 /* Get the data item that is the byte string being entered */
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004414 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004415 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4416 if(pMe->uLastError != QCBOR_SUCCESS) {
4417 return;
4418 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004419
Laurence Lundblade31fddb72024-05-13 13:03:35 -07004420 if(Item.uDataAlloc) {
4421 pMe->uLastError = QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
4422 return;
4423 }
4424
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004425 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4426 &Item,
4427 uTagRequirement,
4428 pBstr);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004429}
4430
4431
Laurence Lundblade02625d42020-06-25 14:41:41 -07004432/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004433 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004434 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004435void
4436QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe,
4437 const int64_t nLabel,
4438 const uint8_t uTagRequirement,
4439 UsefulBufC *pBstr)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004440{
4441 QCBORItem Item;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004442 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004443
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004444 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4445 &Item,
4446 uTagRequirement,
4447 pBstr);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004448}
4449
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004450
Laurence Lundblade02625d42020-06-25 14:41:41 -07004451/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004452 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004453 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004454void
4455QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe,
4456 const char *szLabel,
4457 const uint8_t uTagRequirement,
4458 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004459{
4460 QCBORItem Item;
4461 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4462
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004463 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4464 &Item,
4465 uTagRequirement,
4466 pBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004467}
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004468
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004469
Laurence Lundblade02625d42020-06-25 14:41:41 -07004470/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004471 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004472 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004473void
4474QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004475{
Laurence Lundblade02625d42020-06-25 14:41:41 -07004476 if(pMe->uLastError != QCBOR_SUCCESS) {
4477 // Already in error state; do nothing.
4478 return;
4479 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004480
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004481 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004482 pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade02625d42020-06-25 14:41:41 -07004483 return;
4484 }
4485
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004486 const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
4487
Laurence Lundblade02625d42020-06-25 14:41:41 -07004488 /*
4489 Reset the length of the UsefulInputBuf to what it was before
4490 the bstr wrapped CBOR was entered.
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004491 */
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004492 UsefulInputBuf_SetBufferLength(&(pMe->InBuf),
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004493 DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004494
4495
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004496 QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004497 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004498}
4499
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004500
Laurence Lundbladee6430642020-03-14 21:15:44 -07004501
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004502/**
4503 * @brief Process simple type true and false, a boolean
4504 *
4505 * @param[in] pMe The decode context.
4506 * @param[in] pItem The item with either true or false.
4507 * @param[out] pBool The boolean value output.
4508 *
4509 * Sets the internal error if the item isn't a true or a false. Also
4510 * records any tag numbers as the tag numbers of the last item.
4511 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004512static void
4513QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe,
4514 const QCBORItem *pItem,
4515 bool *pBool)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004516{
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004517 if(pMe->uLastError != QCBOR_SUCCESS) {
4518 /* Already in error state, do nothing */
4519 return;
4520 }
4521
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004522 switch(pItem->uDataType) {
4523 case QCBOR_TYPE_TRUE:
4524 *pBool = true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004525 break;
4526
4527 case QCBOR_TYPE_FALSE:
4528 *pBool = false;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004529 break;
4530
4531 default:
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004532 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004533 break;
4534 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004535 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004536}
Laurence Lundbladee6430642020-03-14 21:15:44 -07004537
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004538
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004539/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004540 * Public function, see header qcbor/qcbor_decode.h file
4541 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004542void
4543QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004544{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004545 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004546 /* Already in error state, do nothing */
Laurence Lundbladee6430642020-03-14 21:15:44 -07004547 return;
4548 }
4549
Laurence Lundbladec4537442020-04-14 18:53:22 -07004550 QCBORItem Item;
4551
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004552 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4553
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004554 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004555}
4556
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004557
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004558/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004559 * Public function, see header qcbor/qcbor_decode.h file
4560 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004561void
4562QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe,
4563 const int64_t nLabel,
4564 bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004565{
4566 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004567 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004568
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004569 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004570}
4571
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004572
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004573/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004574 * Public function, see header qcbor/qcbor_decode.h file
4575 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004576void
4577QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe,
4578 const char *szLabel,
4579 bool *pValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004580{
4581 QCBORItem Item;
4582 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4583
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004584 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004585}
4586
4587
4588
Laurence Lundbladec7114722020-08-13 05:11:40 -07004589
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004590/**
4591 * @brief Common processing for an epoch date.
4592 *
4593 * @param[in] pMe The decode context.
4594 * @param[in] pItem The item with the date.
4595 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4596 * @param[out] pnTime The returned date.
4597 *
4598 * Common processing for the date tag. Mostly make sure the tag
4599 * content is correct and copy forward any further other tag numbers.
4600 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004601static void
4602QCBORDecode_Private_ProcessEpochDate(QCBORDecodeContext *pMe,
4603 QCBORItem *pItem,
4604 const uint8_t uTagRequirement,
4605 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004606{
4607 if(pMe->uLastError != QCBOR_SUCCESS) {
4608 // Already in error state, do nothing
4609 return;
4610 }
4611
4612 QCBORError uErr;
4613
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004614 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladec7114722020-08-13 05:11:40 -07004615 {
4616 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004617 {QCBOR_TYPE_DATE_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4618 {QCBOR_TYPE_INT64, QCBOR_TYPE_DOUBLE, QCBOR_TYPE_FLOAT, QCBOR_TYPE_UINT64}
Laurence Lundbladec7114722020-08-13 05:11:40 -07004619 };
4620
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004621 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004622 if(uErr != QCBOR_SUCCESS) {
4623 goto Done;
4624 }
4625
4626 if(pItem->uDataType != QCBOR_TYPE_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004627 uErr = QCBOR_Private_DecodeDateEpoch(pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004628 if(uErr != QCBOR_SUCCESS) {
4629 goto Done;
4630 }
4631 }
4632
Laurence Lundblade9b334962020-08-27 10:55:53 -07004633 // Save the tags in the last item's tags in the decode context
4634 // for QCBORDecode_GetNthTagOfLast()
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004635 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07004636
Laurence Lundbladec7114722020-08-13 05:11:40 -07004637 *pnTime = pItem->val.epochDate.nSeconds;
4638
4639Done:
4640 pMe->uLastError = (uint8_t)uErr;
4641}
4642
4643
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004644
4645/*
4646 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4647 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004648void
4649QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
4650 uint8_t uTagRequirement,
4651 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004652{
4653 if(pMe->uLastError != QCBOR_SUCCESS) {
4654 // Already in error state, do nothing
4655 return;
4656 }
4657
4658 QCBORItem Item;
4659 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4660
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004661 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004662}
4663
4664
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004665/*
4666 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4667 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07004668void
4669QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
4670 int64_t nLabel,
4671 uint8_t uTagRequirement,
4672 int64_t *pnTime)
4673{
4674 QCBORItem Item;
4675 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004676 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004677}
4678
4679
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004680/*
4681 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4682 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07004683void
4684QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
4685 const char *szLabel,
4686 uint8_t uTagRequirement,
4687 int64_t *pnTime)
4688{
4689 QCBORItem Item;
4690 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004691 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004692}
4693
4694
4695
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004696/**
4697 * @brief Common processing for an epoch date.
4698 *
4699 * @param[in] pMe The decode context.
4700 * @param[in] pItem The item with the date.
4701 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4702 * @param[out] pnDays The returned day count.
4703 *
4704 * Common processing for the RFC 8943 day-count tag. Mostly make sure
4705 * the tag content is correct and copy forward any further other tag
4706 * numbers.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004707 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004708static void
4709QCBORDecode_Private_ProcessEpochDays(QCBORDecodeContext *pMe,
4710 QCBORItem *pItem,
4711 uint8_t uTagRequirement,
4712 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004713{
4714 if(pMe->uLastError != QCBOR_SUCCESS) {
4715 /* Already in error state, do nothing */
4716 return;
4717 }
4718
4719 QCBORError uErr;
4720
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004721 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004722 {
4723 uTagRequirement,
4724 {QCBOR_TYPE_DAYS_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4725 {QCBOR_TYPE_INT64, QCBOR_TYPE_UINT64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4726 };
4727
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004728 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004729 if(uErr != QCBOR_SUCCESS) {
4730 goto Done;
4731 }
4732
4733 if(pItem->uDataType != QCBOR_TYPE_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004734 uErr = QCBOR_Private_DecodeDaysEpoch(pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004735 if(uErr != QCBOR_SUCCESS) {
4736 goto Done;
4737 }
4738 }
4739
4740 /* Save the tags in the last item's tags in the decode context
4741 * for QCBORDecode_GetNthTagOfLast()
4742 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004743 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004744
4745 *pnDays = pItem->val.epochDays;
4746
4747Done:
4748 pMe->uLastError = (uint8_t)uErr;
4749}
4750
4751
4752/*
4753 * Public function, see header qcbor/qcbor_decode.h
4754 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004755void
4756QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe,
4757 uint8_t uTagRequirement,
4758 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004759{
4760 if(pMe->uLastError != QCBOR_SUCCESS) {
4761 /* Already in error state, do nothing */
4762 return;
4763 }
4764
4765 QCBORItem Item;
4766 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4767
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004768 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004769}
4770
4771
4772/*
4773 * Public function, see header qcbor/qcbor_decode.h
4774 */
4775void
4776QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe,
4777 int64_t nLabel,
4778 uint8_t uTagRequirement,
4779 int64_t *pnDays)
4780{
4781 QCBORItem Item;
4782 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004783 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004784}
4785
4786
4787/*
4788 * Public function, see header qcbor/qcbor_decode.h
4789 */
4790void
4791QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe,
4792 const char *szLabel,
4793 uint8_t uTagRequirement,
4794 int64_t *pnDays)
4795{
4796 QCBORItem Item;
4797 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004798 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004799}
4800
4801
4802
Laurence Lundblade37286c02022-09-03 10:05:02 -07004803/*
4804 * @brief Get a string that matches the type/tag specification.
4805 */
4806void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004807QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
4808 const QCBOR_Private_TagSpec TagSpec,
4809 UsefulBufC *pBstr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004810{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004811 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade37286c02022-09-03 10:05:02 -07004812 /* Already in error state, do nothing */
Laurence Lundbladec4537442020-04-14 18:53:22 -07004813 return;
4814 }
4815
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004816 QCBORError uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004817 QCBORItem Item;
4818
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004819 uError = QCBORDecode_GetNext(pMe, &Item);
4820 if(uError != QCBOR_SUCCESS) {
4821 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004822 return;
4823 }
4824
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004825 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004826
4827 if(pMe->uLastError == QCBOR_SUCCESS) {
4828 *pBstr = Item.val.string;
Laurence Lundbladeab40c6f2020-08-28 11:24:58 -07004829 } else {
4830 *pBstr = NULLUsefulBufC;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004831 }
4832}
4833
Laurence Lundbladec4537442020-04-14 18:53:22 -07004834
4835
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004836
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004837/**
4838 * @brief Common processing for a big number tag.
4839 *
4840 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4841 * @param[in] pItem The item with the date.
4842 * @param[out] pValue The returned big number
4843 * @param[out] pbIsNegative The returned sign of the big number.
4844 *
4845 * Common processing for the big number tag. Mostly make sure
4846 * the tag content is correct and copy forward any further other tag
4847 * numbers.
4848 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004849static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004850QCBOR_Private_ProcessBigNum(const uint8_t uTagRequirement,
4851 const QCBORItem *pItem,
4852 UsefulBufC *pValue,
4853 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004854{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004855 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004856 {
4857 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004858 {QCBOR_TYPE_POSBIGNUM, QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4859 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004860 };
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004861
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004862 QCBORError uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004863 if(uErr != QCBOR_SUCCESS) {
4864 return uErr;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004865 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004866
4867 *pValue = pItem->val.string;
4868
4869 if(pItem->uDataType == QCBOR_TYPE_POSBIGNUM) {
4870 *pbIsNegative = false;
4871 } else if(pItem->uDataType == QCBOR_TYPE_NEGBIGNUM) {
4872 *pbIsNegative = true;
4873 }
4874
4875 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004876}
4877
4878
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004879/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004880 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004881 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004882void
4883QCBORDecode_GetBignum(QCBORDecodeContext *pMe,
4884 const uint8_t uTagRequirement,
4885 UsefulBufC *pValue,
4886 bool *pbIsNegative)
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004887{
4888 if(pMe->uLastError != QCBOR_SUCCESS) {
4889 // Already in error state, do nothing
4890 return;
4891 }
4892
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004893 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004894 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
4895 if(uError != QCBOR_SUCCESS) {
4896 pMe->uLastError = (uint8_t)uError;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004897 return;
4898 }
4899
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004900 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4901 &Item,
4902 pValue,
4903 pbIsNegative);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004904}
4905
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004906
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004907/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004908 * Public function, see header qcbor/qcbor_spiffy_decode.h
4909 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004910void
4911QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe,
4912 const int64_t nLabel,
4913 const uint8_t uTagRequirement,
4914 UsefulBufC *pValue,
4915 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004916{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004917 QCBORItem Item;
4918 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004919 if(pMe->uLastError != QCBOR_SUCCESS) {
4920 return;
4921 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004922
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004923 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4924 &Item,
4925 pValue,
4926 pbIsNegative);
Laurence Lundbladec4537442020-04-14 18:53:22 -07004927}
4928
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004929
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004930/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004931 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004932 */
4933void
4934QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe,
4935 const char *szLabel,
4936 const uint8_t uTagRequirement,
4937 UsefulBufC *pValue,
4938 bool *pbIsNegative)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004939{
4940 QCBORItem Item;
4941 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004942 if(pMe->uLastError != QCBOR_SUCCESS) {
4943 return;
4944 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004945
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004946 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4947 &Item,
4948 pValue,
4949 pbIsNegative);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004950}
4951
4952
4953
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004954/**
4955 * @brief Common processing for MIME tag (semi-private).
4956 *
4957 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4958 * @param[in] pItem The item with the date.
4959 * @param[out] pMessage The returned MIME message.
4960 * @param[out] pbIsTag257 If true, binary MIME, if not, text MIME.
4961 *
4962 * Common processing for the MIME tag. Mostly make sure the tag
4963 * content is correct and copy forward any further other tag
4964 * numbers. See QCBORDecode_GetMIMEMessage().
4965 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004966QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004967QCBORDecode_Private_GetMIME(const uint8_t uTagRequirement,
Laurence Lundblade37286c02022-09-03 10:05:02 -07004968 const QCBORItem *pItem,
4969 UsefulBufC *pMessage,
4970 bool *pbIsTag257)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004971{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004972 const QCBOR_Private_TagSpec TagSpecText =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004973 {
4974 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004975 {QCBOR_TYPE_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4976 {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004977 };
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004978 const QCBOR_Private_TagSpec TagSpecBinary =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004979 {
4980 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004981 {QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4982 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004983 };
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004984
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004985 QCBORError uReturn;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004986
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004987 if(QCBOR_Private_CheckTagRequirement(TagSpecText, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004988 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07004989 if(pbIsTag257 != NULL) {
4990 *pbIsTag257 = false;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004991 }
4992 uReturn = QCBOR_SUCCESS;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004993 } else if(QCBOR_Private_CheckTagRequirement(TagSpecBinary, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004994 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07004995 if(pbIsTag257 != NULL) {
4996 *pbIsTag257 = true;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004997 }
4998 uReturn = QCBOR_SUCCESS;
4999
5000 } else {
5001 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
5002 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07005003
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005004 return uReturn;
5005}
5006
Laurence Lundblade93d89472020-10-03 22:30:50 -07005007// Improvement: add methods for wrapped CBOR, a simple alternate
5008// to EnterBstrWrapped
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005009
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005010
5011
5012
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005013#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundbladee6430642020-03-14 21:15:44 -07005014
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005015/**
5016 * @brief Prototype for conversion of exponent and mantissa to unsigned integer.
5017 *
5018 * @param[in] uMantissa The mantissa.
5019 * @param[in] nExponent The exponent.
5020 * @param[out] puResult The resulting integer.
5021 *
5022 * Concrete implementations of this are for exponent base 10 and 2 supporting
5023 * decimal fractions and big floats.
5024 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005025typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005026
5027
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005028/**
5029 * @brief Base 10 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5030 *
5031 * @param[in] uMantissa The unsigned integer mantissa.
5032 * @param[in] nExponent The signed integer exponent.
5033 * @param[out] puResult Place to return the unsigned integer result.
5034 *
5035 * This computes: mantissa * 10 ^^ exponent as for a decimal fraction. The output is a 64-bit
5036 * unsigned integer.
5037 *
5038 * There are many inputs for which the result will not fit in the
5039 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5040 * be returned.
5041 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005042static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005043QCBOR_Private_Exponentitate10(const uint64_t uMantissa,
5044 int64_t nExponent,
5045 uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005046{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005047 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005048
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005049 if(uResult != 0) {
5050 /* This loop will run a maximum of 19 times because
5051 * UINT64_MAX < 10 ^^ 19. More than that will cause
5052 * exit with the overflow error
5053 */
5054 for(; nExponent > 0; nExponent--) {
5055 if(uResult > UINT64_MAX / 10) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005056 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005057 }
5058 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005059 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005060
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005061 for(; nExponent < 0; nExponent++) {
5062 uResult = uResult / 10;
5063 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005064 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005065 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005066 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005067 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005068 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07005069
5070 *puResult = uResult;
5071
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005072 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005073}
5074
5075
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005076/**
5077 * @brief Base 2 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5078 *
5079 * @param[in] uMantissa The unsigned integer mantissa.
5080 * @param[in] nExponent The signed integer exponent.
5081 * @param[out] puResult Place to return the unsigned integer result.
5082 *
5083 * This computes: mantissa * 2 ^^ exponent as for a big float. The
5084 * output is a 64-bit unsigned integer.
5085 *
5086 * There are many inputs for which the result will not fit in the
5087 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5088 * be returned.
5089 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005090static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005091QCBOR_Private_Exponentitate2(const uint64_t uMantissa,
5092 int64_t nExponent,
5093 uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005094{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005095 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005096
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005097 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005098
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005099 /* This loop will run a maximum of 64 times because INT64_MAX <
5100 * 2^31. More than that will cause exit with the overflow error
Laurence Lundbladee6430642020-03-14 21:15:44 -07005101 */
5102 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005103 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005104 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005105 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005106 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005107 nExponent--;
5108 }
5109
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005110 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005111 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005112 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005113 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005114 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005115 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005116 }
5117
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005118 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005119
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005120 return QCBOR_SUCCESS;
5121}
5122
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005123
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005124/**
5125 * @brief Exponentiate a signed mantissa and signed exponent to produce a signed result.
5126 *
5127 * @param[in] nMantissa Signed integer mantissa.
5128 * @param[in] nExponent Signed integer exponent.
5129 * @param[out] pnResult Place to put the signed integer result.
5130 * @param[in] pfExp Exponentiation function.
5131 *
5132 * @returns Error code
5133 *
5134 * \c pfExp performs exponentiation on and unsigned mantissa and
5135 * produces an unsigned result. This converts the mantissa from signed
5136 * and converts the result to signed. The exponentiation function is
5137 * either for base 2 or base 10 (and could be other if needed).
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005138 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005139static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005140QCBOR_Private_ExponentiateNN(const int64_t nMantissa,
5141 const int64_t nExponent,
5142 int64_t *pnResult,
5143 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005144{
5145 uint64_t uResult;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005146 uint64_t uMantissa;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005147
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005148 /* Take the absolute value and put it into an unsigned. */
5149 if(nMantissa >= 0) {
5150 /* Positive case is straightforward */
5151 uMantissa = (uint64_t)nMantissa;
5152 } else if(nMantissa != INT64_MIN) {
5153 /* The common negative case. See next. */
5154 uMantissa = (uint64_t)-nMantissa;
5155 } else {
5156 /* int64_t and uint64_t are always two's complement per the
5157 * C standard (and since QCBOR uses these it only works with
5158 * two's complement, which is pretty much universal these
5159 * days). The range of a negative two's complement integer is
5160 * one more that than a positive, so the simple code above might
5161 * not work all the time because you can't simply negate the
5162 * value INT64_MIN because it can't be represented in an
5163 * int64_t. -INT64_MIN can however be represented in a
5164 * uint64_t. Some compilers seem to recognize this case for the
5165 * above code and put the correct value in uMantissa, however
5166 * they are not required to do this by the C standard. This next
5167 * line does however work for all compilers.
5168 *
5169 * This does assume two's complement where -INT64_MIN ==
5170 * INT64_MAX + 1 (which wouldn't be true for one's complement or
5171 * sign and magnitude (but we know we're using two's complement
5172 * because int64_t requires it)).
5173 *
5174 * See these, particularly the detailed commentary:
5175 * https://stackoverflow.com/questions/54915742/does-c99-mandate-a-int64-t-type-be-available-always
5176 * https://stackoverflow.com/questions/37301078/is-negating-int-min-undefined-behaviour
5177 */
5178 uMantissa = (uint64_t)INT64_MAX+1;
5179 }
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005180
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005181 /* Call the exponentiator passed for either base 2 or base 10.
5182 * Here is where most of the overflow errors are caught. */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005183 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
5184 if(uReturn) {
5185 return uReturn;
5186 }
5187
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005188 /* Convert back to the sign of the original mantissa */
5189 if(nMantissa >= 0) {
5190 if(uResult > INT64_MAX) {
5191 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5192 }
5193 *pnResult = (int64_t)uResult;
5194 } else {
5195 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
5196 * of INT64_MIN. This assumes two's compliment representation
5197 * where INT64_MIN is one increment farther from 0 than
5198 * INT64_MAX. Trying to write -INT64_MIN doesn't work to get
5199 * this because the compiler makes it an int64_t which can't
5200 * represent -INT64_MIN. Also see above.
5201 */
5202 if(uResult > (uint64_t)INT64_MAX+1) {
5203 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5204 }
5205 *pnResult = -(int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005206 }
5207
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005208 return QCBOR_SUCCESS;
5209}
5210
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005211
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005212/**
5213 * @brief Exponentiate an unsigned mantissa and signed exponent to produce an unsigned result.
5214 *
5215 * @param[in] nMantissa Signed integer mantissa.
5216 * @param[in] nExponent Signed integer exponent.
5217 * @param[out] puResult Place to put the signed integer result.
5218 * @param[in] pfExp Exponentiation function.
5219 *
5220 * @returns Error code
5221 *
5222 * \c pfExp performs exponentiation on and unsigned mantissa and
5223 * produces an unsigned result. This errors out if the mantissa
5224 * is negative because the output is unsigned.
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005225 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005226static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005227QCBOR_Private_ExponentitateNU(const int64_t nMantissa,
5228 const int64_t nExponent,
5229 uint64_t *puResult,
5230 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005231{
5232 if(nMantissa < 0) {
5233 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5234 }
5235
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005236 /* Cast to unsigned is OK because of check for negative.
5237 * Cast to unsigned is OK because UINT64_MAX > INT64_MAX.
5238 * Exponentiation is straight forward
5239 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005240 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
5241}
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005242
5243
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005244/**
5245 * @brief Exponentiate an usnigned mantissa and unsigned exponent to produce an unsigned result.
5246 *
5247 * @param[in] uMantissa Unsigned integer mantissa.
5248 * @param[in] nExponent Unsigned integer exponent.
5249 * @param[out] puResult Place to put the unsigned integer result.
5250 * @param[in] pfExp Exponentiation function.
5251 *
5252 * @returns Error code
5253 *
5254 * \c pfExp performs exponentiation on and unsigned mantissa and
5255 * produces an unsigned result so this is just a wrapper that does
5256 * nothing (and is likely inlined).
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005257 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005258static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005259QCBOR_Private_ExponentitateUU(const uint64_t uMantissa,
5260 const int64_t nExponent,
5261 uint64_t *puResult,
5262 fExponentiator pfExp)
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005263{
5264 return (*pfExp)(uMantissa, nExponent, puResult);
5265}
5266
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005267#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005268
5269
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005270
5271
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005272/**
5273 * @brief Convert a CBOR big number to a uint64_t.
5274 *
5275 * @param[in] BigNum Bytes of the big number to convert.
5276 * @param[in] uMax Maximum value allowed for the result.
5277 * @param[out] pResult Place to put the unsigned integer result.
5278 *
5279 * @returns Error code
5280 *
5281 * Many values will overflow because a big num can represent a much
5282 * larger range than uint64_t.
5283 */
5284static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005285QCBOR_Private_ConvertBigNumToUnsigned(const UsefulBufC BigNum,
5286 const uint64_t uMax,
5287 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005288{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005289 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005290
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005291 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005292 const uint8_t *pByte = BigNum.ptr;
5293 size_t uLen = BigNum.len;
5294 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07005295 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005296 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005297 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07005298 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005299 }
5300
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005301 *pResult = uResult;
5302 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005303}
5304
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005305
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005306/**
5307 * @brief Convert a CBOR postive big number to a uint64_t.
5308 *
5309 * @param[in] BigNum Bytes of the big number to convert.
5310 * @param[out] pResult Place to put the unsigned integer result.
5311 *
5312 * @returns Error code
5313 *
5314 * Many values will overflow because a big num can represent a much
5315 * larger range than uint64_t.
5316 */
5317static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005318QCBOR_Private_ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum,
5319 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005320{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005321 return QCBOR_Private_ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005322}
5323
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005324
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005325/**
5326 * @brief Convert a CBOR positive big number to an int64_t.
5327 *
5328 * @param[in] BigNum Bytes of the big number to convert.
5329 * @param[out] pResult Place to put the signed integer result.
5330 *
5331 * @returns Error code
5332 *
5333 * Many values will overflow because a big num can represent a much
5334 * larger range than int64_t.
5335 */
5336static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005337QCBOR_Private_ConvertPositiveBigNumToSigned(const UsefulBufC BigNum,
5338 int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005339{
5340 uint64_t uResult;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005341 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5342 INT64_MAX,
5343 &uResult);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005344 if(uError) {
5345 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005346 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005347 /* Cast is safe because ConvertBigNumToUnsigned limits to INT64_MAX */
Laurence Lundbladee6430642020-03-14 21:15:44 -07005348 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005349 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005350}
5351
5352
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005353/**
5354 * @brief Convert a CBOR negative big number to an int64_t.
5355 *
5356 * @param[in] BigNum Bytes of the big number to convert.
5357 * @param[out] pnResult Place to put the signed integer result.
5358 *
5359 * @returns Error code
5360 *
5361 * Many values will overflow because a big num can represent a much
5362 * larger range than int64_t.
5363 */
5364static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005365QCBOR_Private_ConvertNegativeBigNumToSigned(const UsefulBufC BigNum,
5366 int64_t *pnResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005367{
5368 uint64_t uResult;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005369 /* The negative integer furthest from zero for a C int64_t is
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005370 * INT64_MIN which is expressed as -INT64_MAX - 1. The value of a
5371 * negative number in CBOR is computed as -n - 1 where n is the
5372 * encoded integer, where n is what is in the variable BigNum. When
5373 * converting BigNum to a uint64_t, the maximum value is thus
5374 * INT64_MAX, so that when it -n - 1 is applied to it the result
5375 * will never be further from 0 than INT64_MIN.
5376 *
5377 * -n - 1 <= INT64_MIN.
5378 * -n - 1 <= -INT64_MAX - 1
5379 * n <= INT64_MAX.
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005380 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005381 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5382 INT64_MAX,
5383 &uResult);
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005384 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005385 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005386 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005387
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005388 /* Now apply -n - 1. The cast is safe because
5389 * ConvertBigNumToUnsigned() is limited to INT64_MAX which does fit
5390 * is the largest positive integer that an int64_t can
5391 * represent. */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005392 *pnResult = -(int64_t)uResult - 1;
5393
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005394 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005395}
5396
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005397
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005398
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005399
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005400/**
5401 * @brief Convert integers and floats to an int64_t.
5402 *
5403 * @param[in] pItem The item to convert.
5404 * @param[in] uConvertTypes Bit mask list of conversion options.
5405 * @param[out] pnValue The resulting converted value.
5406 *
5407 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5408 * in uConvertTypes.
5409 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5410 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5411 * or too small.
5412 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005413static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005414QCBOR_Private_ConvertInt64(const QCBORItem *pItem,
5415 const uint32_t uConvertTypes,
5416 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005417{
5418 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005419 case QCBOR_TYPE_FLOAT:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005420 case QCBOR_TYPE_DOUBLE:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005421#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005422 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005423 /* https://pubs.opengroup.org/onlinepubs/009695399/functions/llround.html
5424 http://www.cplusplus.com/reference/cmath/llround/
5425 */
5426 // Not interested in FE_INEXACT
5427 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005428 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5429 *pnValue = llround(pItem->val.dfnum);
5430 } else {
5431 *pnValue = lroundf(pItem->val.fnum);
5432 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005433 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5434 // llround() shouldn't result in divide by zero, but catch
5435 // it here in case it unexpectedly does. Don't try to
5436 // distinguish between the various exceptions because it seems
5437 // they vary by CPU, compiler and OS.
5438 return QCBOR_ERR_FLOAT_EXCEPTION;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005439 }
5440 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005441 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005442 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005443#else
5444 return QCBOR_ERR_HW_FLOAT_DISABLED;
5445#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005446 break;
5447
5448 case QCBOR_TYPE_INT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005449 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005450 *pnValue = pItem->val.int64;
5451 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005452 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005453 }
5454 break;
5455
5456 case QCBOR_TYPE_UINT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005457 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005458 if(pItem->val.uint64 < INT64_MAX) {
5459 *pnValue = pItem->val.int64;
5460 } else {
5461 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5462 }
5463 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005464 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005465 }
5466 break;
5467
5468 default:
5469 return QCBOR_ERR_UNEXPECTED_TYPE;
5470 }
5471 return QCBOR_SUCCESS;
5472}
5473
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005474
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005475/**
5476 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5477 *
5478 * @param[in] pMe The decode context.
5479 * @param[in] uConvertTypes Bit mask list of conversion options.
5480 * @param[out] pnValue Result of the conversion.
5481 * @param[in,out] pItem Temporary space to store Item, returned item.
5482 *
5483 * See QCBORDecode_GetInt64Convert().
5484 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005485void
5486QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pMe,
5487 uint32_t uConvertTypes,
5488 int64_t *pnValue,
5489 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005490{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07005491 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005492 return;
5493 }
5494
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005495 QCBORError uError = QCBORDecode_GetNext(pMe, pItem);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005496 if(uError) {
5497 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005498 return;
5499 }
5500
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005501 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005502 uConvertTypes,
5503 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005504}
5505
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005506/**
5507 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5508 *
5509 * @param[in] pMe The decode context.
5510 * @param[in] nLabel Label to find in map.
5511 * @param[in] uConvertTypes Bit mask list of conversion options.
5512 * @param[out] pnValue Result of the conversion.
5513 * @param[in,out] pItem Temporary space to store Item, returned item.
5514 *
5515 * See QCBORDecode_GetInt64ConvertInMapN().
5516 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005517void
5518QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pMe,
5519 int64_t nLabel,
5520 uint32_t uConvertTypes,
5521 int64_t *pnValue,
5522 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005523{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005524 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005525 if(pMe->uLastError != QCBOR_SUCCESS) {
5526 return;
5527 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005528
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005529 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5530 uConvertTypes,
5531 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005532}
5533
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005534/**
5535 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5536 *
5537 * @param[in] pMe The decode context.
5538 * @param[in] szLabel Label to find in map.
5539 * @param[in] uConvertTypes Bit mask list of conversion options.
5540 * @param[out] pnValue Result of the conversion.
5541 * @param[in,out] pItem Temporary space to store Item, returned item.
5542 *
5543 * See QCBORDecode_GetInt64ConvertInMapSZ().
5544 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005545void
5546QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5547 const char * szLabel,
5548 uint32_t uConvertTypes,
5549 int64_t *pnValue,
5550 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005551{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005552 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005553 if(pMe->uLastError != QCBOR_SUCCESS) {
5554 return;
5555 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005556
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005557 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5558 uConvertTypes,
5559 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005560}
5561
5562
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005563/**
5564 * @brief Convert many number types to an int64_t.
5565 *
5566 * @param[in] pItem The item to convert.
5567 * @param[in] uConvertTypes Bit mask list of conversion options.
5568 * @param[out] pnValue The resulting converted value.
5569 *
5570 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5571 * in uConvertTypes.
5572 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5573 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5574 * or too small.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005575 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005576static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005577QCBOR_Private_Int64ConvertAll(const QCBORItem *pItem,
5578 const uint32_t uConvertTypes,
5579 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005580{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005581 switch(pItem->uDataType) {
5582
5583 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005584 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005585 return QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005586 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005587 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005588 }
5589 break;
5590
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005591 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005592 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005593 return QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005594 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005595 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005596 }
5597 break;
5598
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005599#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005600 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005601 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005602 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005603 pItem->val.expAndMantissa.nExponent,
5604 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005605 &QCBOR_Private_Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005606 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005607 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005608 }
5609 break;
5610
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005611 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005612 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005613 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005614 pItem->val.expAndMantissa.nExponent,
5615 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005616 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005617 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005618 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005619 }
5620 break;
5621
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005622 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005623 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005624 int64_t nMantissa;
5625 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005626 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005627 if(uErr) {
5628 return uErr;
5629 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005630 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005631 pItem->val.expAndMantissa.nExponent,
5632 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005633 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005634 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005635 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005636 }
5637 break;
5638
5639 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005640 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005641 int64_t nMantissa;
5642 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005643 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005644 if(uErr) {
5645 return uErr;
5646 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005647 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005648 pItem->val.expAndMantissa.nExponent,
5649 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005650 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005651 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005652 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005653 }
5654 break;
5655
5656 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005657 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005658 int64_t nMantissa;
5659 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005660 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005661 if(uErr) {
5662 return uErr;
5663 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005664 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005665 pItem->val.expAndMantissa.nExponent,
5666 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005667 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005668 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005669 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005670 }
5671 break;
5672
5673 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005674 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005675 int64_t nMantissa;
5676 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005677 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005678 if(uErr) {
5679 return uErr;
5680 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005681 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005682 pItem->val.expAndMantissa.nExponent,
5683 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005684 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005685 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005686 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005687 }
5688 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005689#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005690
Laurence Lundbladee6430642020-03-14 21:15:44 -07005691
Laurence Lundbladec4537442020-04-14 18:53:22 -07005692 default:
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005693 return QCBOR_ERR_UNEXPECTED_TYPE; }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005694}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005695
5696
Laurence Lundbladec4537442020-04-14 18:53:22 -07005697/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005698 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005699 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005700void
5701QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe,
5702 const uint32_t uConvertTypes,
5703 int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005704{
5705 QCBORItem Item;
5706
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005707 QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005708
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005709 if(pMe->uLastError == QCBOR_SUCCESS) {
5710 // The above conversion succeeded
5711 return;
5712 }
5713
Laurence Lundbladef6c86662020-05-12 02:08:00 -07005714 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005715 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07005716 return;
5717 }
5718
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005719 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5720 uConvertTypes,
5721 pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005722}
5723
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005724
5725/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005726 * Public function, see header qcbor/qcbor_decode.h file
5727 */
5728void
5729QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
5730 const int64_t nLabel,
5731 const uint32_t uConvertTypes,
5732 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005733{
5734 QCBORItem Item;
5735
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005736 QCBORDecode_Private_GetInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07005737 nLabel,
5738 uConvertTypes,
5739 pnValue,
5740 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005741
5742 if(pMe->uLastError == QCBOR_SUCCESS) {
5743 // The above conversion succeeded
5744 return;
5745 }
5746
5747 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5748 // The above conversion failed in a way that code below can't correct
5749 return;
5750 }
5751
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005752 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5753 uConvertTypes,
5754 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005755}
5756
5757
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005758/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005759 * Public function, see header qcbor/qcbor_decode.h file
5760 */
5761void
5762QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
5763 const char *szLabel,
5764 const uint32_t uConvertTypes,
5765 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005766{
5767 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005768 QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07005769 szLabel,
5770 uConvertTypes,
5771 pnValue,
5772 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005773
5774 if(pMe->uLastError == QCBOR_SUCCESS) {
5775 // The above conversion succeeded
5776 return;
5777 }
5778
5779 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5780 // The above conversion failed in a way that code below can't correct
5781 return;
5782 }
5783
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005784 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5785 uConvertTypes,
5786 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005787}
5788
5789
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005790/**
5791 * @brief Convert many number types to an uint64_t.
5792 *
5793 * @param[in] pItem The item to convert.
5794 * @param[in] uConvertTypes Bit mask list of conversion options.
5795 * @param[out] puValue The resulting converted value.
5796 *
5797 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5798 * in uConvertTypes.
5799 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5800 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5801 * or too small.
5802 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005803static QCBORError
5804QCBOR_Private_ConvertUInt64(const QCBORItem *pItem,
5805 const uint32_t uConvertTypes,
5806 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005807{
5808 switch(pItem->uDataType) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005809 case QCBOR_TYPE_DOUBLE:
5810 case QCBOR_TYPE_FLOAT:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005811#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005812 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005813 // Can't use llround here because it will not convert values
5814 // greater than INT64_MAX and less than UINT64_MAX that
5815 // need to be converted so it is more complicated.
5816 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
5817 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5818 if(isnan(pItem->val.dfnum)) {
5819 return QCBOR_ERR_FLOAT_EXCEPTION;
5820 } else if(pItem->val.dfnum < 0) {
5821 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5822 } else {
5823 double dRounded = round(pItem->val.dfnum);
5824 // See discussion in DecodeDateEpoch() for
5825 // explanation of - 0x7ff
5826 if(dRounded > (double)(UINT64_MAX- 0x7ff)) {
5827 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5828 }
5829 *puValue = (uint64_t)dRounded;
5830 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005831 } else {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005832 if(isnan(pItem->val.fnum)) {
5833 return QCBOR_ERR_FLOAT_EXCEPTION;
5834 } else if(pItem->val.fnum < 0) {
5835 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5836 } else {
5837 float fRounded = roundf(pItem->val.fnum);
5838 // See discussion in DecodeDateEpoch() for
5839 // explanation of - 0x7ff
5840 if(fRounded > (float)(UINT64_MAX- 0x7ff)) {
5841 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5842 }
5843 *puValue = (uint64_t)fRounded;
5844 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005845 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005846 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5847 // round() and roundf() shouldn't result in exceptions here, but
5848 // catch them to be robust and thorough. Don't try to
5849 // distinguish between the various exceptions because it seems
5850 // they vary by CPU, compiler and OS.
5851 return QCBOR_ERR_FLOAT_EXCEPTION;
5852 }
5853
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005854 } else {
5855 return QCBOR_ERR_UNEXPECTED_TYPE;
5856 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005857#else
5858 return QCBOR_ERR_HW_FLOAT_DISABLED;
5859#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005860 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005861
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005862 case QCBOR_TYPE_INT64:
5863 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
5864 if(pItem->val.int64 >= 0) {
5865 *puValue = (uint64_t)pItem->val.int64;
5866 } else {
5867 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5868 }
5869 } else {
5870 return QCBOR_ERR_UNEXPECTED_TYPE;
5871 }
5872 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005873
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005874 case QCBOR_TYPE_UINT64:
5875 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
5876 *puValue = pItem->val.uint64;
5877 } else {
5878 return QCBOR_ERR_UNEXPECTED_TYPE;
5879 }
5880 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005881
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005882 default:
5883 return QCBOR_ERR_UNEXPECTED_TYPE;
5884 }
5885
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005886 return QCBOR_SUCCESS;
5887}
Laurence Lundbladec4537442020-04-14 18:53:22 -07005888
5889
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005890/**
5891 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5892 *
5893 * @param[in] pMe The decode context.
5894 * @param[in] uConvertTypes Bit mask list of conversion options.
5895 * @param[out] puValue Result of the conversion.
5896 * @param[in,out] pItem Temporary space to store Item, returned item.
5897 *
5898 * See QCBORDecode_GetUInt64Convert().
5899 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005900void
5901QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pMe,
5902 const uint32_t uConvertTypes,
5903 uint64_t *puValue,
5904 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005905{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005906 if(pMe->uLastError != QCBOR_SUCCESS) {
5907 return;
5908 }
5909
Laurence Lundbladec4537442020-04-14 18:53:22 -07005910 QCBORItem Item;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005911
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005912 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
5913 if(uError) {
5914 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005915 return;
5916 }
5917
Laurence Lundbladea826c502020-05-10 21:07:00 -07005918 if(pItem) {
5919 *pItem = Item;
5920 }
5921
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005922 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(&Item,
5923 uConvertTypes,
5924 puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005925}
5926
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005927
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005928/**
5929 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5930 *
5931 * @param[in] pMe The decode context.
5932 * @param[in] nLabel Label to find in map.
5933 * @param[in] uConvertTypes Bit mask list of conversion options.
5934 * @param[out] puValue Result of the conversion.
5935 * @param[in,out] pItem Temporary space to store Item, returned item.
5936 *
5937 * See QCBORDecode_GetUInt64ConvertInMapN().
5938 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005939void
5940QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe,
5941 const int64_t nLabel,
5942 const uint32_t uConvertTypes,
5943 uint64_t *puValue,
5944 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005945{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005946 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005947 if(pMe->uLastError != QCBOR_SUCCESS) {
5948 return;
5949 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005950
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005951 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
5952 uConvertTypes,
5953 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005954}
5955
5956
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005957/**
5958 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5959 *
5960 * @param[in] pMe The decode context.
5961 * @param[in] szLabel Label to find in map.
5962 * @param[in] uConvertTypes Bit mask list of conversion options.
5963 * @param[out] puValue Result of the conversion.
5964 * @param[in,out] pItem Temporary space to store Item, returned item.
5965 *
5966 * See QCBORDecode_GetUInt64ConvertInMapSZ().
5967 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005968void
5969QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5970 const char *szLabel,
5971 const uint32_t uConvertTypes,
5972 uint64_t *puValue,
5973 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005974{
5975 if(pMe->uLastError != QCBOR_SUCCESS) {
5976 return;
5977 }
5978
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005979 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005980 if(pMe->uLastError != QCBOR_SUCCESS) {
5981 return;
5982 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005983
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005984 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
5985 uConvertTypes,
5986 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005987}
5988
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005989
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005990/**
5991 * @brief Convert many number types to an unt64_t.
5992 *
5993 * @param[in] pItem The item to convert.
5994 * @param[in] uConvertTypes Bit mask list of conversion options.
5995 * @param[out] puValue The resulting converted value.
5996 *
5997 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5998 * in uConvertTypes.
5999 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6000 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6001 * or too small.
6002 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006003static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006004QCBOR_Private_UInt64ConvertAll(const QCBORItem *pItem,
6005 const uint32_t uConvertTypes,
6006 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006007{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08006008 switch(pItem->uDataType) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006009
6010 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006011 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006012 return QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006013 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006014 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006015 }
6016 break;
6017
6018 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006019 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006020 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6021 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006022 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006023 }
6024 break;
6025
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006026#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006027
6028 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006029 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006030 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006031 pItem->val.expAndMantissa.nExponent,
6032 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006033 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006034 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006035 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006036 }
6037 break;
6038
6039 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006040 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006041 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006042 pItem->val.expAndMantissa.nExponent,
6043 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006044 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006045 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006046 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006047 }
6048 break;
6049
6050 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006051 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006052 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006053 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006054 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &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_Exponentitate10);
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_DECIMAL_FRACTION_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;
6074
6075 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006076 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006077 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006078 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006079 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum,
6080 &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006081 if(uErr != QCBOR_SUCCESS) {
6082 return uErr;
6083 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006084 return QCBOR_Private_ExponentitateUU(uMantissa,
6085 pItem->val.expAndMantissa.nExponent,
6086 puValue,
6087 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006088 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006089 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006090 }
6091 break;
6092
6093 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006094 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006095 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6096 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006097 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006098 }
6099 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006100#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006101 default:
6102 return QCBOR_ERR_UNEXPECTED_TYPE;
6103 }
6104}
6105
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006106
Laurence Lundblade4e2da002020-06-13 23:08:31 -07006107/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006108 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006109 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006110void
6111QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe,
6112 const uint32_t uConvertTypes,
6113 uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006114{
6115 QCBORItem Item;
6116
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006117 QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006118
Laurence Lundbladef6c86662020-05-12 02:08:00 -07006119 if(pMe->uLastError == QCBOR_SUCCESS) {
6120 // The above conversion succeeded
6121 return;
6122 }
6123
6124 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6125 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07006126 return;
6127 }
6128
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006129 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6130 uConvertTypes,
6131 puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006132}
6133
Laurence Lundbladec4537442020-04-14 18:53:22 -07006134
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006135/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006136 * Public function, see header qcbor/qcbor_decode.h file
6137 */
6138void
6139QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
6140 const int64_t nLabel,
6141 const uint32_t uConvertTypes,
6142 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006143{
6144 QCBORItem Item;
6145
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006146 QCBORDecode_Private_GetUInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006147 nLabel,
6148 uConvertTypes,
6149 puValue,
6150 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006151
6152 if(pMe->uLastError == QCBOR_SUCCESS) {
6153 // The above conversion succeeded
6154 return;
6155 }
6156
6157 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6158 // The above conversion failed in a way that code below can't correct
6159 return;
6160 }
6161
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006162 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6163 uConvertTypes,
6164 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006165}
6166
6167
6168/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006169 * Public function, see header qcbor/qcbor_decode.h file
6170 */
6171void
6172QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
6173 const char *szLabel,
6174 const uint32_t uConvertTypes,
6175 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006176{
6177 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006178 QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006179 szLabel,
6180 uConvertTypes,
6181 puValue,
6182 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006183
6184 if(pMe->uLastError == QCBOR_SUCCESS) {
6185 // The above conversion succeeded
6186 return;
6187 }
6188
6189 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6190 // The above conversion failed in a way that code below can't correct
6191 return;
6192 }
6193
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006194 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6195 uConvertTypes,
6196 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006197}
6198
6199
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006200
6201
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006202#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006203/**
6204 * @brief Basic conversions to a double.
6205 *
6206 * @param[in] pItem The item to convert
6207 * @param[in] uConvertTypes Bit flags indicating source types for conversion
6208 * @param[out] pdValue The value converted to a double
6209 *
6210 * This does the conversions that don't need much object code,
6211 * the conversions from int, uint and float to double.
6212 *
6213 * See QCBOR_Private_DoubleConvertAll() for the full set
6214 * of conversions.
6215 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006216static QCBORError
6217QCBOR_Private_ConvertDouble(const QCBORItem *pItem,
6218 const uint32_t uConvertTypes,
6219 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006220{
6221 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006222 case QCBOR_TYPE_FLOAT:
6223#ifndef QCBOR_DISABLE_FLOAT_HW_USE
6224 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6225 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006226 // Simple cast does the job.
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006227 *pdValue = (double)pItem->val.fnum;
6228 } else {
6229 return QCBOR_ERR_UNEXPECTED_TYPE;
6230 }
6231 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006232#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006233 return QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006234#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006235 break;
6236
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006237 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006238 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6239 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006240 *pdValue = pItem->val.dfnum;
6241 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006242 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006243 }
6244 }
6245 break;
6246
6247 case QCBOR_TYPE_INT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006248#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006249 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006250 // A simple cast seems to do the job with no worry of exceptions.
6251 // There will be precision loss for some values.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006252 *pdValue = (double)pItem->val.int64;
6253
6254 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006255 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006256 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006257#else
6258 return QCBOR_ERR_HW_FLOAT_DISABLED;
6259#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006260 break;
6261
6262 case QCBOR_TYPE_UINT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006263#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006264 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006265 // A simple cast seems to do the job with no worry of exceptions.
6266 // There will be precision loss for some values.
6267 *pdValue = (double)pItem->val.uint64;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006268 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006269 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006270 }
6271 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006272#else
6273 return QCBOR_ERR_HW_FLOAT_DISABLED;
6274#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006275
6276 default:
6277 return QCBOR_ERR_UNEXPECTED_TYPE;
6278 }
6279
6280 return QCBOR_SUCCESS;
6281}
6282
6283
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006284/**
6285 * @brief Almost-public method to decode a number and convert to double (semi-private).
6286 *
6287 * @param[in] pMe The decode context.
6288 * @param[in] uConvertTypes Bit mask list of conversion options
6289 * @param[out] pdValue The output of the conversion.
6290 * @param[in,out] pItem Temporary space to store Item, returned item.
6291 *
6292 * See QCBORDecode_GetDoubleConvert().
6293 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006294void
6295QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pMe,
6296 const uint32_t uConvertTypes,
6297 double *pdValue,
6298 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07006299{
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006300 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07006301 return;
6302 }
6303
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006304 QCBORError uError = QCBORDecode_GetNext(pMe, pItem);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006305 if(uError) {
6306 pMe->uLastError = (uint8_t)uError;
6307 return;
6308 }
6309
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006310 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006311 uConvertTypes,
6312 pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006313}
Laurence Lundbladec4537442020-04-14 18:53:22 -07006314
Laurence Lundbladec4537442020-04-14 18:53:22 -07006315
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006316/**
6317 * @brief Almost-public method to decode a number and convert to double (semi-private).
6318 *
6319 * @param[in] pMe The decode context.
6320 * @param[in] nLabel Label to find in map.
6321 * @param[in] uConvertTypes Bit mask list of conversion options
6322 * @param[out] pdValue The output of the conversion.
6323 * @param[in,out] pItem Temporary space to store Item, returned item.
6324 *
6325 * See QCBORDecode_GetDoubleConvertInMapN().
6326 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006327void
6328QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pMe,
6329 const int64_t nLabel,
6330 const uint32_t uConvertTypes,
6331 double *pdValue,
6332 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006333{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006334 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006335 if(pMe->uLastError != QCBOR_SUCCESS) {
6336 return;
6337 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006338
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006339 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6340 uConvertTypes,
6341 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006342}
6343
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006344
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006345/**
6346 * @brief Almost-public method to decode a number and convert to double (semi-private).
6347 *
6348 * @param[in] pMe The decode context.
6349 * @param[in] szLabel Label to find in map.
6350 * @param[in] uConvertTypes Bit mask list of conversion options
6351 * @param[out] pdValue The output of the conversion.
6352 * @param[in,out] pItem Temporary space to store Item, returned item.
6353 *
6354 * See QCBORDecode_GetDoubleConvertInMapSZ().
6355 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006356void
6357QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe,
6358 const char *szLabel,
6359 const uint32_t uConvertTypes,
6360 double *pdValue,
6361 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006362{
6363 if(pMe->uLastError != QCBOR_SUCCESS) {
6364 return;
6365 }
6366
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006367 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006368 if(pMe->uLastError != QCBOR_SUCCESS) {
6369 return;
6370 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006371
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006372 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6373 uConvertTypes,
6374 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006375}
6376
6377
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006378#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006379/**
6380 * @brief Convert a big number to double-precision float.
6381 *
6382 * @param[in] BigNum The big number to convert
6383 *
6384 * @returns The double value.
6385 *
6386 * This will always succeed. It will lose precision for larger
6387 * numbers. If the big number is too large to fit (more than
6388 * 1.7976931348623157E+308) infinity will be returned. NaN is never
6389 * returned.
6390 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006391static double
6392QCBOR_Private_ConvertBigNumToDouble(const UsefulBufC BigNum)
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006393{
6394 double dResult;
6395
6396 dResult = 0.0;
6397 const uint8_t *pByte = BigNum.ptr;
6398 size_t uLen = BigNum.len;
6399 /* This will overflow and become the float value INFINITY if the number
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006400 * is too large to fit. */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006401 while(uLen--) {
6402 dResult = (dResult * 256.0) + (double)*pByte++;
6403 }
6404
6405 return dResult;
6406}
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006407#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6408
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006409
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006410
6411
6412/**
6413 * @brief Convert many number types to a double.
6414 *
6415 * @param[in] pItem The item to convert.
6416 * @param[in] uConvertTypes Bit mask list of conversion options.
6417 * @param[out] pdValue The resulting converted value.
6418 *
6419 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6420 * in uConvertTypes.
6421 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6422 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6423 * or too small.
6424 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006425static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006426QCBOR_Private_DoubleConvertAll(const QCBORItem *pItem,
6427 const uint32_t uConvertTypes,
6428 double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006429{
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006430#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07006431 /*
Laurence Lundblade16a207a2021-09-18 17:22:46 -07006432 * What Every Computer Scientist Should Know About Floating-Point Arithmetic
6433 * https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
6434 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006435 switch(pItem->uDataType) {
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006436
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006437#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006438 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006439 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006440 // Underflow gives 0, overflow gives infinity
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006441 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6442 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
6443 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006444 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006445 }
6446 break;
6447
6448 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006449 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006450 // Underflow gives 0, overflow gives infinity
6451 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6452 exp2((double)pItem->val.expAndMantissa.nExponent);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006453 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006454 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006455 }
6456 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006457#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006458
6459 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006460 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006461 *pdValue = QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006462 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006463 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006464 }
6465 break;
6466
6467 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006468 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006469 *pdValue = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006470 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006471 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006472 }
6473 break;
6474
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006475#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006476 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006477 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006478 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006479 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6480 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006481 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006482 }
6483 break;
6484
6485 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006486 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006487 double dMantissa = -QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006488 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6489 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006490 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006491 }
6492 break;
6493
6494 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006495 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006496 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006497 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6498 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006499 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006500 }
6501 break;
6502
6503 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006504 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006505 double dMantissa = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006506 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6507 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006508 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006509 }
6510 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006511#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006512
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006513 default:
6514 return QCBOR_ERR_UNEXPECTED_TYPE;
6515 }
6516
6517 return QCBOR_SUCCESS;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006518
6519#else
6520 (void)pItem;
6521 (void)uConvertTypes;
6522 (void)pdValue;
6523 return QCBOR_ERR_HW_FLOAT_DISABLED;
6524#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6525
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006526}
6527
6528
6529/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006530 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006531 */
6532void
6533QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe,
6534 const uint32_t uConvertTypes,
6535 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006536{
6537
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006538 QCBORItem Item;
6539
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006540 QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006541
6542 if(pMe->uLastError == QCBOR_SUCCESS) {
6543 // The above conversion succeeded
6544 return;
6545 }
6546
6547 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6548 // The above conversion failed in a way that code below can't correct
6549 return;
6550 }
6551
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006552 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6553 uConvertTypes,
6554 pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006555}
6556
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006557
6558/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006559 * Public function, see header qcbor/qcbor_decode.h file
6560 */
6561void
6562QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe,
6563 const int64_t nLabel,
6564 const uint32_t uConvertTypes,
6565 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006566{
6567 QCBORItem Item;
6568
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006569 QCBORDecode_Private_GetDoubleConvertInMapN(pMe,
6570 nLabel,
6571 uConvertTypes,
6572 pdValue,
6573 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006574
6575 if(pMe->uLastError == QCBOR_SUCCESS) {
6576 // The above conversion succeeded
6577 return;
6578 }
6579
6580 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6581 // The above conversion failed in a way that code below can't correct
6582 return;
6583 }
6584
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006585 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6586 uConvertTypes,
6587 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006588}
6589
6590
6591/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006592 * Public function, see header qcbor/qcbor_decode.h file
6593 */
6594void
6595QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe,
6596 const char *szLabel,
6597 const uint32_t uConvertTypes,
6598 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006599{
6600 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006601 QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe,
6602 szLabel,
6603 uConvertTypes,
6604 pdValue,
6605 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006606
6607 if(pMe->uLastError == QCBOR_SUCCESS) {
6608 // The above conversion succeeded
6609 return;
6610 }
6611
6612 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6613 // The above conversion failed in a way that code below can't correct
6614 return;
6615 }
6616
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006617 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6618 uConvertTypes,
6619 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006620}
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006621#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006622
6623
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006624
6625
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006626#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006627/**
6628 * @brief Convert an integer to a big number
6629 *
6630 * @param[in] uInt The integer to convert.
6631 * @param[in] Buffer The buffer to output the big number to.
6632 *
6633 * @returns The big number or NULLUsefulBufC is the buffer is to small.
6634 *
6635 * This always succeeds unless the buffer is too small.
6636 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006637static UsefulBufC
6638QCBOR_Private_ConvertIntToBigNum(uint64_t uInt, const UsefulBuf Buffer)
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006639{
6640 while((uInt & 0xff00000000000000UL) == 0) {
6641 uInt = uInt << 8;
6642 };
6643
6644 UsefulOutBuf UOB;
6645
6646 UsefulOutBuf_Init(&UOB, Buffer);
6647
6648 while(uInt) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006649 UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff00000000000000UL) >> 56));
6650 uInt = uInt << 8;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006651 }
6652
6653 return UsefulOutBuf_OutUBuf(&UOB);
6654}
6655
6656
Laurence Lundblade37286c02022-09-03 10:05:02 -07006657/**
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006658 * @brief Check and/or complete exponent and mantissa item.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006659 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006660 * @param[in] pMe The decoder context.
6661 * @param[in] TagSpec Expected type(s).
6662 * @param[in,out] pItem See below.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006663 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006664 * This is for decimal fractions and big floats, both of which are an
6665 * exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006666 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006667 * If the item item had a tag number indicating it was a
6668 * decimal fraction or big float, then the input @c pItem will
6669 * have been decoded as exponent and mantissa. If there was
6670 * no tag number, the caller is asking this be decoded as a
6671 * big float or decimal fraction and @c pItem just has the
6672 * first item in an exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006673 *
6674 * On output, the item is always a fully decoded decimal fraction or
6675 * big float.
6676 *
6677 * This errors out if the input type does not meet the TagSpec.
6678 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07006679static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006680QCBOR_Private_ExpMantissaTypeHandler(QCBORDecodeContext *pMe,
6681 const QCBOR_Private_TagSpec TagSpec,
6682 QCBORItem *pItem)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006683{
6684 QCBORError uErr;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006685
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006686 /* pItem could either be a decoded exponent and mantissa or
6687 * the opening array of an undecoded exponent and mantissa. This
Laurence Lundblade37286c02022-09-03 10:05:02 -07006688 * check will succeed on either, but doesn't say which it was.
6689 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006690 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07006691 if(uErr != QCBOR_SUCCESS) {
6692 goto Done;
6693 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006694
Laurence Lundblade37286c02022-09-03 10:05:02 -07006695 if(pItem->uDataType == QCBOR_TYPE_ARRAY) {
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006696 /* The item is an array, which means is is an undecoded exponent
6697 * and mantissa. This call consumes the items in the array and
6698 * results in a decoded exponent and mantissa in pItem. This is
Laurence Lundblade37286c02022-09-03 10:05:02 -07006699 * the case where there was no tag.
6700 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006701 uErr = QCBORDecode_Private_ExpMantissa(pMe, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006702 if(uErr != QCBOR_SUCCESS) {
6703 goto Done;
6704 }
6705
Laurence Lundblade37286c02022-09-03 10:05:02 -07006706 /* The above decode didn't determine whether it is a decimal
6707 * fraction or big num. Which of these two depends on what the
6708 * caller wants it decoded as since there is no tag, so fish the
6709 * type out of the TagSpec. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006710 pItem->uDataType = QCBOR_Private_ExpMantissaDataType(TagSpec.uTaggedTypes[0], pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07006711
6712 /* No need to check the type again. All that we need to know was
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006713 * that it decoded correctly as a exponent and mantissa. The
Laurence Lundblade37286c02022-09-03 10:05:02 -07006714 * QCBOR type is set out by what was requested.
6715 */
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006716 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07006717
6718 /* If the item was not an array and the check passed, then
6719 * it is a fully decoded big float or decimal fraction and
6720 * matches what is requested.
6721 */
6722
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006723Done:
6724 return uErr;
6725}
6726
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006727
Laurence Lundblade37286c02022-09-03 10:05:02 -07006728/* Some notes from the work to disable tags.
6729 *
6730 * The API for big floats and decimal fractions seems good.
6731 * If there's any issue with it it's that the code size to
6732 * implement is a bit large because of the conversion
6733 * to/from int and bignum that is required. There is no API
6734 * that doesn't do the conversion so dead stripping will never
6735 * leave that code out.
6736 *
6737 * The implementation itself seems correct, but not as clean
6738 * and neat as it could be. It could probably be smaller too.
6739 *
6740 * The implementation has three main parts / functions
6741 * - The decoding of the array of two
6742 * - All the tag and type checking for the various API functions
6743 * - Conversion to/from bignum and int
6744 *
6745 * The type checking seems like it wastes the most code for
6746 * what it needs to do.
6747 *
6748 * The inlining for the conversion is probably making the
6749 * overall code base larger.
6750 *
6751 * The tests cases could be organized a lot better and be
6752 * more thorough.
6753 *
6754 * Seems also like there could be more common code in the
6755 * first tier part of the public API. Some functions only
6756 * vary by a TagSpec.
6757 */
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006758
6759/**
6760 * @brief Common processor for exponent and mantissa.
6761 *
6762 * @param[in] pMe The decode context.
6763 * @param[in] TagSpec The expected/allowed tags.
6764 * @param[in] pItem The data item to process.
6765 * @param[out] pnMantissa The returned mantissa as an int64_t.
6766 * @param[out] pnExponent The returned exponent as an int64_t.
6767 *
6768 * This handles exponent and mantissa for base 2 and 10. This
6769 * is limited to a mantissa that is an int64_t. See also
6770 * QCBORDecode_Private_ProcessExpMantissaBig().
6771 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006772static void
6773QCBOR_Private_ProcessExpMantissa(QCBORDecodeContext *pMe,
6774 const QCBOR_Private_TagSpec TagSpec,
6775 QCBORItem *pItem,
6776 int64_t *pnMantissa,
6777 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006778{
6779 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006780
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006781 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006782 if(uErr != QCBOR_SUCCESS) {
6783 goto Done;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006784 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006785
Laurence Lundblade9b334962020-08-27 10:55:53 -07006786 switch (pItem->uDataType) {
6787
6788 case QCBOR_TYPE_DECIMAL_FRACTION:
6789 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade9b334962020-08-27 10:55:53 -07006790 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006791 *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
Laurence Lundblade9b334962020-08-27 10:55:53 -07006792 break;
6793
Laurence Lundblade37286c02022-09-03 10:05:02 -07006794#ifndef QCBOR_DISABLE_TAGS
6795 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006796 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
6797 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
6798 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006799 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006800 break;
6801
6802 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
6803 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
6804 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006805 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006806 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006807#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006808
6809 default:
6810 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
6811 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006812
6813 Done:
6814 pMe->uLastError = (uint8_t)uErr;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006815}
6816
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006817
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006818/**
6819 * @brief Decode exponent and mantissa into a big number.
6820 *
6821 * @param[in] pMe The decode context.
6822 * @param[in] TagSpec The expected/allowed tags.
6823 * @param[in] pItem Item to decode and convert.
6824 * @param[in] BufferForMantissa Buffer to output mantissa into.
6825 * @param[out] pMantissa The output mantissa.
6826 * @param[out] pbIsNegative The sign of the output.
6827 * @param[out] pnExponent The mantissa of the output.
6828 *
6829 * This is the common processing of a decimal fraction or a big float
6830 * into a big number. This will decode and consume all the CBOR items
6831 * that make up the decimal fraction or big float.
6832 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006833static void
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006834QCBORDecode_Private_ProcessExpMantissaBig(QCBORDecodeContext *pMe,
6835 const QCBOR_Private_TagSpec TagSpec,
6836 QCBORItem *pItem,
6837 const UsefulBuf BufferForMantissa,
6838 UsefulBufC *pMantissa,
6839 bool *pbIsNegative,
6840 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006841{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006842 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006843
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006844 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006845 if(uErr != QCBOR_SUCCESS) {
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006846 goto Done;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006847 }
6848
6849 uint64_t uMantissa;
6850
6851 switch (pItem->uDataType) {
6852
6853 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006854 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006855 /* See comments in ExponentiateNN() on handling INT64_MIN */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006856 if(pItem->val.expAndMantissa.Mantissa.nInt >= 0) {
6857 uMantissa = (uint64_t)pItem->val.expAndMantissa.Mantissa.nInt;
6858 *pbIsNegative = false;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006859 } else if(pItem->val.expAndMantissa.Mantissa.nInt != INT64_MIN) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006860 uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt;
6861 *pbIsNegative = true;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006862 } else {
6863 uMantissa = (uint64_t)INT64_MAX+1;
6864 *pbIsNegative = true;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006865 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006866 *pMantissa = QCBOR_Private_ConvertIntToBigNum(uMantissa,
6867 BufferForMantissa);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006868 *pnExponent = pItem->val.expAndMantissa.nExponent;
6869 break;
6870
Laurence Lundblade37286c02022-09-03 10:05:02 -07006871#ifndef QCBOR_DISABLE_TAGS
6872 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006873 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006874 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006875 *pnExponent = pItem->val.expAndMantissa.nExponent;
6876 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6877 *pbIsNegative = false;
6878 break;
6879
6880 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006881 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006882 *pnExponent = pItem->val.expAndMantissa.nExponent;
6883 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6884 *pbIsNegative = true;
6885 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006886#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006887
6888 default:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006889 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006890 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006891
6892Done:
6893 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006894}
6895
6896
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006897/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006898 * Public function, see header qcbor/qcbor_decode.h file
6899 */
6900void
6901QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe,
6902 const uint8_t uTagRequirement,
6903 int64_t *pnMantissa,
6904 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006905{
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006906 if(pMe->uLastError != QCBOR_SUCCESS) {
6907 return;
6908 }
6909
6910 QCBORItem Item;
6911 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
6912 if(uError) {
6913 pMe->uLastError = (uint8_t)uError;
6914 return;
6915 }
6916
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006917 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006918 {
6919 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006920 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6921 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6922 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006923 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006924
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006925 QCBOR_Private_ProcessExpMantissa(pMe,
6926 TagSpec,
6927 &Item,
6928 pnMantissa,
6929 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006930}
6931
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006932
6933/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006934 * Public function, see header qcbor/qcbor_decode.h file
6935 */
6936void
6937QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe,
6938 const int64_t nLabel,
6939 const uint8_t uTagRequirement,
6940 int64_t *pnMantissa,
6941 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006942{
6943 if(pMe->uLastError != QCBOR_SUCCESS) {
6944 return;
6945 }
6946
6947 QCBORItem Item;
6948 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
6949
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006950 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006951 {
6952 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006953 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6954 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6955 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006956 };
6957
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006958 QCBOR_Private_ProcessExpMantissa(pMe,
6959 TagSpec,
6960 &Item,
6961 pnMantissa,
6962 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006963}
6964
6965
6966/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006967 * Public function, see header qcbor/qcbor_decode.h file
6968 */
6969void
6970QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
6971 const char *szLabel,
6972 const uint8_t uTagRequirement,
6973 int64_t *pnMantissa,
6974 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006975{
6976 if(pMe->uLastError != QCBOR_SUCCESS) {
6977 return;
6978 }
6979
6980 QCBORItem Item;
6981 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
6982
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006983 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006984 {
6985 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006986 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6987 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6988 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006989 };
Laurence Lundblade9b334962020-08-27 10:55:53 -07006990
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006991 QCBOR_Private_ProcessExpMantissa(pMe,
6992 TagSpec,
6993 &Item,
6994 pnMantissa,
6995 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006996}
6997
6998
6999/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007000 * Public function, see header qcbor/qcbor_decode.h file
7001 */
7002void
7003QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe,
7004 const uint8_t uTagRequirement,
7005 const UsefulBuf MantissaBuffer,
7006 UsefulBufC *pMantissa,
7007 bool *pbMantissaIsNegative,
7008 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007009{
7010 if(pMe->uLastError != QCBOR_SUCCESS) {
7011 return;
7012 }
7013
7014 QCBORItem Item;
7015 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
7016 if(uError) {
7017 pMe->uLastError = (uint8_t)uError;
7018 return;
7019 }
7020
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007021 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007022 {
7023 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007024 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7025 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7026 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007027 };
7028
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007029 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7030 TagSpec,
7031 &Item,
7032 MantissaBuffer,
7033 pMantissa,
7034 pbMantissaIsNegative,
7035 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007036}
7037
7038
7039/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007040 * Public function, see header qcbor/qcbor_decode.h file
7041 */
7042void
7043QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe,
7044 const int64_t nLabel,
7045 const uint8_t uTagRequirement,
7046 const UsefulBuf BufferForMantissa,
7047 UsefulBufC *pMantissa,
7048 bool *pbIsNegative,
7049 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007050{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007051 if(pMe->uLastError != QCBOR_SUCCESS) {
7052 return;
7053 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007054
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007055 QCBORItem Item;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007056 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007057 if(pMe->uLastError != QCBOR_SUCCESS) {
7058 return;
7059 }
7060
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007061 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007062 {
7063 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007064 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7065 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7066 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007067 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007068
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007069 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7070 TagSpec,
7071 &Item,
7072 BufferForMantissa,
7073 pMantissa,
7074 pbIsNegative,
7075 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007076}
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007077
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007078
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007079/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007080 * Public function, see header qcbor/qcbor_decode.h file
7081 */
7082void
7083QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe,
7084 const char *szLabel,
7085 const uint8_t uTagRequirement,
7086 const UsefulBuf BufferForMantissa,
7087 UsefulBufC *pMantissa,
7088 bool *pbIsNegative,
7089 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007090{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007091 if(pMe->uLastError != QCBOR_SUCCESS) {
7092 return;
7093 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007094
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007095 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007096 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7097 if(pMe->uLastError != QCBOR_SUCCESS) {
7098 return;
7099 }
7100
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007101 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007102 {
7103 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007104 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7105 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7106 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007107 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007108
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007109 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7110 TagSpec,
7111 &Item,
7112 BufferForMantissa,
7113 pMantissa,
7114 pbIsNegative,
7115 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007116}
7117
7118
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007119/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007120 * Public function, see header qcbor/qcbor_decode.h file
7121 */
7122void
7123QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe,
7124 const uint8_t uTagRequirement,
7125 int64_t *pnMantissa,
7126 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007127{
7128 if(pMe->uLastError != QCBOR_SUCCESS) {
7129 return;
7130 }
7131
7132 QCBORItem Item;
7133 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
7134 if(uError) {
7135 pMe->uLastError = (uint8_t)uError;
7136 return;
7137 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007138 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007139 {
7140 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007141 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7142 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7143 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007144 };
7145
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007146 QCBOR_Private_ProcessExpMantissa(pMe,
7147 TagSpec,
7148 &Item,
7149 pnMantissa,
7150 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007151}
7152
7153
7154/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007155 * Public function, see header qcbor/qcbor_decode.h file
7156 */
7157void
7158QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe,
7159 const int64_t nLabel,
7160 const uint8_t uTagRequirement,
7161 int64_t *pnMantissa,
7162 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007163{
7164 if(pMe->uLastError != QCBOR_SUCCESS) {
7165 return;
7166 }
7167
7168 QCBORItem Item;
7169 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7170 if(pMe->uLastError != QCBOR_SUCCESS) {
7171 return;
7172 }
7173
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007174 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007175 {
7176 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007177 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7178 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7179 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007180 };
7181
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007182 QCBOR_Private_ProcessExpMantissa(pMe,
7183 TagSpec,
7184 &Item,
7185 pnMantissa,
7186 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007187}
7188
7189
7190/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007191 * Public function, see header qcbor/qcbor_decode.h file
7192 */
7193void
7194QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe,
7195 const char *szLabel,
7196 const uint8_t uTagRequirement,
7197 int64_t *pnMantissa,
7198 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007199{
7200 if(pMe->uLastError != QCBOR_SUCCESS) {
7201 return;
7202 }
7203
7204 QCBORItem Item;
7205 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7206 if(pMe->uLastError != QCBOR_SUCCESS) {
7207 return;
7208 }
7209
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007210 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007211 {
7212 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007213 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7214 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7215 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007216 };
7217
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007218 QCBOR_Private_ProcessExpMantissa(pMe,
7219 TagSpec,
7220 &Item,
7221 pnMantissa,
7222 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007223}
7224
7225
7226/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007227 * Public function, see header qcbor/qcbor_decode.h file
7228 */
7229void
7230QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe,
7231 const uint8_t uTagRequirement,
7232 const UsefulBuf MantissaBuffer,
7233 UsefulBufC *pMantissa,
7234 bool *pbMantissaIsNegative,
7235 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007236{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007237 if(pMe->uLastError != QCBOR_SUCCESS) {
7238 return;
7239 }
7240
7241 QCBORItem Item;
7242 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
7243 if(uError) {
7244 pMe->uLastError = (uint8_t)uError;
7245 return;
7246 }
7247
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007248 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007249 {
7250 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007251 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7252 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7253 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007254 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007255
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007256 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7257 TagSpec,
7258 &Item,
7259 MantissaBuffer,
7260 pMantissa,
7261 pbMantissaIsNegative,
7262 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007263}
7264
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007265
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007266/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007267 * Public function, see header qcbor/qcbor_decode.h file
7268 */
7269void
7270QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe,
7271 const int64_t nLabel,
7272 const uint8_t uTagRequirement,
7273 const UsefulBuf BufferForMantissa,
7274 UsefulBufC *pMantissa,
7275 bool *pbIsNegative,
7276 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007277{
7278 if(pMe->uLastError != QCBOR_SUCCESS) {
7279 return;
7280 }
7281
7282 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007283 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7284 if(pMe->uLastError != QCBOR_SUCCESS) {
7285 return;
7286 }
7287
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007288 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007289 {
7290 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007291 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7292 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7293 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007294 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007295
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007296 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7297 TagSpec,
7298 &Item,
7299 BufferForMantissa,
7300 pMantissa,
7301 pbIsNegative,
7302 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007303}
7304
7305
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007306/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007307 * Public function, see header qcbor/qcbor_decode.h file
7308 */
7309void
7310QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe,
7311 const char *szLabel,
7312 const uint8_t uTagRequirement,
7313 const UsefulBuf BufferForMantissa,
7314 UsefulBufC *pMantissa,
7315 bool *pbIsNegative,
7316 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007317{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007318 if(pMe->uLastError != QCBOR_SUCCESS) {
7319 return;
7320 }
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007321
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007322 QCBORItem Item;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007323 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7324 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007325 return;
7326 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007327
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007328 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007329 {
7330 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007331 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7332 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7333 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007334 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007335
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007336 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7337 TagSpec,
7338 &Item,
7339 BufferForMantissa,
7340 pMantissa,
7341 pbIsNegative,
7342 pnExponent);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007343}
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007344
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07007345#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */