blob: 0107a5b3d0eba8df50fde9b3269afef0de8049b2 [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 Lundbladeec290b82024-06-10 11:10:54 -0700108#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
109 uDataType == QCBOR_TYPE_MAP_AS_ARRAY ||
110#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
111 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 Lundbladeec290b82024-06-10 11:10:54 -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 Lundbladeec290b82024-06-10 11:10:54 -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 Lundbladeec290b82024-06-10 11:10:54 -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 Lundbladeec290b82024-06-10 11:10:54 -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 Lundblade2ce22a72024-08-24 07:09:57 -0700464 const uint8_t uQCBORType,
465 const uint16_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 Lundblade2ce22a72024-08-24 07:09:57 -0700477 /* Rely on check in QCBOR_Private_DecodeArrayOrMap() for definite-length
478 * arrays and maps that are too long */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700479
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700480 uError = DecodeNesting_Descend(pNesting, uQCBORType);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700481 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700482 goto Done;
483 }
484
Laurence Lundblade2ce22a72024-08-24 07:09:57 -0700485 pNesting->pCurrent->u.ma.uCountCursor = uCount;
486 pNesting->pCurrent->u.ma.uCountTotal = uCount;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700487
488 DecodeNesting_ClearBoundedMode(pNesting);
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700489
490Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700491 return uError;;
492}
493
494
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700495static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700496DecodeNesting_LevelUpCurrent(QCBORDecodeNesting *pNesting)
497{
498 pNesting->pCurrent = pNesting->pCurrentBounded - 1;
499}
500
501
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700502static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700503DecodeNesting_LevelUpBounded(QCBORDecodeNesting *pNesting)
504{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700505 while(pNesting->pCurrentBounded != &(pNesting->pLevels[0])) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700506 pNesting->pCurrentBounded--;
507 if(DecodeNesting_IsCurrentBounded(pNesting)) {
508 break;
509 }
510 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700511}
512
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800513
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700514static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700515DecodeNesting_SetCurrentToBoundedLevel(QCBORDecodeNesting *pNesting)
516{
517 pNesting->pCurrent = pNesting->pCurrentBounded;
518}
519
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700520
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700521static QCBORError
Laurence Lundblade02625d42020-06-25 14:41:41 -0700522DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting,
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700523 uint32_t uEndOffset,
524 uint32_t uStartOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700525{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700526 QCBORError uError;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700527
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700528 uError = DecodeNesting_Descend(pNesting, QCBOR_TYPE_BYTE_STRING);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700529 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700530 goto Done;
531 }
532
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800533 /* Fill in the new byte string level */
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700534 pNesting->pCurrent->u.bs.uSavedEndOffset = uEndOffset;
535 pNesting->pCurrent->u.bs.uBstrStartOffset = uStartOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700536
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800537 /* Bstr wrapped levels are always bounded */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700538 pNesting->pCurrentBounded = pNesting->pCurrent;
539
540Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700541 return uError;;
542}
543
Laurence Lundbladed0304932020-06-27 10:59:38 -0700544
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700545static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700546DecodeNesting_ZeroMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700547{
548 pNesting->pCurrent->u.ma.uCountCursor = 0;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700549}
550
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700551
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700552static void
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800553DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting)
554{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700555 if(pNesting->pCurrent->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
556 pNesting->pCurrentBounded->u.ma.uCountCursor = pNesting->pCurrentBounded->u.ma.uCountTotal;
557 }
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800558}
559
560
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700561static void
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700562DecodeNesting_Init(QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700563{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700564 /* Assumes that *pNesting has been zero'd before this call. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700565 pNesting->pLevels[0].uLevelType = QCBOR_TYPE_BYTE_STRING;
566 pNesting->pCurrent = &(pNesting->pLevels[0]);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700567}
568
569
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700570static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800571DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting,
572 QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700573{
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700574 *pSave = *pNesting;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700575}
576
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700577
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700578static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800579DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting,
580 const QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700581{
582 *pNesting = *pSave;
583}
584
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700585
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700586static uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700587DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700588{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700589 return pMe->pCurrentBounded->u.bs.uSavedEndOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700590}
591
592
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800593
594
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800595#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladeee851742020-01-08 08:37:05 -0800596/*===========================================================================
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800597 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
598
599 The following four functions are pretty wrappers for invocation of
600 the string allocator supplied by the caller.
601
Laurence Lundbladeee851742020-01-08 08:37:05 -0800602 ===========================================================================*/
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800603
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700604static void
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800605StringAllocator_Free(const QCBORInternalAllocator *pMe, const void *pMem)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800606{
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300607 /* This cast to uintptr_t suppresses the "-Wcast-qual" warnings.
608 * This is the one place where the const needs to be cast away so const can
609 * be use in the rest of the code.
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800610 */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300611 (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, 0);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800612}
613
Laurence Lundbladeee851742020-01-08 08:37:05 -0800614// StringAllocator_Reallocate called with pMem NULL is
615// equal to StringAllocator_Allocate()
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700616static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800617StringAllocator_Reallocate(const QCBORInternalAllocator *pMe,
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800618 const void *pMem,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800619 size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800620{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800621 /* See comment in StringAllocator_Free() */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300622 return (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, uSize);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800623}
624
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700625static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800626StringAllocator_Allocate(const QCBORInternalAllocator *pMe, size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800627{
628 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
629}
630
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700631static void
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800632StringAllocator_Destruct(const QCBORInternalAllocator *pMe)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800633{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800634 /* See comment in StringAllocator_Free() */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800635 if(pMe->pfAllocator) {
636 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
637 }
638}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800639#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800640
641
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800642
643
Laurence Lundbladeee851742020-01-08 08:37:05 -0800644/*===========================================================================
645 QCBORDecode -- The main implementation of CBOR decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700646
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800647 See qcbor/qcbor_decode.h for definition of the object
648 used here: QCBORDecodeContext
Laurence Lundbladeee851742020-01-08 08:37:05 -0800649 ===========================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700650/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800651 * Public function, see header file
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700652 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700653void
654QCBORDecode_Init(QCBORDecodeContext *pMe,
655 UsefulBufC EncodedCBOR,
656 QCBORDecodeMode nDecodeMode)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700657{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800658 memset(pMe, 0, sizeof(QCBORDecodeContext));
659 UsefulInputBuf_Init(&(pMe->InBuf), EncodedCBOR);
660 /* Don't bother with error check on decode mode. If a bad value is
661 * passed it will just act as if the default normal mode of 0 was set.
662 */
663 pMe->uDecodeMode = (uint8_t)nDecodeMode;
664 DecodeNesting_Init(&(pMe->nesting));
665
666 /* Inialize me->auMappedTags to CBOR_TAG_INVALID16. See
667 * GetNext_TaggedItem() and MapTagNumber(). */
668 memset(pMe->auMappedTags, 0xff, sizeof(pMe->auMappedTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700669}
670
671
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800672#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
673
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700674/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800675 * Public function, see header file
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700676 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700677void
678QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
679 QCBORStringAllocate pfAllocateFunction,
680 void *pAllocateContext,
681 bool bAllStrings)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700682{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800683 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
684 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
685 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700686}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800687#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700688
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800689
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800690
691
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800692/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800693 * Deprecated public function, see header file
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800694 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700695void
696QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pMe,
697 const QCBORTagListIn *pTagList)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700698{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800699 /* This does nothing now. It is retained for backwards compatibility */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700700 (void)pMe;
701 (void)pTagList;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700702}
703
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700704
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800705
706
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700707/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800708 * Decoding items is done in six layers, one calling the next one
709 * down. If a layer has no work to do for a particular item, it
710 * returns quickly.
711 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700712 * 1. QCBORDecode_Private_GetNextTagContent - The top layer processes
713 * tagged data items, turning them into the local C representation.
714 * For the most simple it is just associating a QCBOR_TYPE with the
715 * data. For the complex ones that an aggregate of data items, there
716 * is some further decoding and some limited recursion.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800717 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700718 * 2. QCBORDecode_Private_GetNextMapOrArray - This manages the
719 * beginnings and ends of maps and arrays. It tracks descending into
720 * and ascending out of maps/arrays. It processes breaks that
721 * terminate indefinite-length maps and arrays.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800722 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700723 * 3. QCBORDecode_Private_GetNextMapEntry - This handles the combining
724 * of two items, the label and the data, that make up a map entry. It
725 * only does work on maps. It combines the label and data items into
726 * one labeled item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800727 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700728 * 4. QCBORDecode_Private_GetNextTagNumber - This decodes type 6 tag
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800729 * numbers. It turns the tag numbers into bit flags associated with
730 * the data item. No actual decoding of the contents of the tag is
731 * performed here.
732 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700733 * 5. QCBORDecode_Private_GetNextFullString - This assembles the
734 * sub-items that make up an indefinite-length string into one string
735 * item. It uses the string allocator to create contiguous space for
736 * the item. It processes all breaks that are part of
737 * indefinite-length strings.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800738 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700739 * 6. QCBOR_Private_DecodeAtomicDataItem - This decodes the atomic
740 * data items in CBOR. Each atomic data item has a "major type", an
741 * integer "argument" and optionally some content. For text and byte
742 * strings, the content is the bytes that make up the string. These
743 * are the smallest data items that are considered to be well-formed.
744 * The content may also be other data items in the case of aggregate
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800745 * types. They are not handled in this layer.
746 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700747 * This uses about 350 bytes of stack. This number comes from
748 * instrumenting (printf address of stack variables) the code on x86
749 * compiled for size optimization.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700750 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800751
752
753/*
754 * Note about use of int and unsigned variables.
755 *
756 * See http://www.unix.org/whitepapers/64bit.html for reasons int is
757 * used carefully here, and in particular why it isn't used in the
758 * public interface. Also see
759 * https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers
760 *
761 * Int is used for values that need less than 16-bits and would be
762 * subject to integer promotion and result in complaining from static
763 * analyzers.
764 */
765
766
767/**
768 * @brief Decode the CBOR head, the type and argument.
769 *
770 * @param[in] pUInBuf The input buffer to read from.
771 * @param[out] pnMajorType The decoded major type.
772 * @param[out] puArgument The decoded argument.
773 * @param[out] pnAdditionalInfo The decoded Lower 5 bits of initial byte.
774 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -0700775 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved features
776 * @retval QCBOR_ERR_HIT_END Unexpected end of input
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800777 *
778 * This decodes the CBOR "head" that every CBOR data item has. See
779 * longer explaination of the head in documentation for
780 * QCBOREncode_EncodeHead().
781 *
782 * This does the network->host byte order conversion. The conversion
783 * here also results in the conversion for floats in addition to that
784 * for lengths, tags and integer values.
785 *
786 * The int type is preferred to uint8_t for some variables as this
787 * avoids integer promotions, can reduce code size and makes static
788 * analyzers happier.
789 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700790static QCBORError
791QCBOR_Private_DecodeHead(UsefulInputBuf *pUInBuf,
792 int *pnMajorType,
793 uint64_t *puArgument,
794 int *pnAdditionalInfo)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700795{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800796 QCBORError uReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800797
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800798 /* Get the initial byte that every CBOR data item has and break it
799 * down. */
800 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800801 const int nTmpMajorType = nInitialByte >> 5;
802 const int nAdditionalInfo = nInitialByte & 0x1f;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800803
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800804 /* Where the argument accumulates */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800805 uint64_t uArgument;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800806
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800807 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800808 /* Need to get 1,2,4 or 8 additional argument bytes. Map
809 * LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length.
810 */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800811 static const uint8_t aIterate[] = {1,2,4,8};
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800812
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800813 /* Loop getting all the bytes in the argument */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800814 uArgument = 0;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800815 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800816 /* This shift and add gives the endian conversion. */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800817 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
818 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800819 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800820 /* The reserved and thus-far unused additional info values */
821 uReturn = QCBOR_ERR_UNSUPPORTED;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800822 goto Done;
823 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800824 /* Less than 24, additional info is argument or 31, an
825 * indefinite-length. No more bytes to get.
826 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800827 uArgument = (uint64_t)nAdditionalInfo;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700828 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800829
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700830 if(UsefulInputBuf_GetError(pUInBuf)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800831 uReturn = QCBOR_ERR_HIT_END;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700832 goto Done;
833 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800834
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800835 /* All successful if arrived here. */
836 uReturn = QCBOR_SUCCESS;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800837 *pnMajorType = nTmpMajorType;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800838 *puArgument = uArgument;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800839 *pnAdditionalInfo = nAdditionalInfo;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800840
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700841Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800842 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700843}
844
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800845
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800846/**
847 * @brief Decode integer types, major types 0 and 1.
848 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700849 * @param[in] nMajorType The CBOR major type (0 or 1).
850 * @param[in] uArgument The argument from the head.
851 * @param[in] nAdditionalInfo So it can be error-checked.
852 * @param[out] pDecodedItem The filled in decoded item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800853 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700854 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered.
855 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800856 *
857 * Must only be called when major type is 0 or 1.
858 *
859 * CBOR doesn't explicitly specify two's compliment for integers but
860 * all CPUs use it these days and the test vectors in the RFC are
861 * so. All integers in the CBOR structure are positive and the major
862 * type indicates positive or negative. CBOR can express positive
863 * integers up to 2^x - 1 where x is the number of bits and negative
864 * integers down to 2^x. Note that negative numbers can be one more
865 * away from zero than positive. Stdint, as far as I can tell, uses
866 * two's compliment to represent negative integers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700867 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700868static QCBORError
869QCBOR_Private_DecodeInteger(const int nMajorType,
870 const uint64_t uArgument,
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700871 const int nAdditionalInfo,
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700872 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700873{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800874 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800875
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700876 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
877 uReturn = QCBOR_ERR_BAD_INT;
878 goto Done;
879 }
880
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700881 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800882 if (uArgument <= INT64_MAX) {
883 pDecodedItem->val.int64 = (int64_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700884 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800885
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700886 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800887 pDecodedItem->val.uint64 = uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700888 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700889 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800890
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700891 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800892 if(uArgument <= INT64_MAX) {
893 /* CBOR's representation of negative numbers lines up with
894 * the two-compliment representation. A negative integer has
895 * one more in range than a positive integer. INT64_MIN is
896 * equal to (-INT64_MAX) - 1.
897 */
898 pDecodedItem->val.int64 = (-(int64_t)uArgument) - 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700899 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800900
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700901 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800902 /* C can't represent a negative integer in this range so it
903 * is an error.
904 */
905 uReturn = QCBOR_ERR_INT_OVERFLOW;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700906 }
907 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800908
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700909Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800910 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700911}
912
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800913
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700914/**
915 * @brief Decode text and byte strings
916 *
917 * @param[in] pMe Decoder context.
918 * @param[in] bAllocate Whether to allocate and copy string.
919 * @param[in] nMajorType Whether it is a byte or text string.
920 * @param[in] uStrLen The length of the string.
921 * @param[in] nAdditionalInfo Whether it is an indefinite-length string.
922 * @param[out] pDecodedItem The filled-in decoded item.
923 *
924 * @retval QCBOR_ERR_HIT_END Unexpected end of input.
925 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
926 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
927 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator
928 *
929 * This reads @c uStrlen bytes from the input and fills in @c
930 * pDecodedItem. If @c bAllocate is true, then memory for the string
931 * is allocated.
932 */
933static QCBORError
934QCBOR_Private_DecodeString(QCBORDecodeContext *pMe,
935 const bool bAllocate,
936 const int nMajorType,
937 const uint64_t uStrLen,
938 const int nAdditionalInfo,
939 QCBORItem *pDecodedItem)
940{
941 QCBORError uReturn = QCBOR_SUCCESS;
942
943 /* ---- Figure out the major type ---- */
944 #if CBOR_MAJOR_TYPE_BYTE_STRING + 4 != QCBOR_TYPE_BYTE_STRING
945 #error QCBOR_TYPE_BYTE_STRING not lined up with major type
946 #endif
947
948 #if CBOR_MAJOR_TYPE_TEXT_STRING + 4 != QCBOR_TYPE_TEXT_STRING
949 #error QCBOR_TYPE_TEXT_STRING not lined up with major type
950 #endif
951 pDecodedItem->uDataType = (uint8_t)(nMajorType + 4);
952
953 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
954 /* --- Just the head of an indefinite-length string --- */
955 pDecodedItem->val.string = (UsefulBufC){NULL, QCBOR_STRING_LENGTH_INDEFINITE};
956
957 } else {
958 /* --- A definite-length string --- */
959 /* --- (which might be a chunk of an indefinte-length string) --- */
960
961 /* CBOR lengths can be 64 bits, but size_t is not 64 bits on all
962 * CPUs. This check makes the casts to size_t below safe.
963 *
964 * The max is 4 bytes less than the largest sizeof() so this can be
965 * tested by putting a SIZE_MAX length in the CBOR test input (no
966 * one will care the limit on strings is 4 bytes shorter).
967 */
968 if(uStrLen > SIZE_MAX-4) {
969 uReturn = QCBOR_ERR_STRING_TOO_LONG;
970 goto Done;
971 }
972
973 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(&(pMe->InBuf), (size_t)uStrLen);
974 if(UsefulBuf_IsNULLC(Bytes)) {
975 /* Failed to get the bytes for this string item */
976 uReturn = QCBOR_ERR_HIT_END;
977 goto Done;
978 }
979
980 if(bAllocate) {
981#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
982 /* --- Put string in allocated memory --- */
983
984 /* Note that this is not where allocation to coalesce
985 * indefinite-length strings is done. This is for when the
986 * caller has requested all strings be allocated. Disabling
987 * indefinite length strings also disables this allocate-all
988 * option.
989 */
990
991 if(pMe->StringAllocator.pfAllocator == NULL) {
992 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
993 goto Done;
994 }
995 UsefulBuf NewMem = StringAllocator_Allocate(&(pMe->StringAllocator), (size_t)uStrLen);
996 if(UsefulBuf_IsNULL(NewMem)) {
997 uReturn = QCBOR_ERR_STRING_ALLOCATE;
998 goto Done;
999 }
1000 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
1001 pDecodedItem->uDataAlloc = 1;
1002#else
1003 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1004#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1005 } else {
1006 /* --- Normal case with no string allocator --- */
1007 pDecodedItem->val.string = Bytes;
1008 }
1009 }
1010
1011Done:
1012 return uReturn;
1013}
1014
1015
1016/**
1017 * @brief Decode array or map.
1018 *
1019 * @param[in] uMode Decoder mode.
1020 * @param[in] nMajorType Whether it is a byte or text string.
1021 * @param[in] uItemCount The length of the string.
1022 * @param[in] nAdditionalInfo Whether it is an indefinite-length.
1023 * @param[out] pDecodedItem The filled-in decoded item.
1024 *
1025 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinites disabled.
1026 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map.
1027 *
1028 * Not much to do for arrays and maps. Just the type item count (but a
1029 * little messy because of ifdefs for indefinite-lengths and
1030 * map-as-array decoding).
1031 *
1032 * This also does the bulk of the work for @ref
1033 * QCBOR_DECODE_MODE_MAP_AS_ARRAY, a special mode to handle
1034 * arbitrarily complex map labels. This ifdefs out with
1035 * QCBOR_DISABLE_NON_INTEGER_LABELS.
1036 */
1037static QCBORError
1038QCBOR_Private_DecodeArrayOrMap(const uint8_t uMode,
1039 const int nMajorType,
Laurence Lundblade2ce22a72024-08-24 07:09:57 -07001040 uint64_t uItemCount,
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001041 const int nAdditionalInfo,
1042 QCBORItem *pDecodedItem)
1043{
1044 QCBORError uReturn;
1045
1046 /* ------ Sort out the data type ------ */
1047 #if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
1048 #error QCBOR_TYPE_ARRAY value not lined up with major type
1049 #endif
1050
1051 #if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
1052 #error QCBOR_TYPE_MAP value not lined up with major type
1053 #endif
1054 pDecodedItem->uDataType = (uint8_t)nMajorType;
1055#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1056 if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
1057 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
1058 }
1059#else
1060 (void)uMode;
1061#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
1062
1063 uReturn = QCBOR_SUCCESS;
1064
1065 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1066 /* ------ Indefinite-length array/map ----- */
1067#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
1068 pDecodedItem->val.uCount = QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH;
1069#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1070 uReturn = QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED;
1071#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1072 } else {
Laurence Lundblade2ce22a72024-08-24 07:09:57 -07001073 /* ----- Definite-length array/map ----- */
1074 if(uItemCount > (nMajorType == QCBOR_TYPE_MAP ? QCBOR_MAX_ITEMS_IN_MAP : QCBOR_MAX_ITEMS_IN_ARRAY)) {
1075 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
1076 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001077
1078#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1079 if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
Laurence Lundblade2ce22a72024-08-24 07:09:57 -07001080 /* ------ Map as array ------ */
1081 uItemCount *= 2;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001082 }
Laurence Lundblade2ce22a72024-08-24 07:09:57 -07001083#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
1084
1085 /* cast OK because of check above */
1086 pDecodedItem->val.uCount = (uint16_t)uItemCount;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001087 }
1088
1089 return uReturn;
1090}
1091
1092
1093/**
1094 * @brief Decode a tag number.
1095 *
1096 * @param[in] uTagNumber The length of the string.
1097 * @param[in] nAdditionalInfo So this can be error-checked.
1098 * @param[out] pDecodedItem The filled-in decoded item.
1099 *
1100 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo is LEN_IS_INDEFINITE.
1101 * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined.
1102 *
1103 * Not much to do for tags, but fill in pDecodedItem and check for
1104 * error in nAdditionalInfo.
1105 */
1106static QCBORError
1107QCBOR_Private_DecodeTag(const uint64_t uTagNumber,
1108 const int nAdditionalInfo,
1109 QCBORItem *pDecodedItem)
1110{
1111#ifndef QCBOR_DISABLE_TAGS
1112 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1113 return QCBOR_ERR_BAD_INT;
1114 } else {
1115 pDecodedItem->val.uTagV = uTagNumber;
1116 pDecodedItem->uDataType = QCBOR_TYPE_TAG;
1117 return QCBOR_SUCCESS;
1118 }
1119#else /* QCBOR_DISABLE_TAGS */
1120 (void)nAdditionalInfo;
Laurence Lundblade6c9a8242024-06-12 20:34:52 -07001121 (void)uTagNumber;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001122 (void)pDecodedItem;
1123 return QCBOR_ERR_TAGS_DISABLED;
1124#endif /* QCBOR_DISABLE_TAGS */
1125}
1126
1127
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001128/* Make sure #define value line up as DecodeSimple counts on this. */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001129#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
1130#error QCBOR_TYPE_FALSE macro value wrong
1131#endif
1132
1133#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
1134#error QCBOR_TYPE_TRUE macro value wrong
1135#endif
1136
1137#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
1138#error QCBOR_TYPE_NULL macro value wrong
1139#endif
1140
1141#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
1142#error QCBOR_TYPE_UNDEF macro value wrong
1143#endif
1144
Laurence Lundblade0f99d692018-09-26 14:39:28 -07001145#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
1146#error QCBOR_TYPE_BREAK macro value wrong
1147#endif
1148
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001149#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
1150#error QCBOR_TYPE_DOUBLE macro value wrong
1151#endif
1152
1153#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
1154#error QCBOR_TYPE_FLOAT macro value wrong
1155#endif
1156
Laurence Lundblade9b334962020-08-27 10:55:53 -07001157
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001158/**
1159 * @brief Decode major type 7 -- true, false, floating-point, break...
1160 *
1161 * @param[in] nAdditionalInfo The lower five bits from the initial byte.
1162 * @param[in] uArgument The argument from the head.
1163 * @param[out] pDecodedItem The filled in decoded item.
1164 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001165 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1166 * of half-precision disabled
1167 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all float
1168 * decode is disabled.
1169 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of simple
1170 * type in input.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001171 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001172static QCBORError
1173QCBOR_Private_DecodeType7(const int nAdditionalInfo,
1174 const uint64_t uArgument,
1175 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001176{
1177 QCBORError uReturn = QCBOR_SUCCESS;
1178
1179 /* uAdditionalInfo is 5 bits from the initial byte. Compile time
1180 * checks above make sure uAdditionalInfo values line up with
1181 * uDataType values. DecodeHead() never returns an AdditionalInfo
1182 * > 0x1f so cast is safe.
1183 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001184 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001185
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001186 switch(nAdditionalInfo) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001187 /* No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they
1188 * are caught before this is called.
1189 */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001190
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001191 case HALF_PREC_FLOAT: /* 25 */
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -07001192#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001193 /* Half-precision is returned as a double. The cast to
1194 * uint16_t is safe because the encoded value was 16 bits. It
1195 * was widened to 64 bits to be passed in here.
1196 */
1197 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uArgument);
Laurence Lundblade67bd5512018-11-02 21:44:06 +07001198 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001199#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001200 uReturn = FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001201 break;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001202 case SINGLE_PREC_FLOAT: /* 26 */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001203#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001204 /* Single precision is normally returned as a double since
1205 * double is widely supported, there is no loss of precision,
1206 * it makes it easy for the caller in most cases and it can
1207 * be converted back to single with no loss of precision
1208 *
1209 * The cast to uint32_t is safe because the encoded value was
1210 * 32 bits. It was widened to 64 bits to be passed in here.
1211 */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001212 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001213 const float f = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uArgument);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001214#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001215 /* In the normal case, use HW to convert float to
1216 * double. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001217 pDecodedItem->val.dfnum = (double)f;
1218 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001219#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001220 /* Use of float HW is disabled, return as a float. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001221 pDecodedItem->val.fnum = f;
1222 pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
1223
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001224 /* IEEE754_FloatToDouble() could be used here to return as
1225 * a double, but it adds object code and most likely
1226 * anyone disabling FLOAT HW use doesn't care about floats
1227 * and wants to save object code.
1228 */
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001229#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001230 }
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001231#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1232 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001233 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001234
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001235 case DOUBLE_PREC_FLOAT: /* 27 */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001236#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001237 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uArgument);
Laurence Lundblade67bd5512018-11-02 21:44:06 +07001238 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001239#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1240 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001241 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001242
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001243 case CBOR_SIMPLEV_FALSE: /* 20 */
1244 case CBOR_SIMPLEV_TRUE: /* 21 */
1245 case CBOR_SIMPLEV_NULL: /* 22 */
1246 case CBOR_SIMPLEV_UNDEF: /* 23 */
1247 case CBOR_SIMPLE_BREAK: /* 31 */
1248 break; /* nothing to do */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001249
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001250 case CBOR_SIMPLEV_ONEBYTE: /* 24 */
1251 if(uArgument <= CBOR_SIMPLE_BREAK) {
1252 /* This takes out f8 00 ... f8 1f which should be encoded
1253 * as e0 … f7
1254 */
1255 uReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001256 goto Done;
1257 }
Laurence Lundblade5e390822019-01-06 12:35:01 -08001258 /* FALLTHROUGH */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001259
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001260 default: /* 0-19 */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001261 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001262 /* DecodeHead() will make uArgument equal to
1263 * nAdditionalInfo when nAdditionalInfo is < 24. This cast is
1264 * safe because the 2, 4 and 8 byte lengths of uNumber are in
1265 * the double/float cases above
Laurence Lundbladeee851742020-01-08 08:37:05 -08001266 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001267 pDecodedItem->val.uSimple = (uint8_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001268 break;
1269 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001270
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001271Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001272 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001273}
1274
1275
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001276/**
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001277 * @brief Decode a single primitive data item (decode layer 6).
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001278 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001279 * @param[in] pMe Decoder context.
1280 * @param[in] bAllocateStrings If true, use allocator for strings.
1281 * @param[out] pDecodedItem The filled-in decoded item.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001282 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001283 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1284 * features
1285 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1286 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1287 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1288 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001289 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001290 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1291 * of half-precision disabled
1292 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1293 * float decode is disabled.
1294 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1295 * simple type in input.
1296 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1297 * in input, but indefinite
1298 * lengths disabled.
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001299 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte.
1300 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map.
1301 * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001302 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001303 * This decodes the most primitive/atomic data item. It does no
1304 * combining of data items.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001305 */
1306static QCBORError
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001307QCBOR_Private_DecodeAtomicDataItem(QCBORDecodeContext *pMe,
1308 const bool bAllocateStrings,
1309 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001310{
1311 QCBORError uReturn;
Laurence Lundbladec7374282024-07-29 12:47:18 -07001312 int nMajorType = 0;
1313 uint64_t uArgument = 0;
1314 int nAdditionalInfo = 0;
1315
1316 memset(pDecodedItem, 0, sizeof(QCBORItem));
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001317
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001318 /* Decode the "head" that every CBOR item has into the major type,
1319 * argument and the additional info.
1320 */
1321 uReturn = QCBOR_Private_DecodeHead(&(pMe->InBuf), &nMajorType, &uArgument, &nAdditionalInfo);
1322 if(uReturn != QCBOR_SUCCESS) {
1323 return uReturn;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001324 }
1325
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001326 /* All the functions below get inlined by the optimizer. This code
1327 * is easier to read with them all being similar functions, even if
1328 * some functions don't do much.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001329 */
1330 switch (nMajorType) {
1331 case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
1332 case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001333 return QCBOR_Private_DecodeInteger(nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001334 break;
1335
1336 case CBOR_MAJOR_TYPE_BYTE_STRING: /* Major type 2 */
1337 case CBOR_MAJOR_TYPE_TEXT_STRING: /* Major type 3 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001338 return QCBOR_Private_DecodeString(pMe, bAllocateStrings, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001339 break;
1340
1341 case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */
1342 case CBOR_MAJOR_TYPE_MAP: /* Major type 5 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001343 return QCBOR_Private_DecodeArrayOrMap(pMe->uDecodeMode, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001344 break;
1345
1346 case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001347 return QCBOR_Private_DecodeTag(uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001348 break;
1349
1350 case CBOR_MAJOR_TYPE_SIMPLE:
1351 /* Major type 7: float, double, true, false, null... */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001352 return QCBOR_Private_DecodeType7(nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001353 break;
1354
1355 default:
1356 /* Never happens because DecodeHead() should never return > 7 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001357 return QCBOR_ERR_UNSUPPORTED;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001358 break;
1359 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001360}
1361
1362
1363/**
1364 * @brief Process indefinite-length strings (decode layer 5).
1365 *
1366 * @param[in] pMe Decoder context
1367 * @param[out] pDecodedItem The decoded item that work is done on.
1368 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001369 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1370 * features
1371 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1372 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1373 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1374 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1375 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1376 * of half-precision disabled
1377 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1378 * float decode is disabled.
1379 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1380 * simple type in input.
1381 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1382 * in input, but indefinite
1383 * lengths disabled.
1384 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1385 * but no string allocator.
1386 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1387 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1388 * input, but indefinite-length
1389 * strings are disabled.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001390 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001391 * If @c pDecodedItem is not an indefinite-length string, this does nothing.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001392 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001393 * If it is, this loops getting the subsequent chunk data items that
1394 * make up the string. The string allocator is used to make a
1395 * contiguous buffer for the chunks. When this completes @c
1396 * pDecodedItem contains the put-together string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001397 *
1398 * Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001399 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001400static QCBORError
1401QCBORDecode_Private_GetNextFullString(QCBORDecodeContext *pMe,
1402 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001403{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001404 /* Aproximate stack usage
1405 * 64-bit 32-bit
1406 * local vars 32 16
1407 * 2 UsefulBufs 32 16
1408 * QCBORItem 56 52
1409 * TOTAL 120 74
1410 */
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001411 QCBORError uReturn;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001412
1413 /* A note about string allocation -- Memory for strings is
1414 * allocated either because 1) indefinte-length string chunks are
1415 * being coalecsed or 2) caller has requested all strings be
1416 * allocated. The first case is handed below here. The second case
1417 * is handled in DecodeString if the bAllocate is true. That
1418 * boolean originates here with pMe->bStringAllocateAll immediately
1419 * below. That is, QCBOR_Private_DecodeAtomicDataItem() is called
1420 * in two different contexts here 1) main-line processing which is
1421 * where definite-length strings need to be allocated if
1422 * bStringAllocateAll is true and 2) processing chunks of
1423 * indefinite-lengths strings in in which case there must be no
1424 * allocation.
1425 */
1426
1427
1428 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, pMe->bStringAllocateAll, pDecodedItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001429 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001430 goto Done;
1431 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001432
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001433
1434 /* This is where out-of-place break is detected for the whole
1435 * decoding stack. Break is an error for everything that calls
1436 * QCBORDecode_Private_GetNextFullString(), so the check is
1437 * centralized here.
1438 */
1439 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
1440 uReturn = QCBOR_ERR_BAD_BREAK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001441 goto Done;
1442 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001443
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001444
1445 /* Skip out if not an indefinite-length string */
1446 const uint8_t uStringType = pDecodedItem->uDataType;
1447 if(uStringType != QCBOR_TYPE_BYTE_STRING &&
1448 uStringType != QCBOR_TYPE_TEXT_STRING) {
1449 goto Done;
1450 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001451 if(pDecodedItem->val.string.len != QCBOR_STRING_LENGTH_INDEFINITE) {
1452 goto Done;
1453 }
1454
1455#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001456 /* Can't decode indefinite-length strings without a string allocator */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001457 if(!pMe->StringAllocator.pfAllocator) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001458 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1459 goto Done;
1460 }
1461
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001462 /* Loop getting chunks of the indefinite-length string */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001463 UsefulBufC FullString = NULLUsefulBufC;
1464
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001465 for(;;) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001466 /* Get QCBORItem for next chunk */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001467 QCBORItem StringChunkItem;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001468 /* Pass false to DecodeAtomicDataItem() because the individual
1469 * string chunks in an indefinite-length must not be
1470 * allocated. They are always copied into the allocated
1471 * contiguous buffer allocated here.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001472 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001473 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &StringChunkItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001474 if(uReturn) {
1475 break;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001476 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001477
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001478 /* Is item is the marker for end of the indefinite-length string? */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001479 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001480 /* String is complete */
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001481 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301482 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001483 break;
1484 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001485
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001486 /* All chunks must be of the same type, the type of the item
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001487 * that introduces the indefinite-length string. This also
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001488 * catches errors where the chunk is not a string at all and an
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001489 * indefinite-length string inside an indefinite-length string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001490 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001491 if(StringChunkItem.uDataType != uStringType ||
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001492 StringChunkItem.val.string.len == QCBOR_STRING_LENGTH_INDEFINITE) {
1493 uReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001494 break;
1495 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001496
David Navarro9123e5b2022-03-28 16:04:03 +02001497 if (StringChunkItem.val.string.len > 0) {
1498 /* The first time throurgh FullString.ptr is NULL and this is
1499 * equivalent to StringAllocator_Allocate(). Subsequently it is
1500 * not NULL and a reallocation happens.
1501 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001502 UsefulBuf NewMem = StringAllocator_Reallocate(&(pMe->StringAllocator),
David Navarro9123e5b2022-03-28 16:04:03 +02001503 FullString.ptr,
1504 FullString.len + StringChunkItem.val.string.len);
David Navarro9123e5b2022-03-28 16:04:03 +02001505 if(UsefulBuf_IsNULL(NewMem)) {
1506 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1507 break;
1508 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001509
David Navarro9123e5b2022-03-28 16:04:03 +02001510 /* Copy new string chunk to the end of accumulated string */
1511 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001512 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001513 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001514
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001515 if(uReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
1516 /* Getting the item failed, clean up the allocated memory */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001517 StringAllocator_Free(&(pMe->StringAllocator), FullString.ptr);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001518 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001519#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1520 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1521#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001522
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001523Done:
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001524 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001525}
1526
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001527
Laurence Lundblade37286c02022-09-03 10:05:02 -07001528#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001529/**
1530 * @brief This converts a tag number to a shorter mapped value for storage.
1531 *
1532 * @param[in] pMe The decode context.
1533 * @param[in] uUnMappedTag The tag number to map
1534 * @param[out] puMappedTagNumer The stored tag number.
1535 *
1536 * @return error code.
1537 *
1538 * The main point of mapping tag numbers is make QCBORItem
1539 * smaller. With this mapping storage of 4 tags takes up 8
1540 * bytes. Without, it would take up 32 bytes.
1541 *
1542 * This maps tag numbers greater than QCBOR_LAST_UNMAPPED_TAG.
1543 * QCBOR_LAST_UNMAPPED_TAG is a little smaller than MAX_UINT16.
1544 *
1545 * See also UnMapTagNumber() and @ref QCBORItem.
1546 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001547static QCBORError
1548QCBORDecode_Private_MapTagNumber(QCBORDecodeContext *pMe,
1549 const uint64_t uUnMappedTag,
1550 uint16_t *puMappedTagNumer)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001551{
1552 if(uUnMappedTag > QCBOR_LAST_UNMAPPED_TAG) {
1553 unsigned uTagMapIndex;
1554 /* Is there room in the tag map, or is it in it already? */
1555 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
1556 if(pMe->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID64) {
1557 break;
1558 }
1559 if(pMe->auMappedTags[uTagMapIndex] == uUnMappedTag) {
1560 break;
1561 }
1562 }
1563 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
1564 return QCBOR_ERR_TOO_MANY_TAGS;
1565 }
1566
1567 /* Covers the cases where tag is new and were it is already in the map */
1568 pMe->auMappedTags[uTagMapIndex] = uUnMappedTag;
1569 *puMappedTagNumer = (uint16_t)(uTagMapIndex + QCBOR_LAST_UNMAPPED_TAG + 1);
1570
1571 } else {
1572 *puMappedTagNumer = (uint16_t)uUnMappedTag;
1573 }
1574
1575 return QCBOR_SUCCESS;
1576}
1577
1578
1579/**
1580 * @brief This converts a mapped tag number to the actual tag number.
1581 *
1582 * @param[in] pMe The decode context.
1583 * @param[in] uMappedTagNumber The stored tag number.
1584 *
1585 * @return The actual tag number is returned or
1586 * @ref CBOR_TAG_INVALID64 on error.
1587 *
1588 * This is the reverse of MapTagNumber()
1589 */
1590static uint64_t
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001591QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe,
1592 const uint16_t uMappedTagNumber)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001593{
1594 if(uMappedTagNumber <= QCBOR_LAST_UNMAPPED_TAG) {
1595 return uMappedTagNumber;
1596 } else if(uMappedTagNumber == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07001597 return CBOR_TAG_INVALID64;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001598 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001599 /* This won't be negative because of code below in
1600 * MapTagNumber()
1601 */
1602 const unsigned uIndex = uMappedTagNumber - (QCBOR_LAST_UNMAPPED_TAG + 1);
1603 return pMe->auMappedTags[uIndex];
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001604 }
1605}
Laurence Lundblade37286c02022-09-03 10:05:02 -07001606#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001607
Laurence Lundblade9b334962020-08-27 10:55:53 -07001608
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001609/**
1610 * @brief Aggregate all tags wrapping a data item (decode layer 4).
1611 *
1612 * @param[in] pMe Decoder context
1613 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001614 *
1615 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1616 * features
1617 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1618 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1619 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1620 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1621 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1622 * of half-precision disabled
1623 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1624 * float decode is disabled.
1625 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1626 * simple type in input.
1627 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1628 * in input, but indefinite
1629 * lengths disabled.
1630 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1631 * but no string allocator.
1632 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1633 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1634 * input, but indefinite-length
1635 * strings are disabled.
1636 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001637 *
1638 * This loops getting atomic data items until one is not a tag
1639 * number. Usually this is largely pass-through because most
1640 * item are not tag numbers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001641 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001642static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001643QCBORDecode_Private_GetNextTagNumber(QCBORDecodeContext *pMe,
1644 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001645{
Laurence Lundblade37286c02022-09-03 10:05:02 -07001646#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001647 /* Accummulate the tags from multiple items here and then copy them
1648 * into the last item, the non-tag item.
1649 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001650 uint16_t auItemsTags[QCBOR_MAX_TAGS_PER_ITEM];
1651
1652 /* Initialize to CBOR_TAG_INVALID16 */
1653 #if CBOR_TAG_INVALID16 != 0xffff
1654 /* Be sure the memset does the right thing. */
1655 #err CBOR_TAG_INVALID16 tag not defined as expected
1656 #endif
1657 memset(auItemsTags, 0xff, sizeof(auItemsTags));
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001658
Laurence Lundblade9b334962020-08-27 10:55:53 -07001659 QCBORError uReturn = QCBOR_SUCCESS;
1660
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001661 /* Loop fetching data items until the item fetched is not a tag */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001662 for(;;) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001663 QCBORError uErr = QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07001664 if(uErr != QCBOR_SUCCESS) {
1665 uReturn = uErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001666 goto Done;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001667 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001668
Laurence Lundblade9b334962020-08-27 10:55:53 -07001669 if(pDecodedItem->uDataType != QCBOR_TYPE_TAG) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001670 /* Successful exit from loop; maybe got some tags, maybe not */
1671 memcpy(pDecodedItem->uTags, auItemsTags, sizeof(auItemsTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001672 break;
1673 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001674
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001675 if(auItemsTags[QCBOR_MAX_TAGS_PER_ITEM - 1] != CBOR_TAG_INVALID16) {
1676 /* No room in the tag list */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001677 uReturn = QCBOR_ERR_TOO_MANY_TAGS;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001678 /* Continue on to get all tags wrapping this item even though
1679 * it is erroring out in the end. This allows decoding to
1680 * continue. This is a resource limit error, not a problem
1681 * with being well-formed CBOR.
1682 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001683 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001684 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001685 /* Slide tags over one in the array to make room at index 0.
1686 * Must use memmove because the move source and destination
1687 * overlap.
1688 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001689 memmove(&auItemsTags[1],
1690 auItemsTags,
1691 sizeof(auItemsTags) - sizeof(auItemsTags[0]));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001692
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001693 /* Map the tag */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001694 uint16_t uMappedTagNumber = 0;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001695 uReturn = QCBORDecode_Private_MapTagNumber(pMe, pDecodedItem->val.uTagV, &uMappedTagNumber);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001696 /* Continue even on error so as to consume all tags wrapping
1697 * this data item so decoding can go on. If MapTagNumber()
1698 * errors once it will continue to error.
1699 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001700 auItemsTags[0] = uMappedTagNumber;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001701 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001702
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001703Done:
Laurence Lundblade9b334962020-08-27 10:55:53 -07001704 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001705
Laurence Lundblade37286c02022-09-03 10:05:02 -07001706#else /* QCBOR_DISABLE_TAGS */
1707
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07001708 return QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07001709
1710#endif /* QCBOR_DISABLE_TAGS */
1711}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001712
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001713
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001714/**
1715 * @brief Combine a map entry label and value into one item (decode layer 3).
1716 *
1717 * @param[in] pMe Decoder context
1718 * @param[out] pDecodedItem The decoded item that work is done on.
1719 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001720 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1721 * features
1722 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1723 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1724 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1725 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1726 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1727 * of half-precision disabled
1728 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1729 * float decode is disabled.
1730 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1731 * simple type in input.
1732 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1733 * in input, but indefinite
1734 * lengths disabled.
1735 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1736 * but no string allocator.
1737 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1738 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1739 * input, but indefinite-length
1740 * strings are disabled.
1741 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1742 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1743 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001744 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001745 * If the current nesting level is a map, then this combines pairs of
1746 * items into one data item with a label and value.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001747 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001748 * This is passthrough if the current nesting level is not a map.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001749 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001750 * This also implements maps-as-array mode where a map is treated like
1751 * an array to allow caller to do their own label processing.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001752 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001753
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001754static QCBORError
1755QCBORDecode_Private_GetNextMapEntry(QCBORDecodeContext *pMe,
1756 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001757{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001758 QCBORItem LabelItem;
1759 QCBORError uErr;
1760
1761 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1762 if(QCBORDecode_IsUnrecoverableError(uErr)) {
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001763 goto Done;
1764 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001765
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001766 if(!DecodeNesting_IsCurrentTypeMap(&(pMe->nesting))) {
1767 /* Not decoding a map. Nothing to do. */
1768 /* When decoding maps-as-arrays, the type will be
1769 * QCBOR_TYPE_MAP_AS_ARRAY and this function will exit
1770 * here. This is now map processing for maps-as-arrays is not
1771 * done. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001772 goto Done;
1773 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001774
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001775 /* Decoding a map entry, so the item decoded above was the label */
1776 LabelItem = *pDecodedItem;
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001777
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001778 /* Get the value of the map item */
1779 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1780 if(QCBORDecode_IsUnrecoverableError(uErr)) {
1781 goto Done;
1782 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001783
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001784 /* Combine the label item and value item into one */
1785 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
1786 pDecodedItem->uLabelType = LabelItem.uDataType;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001787
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001788#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1789 /* QCBOR_DECODE_MODE_MAP_STRINGS_ONLY might have been a bad idea. Maybe
1790 * get rid of it in QCBOR 2.0
1791 */
1792 if(pMe->uDecodeMode == QCBOR_DECODE_MODE_MAP_STRINGS_ONLY &&
1793 LabelItem.uDataType != QCBOR_TYPE_TEXT_STRING) {
1794 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
1795 goto Done;
1796 }
1797#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
1798
1799 switch(LabelItem.uDataType) {
1800 case QCBOR_TYPE_INT64:
1801 pDecodedItem->label.int64 = LabelItem.val.int64;
1802 break;
1803
1804#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1805 case QCBOR_TYPE_UINT64:
1806 pDecodedItem->label.uint64 = LabelItem.val.uint64;
1807 break;
1808
1809 case QCBOR_TYPE_TEXT_STRING:
1810 case QCBOR_TYPE_BYTE_STRING:
1811 pDecodedItem->label.string = LabelItem.val.string;
1812 break;
1813#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
1814
1815 default:
1816 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
1817 goto Done;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001818 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001819
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001820Done:
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001821 return uErr;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001822}
1823
1824
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001825#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001826/**
1827 * @brief Peek and see if next data item is a break;
1828 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001829 * param[in] pUIB UsefulInputBuf to read from.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001830 * @param[out] pbNextIsBreak Indicate if next was a break or not.
1831 *
1832 * @return Any decoding error.
1833 *
1834 * See if next item is a CBOR break. If it is, it is consumed,
1835 * if not it is not consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07001836*/
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001837static QCBORError
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001838QCBOR_Private_NextIsBreak(QCBORDecodeContext *pMe, bool *pbNextIsBreak)
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001839{
1840 *pbNextIsBreak = false;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001841 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) != 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001842 QCBORItem Peek;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001843 size_t uPeek = UsefulInputBuf_Tell(&(pMe->InBuf));
1844 QCBORError uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &Peek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001845 if(uReturn != QCBOR_SUCCESS) {
1846 return uReturn;
1847 }
1848 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001849 /* It is not a break, rewind so it can be processed normally. */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001850 UsefulInputBuf_Seek(&(pMe->InBuf), uPeek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001851 } else {
1852 *pbNextIsBreak = true;
1853 }
1854 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001855
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001856 return QCBOR_SUCCESS;
1857}
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001858#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001859
1860
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001861/**
1862 * @brief Ascend up nesting levels if all items in them have been consumed.
1863 *
1864 * @param[in] pMe The decode context.
1865 * @param[in] bMarkEnd If true mark end of maps/arrays with count of zero.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001866 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001867 *
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001868 * An item was just consumed, now figure out if it was the
1869 * end of an array/map map that can be closed out. That
1870 * may in turn close out the above array/map...
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001871 *
1872 * When ascending indefinite-length arrays and maps, this will correctly
1873 * consume the break for the level above. This is a problem for the
1874 * implementation of QCBORDecode_GetArray() that must not return
1875 * that break. @c pbBreak is set to true to indicate that one
1876 * byte should be removed.
1877 *
1878 * Improvement: this could reduced further if indef is disabled
1879 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001880static QCBORError
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001881QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd, bool *pbBreak)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001882{
1883 QCBORError uReturn;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001884
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001885 /* Loop ascending nesting levels as long as there is ascending to do */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001886 while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001887 if(pbBreak) {
1888 *pbBreak = false;
1889 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001890
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001891 if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) {
1892 /* Nesting level is bstr-wrapped CBOR */
1893
1894 /* Ascent for bstr-wrapped CBOR is always by explicit call
1895 * so no further ascending can happen.
1896 */
1897 break;
1898
1899 } else if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
1900 /* Level is a definite-length array/map */
1901
1902 /* Decrement the item count the definite-length array/map */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001903 DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(&(pMe->nesting));
1904 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001905 /* Didn't close out array/map, so all work here is done */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001906 break;
1907 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001908 /* All items in a definite-length array were consumed so it
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001909 * is time to ascend one level. This happens below.
1910 */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001911
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001912#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001913 } else {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001914 /* Level is an indefinite-length array/map. */
1915
1916 /* Check for a break which is what ends indefinite-length arrays/maps */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001917 bool bIsBreak = false;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001918 uReturn = QCBOR_Private_NextIsBreak(pMe, &bIsBreak);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001919 if(uReturn != QCBOR_SUCCESS) {
1920 goto Done;
1921 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001922
1923 if(!bIsBreak) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001924 /* Not a break so array/map does not close out. All work is done */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001925 break;
1926 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001927
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001928 /* It was a break in an indefinitelength map / array so
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001929 * it is time to ascend one level.
1930 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001931 if(pbBreak) {
1932 *pbBreak = true;
1933 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001934
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001935#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001936 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001937
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001938
1939 /* All items in the array/map have been consumed. */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001940
Laurence Lundblade93d89472020-10-03 22:30:50 -07001941 /* But ascent in bounded mode is only by explicit call to
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001942 * QCBORDecode_ExitBoundedMode().
1943 */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07001944 if(DecodeNesting_IsCurrentBounded(&(pMe->nesting))) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001945 /* Set the count to zero for definite-length arrays to indicate
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001946 * cursor is at end of bounded array/map */
Laurence Lundbladed0304932020-06-27 10:59:38 -07001947 if(bMarkEnd) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001948 /* Used for definite and indefinite to signal end */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07001949 DecodeNesting_ZeroMapOrArrayCount(&(pMe->nesting));
Laurence Lundbladed0304932020-06-27 10:59:38 -07001950
Laurence Lundblade2c1faf92020-06-26 22:43:56 -07001951 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001952 break;
1953 }
1954
1955 /* Finally, actually ascend one level. */
1956 DecodeNesting_Ascend(&(pMe->nesting));
1957 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001958
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001959 uReturn = QCBOR_SUCCESS;
1960
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001961#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001962Done:
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001963#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1964
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001965 return uReturn;
1966}
1967
1968
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001969/**
1970 * @brief Ascending & Descending out of nesting levels (decode layer 2).
1971 *
1972 * @param[in] pMe Decoder context
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001973 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001974 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001975
1976 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1977 * features
1978 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1979 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1980 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1981 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1982 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1983 * of half-precision disabled
1984 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1985 * float decode is disabled.
1986 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1987 * simple type in input.
1988 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1989 * in input, but indefinite
1990 * lengths disabled.
1991 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1992 * but no string allocator.
1993 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1994 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1995 * input, but indefinite-length
1996 * strings are disabled.
1997 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1998 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1999 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
2000 * @retval QCBOR_ERR_NO_MORE_ITEMS Need more items for map or array.
2001 * @retval QCBOR_ERR_BAD_BREAK Indefinite-length break in wrong
2002 * place.
2003 * @retval QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP Nesting deeper than QCBOR
2004 * can handle.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002005 *
2006 * This handles the traversal descending into and asecnding out of
2007 * maps, arrays and bstr-wrapped CBOR. It figures out the ends of
2008 * definite- and indefinte-length maps and arrays by looking at the
2009 * item count or finding CBOR breaks. It detects the ends of the
2010 * top-level sequence and of bstr-wrapped CBOR by byte count.
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002011 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002012static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002013QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002014 bool *pbBreak,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002015 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002016{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002017 QCBORError uReturn;
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002018 /* ==== First: figure out if at the end of a traversal ==== */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002019
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002020 /* If out of bytes to consume, it is either the end of the
2021 * top-level sequence of some bstr-wrapped CBOR that was entered.
2022 *
2023 * In the case of bstr-wrapped CBOR, the length of the
2024 * UsefulInputBuf was set to that of the bstr-wrapped CBOR. When
2025 * the bstr-wrapped CBOR is exited, the length is set back to the
2026 * top-level's length or to the next highest bstr-wrapped CBOR.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002027 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002028 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) == 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002029 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002030 goto Done;
2031 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07002032
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002033 /* Check to see if at the end of a bounded definite-length map or
2034 * array. The check for a break ending indefinite-length array is
2035 * later in QCBORDecode_NestLevelAscender().
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002036 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002037 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002038 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002039 goto Done;
2040 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002041
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002042 /* ==== Next: not at the end, so get another item ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002043 uReturn = QCBORDecode_Private_GetNextMapEntry(pMe, pDecodedItem);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002044 if(QCBORDecode_IsUnrecoverableError(uReturn)) {
2045 /* Error is so bad that traversal is not possible. */
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002046 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002047 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05302048
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002049 /* Record the nesting level for this data item before processing
2050 * any of decrementing and descending.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002051 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002052 pDecodedItem->uNestingLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002053
Laurence Lundblade642282a2020-06-23 12:00:33 -07002054
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002055 /* ==== Next: Process the item for descent, ascent, decrement... ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002056 if(QCBORItem_IsMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002057 /* If the new item is a map or array, descend.
2058 *
2059 * Empty indefinite-length maps and arrays are descended into,
2060 * but then ascended out of in the next chunk of code.
2061 *
2062 * Maps and arrays do count as items in the map/array that
2063 * encloses them so a decrement needs to be done for them too,
2064 * but that is done only when all the items in them have been
2065 * processed, not when they are opened with the exception of an
2066 * empty map or array.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002067 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002068 QCBORError uDescendErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002069 uDescendErr = DecodeNesting_DescendMapOrArray(&(pMe->nesting),
Laurence Lundblade2ce22a72024-08-24 07:09:57 -07002070 pDecodedItem->uDataType,
2071 pDecodedItem->val.uCount);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002072 if(uDescendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002073 /* This error is probably a traversal error and it overrides
2074 * the non-traversal error.
2075 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002076 uReturn = uDescendErr;
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002077 goto Done;
2078 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002079 }
2080
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002081 if(!QCBORItem_IsMapOrArray(*pDecodedItem) ||
2082 QCBORItem_IsEmptyDefiniteLengthMapOrArray(*pDecodedItem) ||
2083 QCBORItem_IsIndefiniteLengthMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002084 /* The following cases are handled here:
2085 * - A non-aggregate item like an integer or string
2086 * - An empty definite-length map or array
2087 * - An indefinite-length map or array that might be empty or might not.
2088 *
2089 * QCBORDecode_NestLevelAscender() does the work of decrementing the count
2090 * for an definite-length map/array and break detection for an
2091 * indefinite-0length map/array. If the end of the map/array was
2092 * reached, then it ascends nesting levels, possibly all the way
2093 * to the top level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002094 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002095 QCBORError uAscendErr;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002096 uAscendErr = QCBORDecode_Private_NestLevelAscender(pMe, true, pbBreak);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002097 if(uAscendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002098 /* This error is probably a traversal error and it overrides
2099 * the non-traversal error.
2100 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002101 uReturn = uAscendErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002102 goto Done;
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002103 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05302104 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002105
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002106 /* ==== Last: tell the caller the nest level of the next item ==== */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002107 /* Tell the caller what level is next. This tells them what
2108 * maps/arrays were closed out and makes it possible for them to
2109 * reconstruct the tree with just the information returned in a
2110 * QCBORItem.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002111 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002112 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07002113 /* At end of a bounded map/array; uNextNestLevel 0 to indicate this */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002114 pDecodedItem->uNextNestLevel = 0;
2115 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002116 pDecodedItem->uNextNestLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002117 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002118
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002119Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002120 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002121}
2122
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002123
Laurence Lundblade37286c02022-09-03 10:05:02 -07002124#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002125/**
2126 * @brief Shift 0th tag out of the tag list.
2127 *
2128 * pDecodedItem[in,out] The data item to convert.
2129 *
2130 * The 0th tag is discarded. \ref CBOR_TAG_INVALID16 is
2131 * shifted into empty slot at the end of the tag list.
2132 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002133static void
2134QCBOR_Private_ShiftTags(QCBORItem *pDecodedItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002135{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002136 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM-1; i++) {
2137 pDecodedItem->uTags[i] = pDecodedItem->uTags[i+1];
2138 }
2139 pDecodedItem->uTags[QCBOR_MAX_TAGS_PER_ITEM-1] = CBOR_TAG_INVALID16;
Laurence Lundblade9b334962020-08-27 10:55:53 -07002140}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002141#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002142
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002143
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002144/**
2145 * @brief Convert different epoch date formats in to the QCBOR epoch date format
2146 *
2147 * pDecodedItem[in,out] The data item to convert.
2148 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002149 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2150 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2151 * floating-point date disabled.
2152 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2153 * all floating-point disabled.
2154 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2155 * error decoding date.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002156 *
2157 * The epoch date tag defined in QCBOR allows for floating-point
2158 * dates. It even allows a protocol to flop between date formats when
2159 * ever it wants. Floating-point dates aren't that useful as they are
2160 * only needed for dates beyond the age of the earth.
2161 *
2162 * This converts all the date formats into one format of an unsigned
2163 * integer plus a floating-point fraction.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002164 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002165static QCBORError
2166QCBOR_Private_DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002167{
Laurence Lundbladec7114722020-08-13 05:11:40 -07002168 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002169
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002170#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade59289e52019-12-30 13:44:37 -08002171 pDecodedItem->val.epochDate.fSecondsFraction = 0;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002172#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002173
2174 switch (pDecodedItem->uDataType) {
2175
2176 case QCBOR_TYPE_INT64:
2177 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
2178 break;
2179
2180 case QCBOR_TYPE_UINT64:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002181 /* This only happens for CBOR type 0 > INT64_MAX so it is
2182 * always an overflow.
2183 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07002184 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2185 goto Done;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002186 break;
2187
2188 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade9682a532020-06-06 18:33:04 -07002189 case QCBOR_TYPE_FLOAT:
2190#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade59289e52019-12-30 13:44:37 -08002191 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002192 /* Convert working value to double if input was a float */
Laurence Lundblade3ed0bca2020-07-14 22:50:10 -07002193 const double d = pDecodedItem->uDataType == QCBOR_TYPE_DOUBLE ?
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002194 pDecodedItem->val.dfnum :
2195 (double)pDecodedItem->val.fnum;
2196
2197 /* The conversion from float to integer requires overflow
2198 * detection since floats can be much larger than integers.
2199 * This implementation errors out on these large float values
2200 * since they are beyond the age of the earth.
2201 *
2202 * These constants for the overflow check are computed by the
2203 * compiler. They are not computed at run time.
2204 *
2205 * The factor of 0x7ff is added/subtracted to avoid a
2206 * rounding error in the wrong direction when the compiler
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002207 * computes these constants. There is rounding because a
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002208 * 64-bit integer has 63 bits of precision where a double
2209 * only has 53 bits. Without the 0x7ff factor, the compiler
2210 * may round up and produce a double for the bounds check
2211 * that is larger than can be stored in a 64-bit integer. The
2212 * amount of 0x7ff is picked because it has 11 bits set.
2213 *
2214 * Without the 0x7ff there is a ~30 minute range of time
2215 * values 10 billion years in the past and in the future
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002216 * where this code could go wrong. Some compilers
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002217 * generate a warning or error without the 0x7ff.
2218 */
2219 const double dDateMax = (double)(INT64_MAX - 0x7ff);
2220 const double dDateMin = (double)(INT64_MIN + 0x7ff);
2221
2222 if(isnan(d) || d > dDateMax || d < dDateMin) {
Laurence Lundbladec7114722020-08-13 05:11:40 -07002223 uReturn = QCBOR_ERR_DATE_OVERFLOW;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002224 goto Done;
2225 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002226
2227 /* The actual conversion */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002228 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
Laurence Lundblade2feb1e12020-07-15 03:50:45 -07002229 pDecodedItem->val.epochDate.fSecondsFraction =
2230 d - (double)pDecodedItem->val.epochDate.nSeconds;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002231 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002232#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade4b270642020-08-14 12:53:07 -07002233
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002234 uReturn = QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundblade4b270642020-08-14 12:53:07 -07002235 goto Done;
2236
Laurence Lundblade9682a532020-06-06 18:33:04 -07002237#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002238 break;
2239
2240 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002241 /* It's the arrays and maps that are unrecoverable because
2242 * they are not consumed here. Since this is just an error
2243 * condition, no extra code is added here to make the error
2244 * recoverable for non-arrays and maps like strings. */
2245 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002246 goto Done;
2247 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002248
Laurence Lundblade59289e52019-12-30 13:44:37 -08002249 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
2250
2251Done:
Laurence Lundbladec7114722020-08-13 05:11:40 -07002252 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002253}
2254
2255
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002256/**
2257 * @brief Convert the days epoch date.
2258 *
2259 * pDecodedItem[in,out] The data item to convert.
2260 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002261 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2262 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2263 * floating-point date disabled.
2264 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2265 * all floating-point disabled.
2266 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2267 * error decoding date.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002268 *
2269 * This is much simpler than the other epoch date format because
2270 * floating-porint is not allowed. This is mostly a simple type check.
2271 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002272static QCBORError
2273QCBOR_Private_DecodeDaysEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002274{
2275 QCBORError uReturn = QCBOR_SUCCESS;
2276
2277 switch (pDecodedItem->uDataType) {
2278
2279 case QCBOR_TYPE_INT64:
2280 pDecodedItem->val.epochDays = pDecodedItem->val.int64;
2281 break;
2282
2283 case QCBOR_TYPE_UINT64:
2284 /* This only happens for CBOR type 0 > INT64_MAX so it is
2285 * always an overflow.
2286 */
2287 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2288 goto Done;
2289 break;
2290
2291 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002292 /* It's the arrays and maps that are unrecoverable because
2293 * they are not consumed here. Since this is just an error
2294 * condition, no extra code is added here to make the error
2295 * recoverable for non-arrays and maps like strings. */
2296 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002297 goto Done;
2298 break;
2299 }
2300
2301 pDecodedItem->uDataType = QCBOR_TYPE_DAYS_EPOCH;
2302
2303Done:
2304 return uReturn;
2305}
2306
2307
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002308#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade37286c02022-09-03 10:05:02 -07002309
2310/* Forward declaration is necessary for
2311 * QCBORDecode_MantissaAndExponent(). to be able to decode bignum
2312 * tags in the mantissa. If the mantissa is a decimal fraction or big
2313 * float in error, this will result in a recurive call to
2314 * QCBORDecode_MantissaAndExponent(), but the recursion will unwined
2315 * correctly and the correct error is returned.
2316 */
2317static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002318QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2319 QCBORItem *pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002320
2321
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002322/**
2323 * @brief Decode decimal fractions and big floats.
2324 *
2325 * @param[in] pMe The decode context.
2326 * @param[in,out] pDecodedItem On input the array data item that
2327 * holds the mantissa and exponent. On
2328 * output the decoded mantissa and
2329 * exponent.
2330 *
2331 * @returns Decoding errors from getting primitive data items or
2332 * \ref QCBOR_ERR_BAD_EXP_AND_MANTISSA.
2333 *
Laurence Lundblade37286c02022-09-03 10:05:02 -07002334 * When called pDecodedItem must be the array with two members, the
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002335 * exponent and mantissa.
2336 *
2337 * This will fetch and decode the exponent and mantissa and put the
2338 * result back into pDecodedItem.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002339 *
2340 * This does no checking or processing of tag numbers. That is to be
2341 * done by the code that calls this.
2342 *
2343 * This stuffs the type of the mantissa into pDecodedItem with the expectation
2344 * the caller will process it.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002345 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002346static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002347QCBORDecode_Private_ExpMantissa(QCBORDecodeContext *pMe,
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002348 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002349{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002350 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002351
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002352 /* --- Make sure it is an array; track nesting level of members --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002353 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002354 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002355 goto Done;
2356 }
2357
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002358 /* A check for pDecodedItem->val.uCount == 2 would work for
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002359 * definite-length arrays, but not for indefinite. Instead remember
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002360 * the nesting level the two integers must be at, which is one
2361 * deeper than that of the array.
2362 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002363 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
2364
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002365 /* --- Get the exponent --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002366 QCBORItem exponentItem;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002367 uReturn = QCBORDecode_GetNext(pMe, &exponentItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002368 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002369 goto Done;
2370 }
2371 if(exponentItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002372 /* Array is empty or a map/array encountered when expecting an int */
2373 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002374 goto Done;
2375 }
2376 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002377 /* Data arriving as an unsigned int < INT64_MAX has been
2378 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2379 * also means that the only data arriving here of type
2380 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2381 * and thus an error that will get handled in the next else.
2382 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002383 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
2384 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002385 /* Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX */
2386 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002387 goto Done;
2388 }
2389
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002390 /* --- Get the mantissa --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002391 QCBORItem mantissaItem;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002392 uReturn = QCBORDecode_GetNext(pMe, &mantissaItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002393 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002394 goto Done;
2395 }
2396 if(mantissaItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002397 /* Mantissa missing or map/array encountered when expecting number */
2398 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002399 goto Done;
2400 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002401 /* Stuff the mantissa data type into the item to send it up to the
2402 * the next level. */
2403 pDecodedItem->uDataType = mantissaItem.uDataType;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002404 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002405 /* Data arriving as an unsigned int < INT64_MAX has been
2406 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2407 * also means that the only data arriving here of type
2408 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2409 * and thus an error that will get handled in an else below.
2410 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002411 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002412#ifndef QCBOR_DISABLE_TAGS
2413 /* With tags fully disabled a big number mantissa will error out
2414 * in the call to QCBORDecode_GetNextWithTags() because it has
2415 * a tag number.
2416 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07002417 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM ||
2418 mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002419 /* Got a good big num mantissa */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002420 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002421#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002422 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002423 /* Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX */
2424 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002425 goto Done;
2426 }
2427
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002428 /* --- Check that array only has the two numbers --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002429 if(mantissaItem.uNextNestLevel == nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002430 /* Extra items in the decimal fraction / big float */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002431 /* Improvement: this should probably be an unrecoverable error. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002432 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002433 goto Done;
2434 }
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002435 pDecodedItem->uNextNestLevel = mantissaItem.uNextNestLevel;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002436
2437Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002438 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002439}
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002440#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002441
2442
Laurence Lundblade37286c02022-09-03 10:05:02 -07002443#ifndef QCBOR_DISABLE_TAGS
2444
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002445#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002446/**
2447 * @brief Decode the MIME type tag
2448 *
2449 * @param[in,out] pDecodedItem The item to decode.
2450 *
2451 * Handle the text and binary MIME type tags. Slightly too complicated
2452 * f or ProcessTaggedString() because the RFC 7049 MIME type was
2453 * incorreclty text-only.
2454 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002455static QCBORError
2456QCBOR_Private_DecodeMIME(QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002457{
2458 if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) {
2459 pDecodedItem->uDataType = QCBOR_TYPE_MIME;
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07002460 } else if(pDecodedItem->uDataType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002461 pDecodedItem->uDataType = QCBOR_TYPE_BINARY_MIME;
2462 } else {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002463 /* It's the arrays and maps that are unrecoverable because
2464 * they are not consumed here. Since this is just an error
2465 * condition, no extra code is added here to make the error
2466 * recoverable for non-arrays and maps like strings. */
2467 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002468 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002469
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002470 return QCBOR_SUCCESS;
2471}
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002472#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002473
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002474/**
Laurence Lundblade99615302020-11-29 11:19:47 -08002475 * Table of CBOR tags whose content is either a text string or a byte
2476 * string. The table maps the CBOR tag to the QCBOR type. The high-bit
2477 * of uQCBORtype indicates the content should be a byte string rather
2478 * than a text string
2479 */
2480struct StringTagMapEntry {
2481 uint16_t uTagNumber;
2482 uint8_t uQCBORtype;
2483};
2484
2485#define IS_BYTE_STRING_BIT 0x80
2486#define QCBOR_TYPE_MASK ~IS_BYTE_STRING_BIT
2487
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002488static const struct StringTagMapEntry QCBOR_Private_StringTagMap[] = {
Laurence Lundblade99615302020-11-29 11:19:47 -08002489 {CBOR_TAG_DATE_STRING, QCBOR_TYPE_DATE_STRING},
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002490 {CBOR_TAG_DAYS_STRING, QCBOR_TYPE_DAYS_STRING},
Laurence Lundblade99615302020-11-29 11:19:47 -08002491 {CBOR_TAG_POS_BIGNUM, QCBOR_TYPE_POSBIGNUM | IS_BYTE_STRING_BIT},
2492 {CBOR_TAG_NEG_BIGNUM, QCBOR_TYPE_NEGBIGNUM | IS_BYTE_STRING_BIT},
2493 {CBOR_TAG_CBOR, QBCOR_TYPE_WRAPPED_CBOR | IS_BYTE_STRING_BIT},
2494 {CBOR_TAG_URI, QCBOR_TYPE_URI},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002495#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002496 {CBOR_TAG_B64URL, QCBOR_TYPE_BASE64URL},
2497 {CBOR_TAG_B64, QCBOR_TYPE_BASE64},
2498 {CBOR_TAG_REGEX, QCBOR_TYPE_REGEX},
2499 {CBOR_TAG_BIN_UUID, QCBOR_TYPE_UUID | IS_BYTE_STRING_BIT},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002500#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade99615302020-11-29 11:19:47 -08002501 {CBOR_TAG_CBOR_SEQUENCE, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE | IS_BYTE_STRING_BIT},
2502 {CBOR_TAG_INVALID16, QCBOR_TYPE_NONE}
2503};
2504
2505
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002506/**
2507 * @brief Process standard CBOR tags whose content is a string
2508 *
2509 * @param[in] uTag The tag.
2510 * @param[in,out] pDecodedItem The data item.
2511 *
2512 * @returns This returns QCBOR_SUCCESS if the tag was procssed,
2513 * \ref QCBOR_ERR_UNSUPPORTED if the tag was not processed and
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002514 * \ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT if the content type was wrong for the tag.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002515 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002516 * Process the CBOR tags that whose content is a byte string or a text
2517 * string and for which the string is just passed on to the caller.
2518 *
2519 * This maps the CBOR tag to the QCBOR type and checks the content
2520 * type. Nothing more. It may not be the most important
Laurence Lundbladec02e13e2020-12-06 05:45:41 -08002521 * functionality, but it part of implementing as much of RFC 8949 as
Laurence Lundblade99615302020-11-29 11:19:47 -08002522 * possible.
Laurence Lundblade99615302020-11-29 11:19:47 -08002523 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002524static QCBORError
2525QCBOR_Private_ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002526{
Laurence Lundblade99615302020-11-29 11:19:47 -08002527 /* This only works on tags that were not mapped; no need for other yet */
2528 if(uTag > QCBOR_LAST_UNMAPPED_TAG) {
2529 return QCBOR_ERR_UNSUPPORTED;
2530 }
2531
2532 unsigned uIndex;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002533 for(uIndex = 0; QCBOR_Private_StringTagMap[uIndex].uTagNumber != CBOR_TAG_INVALID16; uIndex++) {
2534 if(QCBOR_Private_StringTagMap[uIndex].uTagNumber == uTag) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002535 break;
2536 }
2537 }
2538
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002539 const uint8_t uQCBORType = QCBOR_Private_StringTagMap[uIndex].uQCBORtype;
Laurence Lundblade99615302020-11-29 11:19:47 -08002540 if(uQCBORType == QCBOR_TYPE_NONE) {
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002541 /* repurpose this error to mean not handled here */
Laurence Lundblade99615302020-11-29 11:19:47 -08002542 return QCBOR_ERR_UNSUPPORTED;
2543 }
2544
2545 uint8_t uExpectedType = QCBOR_TYPE_TEXT_STRING;
2546 if(uQCBORType & IS_BYTE_STRING_BIT) {
2547 uExpectedType = QCBOR_TYPE_BYTE_STRING;
2548 }
2549
2550 if(pDecodedItem->uDataType != uExpectedType) {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002551 /* It's the arrays and maps that are unrecoverable because
2552 * they are not consumed here. Since this is just an error
2553 * condition, no extra code is added here to make the error
2554 * recoverable for non-arrays and maps like strings. */
2555 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002556 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002557
Laurence Lundblade99615302020-11-29 11:19:47 -08002558 pDecodedItem->uDataType = (uint8_t)(uQCBORType & QCBOR_TYPE_MASK);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002559 return QCBOR_SUCCESS;
2560}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002561#endif /* QCBOR_DISABLE_TAGS */
2562
2563
2564#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002565/**
2566 * @brief Figures out data type for exponent mantissa tags.
2567 *
2568 * @param[in] uTagToProcess Either @ref CBOR_TAG_DECIMAL_FRACTION or
2569 * @ref CBOR_TAG_BIG_FLOAT.
2570 * @param[in] pDecodedItem Item being decoded.
2571 *
2572 * @returns One of the 6 values between \ref QCBOR_TYPE_DECIMAL_FRACTION
2573 * and @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM.
2574 *
2575 * Does mapping between a CBOR tag number and a QCBOR type. with a
2576 * little bit of logic and arithmatic.
2577 *
2578 * Used in serveral contexts. Does the work where sometimes the data
2579 * item is explicitly tagged and sometimes not.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002580 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002581static uint8_t
2582QCBOR_Private_ExpMantissaDataType(const uint16_t uTagToProcess,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002583 const QCBORItem *pDecodedItem)
Laurence Lundblade37286c02022-09-03 10:05:02 -07002584{
2585 uint8_t uBase = uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ?
2586 QCBOR_TYPE_DECIMAL_FRACTION :
2587 QCBOR_TYPE_BIGFLOAT;
2588 if(pDecodedItem->uDataType != QCBOR_TYPE_INT64) {
2589 uBase = (uint8_t)(uBase + pDecodedItem->uDataType - QCBOR_TYPE_POSBIGNUM + 1);
2590 }
2591 return uBase;
2592}
2593#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002594
2595
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002596/**
2597 * @brief Decode tag content for select tags (decoding layer 1).
2598 *
2599 * @param[in] pMe The decode context.
2600 * @param[out] pDecodedItem The decoded item.
2601 *
2602 * @return Decoding error code.
2603 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002604 * CBOR tag numbers for the item were decoded in GetNext_TaggedItem(),
2605 * but the whole tag was not decoded. Here, the whole tags (tag number
2606 * and tag content) that are supported by QCBOR are decoded. This is a
2607 * quick pass through for items that are not tags.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002608 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002609static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002610QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2611 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002612{
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002613 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002614
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002615 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pDecodedItem);
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002616 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002617 goto Done;
2618 }
2619
Laurence Lundblade37286c02022-09-03 10:05:02 -07002620#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002621 /* When there are no tag numbers for the item, this exits first
2622 * thing and effectively does nothing.
2623 *
2624 * This loops over all the tag numbers accumulated for this item
2625 * trying to decode and interpret them. This stops at the end of
2626 * the list or at the first tag number that can't be interpreted by
2627 * this code. This is effectively a recursive processing of the
2628 * tags number list that handles nested tags.
2629 */
2630 while(1) {
2631 /* Don't bother to unmap tags via QCBORITem.uTags since this
2632 * code only works on tags less than QCBOR_LAST_UNMAPPED_TAG.
2633 */
2634 const uint16_t uTagToProcess = pDecodedItem->uTags[0];
Laurence Lundblade59289e52019-12-30 13:44:37 -08002635
Laurence Lundblade99615302020-11-29 11:19:47 -08002636 if(uTagToProcess == CBOR_TAG_INVALID16) {
2637 /* Hit the end of the tag list. A successful exit. */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002638 break;
2639
Laurence Lundblade99615302020-11-29 11:19:47 -08002640 } else if(uTagToProcess == CBOR_TAG_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002641 uReturn = QCBOR_Private_DecodeDateEpoch(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002642
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002643 } else if(uTagToProcess == CBOR_TAG_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002644 uReturn = QCBOR_Private_DecodeDaysEpoch(pDecodedItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002645
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002646#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade99615302020-11-29 11:19:47 -08002647 } else if(uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ||
2648 uTagToProcess == CBOR_TAG_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002649 uReturn = QCBORDecode_Private_ExpMantissa(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002650 /* --- Which is it, decimal fraction or a bigfloat? --- */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002651 pDecodedItem->uDataType = QCBOR_Private_ExpMantissaDataType(uTagToProcess, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002652
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002653#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002654#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002655 } else if(uTagToProcess == CBOR_TAG_MIME ||
2656 uTagToProcess == CBOR_TAG_BINARY_MIME) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002657 uReturn = QCBOR_Private_DecodeMIME(pDecodedItem);
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002658#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002659
Laurence Lundblade99615302020-11-29 11:19:47 -08002660 } else {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002661 /* See if it is a passthrough byte/text string tag; process if so */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002662 uReturn = QCBOR_Private_ProcessTaggedString(pDecodedItem->uTags[0], pDecodedItem);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002663
Laurence Lundblade99615302020-11-29 11:19:47 -08002664 if(uReturn == QCBOR_ERR_UNSUPPORTED) {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002665 /* It wasn't a passthrough byte/text string tag so it is
Laurence Lundblade99615302020-11-29 11:19:47 -08002666 * an unknown tag. This is the exit from the loop on the
2667 * first unknown tag. It is a successful exit.
2668 */
2669 uReturn = QCBOR_SUCCESS;
2670 break;
2671 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002672 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002673
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002674 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002675 /* Error exit from the loop */
2676 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002677 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002678
2679 /* A tag was successfully processed, shift it out of the list of
2680 * tags returned. This is the loop increment.
2681 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002682 QCBOR_Private_ShiftTags(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002683 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002684#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002685
2686Done:
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002687 return uReturn;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002688}
2689
2690
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002691/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002692 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002693 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002694QCBORError
2695QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2696{
2697 QCBORError uErr;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002698 uErr = QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002699 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002700 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2701 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
2702 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002703 return uErr;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002704}
2705
2706
2707/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002708 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08002709 */
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002710QCBORError
2711QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2712{
2713 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2714 const UsefulInputBuf Save = pMe->InBuf;
2715
2716 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
2717
2718 pMe->nesting = SaveNesting;
2719 pMe->InBuf = Save;
2720
2721 return uErr;
2722}
2723
2724
2725/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002726 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002727 */
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002728void
2729QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2730{
2731 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002732 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2733 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002734 return;
2735 }
2736
2737 pMe->uLastError = (uint8_t)QCBORDecode_PeekNext(pMe, pDecodedItem);
2738}
2739
2740
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002741static void
2742QCBORDecode_Private_CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem)
2743{
2744#ifndef QCBOR_DISABLE_TAGS
2745 memcpy(pMe->uLastTags, pItem->uTags, sizeof(pItem->uTags));
2746#else
2747 (void)pMe;
2748 (void)pItem;
2749#endif
2750}
2751
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002752/*
2753 * Public function, see header qcbor/qcbor_decode.h file
2754 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002755void
2756QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002757{
2758 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002759 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2760 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002761 return;
2762 }
2763
2764 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem);
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002765 QCBORDecode_Private_CopyTags(pMe, pDecodedItem);
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002766}
2767
2768
2769/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002770 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002771 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002772QCBORError
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002773QCBORDecode_GetNextWithTags(QCBORDecodeContext *pMe,
2774 QCBORItem *pDecodedItem,
2775 QCBORTagListOut *pTags)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002776{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002777#ifndef QCBOR_DISABLE_TAGS
2778
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002779 QCBORError uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002780
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002781 uReturn = QCBORDecode_GetNext(pMe, pDecodedItem);
2782 if(uReturn != QCBOR_SUCCESS) {
2783 return uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002784 }
2785
2786 if(pTags != NULL) {
2787 pTags->uNumUsed = 0;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002788 /* Reverse the order because pTags is reverse of QCBORItem.uTags. */
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002789 for(int nTagIndex = QCBOR_MAX_TAGS_PER_ITEM-1; nTagIndex >=0; nTagIndex--) {
2790 if(pDecodedItem->uTags[nTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07002791 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002792 }
2793 if(pTags->uNumUsed >= pTags->uNumAllocated) {
2794 return QCBOR_ERR_TOO_MANY_TAGS;
2795 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002796 pTags->puTags[pTags->uNumUsed] = QCBORDecode_Private_UnMapTagNumber(pMe,pDecodedItem->uTags[nTagIndex]);
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002797 pTags->uNumUsed++;
2798 }
2799 }
2800
2801 return QCBOR_SUCCESS;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002802
2803#else /* QCBOR_DISABLE_TAGS */
2804 (void)pMe;
2805 (void)pDecodedItem;
2806 (void)pTags;
2807 return QCBOR_ERR_TAGS_DISABLED;
2808#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002809}
2810
2811
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002812/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002813 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05302814 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002815bool
2816QCBORDecode_IsTagged(QCBORDecodeContext *pMe,
2817 const QCBORItem *pItem,
2818 uint64_t uTag)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002819{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002820#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002821 for(unsigned uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) {
2822 if(pItem->uTags[uTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002823 break;
2824 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002825 if(QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uTagIndex]) == uTag) {
Laurence Lundbladef71e1622020-08-06 18:52:13 -07002826 return true;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002827 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002828 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002829#else /* QCBOR_TAGS_DISABLED */
2830 (void)pMe;
2831 (void)pItem;
2832 (void)uTag;
2833#endif /* QCBOR_TAGS_DISABLED */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002834
Laurence Lundbladef71e1622020-08-06 18:52:13 -07002835 return false;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002836}
2837
2838
2839/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002840 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002841 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002842QCBORError
2843QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002844{
Laurence Lundblade87495732021-02-26 10:05:55 -07002845 if(puConsumed != NULL) {
2846 *puConsumed = pMe->InBuf.cursor;
2847 }
2848
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002849 QCBORError uReturn = pMe->uLastError;
Laurence Lundblade085d7952020-07-24 10:26:30 -07002850
2851 if(uReturn != QCBOR_SUCCESS) {
2852 goto Done;
2853 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002854
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002855 /* Error out if all the maps/arrays are not closed out */
2856 if(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002857 uReturn = QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002858 goto Done;
2859 }
2860
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002861 /* Error out if not all the bytes are consumed */
2862 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf))) {
Laurence Lundblade085d7952020-07-24 10:26:30 -07002863 uReturn = QCBOR_ERR_EXTRA_BYTES;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002864 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002865
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002866Done:
Laurence Lundblade87495732021-02-26 10:05:55 -07002867 return uReturn;
2868}
2869
2870
2871/*
2872 * Public function, see header qcbor/qcbor_decode.h file
2873 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002874QCBORError
2875QCBORDecode_Finish(QCBORDecodeContext *pMe)
Laurence Lundblade87495732021-02-26 10:05:55 -07002876{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002877#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002878 /* Call the destructor for the string allocator if there is one.
2879 * Always called, even if there are errors; always have to clean up.
2880 */
2881 StringAllocator_Destruct(&(pMe->StringAllocator));
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002882#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002883
Laurence Lundblade87495732021-02-26 10:05:55 -07002884 return QCBORDecode_PartialFinish(pMe, NULL);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002885}
2886
2887
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002888/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002889 * Public function, see header qcbor/qcbor_decode.h file
2890 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002891uint64_t
2892QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
2893 const QCBORItem *pItem,
2894 uint32_t uIndex)
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002895{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002896#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002897 if(pItem->uDataType == QCBOR_TYPE_NONE) {
2898 return CBOR_TAG_INVALID64;
2899 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002900 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2901 return CBOR_TAG_INVALID64;
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002902 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002903 return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uIndex]);
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002904 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002905#else /* QCBOR_DISABLE_TAGS */
2906 (void)pMe;
2907 (void)pItem;
2908 (void)uIndex;
2909
2910 return CBOR_TAG_INVALID64;
2911#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002912}
2913
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002914
Laurence Lundblade9b334962020-08-27 10:55:53 -07002915/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002916 * Public function, see header qcbor/qcbor_decode.h file
2917 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002918uint64_t
2919QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe,
2920 uint32_t uIndex)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002921{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002922#ifndef QCBOR_DISABLE_TAGS
2923
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002924 if(pMe->uLastError != QCBOR_SUCCESS) {
2925 return CBOR_TAG_INVALID64;
2926 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002927 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2928 return CBOR_TAG_INVALID64;
2929 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002930 return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->uLastTags[uIndex]);
Laurence Lundblade9b334962020-08-27 10:55:53 -07002931 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002932#else /* QCBOR_DISABLE_TAGS */
2933 (void)pMe;
2934 (void)uIndex;
2935
2936 return CBOR_TAG_INVALID64;
2937#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07002938}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002939
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002940
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002941
2942
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002943#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladef6531662018-12-04 10:42:22 +09002944
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002945/* ===========================================================================
2946 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002947
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002948 This implements a simple sting allocator for indefinite-length
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002949 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
2950 implements the function type QCBORStringAllocate and allows easy
2951 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09002952
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002953 This particular allocator is built-in for convenience. The caller
2954 can implement their own. All of this following code will get
2955 dead-stripped if QCBORDecode_SetMemPool() is not called.
2956
2957 This is a very primitive memory allocator. It does not track
2958 individual allocations, only a high-water mark. A free or
2959 reallocation must be of the last chunk allocated.
2960
2961 The size of the pool and offset to free memory are packed into the
2962 first 8 bytes of the memory pool so we don't have to keep them in
2963 the decode context. Since the address of the pool may not be
2964 aligned, they have to be packed and unpacked as if they were
2965 serialized data of the wire or such.
2966
2967 The sizes packed in are uint32_t to be the same on all CPU types
2968 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08002969 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002970
2971
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002972static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08002973MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002974{
2975 // Use of UsefulInputBuf is overkill, but it is convenient.
2976 UsefulInputBuf UIB;
2977
Laurence Lundbladeee851742020-01-08 08:37:05 -08002978 // Just assume the size here. It was checked during SetUp so
2979 // the assumption is safe.
Laurence Lundblade93d89472020-10-03 22:30:50 -07002980 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem,QCBOR_DECODE_MIN_MEM_POOL_SIZE});
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002981 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
2982 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
2983 return UsefulInputBuf_GetError(&UIB);
2984}
2985
2986
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002987static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08002988MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002989{
2990 // Use of UsefulOutBuf is overkill, but convenient. The
2991 // length check performed here is useful.
2992 UsefulOutBuf UOB;
2993
2994 UsefulOutBuf_Init(&UOB, Pool);
2995 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
2996 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
2997 return UsefulOutBuf_GetError(&UOB);
2998}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002999
3000
3001/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003002 Internal function for an allocation, reallocation free and destuct.
3003
3004 Having only one function rather than one each per mode saves space in
3005 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003006
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003007 Code Reviewers: THIS FUNCTION DOES POINTER MATH
3008 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08003009static UsefulBuf
3010MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003011{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003012 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003013
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003014 uint32_t uPoolSize;
3015 uint32_t uFreeOffset;
3016
3017 if(uNewSize > UINT32_MAX) {
3018 // This allocator is only good up to 4GB. This check should
3019 // optimize out if sizeof(size_t) == sizeof(uint32_t)
3020 goto Done;
3021 }
3022 const uint32_t uNewSize32 = (uint32_t)uNewSize;
3023
3024 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
3025 goto Done;
3026 }
3027
3028 if(uNewSize) {
3029 if(pMem) {
3030 // REALLOCATION MODE
3031 // Calculate pointer to the end of the memory pool. It is
3032 // assumed that pPool + uPoolSize won't wrap around by
3033 // assuming the caller won't pass a pool buffer in that is
3034 // not in legitimate memory space.
3035 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
3036
3037 // Check that the pointer for reallocation is in the range of the
3038 // pool. This also makes sure that pointer math further down
3039 // doesn't wrap under or over.
3040 if(pMem >= pPool && pMem < pPoolEnd) {
3041 // Offset to start of chunk for reallocation. This won't
3042 // wrap under because of check that pMem >= pPool. Cast
3043 // is safe because the pool is always less than UINT32_MAX
3044 // because of check in QCBORDecode_SetMemPool().
3045 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3046
3047 // Check to see if the allocation will fit. uPoolSize -
3048 // uMemOffset will not wrap under because of check that
3049 // pMem is in the range of the uPoolSize by check above.
3050 if(uNewSize <= uPoolSize - uMemOffset) {
3051 ReturnValue.ptr = pMem;
3052 ReturnValue.len = uNewSize;
3053
3054 // Addition won't wrap around over because uNewSize was
3055 // checked to be sure it is less than the pool size.
3056 uFreeOffset = uMemOffset + uNewSize32;
3057 }
3058 }
3059 } else {
3060 // ALLOCATION MODE
3061 // uPoolSize - uFreeOffset will not underflow because this
3062 // pool implementation makes sure uFreeOffset is always
3063 // smaller than uPoolSize through this check here and
3064 // reallocation case.
3065 if(uNewSize <= uPoolSize - uFreeOffset) {
3066 ReturnValue.len = uNewSize;
3067 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08003068 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003069 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003070 }
3071 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003072 if(pMem) {
3073 // FREE MODE
3074 // Cast is safe because of limit on pool size in
3075 // QCBORDecode_SetMemPool()
3076 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3077 } else {
3078 // DESTRUCT MODE
3079 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003080 }
3081 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003082
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003083 UsefulBuf Pool = {pPool, uPoolSize};
3084 MemPool_Pack(Pool, uFreeOffset);
3085
3086Done:
3087 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003088}
3089
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003090
Laurence Lundbladef6531662018-12-04 10:42:22 +09003091/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003092 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09003093 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003094QCBORError
3095QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
3096 UsefulBuf Pool,
3097 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003098{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003099 // The pool size and free mem offset are packed into the beginning
Dave Thaler93c01182022-08-06 15:08:35 -04003100 // of the pool memory. This compile time check makes sure the
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003101 // constant in the header is correct. This check should optimize
3102 // down to nothing.
Dave Thaler93c01182022-08-06 15:08:35 -04003103#ifdef _MSC_VER
3104#pragma warning(push)
3105#pragma warning(disable:4127) // conditional expression is constant
3106#endif
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003107 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003108 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003109 }
Dave Thaler93c01182022-08-06 15:08:35 -04003110#ifdef _MSC_VER
3111#pragma warning(pop)
3112#endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003113
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003114 // The pool size and free offset packed in to the beginning of pool
3115 // memory are only 32-bits. This check will optimize out on 32-bit
3116 // machines.
3117 if(Pool.len > UINT32_MAX) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003118 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003119 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003120
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003121 // This checks that the pool buffer given is big enough.
3122 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003123 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003124 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003125
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003126 QCBORDecode_SetUpAllocator(pMe, MemPool_Function, Pool.ptr, bAllStrings);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003127
Laurence Lundblade30816f22018-11-10 13:40:22 +07003128 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003129}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003130#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003131
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003132
3133
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003134
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003135/**
3136 * @brief Consume an entire map or array including its contents.
3137 *
3138 * @param[in] pMe The decoder context.
3139 * @param[in] pItemToConsume The array/map whose contents are to be
3140 * consumed.
3141 * @param[out] puNextNestLevel The next nesting level after the item was
3142 * fully consumed.
3143 *
3144 * This may be called when @c pItemToConsume is not an array or
3145 * map. In that case, this is just a pass through for @c puNextNestLevel
3146 * since there is nothing to do.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003147 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003148static QCBORError
3149QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
3150 const QCBORItem *pItemToConsume,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003151 bool *pbBreak,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003152 uint8_t *puNextNestLevel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003153{
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003154 QCBORError uReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003155 QCBORItem Item;
Laurence Lundblade9b334962020-08-27 10:55:53 -07003156
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003157 /* If it is a map or array, this will tell if it is empty. */
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003158 const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel);
3159
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003160 if(QCBORItem_IsMapOrArray(*pItemToConsume) && !bIsEmpty) {
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003161 /* There is only real work to do for non-empty maps and arrays */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003162
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003163 /* This works for definite- and indefinite-length maps and
3164 * arrays by using the nesting level
Laurence Lundblade1341c592020-04-11 14:19:05 -07003165 */
3166 do {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003167 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pbBreak, &Item);
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003168 if(QCBORDecode_IsUnrecoverableError(uReturn) ||
3169 uReturn == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003170 goto Done;
3171 }
3172 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003173
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003174 *puNextNestLevel = Item.uNextNestLevel;
3175
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003176 uReturn = QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003177
Laurence Lundblade1341c592020-04-11 14:19:05 -07003178 } else {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003179 /* pItemToConsume is not a map or array. Just pass the nesting
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003180 * level through. */
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003181 *puNextNestLevel = pItemToConsume->uNextNestLevel;
3182
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003183 uReturn = QCBOR_SUCCESS;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003184 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003185
3186Done:
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003187 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003188}
3189
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003190
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003191/*
3192 * Public function, see header qcbor/qcbor_decode.h file
3193 */
3194void
3195QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003196{
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003197 QCBORDecode_VGetNext(pMe, pDecodedItem);
3198
3199 if(pMe->uLastError == QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003200 pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL,
Máté Tóth-Pálc6d59682021-05-26 18:55:30 +02003201 &pDecodedItem->uNextNestLevel);
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003202 }
3203}
3204
3205
Laurence Lundblade11654912024-05-09 11:49:24 -07003206/*
3207 * Public function, see header qcbor/qcbor_decode.h file
3208 */
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003209QCBORError
3210QCBORDecode_EndCheck(QCBORDecodeContext *pMe)
Laurence Lundblade11654912024-05-09 11:49:24 -07003211{
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003212 size_t uCursorOffset;
3213 QCBORError uErr;
Laurence Lundblade11654912024-05-09 11:49:24 -07003214
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003215 uErr = QCBORDecode_GetError(pMe);
3216 if(uErr != QCBOR_SUCCESS) {
3217 return uErr;
Laurence Lundblade11654912024-05-09 11:49:24 -07003218 }
3219
3220 uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
3221
3222 if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003223 return QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade11654912024-05-09 11:49:24 -07003224 }
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003225
3226 return QCBOR_SUCCESS;
Laurence Lundblade11654912024-05-09 11:49:24 -07003227}
3228
3229
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003230/**
3231 * @brief Rewind cursor to start as if map or array were just entered.
3232 *
3233 * @param[in] pMe The decoding context
3234 *
3235 * This affects the nesting tracking and the UsefulInputBuf.
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003236 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003237static void
3238QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003239{
3240 /* Reset nesting tracking to the deepest bounded level */
3241 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3242
3243 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3244
3245 /* Reposition traversal cursor to the start of the map/array */
3246 UsefulInputBuf_Seek(&(pMe->InBuf),
3247 DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
3248}
3249
3250
3251/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003252 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003253 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003254void
3255QCBORDecode_Rewind(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003256{
3257 if(pMe->nesting.pCurrentBounded != NULL) {
3258 /* In a bounded map, array or bstr-wrapped CBOR */
3259
3260 if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
3261 /* In bstr-wrapped CBOR. */
3262
3263 /* Reposition traversal cursor to start of wrapping byte string */
3264 UsefulInputBuf_Seek(&(pMe->InBuf),
3265 pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
3266 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3267
3268 } else {
3269 /* In a map or array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003270 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003271 }
3272
3273 } else {
3274 /* Not in anything bounded */
3275
3276 /* Reposition traversal cursor to the start of input CBOR */
3277 UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
3278
3279 /* Reset nesting tracking to beginning of input. */
3280 DecodeNesting_Init(&(pMe->nesting));
3281 }
3282
3283 pMe->uLastError = QCBOR_SUCCESS;
3284}
3285
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003286
Laurence Lundblade9b334962020-08-27 10:55:53 -07003287
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003288
3289
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003290typedef struct {
3291 void *pCBContext;
3292 QCBORItemCallback pfCallback;
3293} MapSearchCallBack;
3294
3295typedef struct {
3296 size_t uStartOffset;
3297 uint16_t uItemCount;
3298} MapSearchInfo;
3299
3300
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003301/**
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003302 * @brief Search a map for a set of items.
3303 *
3304 * @param[in] pMe The decode context to search.
3305 * @param[in,out] pItemArray The items to search for and the items found.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003306 * @param[out] pInfo Several bits of meta-info returned by search.
3307 * @param[in] pCallBack Callback object or @c NULL.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003308 *
3309 * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map.
3310 *
3311 * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label)
3312 * were found for one of the labels being
3313 * search for. This duplicate detection is
3314 * only performed for items in pItemArray,
3315 * not every item in the map.
3316 *
3317 * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was
3318 * wrong for the matchd label.
3319 *
3320 * @retval Also errors returned by QCBORDecode_GetNext().
3321 *
3322 * On input, \c pItemArray contains a list of labels and data types of
3323 * items to be found.
3324 *
3325 * On output, the fully retrieved items are filled in with values and
3326 * such. The label was matched, so it never changes.
3327 *
3328 * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE.
3329 *
3330 * This also finds the ends of maps and arrays when they are exited.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003331 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003332static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003333QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
3334 QCBORItem *pItemArray,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003335 MapSearchInfo *pInfo,
3336 MapSearchCallBack *pCallBack)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003337{
Laurence Lundbladee6f15112020-07-23 18:44:16 -07003338 QCBORError uReturn;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003339 uint64_t uFoundItemBitMap = 0;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07003340
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003341 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003342 uReturn = pMe->uLastError;
3343 goto Done2;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003344 }
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003345
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003346 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) &&
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003347 pItemArray->uLabelType != QCBOR_TYPE_NONE) {
3348 /* QCBOR_TYPE_NONE as first item indicates just looking
3349 for the end of an array, so don't give error. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003350 uReturn = QCBOR_ERR_MAP_NOT_ENTERED;
3351 goto Done2;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003352 }
3353
Laurence Lundblade085d7952020-07-24 10:26:30 -07003354 if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) {
3355 // It is an empty bounded array or map
3356 if(pItemArray->uLabelType == QCBOR_TYPE_NONE) {
3357 // Just trying to find the end of the map or array
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003358 pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003359 uReturn = QCBOR_SUCCESS;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003360 } else {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003361 // Nothing is ever found in an empty array or map. All items
3362 // are marked as not found below.
Laurence Lundblade085d7952020-07-24 10:26:30 -07003363 uReturn = QCBOR_SUCCESS;
3364 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003365 goto Done2;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003366 }
3367
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003368 QCBORDecodeNesting SaveNesting;
Laurence Lundblade11654912024-05-09 11:49:24 -07003369 size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003370 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3371
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003372 /* Reposition to search from the start of the map / array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003373 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundblade1341c592020-04-11 14:19:05 -07003374
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003375 /*
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003376 Loop over all the items in the map or array. Each item
3377 could be a map or array, but label matching is only at
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003378 the main level. This handles definite- and indefinite-
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003379 length maps and arrays. The only reason this is ever
3380 called on arrays is to find their end position.
3381
3382 This will always run over all items in order to do
3383 duplicate detection.
3384
3385 This will exit with failure if it encounters an
3386 unrecoverable error, but continue on for recoverable
3387 errors.
3388
3389 If a recoverable error occurs on a matched item, then
3390 that error code is returned.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003391 */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07003392 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003393 if(pInfo) {
3394 pInfo->uItemCount = 0;
3395 }
Máté Tóth-Pál2f2aa5f2021-05-17 21:35:09 +02003396 uint8_t uNextNestLevel;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003397 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003398 /* Remember offset of the item because sometimes it has to be returned */
Laurence Lundblade1341c592020-04-11 14:19:05 -07003399 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003400
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003401 /* Get the item */
3402 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003403 /* QCBORDecode_Private_GetNextTagContent() rather than GetNext()
3404 * because a label match is performed on recoverable errors to
3405 * be able to return the the error code for the found item. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003406 QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003407 if(QCBORDecode_IsUnrecoverableError(uResult)) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003408 /* The map/array can't be decoded when unrecoverable errors occur */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003409 uReturn = uResult;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003410 goto Done;
3411 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003412 if(uResult == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003413 /* Unexpected end of map or array. */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003414 uReturn = uResult;
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003415 goto Done;
3416 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003417
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003418 /* See if item has one of the labels that are of interest */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003419 bool bMatched = false;
3420 for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003421 if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003422 /* A label match has been found */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003423 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
3424 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003425 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003426 }
Laurence Lundblade63926052021-03-29 16:05:51 -07003427 if(uResult != QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003428 /* The label matches, but the data item is in error.
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003429 * It is OK to have recoverable errors on items that
3430 * are not matched. */
Laurence Lundblade63926052021-03-29 16:05:51 -07003431 uReturn = uResult;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003432 goto Done;
3433 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003434 if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) {
Laurence Lundblade63926052021-03-29 16:05:51 -07003435 /* The data item is not of the type(s) requested */
3436 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003437 goto Done;
3438 }
3439
Laurence Lundblade1341c592020-04-11 14:19:05 -07003440 /* Successful match. Return the item. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003441 pItemArray[nIndex] = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003442 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003443 if(pInfo) {
3444 pInfo->uStartOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003445 }
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003446 bMatched = true;
3447 }
3448 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003449
3450
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003451 if(!bMatched && pCallBack != NULL) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003452 /*
3453 Call the callback on unmatched labels.
3454 (It is tempting to do duplicate detection here, but that would
3455 require dynamic memory allocation because the number of labels
3456 that might be encountered is unbounded.)
3457 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003458 uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item);
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003459 if(uReturn != QCBOR_SUCCESS) {
3460 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003461 }
3462 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003463
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003464 /*
3465 Consume the item whether matched or not. This
3466 does the work of traversing maps and array and
3467 everything in them. In this loop only the
3468 items at the current nesting level are examined
3469 to match the labels.
3470 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003471 uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel);
Laurence Lundbladec7114722020-08-13 05:11:40 -07003472 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003473 goto Done;
3474 }
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003475
3476 if(pInfo) {
3477 pInfo->uItemCount++;
3478 }
3479
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003480 } while (uNextNestLevel >= uMapNestLevel);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003481
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003482 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003483
3484 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003485
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003486 // Check here makes sure that this won't accidentally be
3487 // QCBOR_MAP_OFFSET_CACHE_INVALID which is larger than
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003488 // QCBOR_MAX_DECODE_INPUT_SIZE.
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -08003489 // Cast to uint32_t to possibly address cases where SIZE_MAX < UINT32_MAX
3490 if((uint32_t)uEndOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003491 uReturn = QCBOR_ERR_INPUT_TOO_LARGE;
3492 goto Done;
3493 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003494 /* Cast OK because encoded CBOR is limited to UINT32_MAX */
3495 pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003496
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003497 Done:
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003498 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade11654912024-05-09 11:49:24 -07003499 UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos);
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003500
3501 Done2:
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003502 /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */
Laurence Lundbladec7114722020-08-13 05:11:40 -07003503 for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003504 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003505 pItemArray[i].uDataType = QCBOR_TYPE_NONE;
3506 pItemArray[i].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003507 }
3508 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003509
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003510 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003511}
3512
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003513
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003514/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003515 * Public function, see header qcbor/qcbor_decode.h file
3516 */
3517void
3518QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
3519 int64_t nLabel,
3520 uint8_t uQcborType,
3521 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003522{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003523 if(pMe->uLastError != QCBOR_SUCCESS) {
3524 return;
3525 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003526
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003527 QCBORItem OneItemSeach[2];
3528 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3529 OneItemSeach[0].label.int64 = nLabel;
3530 OneItemSeach[0].uDataType = uQcborType;
3531 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003532
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003533 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003534
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003535 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003536 pItem->uDataType = QCBOR_TYPE_NONE;
3537 pItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003538 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003539 }
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003540
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003541 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003542 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003543 }
3544
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003545 *pItem = OneItemSeach[0];
3546 QCBORDecode_Private_CopyTags(pMe, pItem);
3547
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003548 Done:
3549 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003550}
3551
3552
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003553/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003554 * Public function, see header qcbor/qcbor_decode.h file
3555 */
3556void
3557QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
3558 const char *szLabel,
3559 uint8_t uQcborType,
3560 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003561{
Laurence Lundbladeda095972020-06-06 18:35:33 -07003562 if(pMe->uLastError != QCBOR_SUCCESS) {
3563 return;
3564 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003565
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003566#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003567 QCBORItem OneItemSeach[2];
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003568 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3569 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3570 OneItemSeach[0].uDataType = uQcborType;
3571 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003572
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003573 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
3574
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003575 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003576 pItem->uDataType = QCBOR_TYPE_NONE;
3577 pItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003578 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003579 }
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003580 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003581 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003582 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003583 }
3584
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003585 *pItem = OneItemSeach[0];
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003586 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003587
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003588Done:
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003589#else
3590 (void)pMe;
3591 (void)szLabel;
3592 (void)uQcborType;
3593 (void)pItem;
3594 QCBORError uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
3595#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
3596
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003597 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003598}
3599
3600
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003601
3602/**
3603 * @brief Semi-private. Get pointer, length and item for an array or map.
3604 *
3605 * @param[in] pMe The decode context.
3606 * @param[in] uType CBOR major type, either array/map.
3607 * @param[out] pItem The item for the array/map.
3608 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3609 *
3610 * The next item to be decoded must be a map or array as specified by \c uType.
3611 *
3612 * \c pItem will be filled in with the label and tags of the array or map
3613 * in addition to \c pEncodedCBOR giving the pointer and length of the
3614 * encoded CBOR.
3615 *
3616 * When this is complete, the traversal cursor is at the end of the array or
3617 * map that was retrieved.
3618 */
3619void
3620QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe,
3621 const uint8_t uType,
3622 QCBORItem *pItem,
3623 UsefulBufC *pEncodedCBOR)
3624{
3625 QCBORError uErr;
3626 uint8_t uNestLevel;
3627 size_t uStartingCursor;
3628 size_t uStartOfReturned;
3629 size_t uEndOfReturned;
3630 size_t uTempSaveCursor;
3631 bool bInMap;
3632 QCBORItem LabelItem;
3633 bool EndedByBreak;
3634
3635 uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3636 bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting));
3637
3638 /* Could call GetNext here, but don't need to because this
3639 * is only interested in arrays and maps. */
3640 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem);
3641 if(uErr != QCBOR_SUCCESS) {
3642 pMe->uLastError = (uint8_t)uErr;
3643 return;
3644 }
3645
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003646 uint8_t uItemDataType = pItem->uDataType;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003647#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003648 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
3649 uItemDataType = QCBOR_TYPE_ARRAY;
3650 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003651#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003652
3653 if(uItemDataType != uType) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003654 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
3655 return;
3656 }
3657
3658 if(bInMap) {
3659 /* If the item is in a map, the start of the array/map
3660 * itself, not the label, must be found. Do this by
3661 * rewinding to the starting position and fetching
3662 * just the label data item. QCBORDecode_Private_GetNextTagNumber()
3663 * doesn't do any of the array/map item counting or nesting
3664 * level tracking. Used here it will just fetech the label
3665 * data item.
3666 *
3667 * Have to save the cursor and put it back to the position
3668 * after the full item once the label as been fetched by
3669 * itself.
3670 */
3671 uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3672 UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor);
3673
3674 /* Item has been fetched once so safe to ignore error */
3675 (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem);
3676
3677 uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3678 UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor);
3679 } else {
3680 uStartOfReturned = uStartingCursor;
3681 }
3682
3683 /* Consume the entire array/map to find the end */
3684 uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel);
3685 if(uErr != QCBOR_SUCCESS) {
3686 pMe->uLastError = (uint8_t)uErr;
3687 goto Done;
3688 }
3689
3690 /* Fill in returned values */
3691 uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3692 if(EndedByBreak) {
3693 /* When ascending nesting levels, a break for the level above
3694 * was consumed. That break is not a part of what is consumed here. */
3695 uEndOfReturned--;
3696 }
3697 pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned);
3698 pEncodedCBOR->len = uEndOfReturned - uStartOfReturned;
3699
3700Done:
3701 return;
3702}
3703
3704
3705/**
3706 * @brief Semi-private. Get pointer, length and item count of an array or map.
3707 *
3708 * @param[in] pMe The decode context.
3709 * @param[in] pTarget The label and type of the array or map to retrieve.
3710 * @param[out] pItem The item for the array/map.
3711 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3712 *
3713 * The next item to be decoded must be a map or array as specified by \c uType.
3714 *
3715 * When this is complete, the traversal cursor is unchanged.
3716 */void
3717QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe,
3718 QCBORItem *pTarget,
3719 QCBORItem *pItem,
3720 UsefulBufC *pEncodedCBOR)
3721{
3722 MapSearchInfo Info;
3723 QCBORDecodeNesting SaveNesting;
3724 size_t uSaveCursor;
3725
3726 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL);
3727 if(pMe->uLastError != QCBOR_SUCCESS) {
3728 return;
3729 }
3730
3731 /* Save the whole position of things so they can be restored.
3732 * so the cursor position is unchanged by this operation, like
3733 * all the other GetXxxxInMap() operations. */
3734 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3735 uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3736
3737 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3738 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
3739 QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR);
3740
3741 UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor);
3742 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
3743}
3744
3745
3746
3747
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003748/**
3749 * @brief Is a QCBOR_TYPE in the type list?
3750 *
3751 * @param[in] uDataType Type to check for.
3752 * @param[in] puTypeList List to check.
3753 *
3754 * @retval QCBOR_SUCCESS If in the list.
3755 * @retval QCBOR_ERR_UNEXPECTED_TYPE Not in the list.
3756 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07003757static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003758QCBOR_Private_CheckTypeList(const int uDataType,
3759 const uint8_t puTypeList[QCBOR_TAGSPEC_NUM_TYPES])
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003760{
3761 for(size_t i = 0; i < QCBOR_TAGSPEC_NUM_TYPES; i++) {
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003762 if(uDataType == puTypeList[i]) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003763 return QCBOR_SUCCESS;
3764 }
3765 }
3766 return QCBOR_ERR_UNEXPECTED_TYPE;
3767}
3768
Laurence Lundblade67257dc2020-07-27 03:33:37 -07003769
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003770/**
Laurence Lundblade37286c02022-09-03 10:05:02 -07003771 * Match a tag/type specification against the type of the item.
3772 *
3773 * @param[in] TagSpec Specification for matching tags.
3774 * @param[in] pItem The item to check.
3775 *
3776 * @retval QCBOR_SUCCESS \c uDataType is allowed by @c TagSpec
3777 * @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec
3778 *
3779 * This checks the item data type of untagged items as well as of
3780 * tagged items against a specification to see if decoding should
3781 * proceed.
3782 *
3783 * This relies on the automatic tag decoding done by QCBOR that turns
3784 * tag numbers into particular QCBOR_TYPEs so there is no actual
3785 * comparsion of tag numbers, just of QCBOR_TYPEs.
3786 *
3787 * This checks the data item type as possibly representing the tag
3788 * number or as the tag content type.
3789 *
3790 * If QCBOR_DISABLE_TAGS is #defined, this primarily checks the item
3791 * data type against the allowed tag content types. It will also error out
3792 * if the caller tries to require a tag because there is no way that can
3793 * ever be fulfilled.
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003794 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07003795static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003796QCBOR_Private_CheckTagRequirement(const QCBOR_Private_TagSpec TagSpec,
3797 const QCBORItem *pItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07003798{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003799 const int nItemType = pItem->uDataType; /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade37286c02022-09-03 10:05:02 -07003800 const int nTagReq = TagSpec.uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
3801
3802#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003803 /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003804 if(!(TagSpec.uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS) &&
3805 pItem->uTags[0] != CBOR_TAG_INVALID16) {
3806 /* There are tags that QCBOR couldn't process on this item and
Laurence Lundblade37286c02022-09-03 10:05:02 -07003807 * the caller has told us there should not be.
3808 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003809 return QCBOR_ERR_UNEXPECTED_TYPE;
3810 }
3811
Laurence Lundblade9b334962020-08-27 10:55:53 -07003812 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
Laurence Lundblade37286c02022-09-03 10:05:02 -07003813 /* Must match the tag number and only the tag */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003814 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003815 }
3816
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003817 QCBORError uReturn = QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003818 if(uReturn == QCBOR_SUCCESS) {
3819 return QCBOR_SUCCESS;
3820 }
3821
3822 if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
3823 /* Must match the content type and only the content type.
Laurence Lundblade37286c02022-09-03 10:05:02 -07003824 * There was no match just above so it is a fail. */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003825 return QCBOR_ERR_UNEXPECTED_TYPE;
3826 }
3827
Laurence Lundblade37286c02022-09-03 10:05:02 -07003828 /* QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG: If here it can match either the tag or the content
3829 * and it hasn't matched the content, so the end
3830 * result is whether it matches the tag. This is
3831 * the tag optional case that the CBOR standard discourages.
3832 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003833
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003834 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003835
Laurence Lundblade37286c02022-09-03 10:05:02 -07003836#else /* QCBOR_DISABLE_TAGS */
3837 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
3838 return QCBOR_ERR_UNEXPECTED_TYPE;
3839 }
3840
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07003841 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade37286c02022-09-03 10:05:02 -07003842
3843#endif /* QCBOR_DISABLE_TAGS */
3844}
Laurence Lundblade9b334962020-08-27 10:55:53 -07003845
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003846
3847/**
3848 * @brief Get an item by label to match a tag specification.
3849 *
3850 * @param[in] pMe The decode context.
3851 * @param[in] nLabel The label to search map for.
3852 * @param[in] TagSpec The tag number specification to match.
3853 * @param[out] pItem The item found.
3854 *
3855 * This finds the item with the given label in currently open
3856 * map. Then checks that its tag number and types matches the tag
3857 * specification. If not, an error is set in the decode context.
3858 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003859static void
3860QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
3861 const int64_t nLabel,
3862 const QCBOR_Private_TagSpec TagSpec,
3863 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003864{
3865 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
3866 if(pMe->uLastError != QCBOR_SUCCESS) {
3867 return;
3868 }
3869
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003870 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003871}
3872
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07003873
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003874/**
3875 * @brief Get an item by label to match a tag specification.
3876 *
3877 * @param[in] pMe The decode context.
3878 * @param[in] szLabel The label to search map for.
3879 * @param[in] TagSpec The tag number specification to match.
3880 * @param[out] pItem The item found.
3881 *
3882 * This finds the item with the given label in currently open
3883 * map. Then checks that its tag number and types matches the tag
3884 * specification. If not, an error is set in the decode context.
3885 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003886static void
3887QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
3888 const char *szLabel,
3889 const QCBOR_Private_TagSpec TagSpec,
3890 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003891{
3892 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
3893 if(pMe->uLastError != QCBOR_SUCCESS) {
3894 return;
3895 }
3896
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003897 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003898}
3899
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003900
3901/**
3902 * @brief Semi-private to get an string by label to match a tag specification.
3903 *
3904 * @param[in] pMe The decode context.
3905 * @param[in] nLabel The label to search map for.
3906 * @param[in] TagSpec The tag number specification to match.
3907 * @param[out] pString The string found.
3908 *
3909 * This finds the string with the given label in currently open
3910 * map. Then checks that its tag number and types matches the tag
3911 * specification. If not, an error is set in the decode context.
3912 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003913void
3914QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
3915 const int64_t nLabel,
3916 const QCBOR_Private_TagSpec TagSpec,
3917 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003918{
3919 QCBORItem Item;
3920 QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
3921 if(pMe->uLastError == QCBOR_SUCCESS) {
3922 *pString = Item.val.string;
3923 }
3924}
3925
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003926
3927/**
3928 * @brief Semi-private to get an string by label to match a tag specification.
3929 *
3930 * @param[in] pMe The decode context.
3931 * @param[in] szLabel The label to search map for.
3932 * @param[in] TagSpec The tag number specification to match.
3933 * @param[out] pString The string found.
3934 *
3935 * This finds the string with the given label in currently open
3936 * map. Then checks that its tag number and types matches the tag
3937 * specification. If not, an error is set in the decode context.
3938 */void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003939QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
3940 const char * szLabel,
3941 const QCBOR_Private_TagSpec TagSpec,
3942 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003943{
3944 QCBORItem Item;
3945 QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
3946 if(pMe->uLastError == QCBOR_SUCCESS) {
3947 *pString = Item.val.string;
3948 }
3949}
Laurence Lundblade1341c592020-04-11 14:19:05 -07003950
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003951
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003952/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003953 * Public function, see header qcbor/qcbor_decode.h file
3954 */
3955void
3956QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003957{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003958 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL);
Laurence Lundblade5f53f832020-09-03 12:00:14 -07003959 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003960}
3961
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003962/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003963 * Public function, see header qcbor/qcbor_decode.h file
3964 */
3965void
3966QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe,
3967 QCBORItem *pItemList,
3968 void *pCallbackCtx,
3969 QCBORItemCallback pfCB)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003970{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003971 MapSearchCallBack CallBack;
3972 CallBack.pCBContext = pCallbackCtx;
3973 CallBack.pfCallback = pfCB;
3974
3975 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack);
3976
Laurence Lundblade5f53f832020-09-03 12:00:14 -07003977 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003978}
3979
3980
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08003981/**
3982 * @brief Search for a map/array by label and enter it
3983 *
3984 * @param[in] pMe The decode context.
3985 * @param[in] pSearch The map/array to search for.
3986 *
3987 * @c pSearch is expected to contain one item of type map or array
3988 * with the label specified. The current bounded map will be searched for
3989 * this and if found will be entered.
3990 *
3991 * If the label is not found, or the item found is not a map or array,
3992 * the error state is set.
3993 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003994static void
3995QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07003996{
Laurence Lundblade323f8a92020-09-06 19:43:09 -07003997 // The first item in pSearch is the one that is to be
3998 // entered. It should be the only one filled in. Any other
3999 // will be ignored unless it causes an error.
Laurence Lundblade34691b92020-05-18 22:25:25 -07004000 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07004001 return;
4002 }
4003
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004004 MapSearchInfo Info;
4005 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pSearch, &Info, NULL);
Laurence Lundblade34691b92020-05-18 22:25:25 -07004006 if(pMe->uLastError != QCBOR_SUCCESS) {
4007 return;
4008 }
4009
Laurence Lundblade9b334962020-08-27 10:55:53 -07004010 if(pSearch->uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004011 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004012 return;
4013 }
4014
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004015
4016 /* The map or array was found. Now enter it.
4017 *
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004018 * QCBORDecode_EnterBoundedMapOrArray() used here, requires the
4019 * next item for the pre-order traversal cursor to be the map/array
4020 * found by MapSearch(). The next few lines of code force the
4021 * cursor to that.
4022 *
4023 * There is no need to retain the old cursor because
4024 * QCBORDecode_EnterBoundedMapOrArray() will set it to the
4025 * beginning of the map/array being entered.
4026 *
4027 * The cursor is forced by: 1) setting the input buffer position to
4028 * the item offset found by MapSearch(), 2) setting the map/array
4029 * counter to the total in the map/array, 3) setting the nesting
4030 * level. Setting the map/array counter to the total is not
4031 * strictly correct, but this is OK because this cursor only needs
4032 * to be used to get one item and MapSearch() has already found it
4033 * confirming it exists.
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004034 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004035 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004036
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004037 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
4038
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004039 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07004040
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004041 QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004042}
4043
4044
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004045/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004046 * Public function, see header qcbor/qcbor_decode.h file
4047 */
4048void
4049QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004050{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004051 QCBORItem OneItemSeach[2];
4052 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4053 OneItemSeach[0].label.int64 = nLabel;
4054 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4055 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004056
Laurence Lundblade9b334962020-08-27 10:55:53 -07004057 /* The map to enter was found, now finish off entering it. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004058 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004059}
4060
4061
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004062/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004063 * Public function, see header qcbor/qcbor_decode.h file
4064 */
4065void
4066QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004067{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004068#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004069 QCBORItem OneItemSeach[2];
4070 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4071 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4072 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4073 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004074
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004075 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004076#else
4077 (void)szLabel;
4078 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
4079#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004080}
4081
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004082/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004083 * Public function, see header qcbor/qcbor_decode.h file
4084 */
4085void
4086QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07004087{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004088 QCBORItem OneItemSeach[2];
4089 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4090 OneItemSeach[0].label.int64 = nLabel;
4091 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4092 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004093
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004094 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07004095}
4096
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004097/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004098 * Public function, see header qcbor/qcbor_decode.h file
4099 */
4100void
4101QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundblade34691b92020-05-18 22:25:25 -07004102{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004103#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004104 QCBORItem OneItemSeach[2];
4105 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4106 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4107 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4108 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004109
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004110 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004111#else
4112 (void)szLabel;
4113 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
4114#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade1341c592020-04-11 14:19:05 -07004115}
4116
4117
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004118/**
4119 * @brief Semi-private to do the the work for EnterMap() and EnterArray().
4120 *
4121 * @param[in] pMe The decode context
4122 * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY.
4123 * @param[out] pItem The data item for the map or array entered.
4124 *
4125 * The next item in the traversal must be a map or array. This
4126 * consumes that item and does the book keeping to enter the map or
4127 * array.
4128 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004129void
4130QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe,
4131 const uint8_t uType,
4132 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004133{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004134 QCBORError uErr;
4135
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004136 /* Must only be called on maps and arrays. */
Laurence Lundblade34691b92020-05-18 22:25:25 -07004137 if(pMe->uLastError != QCBOR_SUCCESS) {
4138 // Already in error state; do nothing.
4139 return;
4140 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07004141
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004142 /* Get the data item that is the map or array being entered. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004143 QCBORItem Item;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004144 uErr = QCBORDecode_GetNext(pMe, &Item);
4145 if(uErr != QCBOR_SUCCESS) {
4146 goto Done;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07004147 }
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004148
4149 uint8_t uItemDataType = Item.uDataType;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004150
4151#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004152 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) {
4153 uItemDataType = QCBOR_TYPE_ARRAY;
4154 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004155#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
4156
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004157 if(uItemDataType != uType) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004158 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
4159 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004160 }
4161
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004162 QCBORDecode_Private_CopyTags(pMe, &Item);
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004163
4164
Laurence Lundbladef0499502020-08-01 11:55:57 -07004165 const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
Laurence Lundblade085d7952020-07-24 10:26:30 -07004166 if(bIsEmpty) {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004167 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
4168 // Undo decrement done by QCBORDecode_GetNext() so the the
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004169 // the decrement when exiting the map/array works correctly
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004170 pMe->nesting.pCurrent->u.ma.uCountCursor++;
4171 }
Laurence Lundblade93d89472020-10-03 22:30:50 -07004172 // Special case to increment nesting level for zero-length maps
4173 // and arrays entered in bounded mode.
Laurence Lundbladee6f15112020-07-23 18:44:16 -07004174 DecodeNesting_Descend(&(pMe->nesting), uType);
4175 }
4176
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004177 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004178
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004179 uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty,
4180 UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004181
Laurence Lundblade6545d1b2020-10-14 11:13:13 -07004182 if(pItem != NULL) {
4183 *pItem = Item;
4184 }
4185
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004186Done:
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004187 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004188}
4189
Laurence Lundblade02625d42020-06-25 14:41:41 -07004190
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004191/**
4192 * @brief Exit a bounded map, array or bstr (semi-private).
4193 *
4194 * @param[in] pMe Decode context.
4195 * @param[in] uEndOffset The input buffer offset of the end of item exited.
4196 *
4197 * @returns QCBOR_SUCCESS or an error code.
4198 *
4199 * This is the common work for exiting a level that is a bounded map,
4200 * array or bstr wrapped CBOR.
4201 *
4202 * One chunk of work is to set up the pre-order traversal so it is at
4203 * the item just after the bounded map, array or bstr that is being
4204 * exited. This is somewhat complex.
4205 *
4206 * The other work is to level-up the bounded mode to next higest
4207 * bounded mode or the top level if there isn't one.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004208 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004209static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004210QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
4211 const uint32_t uEndOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004212{
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004213 QCBORError uErr;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004214
Laurence Lundblade02625d42020-06-25 14:41:41 -07004215 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004216 * First the pre-order-traversal byte offset is positioned to the
4217 * item just after the bounded mode item that was just consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004218 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004219 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
4220
Laurence Lundblade02625d42020-06-25 14:41:41 -07004221 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004222 * Next, set the current nesting level to one above the bounded
4223 * level that was just exited.
4224 *
4225 * DecodeNesting_CheckBoundedType() is always called before this
4226 * and makes sure pCurrentBounded is valid.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004227 */
4228 DecodeNesting_LevelUpCurrent(&(pMe->nesting));
4229
4230 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004231 * This does the complex work of leveling up the pre-order
4232 * traversal when the end of a map or array or another bounded
4233 * level is reached. It may do nothing, or ascend all the way to
4234 * the top level.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004235 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004236 uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004237 if(uErr != QCBOR_SUCCESS) {
4238 goto Done;
4239 }
4240
Laurence Lundblade02625d42020-06-25 14:41:41 -07004241 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004242 * This makes the next highest bounded level the current bounded
4243 * level. If there is no next highest level, then no bounded mode
4244 * is in effect.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004245 */
4246 DecodeNesting_LevelUpBounded(&(pMe->nesting));
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004247
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004248 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004249
4250Done:
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004251 return uErr;
4252}
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004253
Laurence Lundblade02625d42020-06-25 14:41:41 -07004254
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004255/**
4256 * @brief Get started exiting a map or array (semi-private)
4257 *
4258 * @param[in] pMe The decode context
4259 * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP
4260 *
4261 * This does some work for map and array exiting (but not
4262 * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel()
4263 * is called to do the rest.
4264 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004265void
4266QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe,
4267 const uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004268{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004269 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07004270 /* Already in error state; do nothing. */
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004271 return;
4272 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004273
Laurence Lundblade02625d42020-06-25 14:41:41 -07004274 QCBORError uErr;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004275
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004276 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004277 uErr = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004278 goto Done;
4279 }
4280
Laurence Lundblade02625d42020-06-25 14:41:41 -07004281 /*
4282 Have to set the offset to the end of the map/array
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004283 that is being exited. If there is no cached value,
Laurence Lundblade02625d42020-06-25 14:41:41 -07004284 from previous map search, then do a dummy search.
4285 */
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004286 if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004287 QCBORItem Dummy;
4288 Dummy.uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004289 uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL);
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004290 if(uErr != QCBOR_SUCCESS) {
4291 goto Done;
4292 }
4293 }
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004294
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004295 uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004296
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004297Done:
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004298 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004299}
4300
4301
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004302/**
4303 * @brief The main work of entering some byte-string wrapped CBOR.
4304 *
4305 * @param[in] pMe The decode context.
4306 * @param[in] pItem The byte string item.
4307 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX
4308 * @param[out] pBstr Pointer and length of byte string entered.
4309 *
4310 * This is called once the byte string item has been decoded to do all
4311 * the book keeping work for descending a nesting level into the
4312 * nested CBOR.
4313 *
4314 * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement.
4315 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004316static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004317QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe,
4318 const QCBORItem *pItem,
4319 const uint8_t uTagRequirement,
4320 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004321{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004322 if(pBstr) {
4323 *pBstr = NULLUsefulBufC;
4324 }
4325
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004326 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004327 /* Already in error state; do nothing. */
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004328 return pMe->uLastError;
4329 }
4330
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004331 QCBORError uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004332
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004333 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004334 {
4335 uTagRequirement,
4336 {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE},
4337 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4338 };
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004339
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004340 uError = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004341 if(uError != QCBOR_SUCCESS) {
4342 goto Done;
4343 }
4344
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004345 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004346 /* Reverse the decrement done by GetNext() for the bstr so the
4347 * increment in QCBORDecode_NestLevelAscender() called by
4348 * ExitBoundedLevel() will work right.
4349 */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004350 DecodeNesting_ReverseDecrement(&(pMe->nesting));
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07004351 }
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004352
4353 if(pBstr) {
4354 *pBstr = pItem->val.string;
4355 }
4356
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004357 /* This saves the current length of the UsefulInputBuf and then
4358 * narrows the UsefulInputBuf to start and length of the wrapped
4359 * CBOR that is being entered.
4360 *
4361 * Most of these calls are simple inline accessors so this doesn't
4362 * amount to much code.
4363 */
4364
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004365 const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004366 /* This check makes the cast of uPreviousLength to uint32_t below safe. */
4367 if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004368 uError = QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladef76a2622020-08-06 19:51:03 -07004369 goto Done;
4370 }
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004371
4372 const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
4373 pItem->val.string.ptr);
4374 /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
4375 if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
4376 /* This should never happen because pItem->val.string.ptr should
4377 * always be valid since it was just returned.
4378 */
4379 uError = QCBOR_ERR_INPUT_TOO_LARGE;
4380 goto Done;
4381 }
4382
4383 const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
4384
4385 UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004386 UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004387
Laurence Lundblade02625d42020-06-25 14:41:41 -07004388 uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004389 (uint32_t)uPreviousLength,
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004390 (uint32_t)uStartOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004391Done:
4392 return uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004393}
4394
4395
Laurence Lundblade02625d42020-06-25 14:41:41 -07004396/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004397 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004398 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004399void
4400QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe,
4401 const uint8_t uTagRequirement,
4402 UsefulBufC *pBstr)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004403{
4404 if(pMe->uLastError != QCBOR_SUCCESS) {
4405 // Already in error state; do nothing.
4406 return;
4407 }
4408
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004409 /* Get the data item that is the byte string being entered */
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004410 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004411 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4412 if(pMe->uLastError != QCBOR_SUCCESS) {
4413 return;
4414 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004415
Laurence Lundblade31fddb72024-05-13 13:03:35 -07004416 if(Item.uDataAlloc) {
4417 pMe->uLastError = QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
4418 return;
4419 }
4420
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004421 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4422 &Item,
4423 uTagRequirement,
4424 pBstr);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004425}
4426
4427
Laurence Lundblade02625d42020-06-25 14:41:41 -07004428/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004429 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004430 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004431void
4432QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe,
4433 const int64_t nLabel,
4434 const uint8_t uTagRequirement,
4435 UsefulBufC *pBstr)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004436{
4437 QCBORItem Item;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004438 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004439
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004440 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4441 &Item,
4442 uTagRequirement,
4443 pBstr);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004444}
4445
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004446
Laurence Lundblade02625d42020-06-25 14:41:41 -07004447/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004448 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004449 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004450void
4451QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe,
4452 const char *szLabel,
4453 const uint8_t uTagRequirement,
4454 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004455{
4456 QCBORItem Item;
4457 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4458
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004459 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4460 &Item,
4461 uTagRequirement,
4462 pBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004463}
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004464
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004465
Laurence Lundblade02625d42020-06-25 14:41:41 -07004466/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004467 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004468 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004469void
4470QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004471{
Laurence Lundblade02625d42020-06-25 14:41:41 -07004472 if(pMe->uLastError != QCBOR_SUCCESS) {
4473 // Already in error state; do nothing.
4474 return;
4475 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004476
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004477 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004478 pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade02625d42020-06-25 14:41:41 -07004479 return;
4480 }
4481
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004482 const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
4483
Laurence Lundblade02625d42020-06-25 14:41:41 -07004484 /*
4485 Reset the length of the UsefulInputBuf to what it was before
4486 the bstr wrapped CBOR was entered.
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004487 */
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004488 UsefulInputBuf_SetBufferLength(&(pMe->InBuf),
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004489 DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004490
4491
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004492 QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004493 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004494}
4495
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004496
Laurence Lundbladee6430642020-03-14 21:15:44 -07004497
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004498/**
4499 * @brief Process simple type true and false, a boolean
4500 *
4501 * @param[in] pMe The decode context.
4502 * @param[in] pItem The item with either true or false.
4503 * @param[out] pBool The boolean value output.
4504 *
4505 * Sets the internal error if the item isn't a true or a false. Also
4506 * records any tag numbers as the tag numbers of the last item.
4507 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004508static void
4509QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe,
4510 const QCBORItem *pItem,
4511 bool *pBool)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004512{
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004513 if(pMe->uLastError != QCBOR_SUCCESS) {
4514 /* Already in error state, do nothing */
4515 return;
4516 }
4517
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004518 switch(pItem->uDataType) {
4519 case QCBOR_TYPE_TRUE:
4520 *pBool = true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004521 break;
4522
4523 case QCBOR_TYPE_FALSE:
4524 *pBool = false;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004525 break;
4526
4527 default:
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004528 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004529 break;
4530 }
4531}
Laurence Lundbladee6430642020-03-14 21:15:44 -07004532
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004533
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004534/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004535 * Public function, see header qcbor/qcbor_decode.h file
4536 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004537void
4538QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004539{
Laurence Lundbladec4537442020-04-14 18:53:22 -07004540 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07004541 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004542 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004543}
4544
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004545
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004546/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004547 * Public function, see header qcbor/qcbor_decode.h file
4548 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004549void
4550QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe,
4551 const int64_t nLabel,
4552 bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004553{
4554 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004555 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004556 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004557}
4558
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004559
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004560/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004561 * Public function, see header qcbor/qcbor_decode.h file
4562 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004563void
4564QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe,
4565 const char *szLabel,
4566 bool *pValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004567{
4568 QCBORItem Item;
4569 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004570 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004571}
4572
4573
Laurence Lundblade3888f002024-06-12 21:20:56 -07004574/**
4575 * @brief Process simple values.
4576 *
4577 * @param[in] pMe The decode context.
4578 * @param[in] pItem The item with the simple value.
4579 * @param[out] puSimple The simple value output.
4580 *
4581 * Sets the internal error if the item isn't a true or a false. Also
4582 * records any tag numbers as the tag numbers of the last item.
4583 */
4584static void
4585QCBORDecode_Private_ProcessSimple(QCBORDecodeContext *pMe,
4586 const QCBORItem *pItem,
4587 uint8_t *puSimple)
4588{
4589 if(pMe->uLastError != QCBOR_SUCCESS) {
4590 return;
4591 }
4592
4593 /* It's kind of lame to remap true...undef back to simple values, but
4594 * this function isn't used much and to not do it would require
4595 * changing GetNext() behavior in an incompatible way.
4596 */
4597 switch(pItem->uDataType) {
4598 case QCBOR_TYPE_UKNOWN_SIMPLE:
4599 *puSimple = pItem->val.uSimple;
4600 break;
4601
4602 case QCBOR_TYPE_TRUE:
4603 *puSimple = CBOR_SIMPLEV_TRUE;
4604 break;
4605
4606 case QCBOR_TYPE_FALSE:
4607 *puSimple = CBOR_SIMPLEV_FALSE;
4608 break;
4609
4610 case QCBOR_TYPE_NULL:
4611 *puSimple = CBOR_SIMPLEV_NULL;
4612 break;
4613
4614 case QCBOR_TYPE_UNDEF:
4615 *puSimple = CBOR_SIMPLEV_UNDEF;
4616 break;
4617
4618 default:
4619 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4620 return;
4621 }
Laurence Lundblade3888f002024-06-12 21:20:56 -07004622}
4623
4624/*
4625 * Public function, see header qcbor/qcbor_decode.h file
4626 */
4627void
4628QCBORDecode_GetSimple(QCBORDecodeContext *pMe, uint8_t *puSimple)
4629{
4630 QCBORItem Item;
Laurence Lundblade3888f002024-06-12 21:20:56 -07004631 QCBORDecode_VGetNext(pMe, &Item);
4632 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimple);
4633}
4634
4635/*
4636 * Public function, see header qcbor/qcbor_decode.h file
4637 */
4638void
4639QCBORDecode_GetSimpleInMapN(QCBORDecodeContext *pMe,
4640 int64_t nLabel,
4641 uint8_t *puSimpleValue)
4642{
4643 QCBORItem Item;
4644 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3888f002024-06-12 21:20:56 -07004645 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
4646}
4647
4648/*
4649 * Public function, see header qcbor/qcbor_decode.h file
4650 */
4651void
4652QCBORDecode_GetSimpleInMapSZ(QCBORDecodeContext *pMe,
4653 const char *szLabel,
4654 uint8_t *puSimpleValue)
4655{
4656 QCBORItem Item;
4657 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3888f002024-06-12 21:20:56 -07004658 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
4659}
4660
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004661
Laurence Lundbladec7114722020-08-13 05:11:40 -07004662
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004663/**
4664 * @brief Common processing for an epoch date.
4665 *
4666 * @param[in] pMe The decode context.
4667 * @param[in] pItem The item with the date.
4668 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4669 * @param[out] pnTime The returned date.
4670 *
4671 * Common processing for the date tag. Mostly make sure the tag
4672 * content is correct and copy forward any further other tag numbers.
4673 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004674static void
4675QCBORDecode_Private_ProcessEpochDate(QCBORDecodeContext *pMe,
4676 QCBORItem *pItem,
4677 const uint8_t uTagRequirement,
4678 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004679{
4680 if(pMe->uLastError != QCBOR_SUCCESS) {
4681 // Already in error state, do nothing
4682 return;
4683 }
4684
4685 QCBORError uErr;
4686
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004687 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladec7114722020-08-13 05:11:40 -07004688 {
4689 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004690 {QCBOR_TYPE_DATE_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4691 {QCBOR_TYPE_INT64, QCBOR_TYPE_DOUBLE, QCBOR_TYPE_FLOAT, QCBOR_TYPE_UINT64}
Laurence Lundbladec7114722020-08-13 05:11:40 -07004692 };
4693
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004694 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004695 if(uErr != QCBOR_SUCCESS) {
4696 goto Done;
4697 }
4698
4699 if(pItem->uDataType != QCBOR_TYPE_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004700 uErr = QCBOR_Private_DecodeDateEpoch(pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004701 if(uErr != QCBOR_SUCCESS) {
4702 goto Done;
4703 }
4704 }
4705
4706 *pnTime = pItem->val.epochDate.nSeconds;
4707
4708Done:
4709 pMe->uLastError = (uint8_t)uErr;
4710}
4711
4712
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004713
4714/*
4715 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4716 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004717void
4718QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
4719 uint8_t uTagRequirement,
4720 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004721{
Laurence Lundbladec7114722020-08-13 05:11:40 -07004722 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07004723 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004724 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004725}
4726
4727
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004728/*
4729 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4730 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07004731void
4732QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
4733 int64_t nLabel,
4734 uint8_t uTagRequirement,
4735 int64_t *pnTime)
4736{
4737 QCBORItem Item;
4738 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004739 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004740}
4741
4742
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004743/*
4744 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4745 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07004746void
4747QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
4748 const char *szLabel,
4749 uint8_t uTagRequirement,
4750 int64_t *pnTime)
4751{
4752 QCBORItem Item;
4753 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004754 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004755}
4756
4757
4758
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004759/**
4760 * @brief Common processing for an epoch date.
4761 *
4762 * @param[in] pMe The decode context.
4763 * @param[in] pItem The item with the date.
4764 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4765 * @param[out] pnDays The returned day count.
4766 *
4767 * Common processing for the RFC 8943 day-count tag. Mostly make sure
4768 * the tag content is correct and copy forward any further other tag
4769 * numbers.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004770 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004771static void
4772QCBORDecode_Private_ProcessEpochDays(QCBORDecodeContext *pMe,
4773 QCBORItem *pItem,
4774 uint8_t uTagRequirement,
4775 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004776{
4777 if(pMe->uLastError != QCBOR_SUCCESS) {
4778 /* Already in error state, do nothing */
4779 return;
4780 }
4781
4782 QCBORError uErr;
4783
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004784 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004785 {
4786 uTagRequirement,
4787 {QCBOR_TYPE_DAYS_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4788 {QCBOR_TYPE_INT64, QCBOR_TYPE_UINT64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4789 };
4790
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004791 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004792 if(uErr != QCBOR_SUCCESS) {
4793 goto Done;
4794 }
4795
4796 if(pItem->uDataType != QCBOR_TYPE_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004797 uErr = QCBOR_Private_DecodeDaysEpoch(pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004798 if(uErr != QCBOR_SUCCESS) {
4799 goto Done;
4800 }
4801 }
4802
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004803 *pnDays = pItem->val.epochDays;
4804
4805Done:
4806 pMe->uLastError = (uint8_t)uErr;
4807}
4808
4809
4810/*
4811 * Public function, see header qcbor/qcbor_decode.h
4812 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004813void
4814QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe,
4815 uint8_t uTagRequirement,
4816 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004817{
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004818 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07004819 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004820 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004821}
4822
4823
4824/*
4825 * Public function, see header qcbor/qcbor_decode.h
4826 */
4827void
4828QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe,
4829 int64_t nLabel,
4830 uint8_t uTagRequirement,
4831 int64_t *pnDays)
4832{
4833 QCBORItem Item;
4834 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004835 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004836}
4837
4838
4839/*
4840 * Public function, see header qcbor/qcbor_decode.h
4841 */
4842void
4843QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe,
4844 const char *szLabel,
4845 uint8_t uTagRequirement,
4846 int64_t *pnDays)
4847{
4848 QCBORItem Item;
4849 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004850 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004851}
4852
4853
4854
Laurence Lundblade37286c02022-09-03 10:05:02 -07004855/*
4856 * @brief Get a string that matches the type/tag specification.
4857 */
4858void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004859QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
4860 const QCBOR_Private_TagSpec TagSpec,
4861 UsefulBufC *pBstr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004862{
Laurence Lundbladec4537442020-04-14 18:53:22 -07004863 QCBORItem Item;
4864
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07004865 QCBORDecode_VGetNext(pMe, &Item);
4866 if(pMe->uLastError) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07004867 return;
4868 }
4869
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004870 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004871
4872 if(pMe->uLastError == QCBOR_SUCCESS) {
4873 *pBstr = Item.val.string;
Laurence Lundbladeab40c6f2020-08-28 11:24:58 -07004874 } else {
4875 *pBstr = NULLUsefulBufC;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004876 }
4877}
4878
Laurence Lundbladec4537442020-04-14 18:53:22 -07004879
4880
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004881
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004882/**
4883 * @brief Common processing for a big number tag.
4884 *
4885 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4886 * @param[in] pItem The item with the date.
4887 * @param[out] pValue The returned big number
4888 * @param[out] pbIsNegative The returned sign of the big number.
4889 *
4890 * Common processing for the big number tag. Mostly make sure
4891 * the tag content is correct and copy forward any further other tag
4892 * numbers.
4893 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004894static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004895QCBOR_Private_ProcessBigNum(const uint8_t uTagRequirement,
4896 const QCBORItem *pItem,
4897 UsefulBufC *pValue,
4898 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004899{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004900 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004901 {
4902 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004903 {QCBOR_TYPE_POSBIGNUM, QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4904 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004905 };
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004906
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004907 QCBORError uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004908 if(uErr != QCBOR_SUCCESS) {
4909 return uErr;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004910 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004911
4912 *pValue = pItem->val.string;
4913
4914 if(pItem->uDataType == QCBOR_TYPE_POSBIGNUM) {
4915 *pbIsNegative = false;
4916 } else if(pItem->uDataType == QCBOR_TYPE_NEGBIGNUM) {
4917 *pbIsNegative = true;
4918 }
4919
4920 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004921}
4922
4923
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004924/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004925 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004926 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004927void
4928QCBORDecode_GetBignum(QCBORDecodeContext *pMe,
4929 const uint8_t uTagRequirement,
4930 UsefulBufC *pValue,
4931 bool *pbIsNegative)
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004932{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004933 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07004934 QCBORDecode_VGetNext(pMe, &Item);
4935 if(pMe->uLastError) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004936 return;
4937 }
4938
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004939 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4940 &Item,
4941 pValue,
4942 pbIsNegative);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004943}
4944
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004945
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004946/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004947 * Public function, see header qcbor/qcbor_spiffy_decode.h
4948 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004949void
4950QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe,
4951 const int64_t nLabel,
4952 const uint8_t uTagRequirement,
4953 UsefulBufC *pValue,
4954 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004955{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004956 QCBORItem Item;
4957 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004958 if(pMe->uLastError != QCBOR_SUCCESS) {
4959 return;
4960 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004961
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004962 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4963 &Item,
4964 pValue,
4965 pbIsNegative);
Laurence Lundbladec4537442020-04-14 18:53:22 -07004966}
4967
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004968
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004969/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004970 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004971 */
4972void
4973QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe,
4974 const char *szLabel,
4975 const uint8_t uTagRequirement,
4976 UsefulBufC *pValue,
4977 bool *pbIsNegative)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004978{
4979 QCBORItem Item;
4980 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004981 if(pMe->uLastError != QCBOR_SUCCESS) {
4982 return;
4983 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004984
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004985 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4986 &Item,
4987 pValue,
4988 pbIsNegative);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004989}
4990
4991
4992
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004993/**
4994 * @brief Common processing for MIME tag (semi-private).
4995 *
4996 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4997 * @param[in] pItem The item with the date.
4998 * @param[out] pMessage The returned MIME message.
4999 * @param[out] pbIsTag257 If true, binary MIME, if not, text MIME.
5000 *
5001 * Common processing for the MIME tag. Mostly make sure the tag
5002 * content is correct and copy forward any further other tag
5003 * numbers. See QCBORDecode_GetMIMEMessage().
5004 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07005005QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005006QCBORDecode_Private_GetMIME(const uint8_t uTagRequirement,
Laurence Lundblade37286c02022-09-03 10:05:02 -07005007 const QCBORItem *pItem,
5008 UsefulBufC *pMessage,
5009 bool *pbIsTag257)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005010{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005011 const QCBOR_Private_TagSpec TagSpecText =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005012 {
5013 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07005014 {QCBOR_TYPE_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
5015 {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005016 };
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005017 const QCBOR_Private_TagSpec TagSpecBinary =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005018 {
5019 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07005020 {QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
5021 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005022 };
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005023
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005024 QCBORError uReturn;
Laurence Lundblade9b334962020-08-27 10:55:53 -07005025
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005026 if(QCBOR_Private_CheckTagRequirement(TagSpecText, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005027 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07005028 if(pbIsTag257 != NULL) {
5029 *pbIsTag257 = false;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005030 }
5031 uReturn = QCBOR_SUCCESS;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005032 } else if(QCBOR_Private_CheckTagRequirement(TagSpecBinary, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005033 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07005034 if(pbIsTag257 != NULL) {
5035 *pbIsTag257 = true;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005036 }
5037 uReturn = QCBOR_SUCCESS;
5038
5039 } else {
5040 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
5041 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07005042
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005043 return uReturn;
5044}
5045
Laurence Lundblade93d89472020-10-03 22:30:50 -07005046// Improvement: add methods for wrapped CBOR, a simple alternate
5047// to EnterBstrWrapped
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005048
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005049
5050
5051
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005052#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundbladee6430642020-03-14 21:15:44 -07005053
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005054/**
5055 * @brief Prototype for conversion of exponent and mantissa to unsigned integer.
5056 *
5057 * @param[in] uMantissa The mantissa.
5058 * @param[in] nExponent The exponent.
5059 * @param[out] puResult The resulting integer.
5060 *
5061 * Concrete implementations of this are for exponent base 10 and 2 supporting
5062 * decimal fractions and big floats.
5063 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005064typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005065
5066
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005067/**
5068 * @brief Base 10 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5069 *
5070 * @param[in] uMantissa The unsigned integer mantissa.
5071 * @param[in] nExponent The signed integer exponent.
5072 * @param[out] puResult Place to return the unsigned integer result.
5073 *
5074 * This computes: mantissa * 10 ^^ exponent as for a decimal fraction. The output is a 64-bit
5075 * unsigned integer.
5076 *
5077 * There are many inputs for which the result will not fit in the
5078 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5079 * be returned.
5080 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005081static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005082QCBOR_Private_Exponentitate10(const uint64_t uMantissa,
5083 int64_t nExponent,
5084 uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005085{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005086 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005087
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005088 if(uResult != 0) {
5089 /* This loop will run a maximum of 19 times because
5090 * UINT64_MAX < 10 ^^ 19. More than that will cause
5091 * exit with the overflow error
5092 */
5093 for(; nExponent > 0; nExponent--) {
5094 if(uResult > UINT64_MAX / 10) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005095 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005096 }
5097 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005098 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005099
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005100 for(; nExponent < 0; nExponent++) {
5101 uResult = uResult / 10;
5102 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005103 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005104 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005105 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005106 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005107 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07005108
5109 *puResult = uResult;
5110
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005111 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005112}
5113
5114
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005115/**
5116 * @brief Base 2 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5117 *
5118 * @param[in] uMantissa The unsigned integer mantissa.
5119 * @param[in] nExponent The signed integer exponent.
5120 * @param[out] puResult Place to return the unsigned integer result.
5121 *
5122 * This computes: mantissa * 2 ^^ exponent as for a big float. The
5123 * output is a 64-bit unsigned integer.
5124 *
5125 * There are many inputs for which the result will not fit in the
5126 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5127 * be returned.
5128 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005129static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005130QCBOR_Private_Exponentitate2(const uint64_t uMantissa,
5131 int64_t nExponent,
5132 uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005133{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005134 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005135
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005136 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005137
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005138 /* This loop will run a maximum of 64 times because INT64_MAX <
5139 * 2^31. More than that will cause exit with the overflow error
Laurence Lundbladee6430642020-03-14 21:15:44 -07005140 */
5141 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005142 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005143 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005144 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005145 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005146 nExponent--;
5147 }
5148
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005149 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005150 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005151 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005152 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005153 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005154 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005155 }
5156
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005157 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005158
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005159 return QCBOR_SUCCESS;
5160}
5161
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005162
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005163/**
5164 * @brief Exponentiate a signed mantissa and signed exponent to produce a signed result.
5165 *
5166 * @param[in] nMantissa Signed integer mantissa.
5167 * @param[in] nExponent Signed integer exponent.
5168 * @param[out] pnResult Place to put the signed integer result.
5169 * @param[in] pfExp Exponentiation function.
5170 *
5171 * @returns Error code
5172 *
5173 * \c pfExp performs exponentiation on and unsigned mantissa and
5174 * produces an unsigned result. This converts the mantissa from signed
5175 * and converts the result to signed. The exponentiation function is
5176 * either for base 2 or base 10 (and could be other if needed).
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005177 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005178static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005179QCBOR_Private_ExponentiateNN(const int64_t nMantissa,
5180 const int64_t nExponent,
5181 int64_t *pnResult,
5182 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005183{
5184 uint64_t uResult;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005185 uint64_t uMantissa;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005186
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005187 /* Take the absolute value and put it into an unsigned. */
5188 if(nMantissa >= 0) {
5189 /* Positive case is straightforward */
5190 uMantissa = (uint64_t)nMantissa;
5191 } else if(nMantissa != INT64_MIN) {
5192 /* The common negative case. See next. */
5193 uMantissa = (uint64_t)-nMantissa;
5194 } else {
5195 /* int64_t and uint64_t are always two's complement per the
5196 * C standard (and since QCBOR uses these it only works with
5197 * two's complement, which is pretty much universal these
5198 * days). The range of a negative two's complement integer is
5199 * one more that than a positive, so the simple code above might
5200 * not work all the time because you can't simply negate the
5201 * value INT64_MIN because it can't be represented in an
5202 * int64_t. -INT64_MIN can however be represented in a
5203 * uint64_t. Some compilers seem to recognize this case for the
5204 * above code and put the correct value in uMantissa, however
5205 * they are not required to do this by the C standard. This next
5206 * line does however work for all compilers.
5207 *
5208 * This does assume two's complement where -INT64_MIN ==
5209 * INT64_MAX + 1 (which wouldn't be true for one's complement or
5210 * sign and magnitude (but we know we're using two's complement
5211 * because int64_t requires it)).
5212 *
5213 * See these, particularly the detailed commentary:
5214 * https://stackoverflow.com/questions/54915742/does-c99-mandate-a-int64-t-type-be-available-always
5215 * https://stackoverflow.com/questions/37301078/is-negating-int-min-undefined-behaviour
5216 */
5217 uMantissa = (uint64_t)INT64_MAX+1;
5218 }
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005219
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005220 /* Call the exponentiator passed for either base 2 or base 10.
5221 * Here is where most of the overflow errors are caught. */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005222 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
5223 if(uReturn) {
5224 return uReturn;
5225 }
5226
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005227 /* Convert back to the sign of the original mantissa */
5228 if(nMantissa >= 0) {
5229 if(uResult > INT64_MAX) {
5230 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5231 }
5232 *pnResult = (int64_t)uResult;
5233 } else {
5234 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
5235 * of INT64_MIN. This assumes two's compliment representation
5236 * where INT64_MIN is one increment farther from 0 than
5237 * INT64_MAX. Trying to write -INT64_MIN doesn't work to get
5238 * this because the compiler makes it an int64_t which can't
5239 * represent -INT64_MIN. Also see above.
5240 */
5241 if(uResult > (uint64_t)INT64_MAX+1) {
5242 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5243 }
5244 *pnResult = -(int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005245 }
5246
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005247 return QCBOR_SUCCESS;
5248}
5249
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005250
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005251/**
5252 * @brief Exponentiate an unsigned mantissa and signed exponent to produce an unsigned result.
5253 *
5254 * @param[in] nMantissa Signed integer mantissa.
5255 * @param[in] nExponent Signed integer exponent.
5256 * @param[out] puResult Place to put the signed integer result.
5257 * @param[in] pfExp Exponentiation function.
5258 *
5259 * @returns Error code
5260 *
5261 * \c pfExp performs exponentiation on and unsigned mantissa and
5262 * produces an unsigned result. This errors out if the mantissa
5263 * is negative because the output is unsigned.
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005264 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005265static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005266QCBOR_Private_ExponentitateNU(const int64_t nMantissa,
5267 const int64_t nExponent,
5268 uint64_t *puResult,
5269 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005270{
5271 if(nMantissa < 0) {
5272 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5273 }
5274
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005275 /* Cast to unsigned is OK because of check for negative.
5276 * Cast to unsigned is OK because UINT64_MAX > INT64_MAX.
5277 * Exponentiation is straight forward
5278 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005279 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
5280}
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005281
5282
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005283/**
5284 * @brief Exponentiate an usnigned mantissa and unsigned exponent to produce an unsigned result.
5285 *
5286 * @param[in] uMantissa Unsigned integer mantissa.
5287 * @param[in] nExponent Unsigned integer exponent.
5288 * @param[out] puResult Place to put the unsigned integer result.
5289 * @param[in] pfExp Exponentiation function.
5290 *
5291 * @returns Error code
5292 *
5293 * \c pfExp performs exponentiation on and unsigned mantissa and
5294 * produces an unsigned result so this is just a wrapper that does
5295 * nothing (and is likely inlined).
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005296 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005297static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005298QCBOR_Private_ExponentitateUU(const uint64_t uMantissa,
5299 const int64_t nExponent,
5300 uint64_t *puResult,
5301 fExponentiator pfExp)
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005302{
5303 return (*pfExp)(uMantissa, nExponent, puResult);
5304}
5305
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005306#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005307
5308
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005309
5310
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005311/**
5312 * @brief Convert a CBOR big number to a uint64_t.
5313 *
5314 * @param[in] BigNum Bytes of the big number to convert.
5315 * @param[in] uMax Maximum value allowed for the result.
5316 * @param[out] pResult Place to put the unsigned integer result.
5317 *
5318 * @returns Error code
5319 *
5320 * Many values will overflow because a big num can represent a much
5321 * larger range than uint64_t.
5322 */
5323static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005324QCBOR_Private_ConvertBigNumToUnsigned(const UsefulBufC BigNum,
5325 const uint64_t uMax,
5326 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005327{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005328 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005329
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005330 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005331 const uint8_t *pByte = BigNum.ptr;
5332 size_t uLen = BigNum.len;
5333 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07005334 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005335 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005336 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07005337 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005338 }
5339
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005340 *pResult = uResult;
5341 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005342}
5343
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005344
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005345/**
5346 * @brief Convert a CBOR postive big number to a uint64_t.
5347 *
5348 * @param[in] BigNum Bytes of the big number to convert.
5349 * @param[out] pResult Place to put the unsigned integer result.
5350 *
5351 * @returns Error code
5352 *
5353 * Many values will overflow because a big num can represent a much
5354 * larger range than uint64_t.
5355 */
5356static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005357QCBOR_Private_ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum,
5358 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005359{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005360 return QCBOR_Private_ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005361}
5362
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005363
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005364/**
5365 * @brief Convert a CBOR positive big number to an int64_t.
5366 *
5367 * @param[in] BigNum Bytes of the big number to convert.
5368 * @param[out] pResult Place to put the signed integer result.
5369 *
5370 * @returns Error code
5371 *
5372 * Many values will overflow because a big num can represent a much
5373 * larger range than int64_t.
5374 */
5375static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005376QCBOR_Private_ConvertPositiveBigNumToSigned(const UsefulBufC BigNum,
5377 int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005378{
5379 uint64_t uResult;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005380 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5381 INT64_MAX,
5382 &uResult);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005383 if(uError) {
5384 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005385 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005386 /* Cast is safe because ConvertBigNumToUnsigned limits to INT64_MAX */
Laurence Lundbladee6430642020-03-14 21:15:44 -07005387 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005388 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005389}
5390
5391
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005392/**
5393 * @brief Convert a CBOR negative big number to an int64_t.
5394 *
5395 * @param[in] BigNum Bytes of the big number to convert.
5396 * @param[out] pnResult Place to put the signed integer result.
5397 *
5398 * @returns Error code
5399 *
5400 * Many values will overflow because a big num can represent a much
5401 * larger range than int64_t.
5402 */
5403static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005404QCBOR_Private_ConvertNegativeBigNumToSigned(const UsefulBufC BigNum,
5405 int64_t *pnResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005406{
5407 uint64_t uResult;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005408 /* The negative integer furthest from zero for a C int64_t is
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005409 * INT64_MIN which is expressed as -INT64_MAX - 1. The value of a
5410 * negative number in CBOR is computed as -n - 1 where n is the
5411 * encoded integer, where n is what is in the variable BigNum. When
5412 * converting BigNum to a uint64_t, the maximum value is thus
5413 * INT64_MAX, so that when it -n - 1 is applied to it the result
5414 * will never be further from 0 than INT64_MIN.
5415 *
5416 * -n - 1 <= INT64_MIN.
5417 * -n - 1 <= -INT64_MAX - 1
5418 * n <= INT64_MAX.
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005419 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005420 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5421 INT64_MAX,
5422 &uResult);
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005423 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005424 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005425 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005426
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005427 /* Now apply -n - 1. The cast is safe because
5428 * ConvertBigNumToUnsigned() is limited to INT64_MAX which does fit
5429 * is the largest positive integer that an int64_t can
5430 * represent. */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005431 *pnResult = -(int64_t)uResult - 1;
5432
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005433 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005434}
5435
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005436
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005437
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005438
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005439/**
5440 * @brief Convert integers and floats to an int64_t.
5441 *
5442 * @param[in] pItem The item to convert.
5443 * @param[in] uConvertTypes Bit mask list of conversion options.
5444 * @param[out] pnValue The resulting converted value.
5445 *
5446 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5447 * in uConvertTypes.
5448 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5449 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5450 * or too small.
5451 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005452static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005453QCBOR_Private_ConvertInt64(const QCBORItem *pItem,
5454 const uint32_t uConvertTypes,
5455 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005456{
5457 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005458 case QCBOR_TYPE_FLOAT:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005459 case QCBOR_TYPE_DOUBLE:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005460#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005461 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005462 /* https://pubs.opengroup.org/onlinepubs/009695399/functions/llround.html
5463 http://www.cplusplus.com/reference/cmath/llround/
5464 */
5465 // Not interested in FE_INEXACT
5466 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005467 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5468 *pnValue = llround(pItem->val.dfnum);
5469 } else {
5470 *pnValue = lroundf(pItem->val.fnum);
5471 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005472 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5473 // llround() shouldn't result in divide by zero, but catch
5474 // it here in case it unexpectedly does. Don't try to
5475 // distinguish between the various exceptions because it seems
5476 // they vary by CPU, compiler and OS.
5477 return QCBOR_ERR_FLOAT_EXCEPTION;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005478 }
5479 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005480 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005481 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005482#else
5483 return QCBOR_ERR_HW_FLOAT_DISABLED;
5484#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005485 break;
5486
5487 case QCBOR_TYPE_INT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005488 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005489 *pnValue = pItem->val.int64;
5490 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005491 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005492 }
5493 break;
5494
5495 case QCBOR_TYPE_UINT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005496 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005497 if(pItem->val.uint64 < INT64_MAX) {
5498 *pnValue = pItem->val.int64;
5499 } else {
5500 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5501 }
5502 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005503 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005504 }
5505 break;
5506
5507 default:
5508 return QCBOR_ERR_UNEXPECTED_TYPE;
5509 }
5510 return QCBOR_SUCCESS;
5511}
5512
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005513
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005514/**
5515 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5516 *
5517 * @param[in] pMe The decode context.
5518 * @param[in] uConvertTypes Bit mask list of conversion options.
5519 * @param[out] pnValue Result of the conversion.
5520 * @param[in,out] pItem Temporary space to store Item, returned item.
5521 *
5522 * See QCBORDecode_GetInt64Convert().
5523 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005524void
5525QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pMe,
5526 uint32_t uConvertTypes,
5527 int64_t *pnValue,
5528 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005529{
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07005530 QCBORDecode_VGetNext(pMe, pItem);
5531 if(pMe->uLastError) {
Laurence Lundbladee6430642020-03-14 21:15:44 -07005532 return;
5533 }
5534
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005535 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005536 uConvertTypes,
5537 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005538}
5539
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005540/**
5541 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5542 *
5543 * @param[in] pMe The decode context.
5544 * @param[in] nLabel Label to find in map.
5545 * @param[in] uConvertTypes Bit mask list of conversion options.
5546 * @param[out] pnValue Result of the conversion.
5547 * @param[in,out] pItem Temporary space to store Item, returned item.
5548 *
5549 * See QCBORDecode_GetInt64ConvertInMapN().
5550 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005551void
5552QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pMe,
5553 int64_t nLabel,
5554 uint32_t uConvertTypes,
5555 int64_t *pnValue,
5556 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005557{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005558 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005559 if(pMe->uLastError != QCBOR_SUCCESS) {
5560 return;
5561 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005562
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005563 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5564 uConvertTypes,
5565 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005566}
5567
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005568/**
5569 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5570 *
5571 * @param[in] pMe The decode context.
5572 * @param[in] szLabel Label to find in map.
5573 * @param[in] uConvertTypes Bit mask list of conversion options.
5574 * @param[out] pnValue Result of the conversion.
5575 * @param[in,out] pItem Temporary space to store Item, returned item.
5576 *
5577 * See QCBORDecode_GetInt64ConvertInMapSZ().
5578 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005579void
5580QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5581 const char * szLabel,
5582 uint32_t uConvertTypes,
5583 int64_t *pnValue,
5584 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005585{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005586 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005587 if(pMe->uLastError != QCBOR_SUCCESS) {
5588 return;
5589 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005590
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005591 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5592 uConvertTypes,
5593 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005594}
5595
5596
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005597/**
5598 * @brief Convert many number types to an int64_t.
5599 *
5600 * @param[in] pItem The item to convert.
5601 * @param[in] uConvertTypes Bit mask list of conversion options.
5602 * @param[out] pnValue The resulting converted value.
5603 *
5604 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5605 * in uConvertTypes.
5606 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5607 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5608 * or too small.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005609 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005610static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005611QCBOR_Private_Int64ConvertAll(const QCBORItem *pItem,
5612 const uint32_t uConvertTypes,
5613 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005614{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005615 switch(pItem->uDataType) {
5616
5617 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005618 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005619 return QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005620 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005621 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005622 }
5623 break;
5624
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005625 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005626 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005627 return QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005628 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005629 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005630 }
5631 break;
5632
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005633#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005634 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005635 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005636 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005637 pItem->val.expAndMantissa.nExponent,
5638 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005639 &QCBOR_Private_Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005640 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005641 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005642 }
5643 break;
5644
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005645 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005646 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005647 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005648 pItem->val.expAndMantissa.nExponent,
5649 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005650 QCBOR_Private_Exponentitate2);
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
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005656 case QCBOR_TYPE_DECIMAL_FRACTION_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_Exponentitate10);
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_DECIMAL_FRACTION_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_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005685 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005686 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005687 }
5688 break;
5689
5690 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005691 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005692 int64_t nMantissa;
5693 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005694 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005695 if(uErr) {
5696 return uErr;
5697 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005698 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005699 pItem->val.expAndMantissa.nExponent,
5700 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005701 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005702 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005703 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005704 }
5705 break;
5706
5707 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005708 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005709 int64_t nMantissa;
5710 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005711 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005712 if(uErr) {
5713 return uErr;
5714 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005715 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005716 pItem->val.expAndMantissa.nExponent,
5717 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005718 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005719 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005720 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005721 }
5722 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005723#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005724
Laurence Lundbladee6430642020-03-14 21:15:44 -07005725
Laurence Lundbladec4537442020-04-14 18:53:22 -07005726 default:
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005727 return QCBOR_ERR_UNEXPECTED_TYPE; }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005728}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005729
5730
Laurence Lundbladec4537442020-04-14 18:53:22 -07005731/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005732 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005733 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005734void
5735QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe,
5736 const uint32_t uConvertTypes,
5737 int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005738{
5739 QCBORItem Item;
5740
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005741 QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005742
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005743 if(pMe->uLastError == QCBOR_SUCCESS) {
5744 // The above conversion succeeded
5745 return;
5746 }
5747
Laurence Lundbladef6c86662020-05-12 02:08:00 -07005748 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005749 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07005750 return;
5751 }
5752
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005753 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5754 uConvertTypes,
5755 pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005756}
5757
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005758
5759/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005760 * Public function, see header qcbor/qcbor_decode.h file
5761 */
5762void
5763QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
5764 const int64_t nLabel,
5765 const uint32_t uConvertTypes,
5766 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005767{
5768 QCBORItem Item;
5769
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005770 QCBORDecode_Private_GetInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07005771 nLabel,
5772 uConvertTypes,
5773 pnValue,
5774 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005775
5776 if(pMe->uLastError == QCBOR_SUCCESS) {
5777 // The above conversion succeeded
5778 return;
5779 }
5780
5781 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5782 // The above conversion failed in a way that code below can't correct
5783 return;
5784 }
5785
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005786 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5787 uConvertTypes,
5788 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005789}
5790
5791
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005792/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005793 * Public function, see header qcbor/qcbor_decode.h file
5794 */
5795void
5796QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
5797 const char *szLabel,
5798 const uint32_t uConvertTypes,
5799 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005800{
5801 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005802 QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07005803 szLabel,
5804 uConvertTypes,
5805 pnValue,
5806 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005807
5808 if(pMe->uLastError == QCBOR_SUCCESS) {
5809 // The above conversion succeeded
5810 return;
5811 }
5812
5813 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5814 // The above conversion failed in a way that code below can't correct
5815 return;
5816 }
5817
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005818 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5819 uConvertTypes,
5820 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005821}
5822
5823
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005824/**
5825 * @brief Convert many number types to an uint64_t.
5826 *
5827 * @param[in] pItem The item to convert.
5828 * @param[in] uConvertTypes Bit mask list of conversion options.
5829 * @param[out] puValue The resulting converted value.
5830 *
5831 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5832 * in uConvertTypes.
5833 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5834 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5835 * or too small.
5836 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005837static QCBORError
5838QCBOR_Private_ConvertUInt64(const QCBORItem *pItem,
5839 const uint32_t uConvertTypes,
5840 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005841{
5842 switch(pItem->uDataType) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005843 case QCBOR_TYPE_DOUBLE:
5844 case QCBOR_TYPE_FLOAT:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005845#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005846 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005847 // Can't use llround here because it will not convert values
5848 // greater than INT64_MAX and less than UINT64_MAX that
5849 // need to be converted so it is more complicated.
5850 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
5851 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5852 if(isnan(pItem->val.dfnum)) {
5853 return QCBOR_ERR_FLOAT_EXCEPTION;
5854 } else if(pItem->val.dfnum < 0) {
5855 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5856 } else {
5857 double dRounded = round(pItem->val.dfnum);
5858 // See discussion in DecodeDateEpoch() for
5859 // explanation of - 0x7ff
5860 if(dRounded > (double)(UINT64_MAX- 0x7ff)) {
5861 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5862 }
5863 *puValue = (uint64_t)dRounded;
5864 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005865 } else {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005866 if(isnan(pItem->val.fnum)) {
5867 return QCBOR_ERR_FLOAT_EXCEPTION;
5868 } else if(pItem->val.fnum < 0) {
5869 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5870 } else {
5871 float fRounded = roundf(pItem->val.fnum);
5872 // See discussion in DecodeDateEpoch() for
5873 // explanation of - 0x7ff
5874 if(fRounded > (float)(UINT64_MAX- 0x7ff)) {
5875 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5876 }
5877 *puValue = (uint64_t)fRounded;
5878 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005879 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005880 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5881 // round() and roundf() shouldn't result in exceptions here, but
5882 // catch them to be robust and thorough. Don't try to
5883 // distinguish between the various exceptions because it seems
5884 // they vary by CPU, compiler and OS.
5885 return QCBOR_ERR_FLOAT_EXCEPTION;
5886 }
5887
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005888 } else {
5889 return QCBOR_ERR_UNEXPECTED_TYPE;
5890 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005891#else
5892 return QCBOR_ERR_HW_FLOAT_DISABLED;
5893#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005894 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005895
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005896 case QCBOR_TYPE_INT64:
5897 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
5898 if(pItem->val.int64 >= 0) {
5899 *puValue = (uint64_t)pItem->val.int64;
5900 } else {
5901 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5902 }
5903 } else {
5904 return QCBOR_ERR_UNEXPECTED_TYPE;
5905 }
5906 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005907
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005908 case QCBOR_TYPE_UINT64:
5909 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
5910 *puValue = pItem->val.uint64;
5911 } else {
5912 return QCBOR_ERR_UNEXPECTED_TYPE;
5913 }
5914 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005915
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005916 default:
5917 return QCBOR_ERR_UNEXPECTED_TYPE;
5918 }
5919
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005920 return QCBOR_SUCCESS;
5921}
Laurence Lundbladec4537442020-04-14 18:53:22 -07005922
5923
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005924/**
5925 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5926 *
5927 * @param[in] pMe The decode context.
5928 * @param[in] uConvertTypes Bit mask list of conversion options.
5929 * @param[out] puValue Result of the conversion.
5930 * @param[in,out] pItem Temporary space to store Item, returned item.
5931 *
5932 * See QCBORDecode_GetUInt64Convert().
5933 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005934void
5935QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pMe,
5936 const uint32_t uConvertTypes,
5937 uint64_t *puValue,
5938 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005939{
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07005940 QCBORDecode_VGetNext(pMe, pItem);
5941 if(pMe->uLastError) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005942 return;
5943 }
5944
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07005945 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005946 uConvertTypes,
5947 puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005948}
5949
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005950
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005951/**
5952 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5953 *
5954 * @param[in] pMe The decode context.
5955 * @param[in] nLabel Label to find in map.
5956 * @param[in] uConvertTypes Bit mask list of conversion options.
5957 * @param[out] puValue Result of the conversion.
5958 * @param[in,out] pItem Temporary space to store Item, returned item.
5959 *
5960 * See QCBORDecode_GetUInt64ConvertInMapN().
5961 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005962void
5963QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe,
5964 const int64_t nLabel,
5965 const uint32_t uConvertTypes,
5966 uint64_t *puValue,
5967 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005968{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005969 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005970 if(pMe->uLastError != QCBOR_SUCCESS) {
5971 return;
5972 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005973
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005974 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
5975 uConvertTypes,
5976 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005977}
5978
5979
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005980/**
5981 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5982 *
5983 * @param[in] pMe The decode context.
5984 * @param[in] szLabel Label to find in map.
5985 * @param[in] uConvertTypes Bit mask list of conversion options.
5986 * @param[out] puValue Result of the conversion.
5987 * @param[in,out] pItem Temporary space to store Item, returned item.
5988 *
5989 * See QCBORDecode_GetUInt64ConvertInMapSZ().
5990 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005991void
5992QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5993 const char *szLabel,
5994 const uint32_t uConvertTypes,
5995 uint64_t *puValue,
5996 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005997{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005998 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005999 if(pMe->uLastError != QCBOR_SUCCESS) {
6000 return;
6001 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006002
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006003 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
6004 uConvertTypes,
6005 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006006}
6007
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006008
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006009/**
6010 * @brief Convert many number types to an unt64_t.
6011 *
6012 * @param[in] pItem The item to convert.
6013 * @param[in] uConvertTypes Bit mask list of conversion options.
6014 * @param[out] puValue The resulting converted value.
6015 *
6016 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6017 * in uConvertTypes.
6018 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6019 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6020 * or too small.
6021 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006022static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006023QCBOR_Private_UInt64ConvertAll(const QCBORItem *pItem,
6024 const uint32_t uConvertTypes,
6025 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006026{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08006027 switch(pItem->uDataType) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006028
6029 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006030 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006031 return QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006032 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006033 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006034 }
6035 break;
6036
6037 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006038 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006039 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6040 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006041 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006042 }
6043 break;
6044
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006045#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006046
6047 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006048 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006049 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006050 pItem->val.expAndMantissa.nExponent,
6051 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006052 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006053 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006054 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006055 }
6056 break;
6057
6058 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006059 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006060 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006061 pItem->val.expAndMantissa.nExponent,
6062 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006063 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006064 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006065 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006066 }
6067 break;
6068
6069 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006070 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006071 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006072 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006073 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006074 if(uErr != QCBOR_SUCCESS) {
6075 return uErr;
6076 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006077 return QCBOR_Private_ExponentitateUU(uMantissa,
6078 pItem->val.expAndMantissa.nExponent,
6079 puValue,
6080 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006081 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006082 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006083 }
6084 break;
6085
6086 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006087 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006088 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6089 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006090 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006091 }
6092 break;
6093
6094 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006095 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006096 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006097 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006098 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum,
6099 &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006100 if(uErr != QCBOR_SUCCESS) {
6101 return uErr;
6102 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006103 return QCBOR_Private_ExponentitateUU(uMantissa,
6104 pItem->val.expAndMantissa.nExponent,
6105 puValue,
6106 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006107 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006108 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006109 }
6110 break;
6111
6112 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006113 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006114 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6115 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006116 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006117 }
6118 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006119#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006120 default:
6121 return QCBOR_ERR_UNEXPECTED_TYPE;
6122 }
6123}
6124
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006125
Laurence Lundblade4e2da002020-06-13 23:08:31 -07006126/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006127 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006128 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006129void
6130QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe,
6131 const uint32_t uConvertTypes,
6132 uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006133{
6134 QCBORItem Item;
6135
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006136 QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006137
Laurence Lundbladef6c86662020-05-12 02:08:00 -07006138 if(pMe->uLastError == QCBOR_SUCCESS) {
6139 // The above conversion succeeded
6140 return;
6141 }
6142
6143 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6144 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07006145 return;
6146 }
6147
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006148 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6149 uConvertTypes,
6150 puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006151}
6152
Laurence Lundbladec4537442020-04-14 18:53:22 -07006153
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006154/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006155 * Public function, see header qcbor/qcbor_decode.h file
6156 */
6157void
6158QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
6159 const int64_t nLabel,
6160 const uint32_t uConvertTypes,
6161 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006162{
6163 QCBORItem Item;
6164
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006165 QCBORDecode_Private_GetUInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006166 nLabel,
6167 uConvertTypes,
6168 puValue,
6169 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006170
6171 if(pMe->uLastError == QCBOR_SUCCESS) {
6172 // The above conversion succeeded
6173 return;
6174 }
6175
6176 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6177 // The above conversion failed in a way that code below can't correct
6178 return;
6179 }
6180
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006181 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6182 uConvertTypes,
6183 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006184}
6185
6186
6187/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006188 * Public function, see header qcbor/qcbor_decode.h file
6189 */
6190void
6191QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
6192 const char *szLabel,
6193 const uint32_t uConvertTypes,
6194 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006195{
6196 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006197 QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006198 szLabel,
6199 uConvertTypes,
6200 puValue,
6201 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006202
6203 if(pMe->uLastError == QCBOR_SUCCESS) {
6204 // The above conversion succeeded
6205 return;
6206 }
6207
6208 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6209 // The above conversion failed in a way that code below can't correct
6210 return;
6211 }
6212
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006213 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6214 uConvertTypes,
6215 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006216}
6217
6218
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006219
6220
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006221#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006222/**
6223 * @brief Basic conversions to a double.
6224 *
6225 * @param[in] pItem The item to convert
6226 * @param[in] uConvertTypes Bit flags indicating source types for conversion
6227 * @param[out] pdValue The value converted to a double
6228 *
6229 * This does the conversions that don't need much object code,
6230 * the conversions from int, uint and float to double.
6231 *
6232 * See QCBOR_Private_DoubleConvertAll() for the full set
6233 * of conversions.
6234 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006235static QCBORError
6236QCBOR_Private_ConvertDouble(const QCBORItem *pItem,
6237 const uint32_t uConvertTypes,
6238 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006239{
6240 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006241 case QCBOR_TYPE_FLOAT:
6242#ifndef QCBOR_DISABLE_FLOAT_HW_USE
6243 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6244 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006245 // Simple cast does the job.
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006246 *pdValue = (double)pItem->val.fnum;
6247 } else {
6248 return QCBOR_ERR_UNEXPECTED_TYPE;
6249 }
6250 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006251#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006252 return QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006253#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006254 break;
6255
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006256 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006257 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6258 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006259 *pdValue = pItem->val.dfnum;
6260 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006261 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006262 }
6263 }
6264 break;
6265
6266 case QCBOR_TYPE_INT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006267#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006268 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006269 // A simple cast seems to do the job with no worry of exceptions.
6270 // There will be precision loss for some values.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006271 *pdValue = (double)pItem->val.int64;
6272
6273 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006274 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006275 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006276#else
6277 return QCBOR_ERR_HW_FLOAT_DISABLED;
6278#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006279 break;
6280
6281 case QCBOR_TYPE_UINT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006282#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006283 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006284 // A simple cast seems to do the job with no worry of exceptions.
6285 // There will be precision loss for some values.
6286 *pdValue = (double)pItem->val.uint64;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006287 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006288 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006289 }
6290 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006291#else
6292 return QCBOR_ERR_HW_FLOAT_DISABLED;
6293#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006294
6295 default:
6296 return QCBOR_ERR_UNEXPECTED_TYPE;
6297 }
6298
6299 return QCBOR_SUCCESS;
6300}
6301
6302
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006303/**
6304 * @brief Almost-public method to decode a number and convert to double (semi-private).
6305 *
6306 * @param[in] pMe The decode context.
6307 * @param[in] uConvertTypes Bit mask list of conversion options
6308 * @param[out] pdValue The output of the conversion.
6309 * @param[in,out] pItem Temporary space to store Item, returned item.
6310 *
6311 * See QCBORDecode_GetDoubleConvert().
6312 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006313void
6314QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pMe,
6315 const uint32_t uConvertTypes,
6316 double *pdValue,
6317 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07006318{
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07006319 QCBORDecode_VGetNext(pMe, pItem);
6320 if(pMe->uLastError) {
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006321 return;
6322 }
6323
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006324 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006325 uConvertTypes,
6326 pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006327}
Laurence Lundbladec4537442020-04-14 18:53:22 -07006328
Laurence Lundbladec4537442020-04-14 18:53:22 -07006329
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006330/**
6331 * @brief Almost-public method to decode a number and convert to double (semi-private).
6332 *
6333 * @param[in] pMe The decode context.
6334 * @param[in] nLabel Label to find in map.
6335 * @param[in] uConvertTypes Bit mask list of conversion options
6336 * @param[out] pdValue The output of the conversion.
6337 * @param[in,out] pItem Temporary space to store Item, returned item.
6338 *
6339 * See QCBORDecode_GetDoubleConvertInMapN().
6340 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006341void
6342QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pMe,
6343 const int64_t nLabel,
6344 const uint32_t uConvertTypes,
6345 double *pdValue,
6346 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006347{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006348 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006349 if(pMe->uLastError != QCBOR_SUCCESS) {
6350 return;
6351 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006352
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006353 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6354 uConvertTypes,
6355 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006356}
6357
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006358
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006359/**
6360 * @brief Almost-public method to decode a number and convert to double (semi-private).
6361 *
6362 * @param[in] pMe The decode context.
6363 * @param[in] szLabel Label to find in map.
6364 * @param[in] uConvertTypes Bit mask list of conversion options
6365 * @param[out] pdValue The output of the conversion.
6366 * @param[in,out] pItem Temporary space to store Item, returned item.
6367 *
6368 * See QCBORDecode_GetDoubleConvertInMapSZ().
6369 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006370void
6371QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe,
6372 const char *szLabel,
6373 const uint32_t uConvertTypes,
6374 double *pdValue,
6375 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006376{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006377 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006378 if(pMe->uLastError != QCBOR_SUCCESS) {
6379 return;
6380 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006381
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006382 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6383 uConvertTypes,
6384 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006385}
6386
6387
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006388#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006389/**
6390 * @brief Convert a big number to double-precision float.
6391 *
6392 * @param[in] BigNum The big number to convert
6393 *
6394 * @returns The double value.
6395 *
6396 * This will always succeed. It will lose precision for larger
6397 * numbers. If the big number is too large to fit (more than
6398 * 1.7976931348623157E+308) infinity will be returned. NaN is never
6399 * returned.
6400 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006401static double
6402QCBOR_Private_ConvertBigNumToDouble(const UsefulBufC BigNum)
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006403{
6404 double dResult;
6405
6406 dResult = 0.0;
6407 const uint8_t *pByte = BigNum.ptr;
6408 size_t uLen = BigNum.len;
6409 /* This will overflow and become the float value INFINITY if the number
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006410 * is too large to fit. */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006411 while(uLen--) {
6412 dResult = (dResult * 256.0) + (double)*pByte++;
6413 }
6414
6415 return dResult;
6416}
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006417#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6418
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006419
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006420
6421
6422/**
6423 * @brief Convert many number types to a double.
6424 *
6425 * @param[in] pItem The item to convert.
6426 * @param[in] uConvertTypes Bit mask list of conversion options.
6427 * @param[out] pdValue The resulting converted value.
6428 *
6429 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6430 * in uConvertTypes.
6431 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6432 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6433 * or too small.
6434 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006435static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006436QCBOR_Private_DoubleConvertAll(const QCBORItem *pItem,
6437 const uint32_t uConvertTypes,
6438 double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006439{
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006440#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07006441 /*
Laurence Lundblade16a207a2021-09-18 17:22:46 -07006442 * What Every Computer Scientist Should Know About Floating-Point Arithmetic
6443 * https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
6444 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006445 switch(pItem->uDataType) {
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006446
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006447#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006448 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006449 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006450 // Underflow gives 0, overflow gives infinity
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006451 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6452 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
6453 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006454 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006455 }
6456 break;
6457
6458 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006459 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006460 // Underflow gives 0, overflow gives infinity
6461 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6462 exp2((double)pItem->val.expAndMantissa.nExponent);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006463 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006464 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006465 }
6466 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006467#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006468
6469 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006470 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006471 *pdValue = QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006472 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006473 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006474 }
6475 break;
6476
6477 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006478 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006479 *pdValue = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006480 } 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
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006485#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006486 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006487 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006488 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006489 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6490 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006491 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006492 }
6493 break;
6494
6495 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006496 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006497 double dMantissa = -QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006498 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6499 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006500 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006501 }
6502 break;
6503
6504 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006505 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006506 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006507 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6508 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006509 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006510 }
6511 break;
6512
6513 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006514 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006515 double dMantissa = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006516 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6517 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006518 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006519 }
6520 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006521#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006522
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006523 default:
6524 return QCBOR_ERR_UNEXPECTED_TYPE;
6525 }
6526
6527 return QCBOR_SUCCESS;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006528
6529#else
6530 (void)pItem;
6531 (void)uConvertTypes;
6532 (void)pdValue;
6533 return QCBOR_ERR_HW_FLOAT_DISABLED;
6534#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6535
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006536}
6537
6538
6539/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006540 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006541 */
6542void
6543QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe,
6544 const uint32_t uConvertTypes,
6545 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006546{
6547
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006548 QCBORItem Item;
6549
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006550 QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006551
6552 if(pMe->uLastError == QCBOR_SUCCESS) {
6553 // The above conversion succeeded
6554 return;
6555 }
6556
6557 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6558 // The above conversion failed in a way that code below can't correct
6559 return;
6560 }
6561
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006562 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6563 uConvertTypes,
6564 pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006565}
6566
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006567
6568/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006569 * Public function, see header qcbor/qcbor_decode.h file
6570 */
6571void
6572QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe,
6573 const int64_t nLabel,
6574 const uint32_t uConvertTypes,
6575 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006576{
6577 QCBORItem Item;
6578
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006579 QCBORDecode_Private_GetDoubleConvertInMapN(pMe,
6580 nLabel,
6581 uConvertTypes,
6582 pdValue,
6583 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006584
6585 if(pMe->uLastError == QCBOR_SUCCESS) {
6586 // The above conversion succeeded
6587 return;
6588 }
6589
6590 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6591 // The above conversion failed in a way that code below can't correct
6592 return;
6593 }
6594
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006595 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6596 uConvertTypes,
6597 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006598}
6599
6600
6601/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006602 * Public function, see header qcbor/qcbor_decode.h file
6603 */
6604void
6605QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe,
6606 const char *szLabel,
6607 const uint32_t uConvertTypes,
6608 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006609{
6610 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006611 QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe,
6612 szLabel,
6613 uConvertTypes,
6614 pdValue,
6615 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006616
6617 if(pMe->uLastError == QCBOR_SUCCESS) {
6618 // The above conversion succeeded
6619 return;
6620 }
6621
6622 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6623 // The above conversion failed in a way that code below can't correct
6624 return;
6625 }
6626
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006627 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6628 uConvertTypes,
6629 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006630}
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006631#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006632
6633
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006634
6635
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006636#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006637/**
6638 * @brief Convert an integer to a big number
6639 *
6640 * @param[in] uInt The integer to convert.
6641 * @param[in] Buffer The buffer to output the big number to.
6642 *
6643 * @returns The big number or NULLUsefulBufC is the buffer is to small.
6644 *
6645 * This always succeeds unless the buffer is too small.
6646 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006647static UsefulBufC
6648QCBOR_Private_ConvertIntToBigNum(uint64_t uInt, const UsefulBuf Buffer)
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006649{
6650 while((uInt & 0xff00000000000000UL) == 0) {
6651 uInt = uInt << 8;
6652 };
6653
6654 UsefulOutBuf UOB;
6655
6656 UsefulOutBuf_Init(&UOB, Buffer);
6657
6658 while(uInt) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006659 UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff00000000000000UL) >> 56));
6660 uInt = uInt << 8;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006661 }
6662
6663 return UsefulOutBuf_OutUBuf(&UOB);
6664}
6665
6666
Laurence Lundblade37286c02022-09-03 10:05:02 -07006667/**
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006668 * @brief Check and/or complete exponent and mantissa item.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006669 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006670 * @param[in] pMe The decoder context.
6671 * @param[in] TagSpec Expected type(s).
6672 * @param[in,out] pItem See below.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006673 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006674 * This is for decimal fractions and big floats, both of which are an
6675 * exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006676 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006677 * If the item item had a tag number indicating it was a
6678 * decimal fraction or big float, then the input @c pItem will
6679 * have been decoded as exponent and mantissa. If there was
6680 * no tag number, the caller is asking this be decoded as a
6681 * big float or decimal fraction and @c pItem just has the
6682 * first item in an exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006683 *
6684 * On output, the item is always a fully decoded decimal fraction or
6685 * big float.
6686 *
6687 * This errors out if the input type does not meet the TagSpec.
6688 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07006689static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006690QCBOR_Private_ExpMantissaTypeHandler(QCBORDecodeContext *pMe,
6691 const QCBOR_Private_TagSpec TagSpec,
6692 QCBORItem *pItem)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006693{
6694 QCBORError uErr;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006695
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006696 /* pItem could either be a decoded exponent and mantissa or
6697 * the opening array of an undecoded exponent and mantissa. This
Laurence Lundblade37286c02022-09-03 10:05:02 -07006698 * check will succeed on either, but doesn't say which it was.
6699 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006700 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07006701 if(uErr != QCBOR_SUCCESS) {
6702 goto Done;
6703 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006704
Laurence Lundblade37286c02022-09-03 10:05:02 -07006705 if(pItem->uDataType == QCBOR_TYPE_ARRAY) {
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006706 /* The item is an array, which means is is an undecoded exponent
6707 * and mantissa. This call consumes the items in the array and
6708 * results in a decoded exponent and mantissa in pItem. This is
Laurence Lundblade37286c02022-09-03 10:05:02 -07006709 * the case where there was no tag.
6710 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006711 uErr = QCBORDecode_Private_ExpMantissa(pMe, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006712 if(uErr != QCBOR_SUCCESS) {
6713 goto Done;
6714 }
6715
Laurence Lundblade37286c02022-09-03 10:05:02 -07006716 /* The above decode didn't determine whether it is a decimal
6717 * fraction or big num. Which of these two depends on what the
6718 * caller wants it decoded as since there is no tag, so fish the
6719 * type out of the TagSpec. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006720 pItem->uDataType = QCBOR_Private_ExpMantissaDataType(TagSpec.uTaggedTypes[0], pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07006721
6722 /* No need to check the type again. All that we need to know was
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006723 * that it decoded correctly as a exponent and mantissa. The
Laurence Lundblade37286c02022-09-03 10:05:02 -07006724 * QCBOR type is set out by what was requested.
6725 */
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006726 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07006727
6728 /* If the item was not an array and the check passed, then
6729 * it is a fully decoded big float or decimal fraction and
6730 * matches what is requested.
6731 */
6732
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006733Done:
6734 return uErr;
6735}
6736
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006737
Laurence Lundblade37286c02022-09-03 10:05:02 -07006738/* Some notes from the work to disable tags.
6739 *
6740 * The API for big floats and decimal fractions seems good.
6741 * If there's any issue with it it's that the code size to
6742 * implement is a bit large because of the conversion
6743 * to/from int and bignum that is required. There is no API
6744 * that doesn't do the conversion so dead stripping will never
6745 * leave that code out.
6746 *
6747 * The implementation itself seems correct, but not as clean
6748 * and neat as it could be. It could probably be smaller too.
6749 *
6750 * The implementation has three main parts / functions
6751 * - The decoding of the array of two
6752 * - All the tag and type checking for the various API functions
6753 * - Conversion to/from bignum and int
6754 *
6755 * The type checking seems like it wastes the most code for
6756 * what it needs to do.
6757 *
6758 * The inlining for the conversion is probably making the
6759 * overall code base larger.
6760 *
6761 * The tests cases could be organized a lot better and be
6762 * more thorough.
6763 *
6764 * Seems also like there could be more common code in the
6765 * first tier part of the public API. Some functions only
6766 * vary by a TagSpec.
6767 */
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006768
6769/**
6770 * @brief Common processor for exponent and mantissa.
6771 *
6772 * @param[in] pMe The decode context.
6773 * @param[in] TagSpec The expected/allowed tags.
6774 * @param[in] pItem The data item to process.
6775 * @param[out] pnMantissa The returned mantissa as an int64_t.
6776 * @param[out] pnExponent The returned exponent as an int64_t.
6777 *
6778 * This handles exponent and mantissa for base 2 and 10. This
6779 * is limited to a mantissa that is an int64_t. See also
6780 * QCBORDecode_Private_ProcessExpMantissaBig().
6781 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006782static void
6783QCBOR_Private_ProcessExpMantissa(QCBORDecodeContext *pMe,
6784 const QCBOR_Private_TagSpec TagSpec,
6785 QCBORItem *pItem,
6786 int64_t *pnMantissa,
6787 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006788{
6789 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006790
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07006791 if(pMe->uLastError) {
6792 return;
6793 }
6794
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006795 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006796 if(uErr != QCBOR_SUCCESS) {
6797 goto Done;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006798 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006799
Laurence Lundblade9b334962020-08-27 10:55:53 -07006800 switch (pItem->uDataType) {
6801
6802 case QCBOR_TYPE_DECIMAL_FRACTION:
6803 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade9b334962020-08-27 10:55:53 -07006804 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006805 *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
Laurence Lundblade9b334962020-08-27 10:55:53 -07006806 break;
6807
Laurence Lundblade37286c02022-09-03 10:05:02 -07006808#ifndef QCBOR_DISABLE_TAGS
6809 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006810 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
6811 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
6812 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006813 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006814 break;
6815
6816 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
6817 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
6818 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006819 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006820 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006821#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006822
6823 default:
6824 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
6825 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006826
6827 Done:
6828 pMe->uLastError = (uint8_t)uErr;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006829}
6830
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006831
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006832/**
6833 * @brief Decode exponent and mantissa into a big number.
6834 *
6835 * @param[in] pMe The decode context.
6836 * @param[in] TagSpec The expected/allowed tags.
6837 * @param[in] pItem Item to decode and convert.
6838 * @param[in] BufferForMantissa Buffer to output mantissa into.
6839 * @param[out] pMantissa The output mantissa.
6840 * @param[out] pbIsNegative The sign of the output.
6841 * @param[out] pnExponent The mantissa of the output.
6842 *
6843 * This is the common processing of a decimal fraction or a big float
6844 * into a big number. This will decode and consume all the CBOR items
6845 * that make up the decimal fraction or big float.
6846 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006847static void
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006848QCBORDecode_Private_ProcessExpMantissaBig(QCBORDecodeContext *pMe,
6849 const QCBOR_Private_TagSpec TagSpec,
6850 QCBORItem *pItem,
6851 const UsefulBuf BufferForMantissa,
6852 UsefulBufC *pMantissa,
6853 bool *pbIsNegative,
6854 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006855{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006856 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006857
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07006858 if(pMe->uLastError != QCBOR_SUCCESS) {
6859 return;
6860 }
6861
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006862 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006863 if(uErr != QCBOR_SUCCESS) {
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006864 goto Done;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006865 }
6866
6867 uint64_t uMantissa;
6868
6869 switch (pItem->uDataType) {
6870
6871 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006872 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006873 /* See comments in ExponentiateNN() on handling INT64_MIN */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006874 if(pItem->val.expAndMantissa.Mantissa.nInt >= 0) {
6875 uMantissa = (uint64_t)pItem->val.expAndMantissa.Mantissa.nInt;
6876 *pbIsNegative = false;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006877 } else if(pItem->val.expAndMantissa.Mantissa.nInt != INT64_MIN) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006878 uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt;
6879 *pbIsNegative = true;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006880 } else {
6881 uMantissa = (uint64_t)INT64_MAX+1;
6882 *pbIsNegative = true;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006883 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006884 *pMantissa = QCBOR_Private_ConvertIntToBigNum(uMantissa,
6885 BufferForMantissa);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006886 *pnExponent = pItem->val.expAndMantissa.nExponent;
6887 break;
6888
Laurence Lundblade37286c02022-09-03 10:05:02 -07006889#ifndef QCBOR_DISABLE_TAGS
6890 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006891 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006892 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006893 *pnExponent = pItem->val.expAndMantissa.nExponent;
6894 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6895 *pbIsNegative = false;
6896 break;
6897
6898 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006899 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006900 *pnExponent = pItem->val.expAndMantissa.nExponent;
6901 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6902 *pbIsNegative = true;
6903 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006904#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006905
6906 default:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006907 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006908 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006909
6910Done:
6911 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006912}
6913
6914
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006915/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006916 * Public function, see header qcbor/qcbor_decode.h file
6917 */
6918void
6919QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe,
6920 const uint8_t uTagRequirement,
6921 int64_t *pnMantissa,
6922 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006923{
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006924 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07006925 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006926
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006927 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006928 {
6929 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006930 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6931 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6932 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006933 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006934
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006935 QCBOR_Private_ProcessExpMantissa(pMe,
6936 TagSpec,
6937 &Item,
6938 pnMantissa,
6939 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006940}
6941
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006942
6943/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006944 * Public function, see header qcbor/qcbor_decode.h file
6945 */
6946void
6947QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe,
6948 const int64_t nLabel,
6949 const uint8_t uTagRequirement,
6950 int64_t *pnMantissa,
6951 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006952{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006953 QCBORItem Item;
6954 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
6955
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006956 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006957 {
6958 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006959 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6960 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6961 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006962 };
6963
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006964 QCBOR_Private_ProcessExpMantissa(pMe,
6965 TagSpec,
6966 &Item,
6967 pnMantissa,
6968 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006969}
6970
6971
6972/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006973 * Public function, see header qcbor/qcbor_decode.h file
6974 */
6975void
6976QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
6977 const char *szLabel,
6978 const uint8_t uTagRequirement,
6979 int64_t *pnMantissa,
6980 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006981{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006982 QCBORItem Item;
6983 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
6984
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006985 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006986 {
6987 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006988 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6989 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6990 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006991 };
Laurence Lundblade9b334962020-08-27 10:55:53 -07006992
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006993 QCBOR_Private_ProcessExpMantissa(pMe,
6994 TagSpec,
6995 &Item,
6996 pnMantissa,
6997 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006998}
6999
7000
7001/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007002 * Public function, see header qcbor/qcbor_decode.h file
7003 */
7004void
7005QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe,
7006 const uint8_t uTagRequirement,
7007 const UsefulBuf MantissaBuffer,
7008 UsefulBufC *pMantissa,
7009 bool *pbMantissaIsNegative,
7010 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007011{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007012 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07007013 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007014
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007015 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007016 {
7017 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007018 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7019 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7020 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007021 };
7022
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007023 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7024 TagSpec,
7025 &Item,
7026 MantissaBuffer,
7027 pMantissa,
7028 pbMantissaIsNegative,
7029 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007030}
7031
7032
7033/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007034 * Public function, see header qcbor/qcbor_decode.h file
7035 */
7036void
7037QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe,
7038 const int64_t nLabel,
7039 const uint8_t uTagRequirement,
7040 const UsefulBuf BufferForMantissa,
7041 UsefulBufC *pMantissa,
7042 bool *pbIsNegative,
7043 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007044{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007045
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007046 QCBORItem Item;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007047 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007048
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007049 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007050 {
7051 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007052 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7053 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7054 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007055 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007056
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007057 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7058 TagSpec,
7059 &Item,
7060 BufferForMantissa,
7061 pMantissa,
7062 pbIsNegative,
7063 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007064}
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007065
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007066
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007067/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007068 * Public function, see header qcbor/qcbor_decode.h file
7069 */
7070void
7071QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe,
7072 const char *szLabel,
7073 const uint8_t uTagRequirement,
7074 const UsefulBuf BufferForMantissa,
7075 UsefulBufC *pMantissa,
7076 bool *pbIsNegative,
7077 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007078{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007079 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007080 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007081
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007082 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007083 {
7084 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007085 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7086 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7087 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007088 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007089
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007090 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7091 TagSpec,
7092 &Item,
7093 BufferForMantissa,
7094 pMantissa,
7095 pbIsNegative,
7096 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007097}
7098
7099
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007100/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007101 * Public function, see header qcbor/qcbor_decode.h file
7102 */
7103void
7104QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe,
7105 const uint8_t uTagRequirement,
7106 int64_t *pnMantissa,
7107 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007108{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007109 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07007110 QCBORDecode_VGetNext(pMe, &Item);
7111
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007112 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007113 {
7114 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007115 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7116 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7117 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007118 };
7119
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007120 QCBOR_Private_ProcessExpMantissa(pMe,
7121 TagSpec,
7122 &Item,
7123 pnMantissa,
7124 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007125}
7126
7127
7128/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007129 * Public function, see header qcbor/qcbor_decode.h file
7130 */
7131void
7132QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe,
7133 const int64_t nLabel,
7134 const uint8_t uTagRequirement,
7135 int64_t *pnMantissa,
7136 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007137{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007138 QCBORItem Item;
7139 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007140
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007141 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007142 {
7143 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007144 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7145 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7146 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007147 };
7148
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007149 QCBOR_Private_ProcessExpMantissa(pMe,
7150 TagSpec,
7151 &Item,
7152 pnMantissa,
7153 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007154}
7155
7156
7157/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007158 * Public function, see header qcbor/qcbor_decode.h file
7159 */
7160void
7161QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe,
7162 const char *szLabel,
7163 const uint8_t uTagRequirement,
7164 int64_t *pnMantissa,
7165 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007166{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007167 QCBORItem Item;
7168 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007169
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007170 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007171 {
7172 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007173 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7174 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7175 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007176 };
7177
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007178 QCBOR_Private_ProcessExpMantissa(pMe,
7179 TagSpec,
7180 &Item,
7181 pnMantissa,
7182 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007183}
7184
7185
7186/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007187 * Public function, see header qcbor/qcbor_decode.h file
7188 */
7189void
7190QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe,
7191 const uint8_t uTagRequirement,
7192 const UsefulBuf MantissaBuffer,
7193 UsefulBufC *pMantissa,
7194 bool *pbMantissaIsNegative,
7195 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007196{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007197 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07007198 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007199
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007200 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007201 {
7202 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007203 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7204 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7205 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007206 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007207
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007208 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7209 TagSpec,
7210 &Item,
7211 MantissaBuffer,
7212 pMantissa,
7213 pbMantissaIsNegative,
7214 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007215}
7216
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007217
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007218/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007219 * Public function, see header qcbor/qcbor_decode.h file
7220 */
7221void
7222QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe,
7223 const int64_t nLabel,
7224 const uint8_t uTagRequirement,
7225 const UsefulBuf BufferForMantissa,
7226 UsefulBufC *pMantissa,
7227 bool *pbIsNegative,
7228 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007229{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007230 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007231 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007232
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007233 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007234 {
7235 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007236 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7237 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7238 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007239 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007240
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007241 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7242 TagSpec,
7243 &Item,
7244 BufferForMantissa,
7245 pMantissa,
7246 pbIsNegative,
7247 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007248}
7249
7250
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007251/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007252 * Public function, see header qcbor/qcbor_decode.h file
7253 */
7254void
7255QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe,
7256 const char *szLabel,
7257 const uint8_t uTagRequirement,
7258 const UsefulBuf BufferForMantissa,
7259 UsefulBufC *pMantissa,
7260 bool *pbIsNegative,
7261 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007262{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007263 QCBORItem Item;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007264 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007265
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007266 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007267 {
7268 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007269 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7270 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7271 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007272 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007273
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007274 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7275 TagSpec,
7276 &Item,
7277 BufferForMantissa,
7278 pMantissa,
7279 pbIsNegative,
7280 pnExponent);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007281}
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007282
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07007283#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */