blob: 13a728db3fd815756449766737ed1d6edaf58595 [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 Lundblade02625d42020-06-25 14:41:41 -0700464 uint8_t uQCBORType,
465 uint64_t uCount)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700466{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700467 QCBORError uError = QCBOR_SUCCESS;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700468
469 if(uCount == 0) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800470 /* Nothing to do for empty definite-length arrays. They are just are
471 * effectively the same as an item that is not a map or array.
472 */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700473 goto Done;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800474 /* Empty indefinite-length maps and arrays are handled elsewhere */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700475 }
476
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800477 /* Error out if arrays is too long to handle */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700478 if(uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH &&
479 uCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700480 uError = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700481 goto Done;
482 }
483
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700484 uError = DecodeNesting_Descend(pNesting, uQCBORType);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700485 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700486 goto Done;
487 }
488
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800489 /* Fill in the new map/array level. Check above makes casts OK. */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -0700490 pNesting->pCurrent->u.ma.uCountCursor = (uint16_t)uCount;
491 pNesting->pCurrent->u.ma.uCountTotal = (uint16_t)uCount;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700492
493 DecodeNesting_ClearBoundedMode(pNesting);
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700494
495Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700496 return uError;;
497}
498
499
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700500static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700501DecodeNesting_LevelUpCurrent(QCBORDecodeNesting *pNesting)
502{
503 pNesting->pCurrent = pNesting->pCurrentBounded - 1;
504}
505
506
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700507static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700508DecodeNesting_LevelUpBounded(QCBORDecodeNesting *pNesting)
509{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700510 while(pNesting->pCurrentBounded != &(pNesting->pLevels[0])) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700511 pNesting->pCurrentBounded--;
512 if(DecodeNesting_IsCurrentBounded(pNesting)) {
513 break;
514 }
515 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700516}
517
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800518
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700519static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700520DecodeNesting_SetCurrentToBoundedLevel(QCBORDecodeNesting *pNesting)
521{
522 pNesting->pCurrent = pNesting->pCurrentBounded;
523}
524
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700525
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700526static QCBORError
Laurence Lundblade02625d42020-06-25 14:41:41 -0700527DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting,
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700528 uint32_t uEndOffset,
529 uint32_t uStartOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700530{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700531 QCBORError uError;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700532
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700533 uError = DecodeNesting_Descend(pNesting, QCBOR_TYPE_BYTE_STRING);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700534 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700535 goto Done;
536 }
537
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800538 /* Fill in the new byte string level */
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700539 pNesting->pCurrent->u.bs.uSavedEndOffset = uEndOffset;
540 pNesting->pCurrent->u.bs.uBstrStartOffset = uStartOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700541
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800542 /* Bstr wrapped levels are always bounded */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700543 pNesting->pCurrentBounded = pNesting->pCurrent;
544
545Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700546 return uError;;
547}
548
Laurence Lundbladed0304932020-06-27 10:59:38 -0700549
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700550static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700551DecodeNesting_ZeroMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700552{
553 pNesting->pCurrent->u.ma.uCountCursor = 0;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700554}
555
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700556
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700557static void
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800558DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting)
559{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700560 if(pNesting->pCurrent->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
561 pNesting->pCurrentBounded->u.ma.uCountCursor = pNesting->pCurrentBounded->u.ma.uCountTotal;
562 }
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800563}
564
565
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700566static void
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700567DecodeNesting_Init(QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700568{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700569 /* Assumes that *pNesting has been zero'd before this call. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700570 pNesting->pLevels[0].uLevelType = QCBOR_TYPE_BYTE_STRING;
571 pNesting->pCurrent = &(pNesting->pLevels[0]);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700572}
573
574
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700575static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800576DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting,
577 QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700578{
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700579 *pSave = *pNesting;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700580}
581
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700582
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700583static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800584DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting,
585 const QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700586{
587 *pNesting = *pSave;
588}
589
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700590
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700591static uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700592DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700593{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700594 return pMe->pCurrentBounded->u.bs.uSavedEndOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700595}
596
597
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800598
599
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800600#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladeee851742020-01-08 08:37:05 -0800601/*===========================================================================
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800602 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
603
604 The following four functions are pretty wrappers for invocation of
605 the string allocator supplied by the caller.
606
Laurence Lundbladeee851742020-01-08 08:37:05 -0800607 ===========================================================================*/
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800608
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700609static void
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800610StringAllocator_Free(const QCBORInternalAllocator *pMe, const void *pMem)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800611{
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300612 /* This cast to uintptr_t suppresses the "-Wcast-qual" warnings.
613 * This is the one place where the const needs to be cast away so const can
614 * be use in the rest of the code.
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800615 */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300616 (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, 0);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800617}
618
Laurence Lundbladeee851742020-01-08 08:37:05 -0800619// StringAllocator_Reallocate called with pMem NULL is
620// equal to StringAllocator_Allocate()
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700621static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800622StringAllocator_Reallocate(const QCBORInternalAllocator *pMe,
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800623 const void *pMem,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800624 size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800625{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800626 /* See comment in StringAllocator_Free() */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300627 return (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, uSize);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800628}
629
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700630static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800631StringAllocator_Allocate(const QCBORInternalAllocator *pMe, size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800632{
633 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
634}
635
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700636static void
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800637StringAllocator_Destruct(const QCBORInternalAllocator *pMe)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800638{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800639 /* See comment in StringAllocator_Free() */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800640 if(pMe->pfAllocator) {
641 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
642 }
643}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800644#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800645
646
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800647
648
Laurence Lundbladeee851742020-01-08 08:37:05 -0800649/*===========================================================================
650 QCBORDecode -- The main implementation of CBOR decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700651
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800652 See qcbor/qcbor_decode.h for definition of the object
653 used here: QCBORDecodeContext
Laurence Lundbladeee851742020-01-08 08:37:05 -0800654 ===========================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700655/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800656 * Public function, see header file
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700657 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700658void
659QCBORDecode_Init(QCBORDecodeContext *pMe,
660 UsefulBufC EncodedCBOR,
661 QCBORDecodeMode nDecodeMode)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700662{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800663 memset(pMe, 0, sizeof(QCBORDecodeContext));
664 UsefulInputBuf_Init(&(pMe->InBuf), EncodedCBOR);
665 /* Don't bother with error check on decode mode. If a bad value is
666 * passed it will just act as if the default normal mode of 0 was set.
667 */
668 pMe->uDecodeMode = (uint8_t)nDecodeMode;
669 DecodeNesting_Init(&(pMe->nesting));
670
671 /* Inialize me->auMappedTags to CBOR_TAG_INVALID16. See
672 * GetNext_TaggedItem() and MapTagNumber(). */
673 memset(pMe->auMappedTags, 0xff, sizeof(pMe->auMappedTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700674}
675
676
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800677#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
678
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700679/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800680 * Public function, see header file
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700681 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700682void
683QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
684 QCBORStringAllocate pfAllocateFunction,
685 void *pAllocateContext,
686 bool bAllStrings)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700687{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800688 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
689 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
690 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700691}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800692#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700693
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800694
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800695
696
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800697/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800698 * Deprecated public function, see header file
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800699 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700700void
701QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pMe,
702 const QCBORTagListIn *pTagList)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700703{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800704 /* This does nothing now. It is retained for backwards compatibility */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700705 (void)pMe;
706 (void)pTagList;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700707}
708
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700709
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800710
711
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700712/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800713 * Decoding items is done in six layers, one calling the next one
714 * down. If a layer has no work to do for a particular item, it
715 * returns quickly.
716 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700717 * 1. QCBORDecode_Private_GetNextTagContent - The top layer processes
718 * tagged data items, turning them into the local C representation.
719 * For the most simple it is just associating a QCBOR_TYPE with the
720 * data. For the complex ones that an aggregate of data items, there
721 * is some further decoding and some limited recursion.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800722 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700723 * 2. QCBORDecode_Private_GetNextMapOrArray - This manages the
724 * beginnings and ends of maps and arrays. It tracks descending into
725 * and ascending out of maps/arrays. It processes breaks that
726 * terminate indefinite-length maps and arrays.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800727 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700728 * 3. QCBORDecode_Private_GetNextMapEntry - This handles the combining
729 * of two items, the label and the data, that make up a map entry. It
730 * only does work on maps. It combines the label and data items into
731 * one labeled item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800732 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700733 * 4. QCBORDecode_Private_GetNextTagNumber - This decodes type 6 tag
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800734 * numbers. It turns the tag numbers into bit flags associated with
735 * the data item. No actual decoding of the contents of the tag is
736 * performed here.
737 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700738 * 5. QCBORDecode_Private_GetNextFullString - This assembles the
739 * sub-items that make up an indefinite-length string into one string
740 * item. It uses the string allocator to create contiguous space for
741 * the item. It processes all breaks that are part of
742 * indefinite-length strings.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800743 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700744 * 6. QCBOR_Private_DecodeAtomicDataItem - This decodes the atomic
745 * data items in CBOR. Each atomic data item has a "major type", an
746 * integer "argument" and optionally some content. For text and byte
747 * strings, the content is the bytes that make up the string. These
748 * are the smallest data items that are considered to be well-formed.
749 * The content may also be other data items in the case of aggregate
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800750 * types. They are not handled in this layer.
751 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700752 * This uses about 350 bytes of stack. This number comes from
753 * instrumenting (printf address of stack variables) the code on x86
754 * compiled for size optimization.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700755 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800756
757
758/*
759 * Note about use of int and unsigned variables.
760 *
761 * See http://www.unix.org/whitepapers/64bit.html for reasons int is
762 * used carefully here, and in particular why it isn't used in the
763 * public interface. Also see
764 * https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers
765 *
766 * Int is used for values that need less than 16-bits and would be
767 * subject to integer promotion and result in complaining from static
768 * analyzers.
769 */
770
771
772/**
773 * @brief Decode the CBOR head, the type and argument.
774 *
775 * @param[in] pUInBuf The input buffer to read from.
776 * @param[out] pnMajorType The decoded major type.
777 * @param[out] puArgument The decoded argument.
778 * @param[out] pnAdditionalInfo The decoded Lower 5 bits of initial byte.
779 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -0700780 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved features
781 * @retval QCBOR_ERR_HIT_END Unexpected end of input
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800782 *
783 * This decodes the CBOR "head" that every CBOR data item has. See
784 * longer explaination of the head in documentation for
785 * QCBOREncode_EncodeHead().
786 *
787 * This does the network->host byte order conversion. The conversion
788 * here also results in the conversion for floats in addition to that
789 * for lengths, tags and integer values.
790 *
791 * The int type is preferred to uint8_t for some variables as this
792 * avoids integer promotions, can reduce code size and makes static
793 * analyzers happier.
794 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700795static QCBORError
796QCBOR_Private_DecodeHead(UsefulInputBuf *pUInBuf,
797 int *pnMajorType,
798 uint64_t *puArgument,
799 int *pnAdditionalInfo)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700800{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800801 QCBORError uReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800802
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800803 /* Get the initial byte that every CBOR data item has and break it
804 * down. */
805 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800806 const int nTmpMajorType = nInitialByte >> 5;
807 const int nAdditionalInfo = nInitialByte & 0x1f;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800808
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800809 /* Where the argument accumulates */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800810 uint64_t uArgument;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800811
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800812 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800813 /* Need to get 1,2,4 or 8 additional argument bytes. Map
814 * LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length.
815 */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800816 static const uint8_t aIterate[] = {1,2,4,8};
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800817
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800818 /* Loop getting all the bytes in the argument */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800819 uArgument = 0;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800820 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800821 /* This shift and add gives the endian conversion. */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800822 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
823 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800824 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800825 /* The reserved and thus-far unused additional info values */
826 uReturn = QCBOR_ERR_UNSUPPORTED;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800827 goto Done;
828 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800829 /* Less than 24, additional info is argument or 31, an
830 * indefinite-length. No more bytes to get.
831 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800832 uArgument = (uint64_t)nAdditionalInfo;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700833 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800834
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700835 if(UsefulInputBuf_GetError(pUInBuf)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800836 uReturn = QCBOR_ERR_HIT_END;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700837 goto Done;
838 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800839
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800840 /* All successful if arrived here. */
841 uReturn = QCBOR_SUCCESS;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800842 *pnMajorType = nTmpMajorType;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800843 *puArgument = uArgument;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800844 *pnAdditionalInfo = nAdditionalInfo;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800845
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700846Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800847 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700848}
849
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800850
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800851/**
852 * @brief Decode integer types, major types 0 and 1.
853 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700854 * @param[in] nMajorType The CBOR major type (0 or 1).
855 * @param[in] uArgument The argument from the head.
856 * @param[in] nAdditionalInfo So it can be error-checked.
857 * @param[out] pDecodedItem The filled in decoded item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800858 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700859 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered.
860 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800861 *
862 * Must only be called when major type is 0 or 1.
863 *
864 * CBOR doesn't explicitly specify two's compliment for integers but
865 * all CPUs use it these days and the test vectors in the RFC are
866 * so. All integers in the CBOR structure are positive and the major
867 * type indicates positive or negative. CBOR can express positive
868 * integers up to 2^x - 1 where x is the number of bits and negative
869 * integers down to 2^x. Note that negative numbers can be one more
870 * away from zero than positive. Stdint, as far as I can tell, uses
871 * two's compliment to represent negative integers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700872 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700873static QCBORError
874QCBOR_Private_DecodeInteger(const int nMajorType,
875 const uint64_t uArgument,
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700876 const int nAdditionalInfo,
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700877 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700878{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800879 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800880
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700881 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
882 uReturn = QCBOR_ERR_BAD_INT;
883 goto Done;
884 }
885
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700886 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800887 if (uArgument <= INT64_MAX) {
888 pDecodedItem->val.int64 = (int64_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700889 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800890
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700891 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800892 pDecodedItem->val.uint64 = uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700893 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700894 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800895
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700896 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800897 if(uArgument <= INT64_MAX) {
898 /* CBOR's representation of negative numbers lines up with
899 * the two-compliment representation. A negative integer has
900 * one more in range than a positive integer. INT64_MIN is
901 * equal to (-INT64_MAX) - 1.
902 */
903 pDecodedItem->val.int64 = (-(int64_t)uArgument) - 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700904 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800905
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700906 } else {
Laurence Lundblade2d493002024-02-01 11:09:17 -0700907 pDecodedItem->val.uint64 = uArgument;
908 pDecodedItem->uDataType = QCBOR_TYPE_65BIT_NEG_INT;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700909 }
910 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800911
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700912Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800913 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700914}
915
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800916
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700917/**
918 * @brief Decode text and byte strings
919 *
920 * @param[in] pMe Decoder context.
921 * @param[in] bAllocate Whether to allocate and copy string.
922 * @param[in] nMajorType Whether it is a byte or text string.
923 * @param[in] uStrLen The length of the string.
924 * @param[in] nAdditionalInfo Whether it is an indefinite-length string.
925 * @param[out] pDecodedItem The filled-in decoded item.
926 *
927 * @retval QCBOR_ERR_HIT_END Unexpected end of input.
928 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
929 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
930 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator
931 *
932 * This reads @c uStrlen bytes from the input and fills in @c
933 * pDecodedItem. If @c bAllocate is true, then memory for the string
934 * is allocated.
935 */
936static QCBORError
937QCBOR_Private_DecodeString(QCBORDecodeContext *pMe,
938 const bool bAllocate,
939 const int nMajorType,
940 const uint64_t uStrLen,
941 const int nAdditionalInfo,
942 QCBORItem *pDecodedItem)
943{
944 QCBORError uReturn = QCBOR_SUCCESS;
945
946 /* ---- Figure out the major type ---- */
947 #if CBOR_MAJOR_TYPE_BYTE_STRING + 4 != QCBOR_TYPE_BYTE_STRING
948 #error QCBOR_TYPE_BYTE_STRING not lined up with major type
949 #endif
950
951 #if CBOR_MAJOR_TYPE_TEXT_STRING + 4 != QCBOR_TYPE_TEXT_STRING
952 #error QCBOR_TYPE_TEXT_STRING not lined up with major type
953 #endif
954 pDecodedItem->uDataType = (uint8_t)(nMajorType + 4);
955
956 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
957 /* --- Just the head of an indefinite-length string --- */
958 pDecodedItem->val.string = (UsefulBufC){NULL, QCBOR_STRING_LENGTH_INDEFINITE};
959
960 } else {
961 /* --- A definite-length string --- */
962 /* --- (which might be a chunk of an indefinte-length string) --- */
963
964 /* CBOR lengths can be 64 bits, but size_t is not 64 bits on all
965 * CPUs. This check makes the casts to size_t below safe.
966 *
967 * The max is 4 bytes less than the largest sizeof() so this can be
968 * tested by putting a SIZE_MAX length in the CBOR test input (no
969 * one will care the limit on strings is 4 bytes shorter).
970 */
971 if(uStrLen > SIZE_MAX-4) {
972 uReturn = QCBOR_ERR_STRING_TOO_LONG;
973 goto Done;
974 }
975
976 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(&(pMe->InBuf), (size_t)uStrLen);
977 if(UsefulBuf_IsNULLC(Bytes)) {
978 /* Failed to get the bytes for this string item */
979 uReturn = QCBOR_ERR_HIT_END;
980 goto Done;
981 }
982
983 if(bAllocate) {
984#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
985 /* --- Put string in allocated memory --- */
986
987 /* Note that this is not where allocation to coalesce
988 * indefinite-length strings is done. This is for when the
989 * caller has requested all strings be allocated. Disabling
990 * indefinite length strings also disables this allocate-all
991 * option.
992 */
993
994 if(pMe->StringAllocator.pfAllocator == NULL) {
995 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
996 goto Done;
997 }
998 UsefulBuf NewMem = StringAllocator_Allocate(&(pMe->StringAllocator), (size_t)uStrLen);
999 if(UsefulBuf_IsNULL(NewMem)) {
1000 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1001 goto Done;
1002 }
1003 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
1004 pDecodedItem->uDataAlloc = 1;
1005#else
1006 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1007#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1008 } else {
1009 /* --- Normal case with no string allocator --- */
1010 pDecodedItem->val.string = Bytes;
1011 }
1012 }
1013
1014Done:
1015 return uReturn;
1016}
1017
1018
1019/**
1020 * @brief Decode array or map.
1021 *
1022 * @param[in] uMode Decoder mode.
1023 * @param[in] nMajorType Whether it is a byte or text string.
1024 * @param[in] uItemCount The length of the string.
1025 * @param[in] nAdditionalInfo Whether it is an indefinite-length.
1026 * @param[out] pDecodedItem The filled-in decoded item.
1027 *
1028 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinites disabled.
1029 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map.
1030 *
1031 * Not much to do for arrays and maps. Just the type item count (but a
1032 * little messy because of ifdefs for indefinite-lengths and
1033 * map-as-array decoding).
1034 *
1035 * This also does the bulk of the work for @ref
1036 * QCBOR_DECODE_MODE_MAP_AS_ARRAY, a special mode to handle
1037 * arbitrarily complex map labels. This ifdefs out with
1038 * QCBOR_DISABLE_NON_INTEGER_LABELS.
1039 */
1040static QCBORError
1041QCBOR_Private_DecodeArrayOrMap(const uint8_t uMode,
1042 const int nMajorType,
1043 const uint64_t uItemCount,
1044 const int nAdditionalInfo,
1045 QCBORItem *pDecodedItem)
1046{
1047 QCBORError uReturn;
1048
1049 /* ------ Sort out the data type ------ */
1050 #if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
1051 #error QCBOR_TYPE_ARRAY value not lined up with major type
1052 #endif
1053
1054 #if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
1055 #error QCBOR_TYPE_MAP value not lined up with major type
1056 #endif
1057 pDecodedItem->uDataType = (uint8_t)nMajorType;
1058#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1059 if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
1060 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
1061 }
1062#else
1063 (void)uMode;
1064#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
1065
1066 uReturn = QCBOR_SUCCESS;
1067
1068 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1069 /* ------ Indefinite-length array/map ----- */
1070#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
1071 pDecodedItem->val.uCount = QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH;
1072#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1073 uReturn = QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED;
1074#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1075 } else {
1076
1077#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1078 if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
1079 /* ------ Definite-length map as array ------ */
1080
1081 if(uItemCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
1082 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
1083 } else {
1084 /* cast OK because of check above */
1085 pDecodedItem->val.uCount = (uint16_t)uItemCount*2;
1086 }
1087
1088 } else
1089#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
1090 {
1091 /* ------ Definite-length array/map ------ */
1092 if(uItemCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
1093 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
1094 } else {
1095 /* cast OK because of check above */
1096 pDecodedItem->val.uCount = (uint16_t)uItemCount;
1097 }
1098 }
1099 }
1100
1101 return uReturn;
1102}
1103
1104
1105/**
1106 * @brief Decode a tag number.
1107 *
1108 * @param[in] uTagNumber The length of the string.
1109 * @param[in] nAdditionalInfo So this can be error-checked.
1110 * @param[out] pDecodedItem The filled-in decoded item.
1111 *
1112 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo is LEN_IS_INDEFINITE.
1113 * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined.
1114 *
1115 * Not much to do for tags, but fill in pDecodedItem and check for
1116 * error in nAdditionalInfo.
1117 */
1118static QCBORError
1119QCBOR_Private_DecodeTag(const uint64_t uTagNumber,
1120 const int nAdditionalInfo,
1121 QCBORItem *pDecodedItem)
1122{
1123#ifndef QCBOR_DISABLE_TAGS
1124 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1125 return QCBOR_ERR_BAD_INT;
1126 } else {
1127 pDecodedItem->val.uTagV = uTagNumber;
1128 pDecodedItem->uDataType = QCBOR_TYPE_TAG;
1129 return QCBOR_SUCCESS;
1130 }
1131#else /* QCBOR_DISABLE_TAGS */
1132 (void)nAdditionalInfo;
Laurence Lundblade6c9a8242024-06-12 20:34:52 -07001133 (void)uTagNumber;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001134 (void)pDecodedItem;
1135 return QCBOR_ERR_TAGS_DISABLED;
1136#endif /* QCBOR_DISABLE_TAGS */
1137}
1138
1139
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001140/* Make sure #define value line up as DecodeSimple counts on this. */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001141#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
1142#error QCBOR_TYPE_FALSE macro value wrong
1143#endif
1144
1145#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
1146#error QCBOR_TYPE_TRUE macro value wrong
1147#endif
1148
1149#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
1150#error QCBOR_TYPE_NULL macro value wrong
1151#endif
1152
1153#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
1154#error QCBOR_TYPE_UNDEF macro value wrong
1155#endif
1156
Laurence Lundblade0f99d692018-09-26 14:39:28 -07001157#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
1158#error QCBOR_TYPE_BREAK macro value wrong
1159#endif
1160
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001161#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
1162#error QCBOR_TYPE_DOUBLE macro value wrong
1163#endif
1164
1165#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
1166#error QCBOR_TYPE_FLOAT macro value wrong
1167#endif
1168
Laurence Lundblade9b334962020-08-27 10:55:53 -07001169
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001170/**
1171 * @brief Decode major type 7 -- true, false, floating-point, break...
1172 *
1173 * @param[in] nAdditionalInfo The lower five bits from the initial byte.
1174 * @param[in] uArgument The argument from the head.
1175 * @param[out] pDecodedItem The filled in decoded item.
1176 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001177 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1178 * of half-precision disabled
1179 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all float
1180 * decode is disabled.
1181 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of simple
1182 * type in input.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001183 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001184static QCBORError
1185QCBOR_Private_DecodeType7(const int nAdditionalInfo,
1186 const uint64_t uArgument,
1187 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001188{
1189 QCBORError uReturn = QCBOR_SUCCESS;
1190
1191 /* uAdditionalInfo is 5 bits from the initial byte. Compile time
1192 * checks above make sure uAdditionalInfo values line up with
1193 * uDataType values. DecodeHead() never returns an AdditionalInfo
1194 * > 0x1f so cast is safe.
1195 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001196 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001197
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001198 switch(nAdditionalInfo) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001199 /* No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they
1200 * are caught before this is called.
1201 */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001202
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001203 case HALF_PREC_FLOAT: /* 25 */
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -07001204#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001205 /* Half-precision is returned as a double. The cast to
1206 * uint16_t is safe because the encoded value was 16 bits. It
1207 * was widened to 64 bits to be passed in here.
1208 */
1209 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uArgument);
Laurence Lundblade67bd5512018-11-02 21:44:06 +07001210 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001211#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001212 uReturn = FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001213 break;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001214 case SINGLE_PREC_FLOAT: /* 26 */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001215#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001216 /* Single precision is normally returned as a double since
1217 * double is widely supported, there is no loss of precision,
1218 * it makes it easy for the caller in most cases and it can
1219 * be converted back to single with no loss of precision
1220 *
1221 * The cast to uint32_t is safe because the encoded value was
1222 * 32 bits. It was widened to 64 bits to be passed in here.
1223 */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001224 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001225 const float f = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uArgument);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001226#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001227 /* In the normal case, use HW to convert float to
1228 * double. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001229 pDecodedItem->val.dfnum = (double)f;
1230 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001231#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001232 /* Use of float HW is disabled, return as a float. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001233 pDecodedItem->val.fnum = f;
1234 pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
1235
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001236 /* IEEE754_FloatToDouble() could be used here to return as
1237 * a double, but it adds object code and most likely
1238 * anyone disabling FLOAT HW use doesn't care about floats
1239 * and wants to save object code.
1240 */
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001241#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001242 }
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001243#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1244 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001245 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001246
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001247 case DOUBLE_PREC_FLOAT: /* 27 */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001248#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001249 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uArgument);
Laurence Lundblade67bd5512018-11-02 21:44:06 +07001250 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001251#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1252 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001253 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001254
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001255 case CBOR_SIMPLEV_FALSE: /* 20 */
1256 case CBOR_SIMPLEV_TRUE: /* 21 */
1257 case CBOR_SIMPLEV_NULL: /* 22 */
1258 case CBOR_SIMPLEV_UNDEF: /* 23 */
1259 case CBOR_SIMPLE_BREAK: /* 31 */
1260 break; /* nothing to do */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001261
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001262 case CBOR_SIMPLEV_ONEBYTE: /* 24 */
1263 if(uArgument <= CBOR_SIMPLE_BREAK) {
1264 /* This takes out f8 00 ... f8 1f which should be encoded
1265 * as e0 … f7
1266 */
1267 uReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001268 goto Done;
1269 }
Laurence Lundblade5e390822019-01-06 12:35:01 -08001270 /* FALLTHROUGH */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001271
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001272 default: /* 0-19 */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001273 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001274 /* DecodeHead() will make uArgument equal to
1275 * nAdditionalInfo when nAdditionalInfo is < 24. This cast is
1276 * safe because the 2, 4 and 8 byte lengths of uNumber are in
1277 * the double/float cases above
Laurence Lundbladeee851742020-01-08 08:37:05 -08001278 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001279 pDecodedItem->val.uSimple = (uint8_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001280 break;
1281 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001282
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001283Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001284 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001285}
1286
1287
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001288/**
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001289 * @brief Decode a single primitive data item (decode layer 6).
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001290 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001291 * @param[in] pMe Decoder context.
1292 * @param[in] bAllocateStrings If true, use allocator for strings.
1293 * @param[out] pDecodedItem The filled-in decoded item.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001294 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001295 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1296 * features
1297 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1298 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1299 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1300 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001301 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001302 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1303 * of half-precision disabled
1304 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1305 * float decode is disabled.
1306 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1307 * simple type in input.
1308 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1309 * in input, but indefinite
1310 * lengths disabled.
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001311 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte.
1312 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map.
1313 * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001314 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001315 * This decodes the most primitive/atomic data item. It does no
1316 * combining of data items.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001317 */
1318static QCBORError
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001319QCBOR_Private_DecodeAtomicDataItem(QCBORDecodeContext *pMe,
1320 const bool bAllocateStrings,
1321 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001322{
1323 QCBORError uReturn;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001324 int nMajorType = 0;
1325 uint64_t uArgument = 0;
1326 int nAdditionalInfo = 0;
1327
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001328 /* Decode the "head" that every CBOR item has into the major type,
1329 * argument and the additional info.
1330 */
1331 uReturn = QCBOR_Private_DecodeHead(&(pMe->InBuf), &nMajorType, &uArgument, &nAdditionalInfo);
1332 if(uReturn != QCBOR_SUCCESS) {
1333 return uReturn;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001334 }
1335
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001336 memset(pDecodedItem, 0, sizeof(QCBORItem));
1337
1338 /* All the functions below get inlined by the optimizer. This code
1339 * is easier to read with them all being similar functions, even if
1340 * some functions don't do much.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001341 */
1342 switch (nMajorType) {
1343 case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
1344 case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001345 return QCBOR_Private_DecodeInteger(nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001346 break;
1347
1348 case CBOR_MAJOR_TYPE_BYTE_STRING: /* Major type 2 */
1349 case CBOR_MAJOR_TYPE_TEXT_STRING: /* Major type 3 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001350 return QCBOR_Private_DecodeString(pMe, bAllocateStrings, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001351 break;
1352
1353 case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */
1354 case CBOR_MAJOR_TYPE_MAP: /* Major type 5 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001355 return QCBOR_Private_DecodeArrayOrMap(pMe->uDecodeMode, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001356 break;
1357
1358 case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001359 return QCBOR_Private_DecodeTag(uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001360 break;
1361
1362 case CBOR_MAJOR_TYPE_SIMPLE:
1363 /* Major type 7: float, double, true, false, null... */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001364 return QCBOR_Private_DecodeType7(nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001365 break;
1366
1367 default:
1368 /* Never happens because DecodeHead() should never return > 7 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001369 return QCBOR_ERR_UNSUPPORTED;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001370 break;
1371 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001372}
1373
1374
1375/**
1376 * @brief Process indefinite-length strings (decode layer 5).
1377 *
1378 * @param[in] pMe Decoder context
1379 * @param[out] pDecodedItem The decoded item that work is done on.
1380 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001381 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1382 * features
1383 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1384 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1385 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1386 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1387 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1388 * of half-precision disabled
1389 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1390 * float decode is disabled.
1391 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1392 * simple type in input.
1393 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1394 * in input, but indefinite
1395 * lengths disabled.
1396 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1397 * but no string allocator.
1398 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1399 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1400 * input, but indefinite-length
1401 * strings are disabled.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001402 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001403 * If @c pDecodedItem is not an indefinite-length string, this does nothing.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001404 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001405 * If it is, this loops getting the subsequent chunk data items that
1406 * make up the string. The string allocator is used to make a
1407 * contiguous buffer for the chunks. When this completes @c
1408 * pDecodedItem contains the put-together string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001409 *
1410 * Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001411 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001412static QCBORError
1413QCBORDecode_Private_GetNextFullString(QCBORDecodeContext *pMe,
1414 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001415{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001416 /* Aproximate stack usage
1417 * 64-bit 32-bit
1418 * local vars 32 16
1419 * 2 UsefulBufs 32 16
1420 * QCBORItem 56 52
1421 * TOTAL 120 74
1422 */
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001423 QCBORError uReturn;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001424
1425 /* A note about string allocation -- Memory for strings is
1426 * allocated either because 1) indefinte-length string chunks are
1427 * being coalecsed or 2) caller has requested all strings be
1428 * allocated. The first case is handed below here. The second case
1429 * is handled in DecodeString if the bAllocate is true. That
1430 * boolean originates here with pMe->bStringAllocateAll immediately
1431 * below. That is, QCBOR_Private_DecodeAtomicDataItem() is called
1432 * in two different contexts here 1) main-line processing which is
1433 * where definite-length strings need to be allocated if
1434 * bStringAllocateAll is true and 2) processing chunks of
1435 * indefinite-lengths strings in in which case there must be no
1436 * allocation.
1437 */
1438
1439
1440 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, pMe->bStringAllocateAll, pDecodedItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001441 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001442 goto Done;
1443 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001444
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001445
1446 /* This is where out-of-place break is detected for the whole
1447 * decoding stack. Break is an error for everything that calls
1448 * QCBORDecode_Private_GetNextFullString(), so the check is
1449 * centralized here.
1450 */
1451 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
1452 uReturn = QCBOR_ERR_BAD_BREAK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001453 goto Done;
1454 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001455
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001456
1457 /* Skip out if not an indefinite-length string */
1458 const uint8_t uStringType = pDecodedItem->uDataType;
1459 if(uStringType != QCBOR_TYPE_BYTE_STRING &&
1460 uStringType != QCBOR_TYPE_TEXT_STRING) {
1461 goto Done;
1462 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001463 if(pDecodedItem->val.string.len != QCBOR_STRING_LENGTH_INDEFINITE) {
1464 goto Done;
1465 }
1466
1467#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001468 /* Can't decode indefinite-length strings without a string allocator */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001469 if(!pMe->StringAllocator.pfAllocator) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001470 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1471 goto Done;
1472 }
1473
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001474 /* Loop getting chunks of the indefinite-length string */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001475 UsefulBufC FullString = NULLUsefulBufC;
1476
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001477 for(;;) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001478 /* Get QCBORItem for next chunk */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001479 QCBORItem StringChunkItem;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001480 /* Pass false to DecodeAtomicDataItem() because the individual
1481 * string chunks in an indefinite-length must not be
1482 * allocated. They are always copied into the allocated
1483 * contiguous buffer allocated here.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001484 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001485 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &StringChunkItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001486 if(uReturn) {
1487 break;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001488 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001489
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001490 /* Is item is the marker for end of the indefinite-length string? */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001491 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001492 /* String is complete */
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001493 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301494 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001495 break;
1496 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001497
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001498 /* All chunks must be of the same type, the type of the item
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001499 * that introduces the indefinite-length string. This also
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001500 * catches errors where the chunk is not a string at all and an
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001501 * indefinite-length string inside an indefinite-length string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001502 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001503 if(StringChunkItem.uDataType != uStringType ||
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001504 StringChunkItem.val.string.len == QCBOR_STRING_LENGTH_INDEFINITE) {
1505 uReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001506 break;
1507 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001508
David Navarro9123e5b2022-03-28 16:04:03 +02001509 if (StringChunkItem.val.string.len > 0) {
1510 /* The first time throurgh FullString.ptr is NULL and this is
1511 * equivalent to StringAllocator_Allocate(). Subsequently it is
1512 * not NULL and a reallocation happens.
1513 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001514 UsefulBuf NewMem = StringAllocator_Reallocate(&(pMe->StringAllocator),
David Navarro9123e5b2022-03-28 16:04:03 +02001515 FullString.ptr,
1516 FullString.len + StringChunkItem.val.string.len);
David Navarro9123e5b2022-03-28 16:04:03 +02001517 if(UsefulBuf_IsNULL(NewMem)) {
1518 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1519 break;
1520 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001521
David Navarro9123e5b2022-03-28 16:04:03 +02001522 /* Copy new string chunk to the end of accumulated string */
1523 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001524 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001525 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001526
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001527 if(uReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
1528 /* Getting the item failed, clean up the allocated memory */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001529 StringAllocator_Free(&(pMe->StringAllocator), FullString.ptr);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001530 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001531#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1532 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1533#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001534
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001535Done:
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001536 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001537}
1538
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001539
Laurence Lundblade37286c02022-09-03 10:05:02 -07001540#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001541/**
1542 * @brief This converts a tag number to a shorter mapped value for storage.
1543 *
1544 * @param[in] pMe The decode context.
1545 * @param[in] uUnMappedTag The tag number to map
1546 * @param[out] puMappedTagNumer The stored tag number.
1547 *
1548 * @return error code.
1549 *
1550 * The main point of mapping tag numbers is make QCBORItem
1551 * smaller. With this mapping storage of 4 tags takes up 8
1552 * bytes. Without, it would take up 32 bytes.
1553 *
1554 * This maps tag numbers greater than QCBOR_LAST_UNMAPPED_TAG.
1555 * QCBOR_LAST_UNMAPPED_TAG is a little smaller than MAX_UINT16.
1556 *
1557 * See also UnMapTagNumber() and @ref QCBORItem.
1558 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001559static QCBORError
1560QCBORDecode_Private_MapTagNumber(QCBORDecodeContext *pMe,
1561 const uint64_t uUnMappedTag,
1562 uint16_t *puMappedTagNumer)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001563{
1564 if(uUnMappedTag > QCBOR_LAST_UNMAPPED_TAG) {
1565 unsigned uTagMapIndex;
1566 /* Is there room in the tag map, or is it in it already? */
1567 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
1568 if(pMe->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID64) {
1569 break;
1570 }
1571 if(pMe->auMappedTags[uTagMapIndex] == uUnMappedTag) {
1572 break;
1573 }
1574 }
1575 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
1576 return QCBOR_ERR_TOO_MANY_TAGS;
1577 }
1578
1579 /* Covers the cases where tag is new and were it is already in the map */
1580 pMe->auMappedTags[uTagMapIndex] = uUnMappedTag;
1581 *puMappedTagNumer = (uint16_t)(uTagMapIndex + QCBOR_LAST_UNMAPPED_TAG + 1);
1582
1583 } else {
1584 *puMappedTagNumer = (uint16_t)uUnMappedTag;
1585 }
1586
1587 return QCBOR_SUCCESS;
1588}
1589
1590
1591/**
1592 * @brief This converts a mapped tag number to the actual tag number.
1593 *
1594 * @param[in] pMe The decode context.
1595 * @param[in] uMappedTagNumber The stored tag number.
1596 *
1597 * @return The actual tag number is returned or
1598 * @ref CBOR_TAG_INVALID64 on error.
1599 *
1600 * This is the reverse of MapTagNumber()
1601 */
1602static uint64_t
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001603QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe,
1604 const uint16_t uMappedTagNumber)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001605{
1606 if(uMappedTagNumber <= QCBOR_LAST_UNMAPPED_TAG) {
1607 return uMappedTagNumber;
1608 } else if(uMappedTagNumber == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07001609 return CBOR_TAG_INVALID64;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001610 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001611 /* This won't be negative because of code below in
1612 * MapTagNumber()
1613 */
1614 const unsigned uIndex = uMappedTagNumber - (QCBOR_LAST_UNMAPPED_TAG + 1);
1615 return pMe->auMappedTags[uIndex];
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001616 }
1617}
Laurence Lundblade37286c02022-09-03 10:05:02 -07001618#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001619
Laurence Lundblade9b334962020-08-27 10:55:53 -07001620
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001621/**
1622 * @brief Aggregate all tags wrapping a data item (decode layer 4).
1623 *
1624 * @param[in] pMe Decoder context
1625 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001626 *
1627 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1628 * features
1629 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1630 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1631 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1632 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1633 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1634 * of half-precision disabled
1635 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1636 * float decode is disabled.
1637 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1638 * simple type in input.
1639 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1640 * in input, but indefinite
1641 * lengths disabled.
1642 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1643 * but no string allocator.
1644 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1645 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1646 * input, but indefinite-length
1647 * strings are disabled.
1648 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001649 *
1650 * This loops getting atomic data items until one is not a tag
1651 * number. Usually this is largely pass-through because most
1652 * item are not tag numbers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001653 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001654static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001655QCBORDecode_Private_GetNextTagNumber(QCBORDecodeContext *pMe,
1656 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001657{
Laurence Lundblade37286c02022-09-03 10:05:02 -07001658#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001659 /* Accummulate the tags from multiple items here and then copy them
1660 * into the last item, the non-tag item.
1661 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001662 uint16_t auItemsTags[QCBOR_MAX_TAGS_PER_ITEM];
1663
1664 /* Initialize to CBOR_TAG_INVALID16 */
1665 #if CBOR_TAG_INVALID16 != 0xffff
1666 /* Be sure the memset does the right thing. */
1667 #err CBOR_TAG_INVALID16 tag not defined as expected
1668 #endif
1669 memset(auItemsTags, 0xff, sizeof(auItemsTags));
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001670
Laurence Lundblade9b334962020-08-27 10:55:53 -07001671 QCBORError uReturn = QCBOR_SUCCESS;
1672
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001673 /* Loop fetching data items until the item fetched is not a tag */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001674 for(;;) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001675 QCBORError uErr = QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07001676 if(uErr != QCBOR_SUCCESS) {
1677 uReturn = uErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001678 goto Done;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001679 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001680
Laurence Lundblade9b334962020-08-27 10:55:53 -07001681 if(pDecodedItem->uDataType != QCBOR_TYPE_TAG) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001682 /* Successful exit from loop; maybe got some tags, maybe not */
1683 memcpy(pDecodedItem->uTags, auItemsTags, sizeof(auItemsTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001684 break;
1685 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001686
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001687 if(auItemsTags[QCBOR_MAX_TAGS_PER_ITEM - 1] != CBOR_TAG_INVALID16) {
1688 /* No room in the tag list */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001689 uReturn = QCBOR_ERR_TOO_MANY_TAGS;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001690 /* Continue on to get all tags wrapping this item even though
1691 * it is erroring out in the end. This allows decoding to
1692 * continue. This is a resource limit error, not a problem
1693 * with being well-formed CBOR.
1694 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001695 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001696 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001697 /* Slide tags over one in the array to make room at index 0.
1698 * Must use memmove because the move source and destination
1699 * overlap.
1700 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001701 memmove(&auItemsTags[1],
1702 auItemsTags,
1703 sizeof(auItemsTags) - sizeof(auItemsTags[0]));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001704
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001705 /* Map the tag */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001706 uint16_t uMappedTagNumber = 0;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001707 uReturn = QCBORDecode_Private_MapTagNumber(pMe, pDecodedItem->val.uTagV, &uMappedTagNumber);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001708 /* Continue even on error so as to consume all tags wrapping
1709 * this data item so decoding can go on. If MapTagNumber()
1710 * errors once it will continue to error.
1711 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001712 auItemsTags[0] = uMappedTagNumber;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001713 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001714
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001715Done:
Laurence Lundblade9b334962020-08-27 10:55:53 -07001716 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001717
Laurence Lundblade37286c02022-09-03 10:05:02 -07001718#else /* QCBOR_DISABLE_TAGS */
1719
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07001720 return QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07001721
1722#endif /* QCBOR_DISABLE_TAGS */
1723}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001724
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001725
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001726/**
1727 * @brief Combine a map entry label and value into one item (decode layer 3).
1728 *
1729 * @param[in] pMe Decoder context
1730 * @param[out] pDecodedItem The decoded item that work is done on.
1731 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001732 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1733 * features
1734 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1735 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1736 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1737 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1738 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1739 * of half-precision disabled
1740 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1741 * float decode is disabled.
1742 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1743 * simple type in input.
1744 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1745 * in input, but indefinite
1746 * lengths disabled.
1747 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1748 * but no string allocator.
1749 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1750 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1751 * input, but indefinite-length
1752 * strings are disabled.
1753 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1754 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1755 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001756 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001757 * If the current nesting level is a map, then this combines pairs of
1758 * items into one data item with a label and value.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001759 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001760 * This is passthrough if the current nesting level is not a map.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001761 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001762 * This also implements maps-as-array mode where a map is treated like
1763 * an array to allow caller to do their own label processing.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001764 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001765
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001766static QCBORError
1767QCBORDecode_Private_GetNextMapEntry(QCBORDecodeContext *pMe,
1768 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001769{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001770 QCBORItem LabelItem;
1771 QCBORError uErr;
1772
1773 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1774 if(QCBORDecode_IsUnrecoverableError(uErr)) {
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001775 goto Done;
1776 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001777
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001778 if(!DecodeNesting_IsCurrentTypeMap(&(pMe->nesting))) {
1779 /* Not decoding a map. Nothing to do. */
1780 /* When decoding maps-as-arrays, the type will be
1781 * QCBOR_TYPE_MAP_AS_ARRAY and this function will exit
1782 * here. This is now map processing for maps-as-arrays is not
1783 * done. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001784 goto Done;
1785 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001786
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001787 /* Decoding a map entry, so the item decoded above was the label */
1788 LabelItem = *pDecodedItem;
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001789
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001790 /* Get the value of the map item */
1791 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1792 if(QCBORDecode_IsUnrecoverableError(uErr)) {
1793 goto Done;
1794 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001795
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001796 /* Combine the label item and value item into one */
1797 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
1798 pDecodedItem->uLabelType = LabelItem.uDataType;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001799
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001800#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1801 /* QCBOR_DECODE_MODE_MAP_STRINGS_ONLY might have been a bad idea. Maybe
1802 * get rid of it in QCBOR 2.0
1803 */
1804 if(pMe->uDecodeMode == QCBOR_DECODE_MODE_MAP_STRINGS_ONLY &&
1805 LabelItem.uDataType != QCBOR_TYPE_TEXT_STRING) {
1806 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
1807 goto Done;
1808 }
1809#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
1810
1811 switch(LabelItem.uDataType) {
1812 case QCBOR_TYPE_INT64:
1813 pDecodedItem->label.int64 = LabelItem.val.int64;
1814 break;
1815
1816#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1817 case QCBOR_TYPE_UINT64:
1818 pDecodedItem->label.uint64 = LabelItem.val.uint64;
1819 break;
1820
1821 case QCBOR_TYPE_TEXT_STRING:
1822 case QCBOR_TYPE_BYTE_STRING:
1823 pDecodedItem->label.string = LabelItem.val.string;
1824 break;
1825#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
1826
1827 default:
1828 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
1829 goto Done;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001830 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001831
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001832Done:
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001833 return uErr;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001834}
1835
1836
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001837#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001838/**
1839 * @brief Peek and see if next data item is a break;
1840 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001841 * param[in] pUIB UsefulInputBuf to read from.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001842 * @param[out] pbNextIsBreak Indicate if next was a break or not.
1843 *
1844 * @return Any decoding error.
1845 *
1846 * See if next item is a CBOR break. If it is, it is consumed,
1847 * if not it is not consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07001848*/
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001849static QCBORError
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001850QCBOR_Private_NextIsBreak(QCBORDecodeContext *pMe, bool *pbNextIsBreak)
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001851{
1852 *pbNextIsBreak = false;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001853 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) != 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001854 QCBORItem Peek;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001855 size_t uPeek = UsefulInputBuf_Tell(&(pMe->InBuf));
1856 QCBORError uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &Peek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001857 if(uReturn != QCBOR_SUCCESS) {
1858 return uReturn;
1859 }
1860 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001861 /* It is not a break, rewind so it can be processed normally. */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001862 UsefulInputBuf_Seek(&(pMe->InBuf), uPeek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001863 } else {
1864 *pbNextIsBreak = true;
1865 }
1866 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001867
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001868 return QCBOR_SUCCESS;
1869}
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001870#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001871
1872
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001873/**
1874 * @brief Ascend up nesting levels if all items in them have been consumed.
1875 *
1876 * @param[in] pMe The decode context.
1877 * @param[in] bMarkEnd If true mark end of maps/arrays with count of zero.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001878 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001879 *
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001880 * An item was just consumed, now figure out if it was the
1881 * end of an array/map map that can be closed out. That
1882 * may in turn close out the above array/map...
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001883 *
1884 * When ascending indefinite-length arrays and maps, this will correctly
1885 * consume the break for the level above. This is a problem for the
1886 * implementation of QCBORDecode_GetArray() that must not return
1887 * that break. @c pbBreak is set to true to indicate that one
1888 * byte should be removed.
1889 *
1890 * Improvement: this could reduced further if indef is disabled
1891 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001892static QCBORError
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001893QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd, bool *pbBreak)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001894{
1895 QCBORError uReturn;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001896
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001897 /* Loop ascending nesting levels as long as there is ascending to do */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001898 while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001899 if(pbBreak) {
1900 *pbBreak = false;
1901 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001902
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001903 if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) {
1904 /* Nesting level is bstr-wrapped CBOR */
1905
1906 /* Ascent for bstr-wrapped CBOR is always by explicit call
1907 * so no further ascending can happen.
1908 */
1909 break;
1910
1911 } else if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
1912 /* Level is a definite-length array/map */
1913
1914 /* Decrement the item count the definite-length array/map */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001915 DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(&(pMe->nesting));
1916 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001917 /* Didn't close out array/map, so all work here is done */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001918 break;
1919 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001920 /* All items in a definite-length array were consumed so it
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001921 * is time to ascend one level. This happens below.
1922 */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001923
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001924#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001925 } else {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001926 /* Level is an indefinite-length array/map. */
1927
1928 /* Check for a break which is what ends indefinite-length arrays/maps */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001929 bool bIsBreak = false;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001930 uReturn = QCBOR_Private_NextIsBreak(pMe, &bIsBreak);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001931 if(uReturn != QCBOR_SUCCESS) {
1932 goto Done;
1933 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001934
1935 if(!bIsBreak) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001936 /* Not a break so array/map does not close out. All work is done */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001937 break;
1938 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001939
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001940 /* It was a break in an indefinitelength map / array so
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001941 * it is time to ascend one level.
1942 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001943 if(pbBreak) {
1944 *pbBreak = true;
1945 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001946
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001947#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001948 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001949
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001950
1951 /* All items in the array/map have been consumed. */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001952
Laurence Lundblade93d89472020-10-03 22:30:50 -07001953 /* But ascent in bounded mode is only by explicit call to
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001954 * QCBORDecode_ExitBoundedMode().
1955 */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07001956 if(DecodeNesting_IsCurrentBounded(&(pMe->nesting))) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001957 /* Set the count to zero for definite-length arrays to indicate
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001958 * cursor is at end of bounded array/map */
Laurence Lundbladed0304932020-06-27 10:59:38 -07001959 if(bMarkEnd) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001960 /* Used for definite and indefinite to signal end */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07001961 DecodeNesting_ZeroMapOrArrayCount(&(pMe->nesting));
Laurence Lundbladed0304932020-06-27 10:59:38 -07001962
Laurence Lundblade2c1faf92020-06-26 22:43:56 -07001963 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001964 break;
1965 }
1966
1967 /* Finally, actually ascend one level. */
1968 DecodeNesting_Ascend(&(pMe->nesting));
1969 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001970
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001971 uReturn = QCBOR_SUCCESS;
1972
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001973#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001974Done:
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001975#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1976
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001977 return uReturn;
1978}
1979
1980
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001981/**
1982 * @brief Ascending & Descending out of nesting levels (decode layer 2).
1983 *
1984 * @param[in] pMe Decoder context
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001985 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001986 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001987
1988 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1989 * features
1990 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1991 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1992 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1993 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1994 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1995 * of half-precision disabled
1996 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1997 * float decode is disabled.
1998 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1999 * simple type in input.
2000 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
2001 * in input, but indefinite
2002 * lengths disabled.
2003 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
2004 * but no string allocator.
2005 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
2006 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
2007 * input, but indefinite-length
2008 * strings are disabled.
2009 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
2010 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
2011 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
2012 * @retval QCBOR_ERR_NO_MORE_ITEMS Need more items for map or array.
2013 * @retval QCBOR_ERR_BAD_BREAK Indefinite-length break in wrong
2014 * place.
2015 * @retval QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP Nesting deeper than QCBOR
2016 * can handle.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002017 *
2018 * This handles the traversal descending into and asecnding out of
2019 * maps, arrays and bstr-wrapped CBOR. It figures out the ends of
2020 * definite- and indefinte-length maps and arrays by looking at the
2021 * item count or finding CBOR breaks. It detects the ends of the
2022 * top-level sequence and of bstr-wrapped CBOR by byte count.
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002023 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002024static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002025QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002026 bool *pbBreak,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002027 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002028{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002029 QCBORError uReturn;
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002030 /* ==== First: figure out if at the end of a traversal ==== */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002031
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002032 /* If out of bytes to consume, it is either the end of the
2033 * top-level sequence of some bstr-wrapped CBOR that was entered.
2034 *
2035 * In the case of bstr-wrapped CBOR, the length of the
2036 * UsefulInputBuf was set to that of the bstr-wrapped CBOR. When
2037 * the bstr-wrapped CBOR is exited, the length is set back to the
2038 * top-level's length or to the next highest bstr-wrapped CBOR.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002039 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002040 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) == 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002041 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002042 goto Done;
2043 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07002044
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002045 /* Check to see if at the end of a bounded definite-length map or
2046 * array. The check for a break ending indefinite-length array is
2047 * later in QCBORDecode_NestLevelAscender().
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002048 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002049 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002050 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002051 goto Done;
2052 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002053
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002054 /* ==== Next: not at the end, so get another item ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002055 uReturn = QCBORDecode_Private_GetNextMapEntry(pMe, pDecodedItem);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002056 if(QCBORDecode_IsUnrecoverableError(uReturn)) {
2057 /* Error is so bad that traversal is not possible. */
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002058 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002059 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05302060
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002061 /* Record the nesting level for this data item before processing
2062 * any of decrementing and descending.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002063 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002064 pDecodedItem->uNestingLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002065
Laurence Lundblade642282a2020-06-23 12:00:33 -07002066
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002067 /* ==== Next: Process the item for descent, ascent, decrement... ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002068 if(QCBORItem_IsMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002069 /* If the new item is a map or array, descend.
2070 *
2071 * Empty indefinite-length maps and arrays are descended into,
2072 * but then ascended out of in the next chunk of code.
2073 *
2074 * Maps and arrays do count as items in the map/array that
2075 * encloses them so a decrement needs to be done for them too,
2076 * but that is done only when all the items in them have been
2077 * processed, not when they are opened with the exception of an
2078 * empty map or array.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002079 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002080 QCBORError uDescendErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002081 uDescendErr = DecodeNesting_DescendMapOrArray(&(pMe->nesting),
Laurence Lundblade642282a2020-06-23 12:00:33 -07002082 pDecodedItem->uDataType,
2083 pDecodedItem->val.uCount);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002084 if(uDescendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002085 /* This error is probably a traversal error and it overrides
2086 * the non-traversal error.
2087 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002088 uReturn = uDescendErr;
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002089 goto Done;
2090 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002091 }
2092
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002093 if(!QCBORItem_IsMapOrArray(*pDecodedItem) ||
2094 QCBORItem_IsEmptyDefiniteLengthMapOrArray(*pDecodedItem) ||
2095 QCBORItem_IsIndefiniteLengthMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002096 /* The following cases are handled here:
2097 * - A non-aggregate item like an integer or string
2098 * - An empty definite-length map or array
2099 * - An indefinite-length map or array that might be empty or might not.
2100 *
2101 * QCBORDecode_NestLevelAscender() does the work of decrementing the count
2102 * for an definite-length map/array and break detection for an
2103 * indefinite-0length map/array. If the end of the map/array was
2104 * reached, then it ascends nesting levels, possibly all the way
2105 * to the top level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002106 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002107 QCBORError uAscendErr;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002108 uAscendErr = QCBORDecode_Private_NestLevelAscender(pMe, true, pbBreak);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002109 if(uAscendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002110 /* This error is probably a traversal error and it overrides
2111 * the non-traversal error.
2112 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002113 uReturn = uAscendErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002114 goto Done;
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002115 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05302116 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002117
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002118 /* ==== Last: tell the caller the nest level of the next item ==== */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002119 /* Tell the caller what level is next. This tells them what
2120 * maps/arrays were closed out and makes it possible for them to
2121 * reconstruct the tree with just the information returned in a
2122 * QCBORItem.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002123 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002124 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07002125 /* At end of a bounded map/array; uNextNestLevel 0 to indicate this */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002126 pDecodedItem->uNextNestLevel = 0;
2127 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002128 pDecodedItem->uNextNestLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002129 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002130
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002131Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002132 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002133}
2134
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002135
Laurence Lundblade37286c02022-09-03 10:05:02 -07002136#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002137/**
2138 * @brief Shift 0th tag out of the tag list.
2139 *
2140 * pDecodedItem[in,out] The data item to convert.
2141 *
2142 * The 0th tag is discarded. \ref CBOR_TAG_INVALID16 is
2143 * shifted into empty slot at the end of the tag list.
2144 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002145static void
2146QCBOR_Private_ShiftTags(QCBORItem *pDecodedItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002147{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002148 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM-1; i++) {
2149 pDecodedItem->uTags[i] = pDecodedItem->uTags[i+1];
2150 }
2151 pDecodedItem->uTags[QCBOR_MAX_TAGS_PER_ITEM-1] = CBOR_TAG_INVALID16;
Laurence Lundblade9b334962020-08-27 10:55:53 -07002152}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002153#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002154
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002155
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002156/**
2157 * @brief Convert different epoch date formats in to the QCBOR epoch date format
2158 *
2159 * pDecodedItem[in,out] The data item to convert.
2160 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002161 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2162 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2163 * floating-point date disabled.
2164 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2165 * all floating-point disabled.
2166 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2167 * error decoding date.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002168 *
2169 * The epoch date tag defined in QCBOR allows for floating-point
2170 * dates. It even allows a protocol to flop between date formats when
2171 * ever it wants. Floating-point dates aren't that useful as they are
2172 * only needed for dates beyond the age of the earth.
2173 *
2174 * This converts all the date formats into one format of an unsigned
2175 * integer plus a floating-point fraction.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002176 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002177static QCBORError
2178QCBOR_Private_DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002179{
Laurence Lundbladec7114722020-08-13 05:11:40 -07002180 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002181
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002182#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade59289e52019-12-30 13:44:37 -08002183 pDecodedItem->val.epochDate.fSecondsFraction = 0;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002184#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002185
2186 switch (pDecodedItem->uDataType) {
2187
2188 case QCBOR_TYPE_INT64:
2189 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
2190 break;
2191
2192 case QCBOR_TYPE_UINT64:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002193 /* This only happens for CBOR type 0 > INT64_MAX so it is
2194 * always an overflow.
2195 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07002196 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2197 goto Done;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002198 break;
2199
2200 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade9682a532020-06-06 18:33:04 -07002201 case QCBOR_TYPE_FLOAT:
2202#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade59289e52019-12-30 13:44:37 -08002203 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002204 /* Convert working value to double if input was a float */
Laurence Lundblade3ed0bca2020-07-14 22:50:10 -07002205 const double d = pDecodedItem->uDataType == QCBOR_TYPE_DOUBLE ?
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002206 pDecodedItem->val.dfnum :
2207 (double)pDecodedItem->val.fnum;
2208
2209 /* The conversion from float to integer requires overflow
2210 * detection since floats can be much larger than integers.
2211 * This implementation errors out on these large float values
2212 * since they are beyond the age of the earth.
2213 *
2214 * These constants for the overflow check are computed by the
2215 * compiler. They are not computed at run time.
2216 *
2217 * The factor of 0x7ff is added/subtracted to avoid a
2218 * rounding error in the wrong direction when the compiler
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002219 * computes these constants. There is rounding because a
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002220 * 64-bit integer has 63 bits of precision where a double
2221 * only has 53 bits. Without the 0x7ff factor, the compiler
2222 * may round up and produce a double for the bounds check
2223 * that is larger than can be stored in a 64-bit integer. The
2224 * amount of 0x7ff is picked because it has 11 bits set.
2225 *
2226 * Without the 0x7ff there is a ~30 minute range of time
2227 * values 10 billion years in the past and in the future
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002228 * where this code could go wrong. Some compilers
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002229 * generate a warning or error without the 0x7ff.
2230 */
2231 const double dDateMax = (double)(INT64_MAX - 0x7ff);
2232 const double dDateMin = (double)(INT64_MIN + 0x7ff);
2233
2234 if(isnan(d) || d > dDateMax || d < dDateMin) {
Laurence Lundbladec7114722020-08-13 05:11:40 -07002235 uReturn = QCBOR_ERR_DATE_OVERFLOW;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002236 goto Done;
2237 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002238
2239 /* The actual conversion */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002240 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
Laurence Lundblade2feb1e12020-07-15 03:50:45 -07002241 pDecodedItem->val.epochDate.fSecondsFraction =
2242 d - (double)pDecodedItem->val.epochDate.nSeconds;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002243 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002244#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade4b270642020-08-14 12:53:07 -07002245
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002246 uReturn = QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundblade4b270642020-08-14 12:53:07 -07002247 goto Done;
2248
Laurence Lundblade9682a532020-06-06 18:33:04 -07002249#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002250 break;
2251
2252 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002253 /* It's the arrays and maps that are unrecoverable because
2254 * they are not consumed here. Since this is just an error
2255 * condition, no extra code is added here to make the error
2256 * recoverable for non-arrays and maps like strings. */
2257 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002258 goto Done;
2259 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002260
Laurence Lundblade59289e52019-12-30 13:44:37 -08002261 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
2262
2263Done:
Laurence Lundbladec7114722020-08-13 05:11:40 -07002264 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002265}
2266
2267
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002268/**
2269 * @brief Convert the days epoch date.
2270 *
2271 * pDecodedItem[in,out] The data item to convert.
2272 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002273 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2274 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2275 * floating-point date disabled.
2276 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2277 * all floating-point disabled.
2278 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2279 * error decoding date.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002280 *
2281 * This is much simpler than the other epoch date format because
2282 * floating-porint is not allowed. This is mostly a simple type check.
2283 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002284static QCBORError
2285QCBOR_Private_DecodeDaysEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002286{
2287 QCBORError uReturn = QCBOR_SUCCESS;
2288
2289 switch (pDecodedItem->uDataType) {
2290
2291 case QCBOR_TYPE_INT64:
2292 pDecodedItem->val.epochDays = pDecodedItem->val.int64;
2293 break;
2294
2295 case QCBOR_TYPE_UINT64:
2296 /* This only happens for CBOR type 0 > INT64_MAX so it is
2297 * always an overflow.
2298 */
2299 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2300 goto Done;
2301 break;
2302
2303 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002304 /* It's the arrays and maps that are unrecoverable because
2305 * they are not consumed here. Since this is just an error
2306 * condition, no extra code is added here to make the error
2307 * recoverable for non-arrays and maps like strings. */
2308 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002309 goto Done;
2310 break;
2311 }
2312
2313 pDecodedItem->uDataType = QCBOR_TYPE_DAYS_EPOCH;
2314
2315Done:
2316 return uReturn;
2317}
2318
2319
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002320#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade37286c02022-09-03 10:05:02 -07002321
2322/* Forward declaration is necessary for
2323 * QCBORDecode_MantissaAndExponent(). to be able to decode bignum
2324 * tags in the mantissa. If the mantissa is a decimal fraction or big
2325 * float in error, this will result in a recurive call to
2326 * QCBORDecode_MantissaAndExponent(), but the recursion will unwined
2327 * correctly and the correct error is returned.
2328 */
2329static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002330QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2331 QCBORItem *pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002332
2333
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002334/**
2335 * @brief Decode decimal fractions and big floats.
2336 *
2337 * @param[in] pMe The decode context.
2338 * @param[in,out] pDecodedItem On input the array data item that
2339 * holds the mantissa and exponent. On
2340 * output the decoded mantissa and
2341 * exponent.
2342 *
2343 * @returns Decoding errors from getting primitive data items or
2344 * \ref QCBOR_ERR_BAD_EXP_AND_MANTISSA.
2345 *
Laurence Lundblade37286c02022-09-03 10:05:02 -07002346 * When called pDecodedItem must be the array with two members, the
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002347 * exponent and mantissa.
2348 *
2349 * This will fetch and decode the exponent and mantissa and put the
2350 * result back into pDecodedItem.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002351 *
2352 * This does no checking or processing of tag numbers. That is to be
2353 * done by the code that calls this.
2354 *
2355 * This stuffs the type of the mantissa into pDecodedItem with the expectation
2356 * the caller will process it.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002357 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002358static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002359QCBORDecode_Private_ExpMantissa(QCBORDecodeContext *pMe,
2360 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002361{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002362 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002363
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002364 /* --- Make sure it is an array; track nesting level of members --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002365 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002366 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002367 goto Done;
2368 }
2369
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002370 /* A check for pDecodedItem->val.uCount == 2 would work for
Laurence Lundblade37286c02022-09-03 10:05:02 -07002371 * definite-length arrays, but not for indefinite. Instead remember
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002372 * the nesting level the two integers must be at, which is one
2373 * deeper than that of the array.
2374 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002375 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
2376
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002377 /* --- Get the exponent --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002378 QCBORItem exponentItem;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002379 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, &exponentItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002380 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002381 goto Done;
2382 }
2383 if(exponentItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002384 /* Array is empty or a map/array encountered when expecting an int */
2385 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002386 goto Done;
2387 }
2388 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002389 /* Data arriving as an unsigned int < INT64_MAX has been
2390 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2391 * also means that the only data arriving here of type
2392 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2393 * and thus an error that will get handled in the next else.
2394 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002395 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
2396 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002397 /* Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX */
2398 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002399 goto Done;
2400 }
2401
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002402 /* --- Get the mantissa --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002403 QCBORItem mantissaItem;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002404 uReturn = QCBORDecode_Private_GetNextTagContent(pMe, &mantissaItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002405 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002406 goto Done;
2407 }
2408 if(mantissaItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002409 /* Mantissa missing or map/array encountered when expecting number */
2410 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002411 goto Done;
2412 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002413 /* Stuff the mantissa data type into the item to send it up to the
2414 * the next level. */
2415 pDecodedItem->uDataType = mantissaItem.uDataType;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002416 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002417 /* Data arriving as an unsigned int < INT64_MAX has been
2418 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2419 * also means that the only data arriving here of type
2420 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2421 * and thus an error that will get handled in an else below.
2422 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002423 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002424#ifndef QCBOR_DISABLE_TAGS
2425 /* With tags fully disabled a big number mantissa will error out
2426 * in the call to QCBORDecode_GetNextWithTags() because it has
2427 * a tag number.
2428 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07002429 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM ||
2430 mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002431 /* Got a good big num mantissa */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002432 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002433#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002434 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002435 /* Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX */
2436 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002437 goto Done;
2438 }
2439
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002440 /* --- Check that array only has the two numbers --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002441 if(mantissaItem.uNextNestLevel == nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002442 /* Extra items in the decimal fraction / big float */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002443 /* Improvement: this should probably be an unrecoverable error. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002444 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002445 goto Done;
2446 }
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002447 pDecodedItem->uNextNestLevel = mantissaItem.uNextNestLevel;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002448
2449Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002450 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002451}
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002452#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002453
2454
Laurence Lundblade37286c02022-09-03 10:05:02 -07002455#ifndef QCBOR_DISABLE_TAGS
2456
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002457#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002458/**
2459 * @brief Decode the MIME type tag
2460 *
2461 * @param[in,out] pDecodedItem The item to decode.
2462 *
2463 * Handle the text and binary MIME type tags. Slightly too complicated
2464 * f or ProcessTaggedString() because the RFC 7049 MIME type was
2465 * incorreclty text-only.
2466 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002467static QCBORError
2468QCBOR_Private_DecodeMIME(QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002469{
2470 if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) {
2471 pDecodedItem->uDataType = QCBOR_TYPE_MIME;
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07002472 } else if(pDecodedItem->uDataType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002473 pDecodedItem->uDataType = QCBOR_TYPE_BINARY_MIME;
2474 } else {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002475 /* It's the arrays and maps that are unrecoverable because
2476 * they are not consumed here. Since this is just an error
2477 * condition, no extra code is added here to make the error
2478 * recoverable for non-arrays and maps like strings. */
2479 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002480 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002481
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002482 return QCBOR_SUCCESS;
2483}
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002484#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002485
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002486/**
Laurence Lundblade99615302020-11-29 11:19:47 -08002487 * Table of CBOR tags whose content is either a text string or a byte
2488 * string. The table maps the CBOR tag to the QCBOR type. The high-bit
2489 * of uQCBORtype indicates the content should be a byte string rather
2490 * than a text string
2491 */
2492struct StringTagMapEntry {
2493 uint16_t uTagNumber;
2494 uint8_t uQCBORtype;
2495};
2496
2497#define IS_BYTE_STRING_BIT 0x80
2498#define QCBOR_TYPE_MASK ~IS_BYTE_STRING_BIT
2499
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002500static const struct StringTagMapEntry QCBOR_Private_StringTagMap[] = {
Laurence Lundblade99615302020-11-29 11:19:47 -08002501 {CBOR_TAG_DATE_STRING, QCBOR_TYPE_DATE_STRING},
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002502 {CBOR_TAG_DAYS_STRING, QCBOR_TYPE_DAYS_STRING},
Laurence Lundblade99615302020-11-29 11:19:47 -08002503 {CBOR_TAG_POS_BIGNUM, QCBOR_TYPE_POSBIGNUM | IS_BYTE_STRING_BIT},
2504 {CBOR_TAG_NEG_BIGNUM, QCBOR_TYPE_NEGBIGNUM | IS_BYTE_STRING_BIT},
2505 {CBOR_TAG_CBOR, QBCOR_TYPE_WRAPPED_CBOR | IS_BYTE_STRING_BIT},
2506 {CBOR_TAG_URI, QCBOR_TYPE_URI},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002507#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002508 {CBOR_TAG_B64URL, QCBOR_TYPE_BASE64URL},
2509 {CBOR_TAG_B64, QCBOR_TYPE_BASE64},
2510 {CBOR_TAG_REGEX, QCBOR_TYPE_REGEX},
2511 {CBOR_TAG_BIN_UUID, QCBOR_TYPE_UUID | IS_BYTE_STRING_BIT},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002512#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade99615302020-11-29 11:19:47 -08002513 {CBOR_TAG_CBOR_SEQUENCE, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE | IS_BYTE_STRING_BIT},
2514 {CBOR_TAG_INVALID16, QCBOR_TYPE_NONE}
2515};
2516
2517
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002518/**
2519 * @brief Process standard CBOR tags whose content is a string
2520 *
2521 * @param[in] uTag The tag.
2522 * @param[in,out] pDecodedItem The data item.
2523 *
2524 * @returns This returns QCBOR_SUCCESS if the tag was procssed,
2525 * \ref QCBOR_ERR_UNSUPPORTED if the tag was not processed and
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002526 * \ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT if the content type was wrong for the tag.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002527 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002528 * Process the CBOR tags that whose content is a byte string or a text
2529 * string and for which the string is just passed on to the caller.
2530 *
2531 * This maps the CBOR tag to the QCBOR type and checks the content
2532 * type. Nothing more. It may not be the most important
Laurence Lundbladec02e13e2020-12-06 05:45:41 -08002533 * functionality, but it part of implementing as much of RFC 8949 as
Laurence Lundblade99615302020-11-29 11:19:47 -08002534 * possible.
Laurence Lundblade99615302020-11-29 11:19:47 -08002535 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002536static QCBORError
2537QCBOR_Private_ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002538{
Laurence Lundblade99615302020-11-29 11:19:47 -08002539 /* This only works on tags that were not mapped; no need for other yet */
2540 if(uTag > QCBOR_LAST_UNMAPPED_TAG) {
2541 return QCBOR_ERR_UNSUPPORTED;
2542 }
2543
2544 unsigned uIndex;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002545 for(uIndex = 0; QCBOR_Private_StringTagMap[uIndex].uTagNumber != CBOR_TAG_INVALID16; uIndex++) {
2546 if(QCBOR_Private_StringTagMap[uIndex].uTagNumber == uTag) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002547 break;
2548 }
2549 }
2550
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002551 const uint8_t uQCBORType = QCBOR_Private_StringTagMap[uIndex].uQCBORtype;
Laurence Lundblade99615302020-11-29 11:19:47 -08002552 if(uQCBORType == QCBOR_TYPE_NONE) {
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002553 /* repurpose this error to mean not handled here */
Laurence Lundblade99615302020-11-29 11:19:47 -08002554 return QCBOR_ERR_UNSUPPORTED;
2555 }
2556
2557 uint8_t uExpectedType = QCBOR_TYPE_TEXT_STRING;
2558 if(uQCBORType & IS_BYTE_STRING_BIT) {
2559 uExpectedType = QCBOR_TYPE_BYTE_STRING;
2560 }
2561
2562 if(pDecodedItem->uDataType != uExpectedType) {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002563 /* It's the arrays and maps that are unrecoverable because
2564 * they are not consumed here. Since this is just an error
2565 * condition, no extra code is added here to make the error
2566 * recoverable for non-arrays and maps like strings. */
2567 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002568 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002569
Laurence Lundblade99615302020-11-29 11:19:47 -08002570 pDecodedItem->uDataType = (uint8_t)(uQCBORType & QCBOR_TYPE_MASK);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002571 return QCBOR_SUCCESS;
2572}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002573#endif /* QCBOR_DISABLE_TAGS */
2574
2575
2576#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002577/**
2578 * @brief Figures out data type for exponent mantissa tags.
2579 *
2580 * @param[in] uTagToProcess Either @ref CBOR_TAG_DECIMAL_FRACTION or
2581 * @ref CBOR_TAG_BIG_FLOAT.
2582 * @param[in] pDecodedItem Item being decoded.
2583 *
2584 * @returns One of the 6 values between \ref QCBOR_TYPE_DECIMAL_FRACTION
2585 * and @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM.
2586 *
2587 * Does mapping between a CBOR tag number and a QCBOR type. with a
2588 * little bit of logic and arithmatic.
2589 *
2590 * Used in serveral contexts. Does the work where sometimes the data
2591 * item is explicitly tagged and sometimes not.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002592 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002593static uint8_t
2594QCBOR_Private_ExpMantissaDataType(const uint16_t uTagToProcess,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002595 const QCBORItem *pDecodedItem)
Laurence Lundblade37286c02022-09-03 10:05:02 -07002596{
2597 uint8_t uBase = uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ?
2598 QCBOR_TYPE_DECIMAL_FRACTION :
2599 QCBOR_TYPE_BIGFLOAT;
2600 if(pDecodedItem->uDataType != QCBOR_TYPE_INT64) {
2601 uBase = (uint8_t)(uBase + pDecodedItem->uDataType - QCBOR_TYPE_POSBIGNUM + 1);
2602 }
2603 return uBase;
2604}
2605#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002606
2607
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002608/**
2609 * @brief Decode tag content for select tags (decoding layer 1).
2610 *
2611 * @param[in] pMe The decode context.
2612 * @param[out] pDecodedItem The decoded item.
2613 *
2614 * @return Decoding error code.
2615 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002616 * CBOR tag numbers for the item were decoded in GetNext_TaggedItem(),
2617 * but the whole tag was not decoded. Here, the whole tags (tag number
2618 * and tag content) that are supported by QCBOR are decoded. This is a
2619 * quick pass through for items that are not tags.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002620 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002621static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002622QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2623 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002624{
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002625 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002626
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002627 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pDecodedItem);
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002628 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002629 goto Done;
2630 }
2631
Laurence Lundblade37286c02022-09-03 10:05:02 -07002632#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002633 /* When there are no tag numbers for the item, this exits first
2634 * thing and effectively does nothing.
2635 *
2636 * This loops over all the tag numbers accumulated for this item
2637 * trying to decode and interpret them. This stops at the end of
2638 * the list or at the first tag number that can't be interpreted by
2639 * this code. This is effectively a recursive processing of the
2640 * tags number list that handles nested tags.
2641 */
2642 while(1) {
2643 /* Don't bother to unmap tags via QCBORITem.uTags since this
2644 * code only works on tags less than QCBOR_LAST_UNMAPPED_TAG.
2645 */
2646 const uint16_t uTagToProcess = pDecodedItem->uTags[0];
Laurence Lundblade59289e52019-12-30 13:44:37 -08002647
Laurence Lundblade99615302020-11-29 11:19:47 -08002648 if(uTagToProcess == CBOR_TAG_INVALID16) {
2649 /* Hit the end of the tag list. A successful exit. */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002650 break;
2651
Laurence Lundblade99615302020-11-29 11:19:47 -08002652 } else if(uTagToProcess == CBOR_TAG_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002653 uReturn = QCBOR_Private_DecodeDateEpoch(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002654
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002655 } else if(uTagToProcess == CBOR_TAG_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002656 uReturn = QCBOR_Private_DecodeDaysEpoch(pDecodedItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002657
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002658#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade99615302020-11-29 11:19:47 -08002659 } else if(uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ||
2660 uTagToProcess == CBOR_TAG_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002661 uReturn = QCBORDecode_Private_ExpMantissa(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002662 /* --- Which is it, decimal fraction or a bigfloat? --- */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002663 pDecodedItem->uDataType = QCBOR_Private_ExpMantissaDataType(uTagToProcess, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002664
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002665#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002666#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002667 } else if(uTagToProcess == CBOR_TAG_MIME ||
2668 uTagToProcess == CBOR_TAG_BINARY_MIME) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002669 uReturn = QCBOR_Private_DecodeMIME(pDecodedItem);
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002670#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002671
Laurence Lundblade99615302020-11-29 11:19:47 -08002672 } else {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002673 /* See if it is a passthrough byte/text string tag; process if so */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002674 uReturn = QCBOR_Private_ProcessTaggedString(pDecodedItem->uTags[0], pDecodedItem);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002675
Laurence Lundblade99615302020-11-29 11:19:47 -08002676 if(uReturn == QCBOR_ERR_UNSUPPORTED) {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002677 /* It wasn't a passthrough byte/text string tag so it is
Laurence Lundblade99615302020-11-29 11:19:47 -08002678 * an unknown tag. This is the exit from the loop on the
2679 * first unknown tag. It is a successful exit.
2680 */
2681 uReturn = QCBOR_SUCCESS;
2682 break;
2683 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002684 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002685
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002686 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002687 /* Error exit from the loop */
2688 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002689 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002690
2691 /* A tag was successfully processed, shift it out of the list of
2692 * tags returned. This is the loop increment.
2693 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002694 QCBOR_Private_ShiftTags(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002695 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002696#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002697
2698Done:
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002699 return uReturn;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002700}
2701
2702
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002703/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002704 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002705 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002706QCBORError
2707QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2708{
2709 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002710 uErr = QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002711 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002712 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2713 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
2714 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002715 return uErr;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002716}
2717
2718
2719/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002720 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08002721 */
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002722QCBORError
2723QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2724{
2725 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2726 const UsefulInputBuf Save = pMe->InBuf;
2727
2728 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
2729
2730 pMe->nesting = SaveNesting;
2731 pMe->InBuf = Save;
2732
2733 return uErr;
2734}
2735
2736
2737/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002738 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002739 */
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002740void
2741QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2742{
2743 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002744 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2745 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002746 return;
2747 }
2748
2749 pMe->uLastError = (uint8_t)QCBORDecode_PeekNext(pMe, pDecodedItem);
2750}
2751
2752
2753/*
2754 * Public function, see header qcbor/qcbor_decode.h file
2755 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002756void
2757QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002758{
2759 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002760 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2761 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002762 return;
2763 }
2764
2765 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem);
2766}
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 Lundblade8e36f812024-01-26 10:59:29 -07003134static void
3135QCBORDecode_Private_CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07003136{
Laurence Lundblade37286c02022-09-03 10:05:02 -07003137#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade9b334962020-08-27 10:55:53 -07003138 memcpy(pMe->uLastTags, pItem->uTags, sizeof(pItem->uTags));
Laurence Lundblade37286c02022-09-03 10:05:02 -07003139#else
3140 (void)pMe;
3141 (void)pItem;
3142#endif
Laurence Lundblade9b334962020-08-27 10:55:53 -07003143}
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003144
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003145
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003146/**
3147 * @brief Consume an entire map or array including its contents.
3148 *
3149 * @param[in] pMe The decoder context.
3150 * @param[in] pItemToConsume The array/map whose contents are to be
3151 * consumed.
3152 * @param[out] puNextNestLevel The next nesting level after the item was
3153 * fully consumed.
3154 *
3155 * This may be called when @c pItemToConsume is not an array or
3156 * map. In that case, this is just a pass through for @c puNextNestLevel
3157 * since there is nothing to do.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003158 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003159static QCBORError
3160QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
3161 const QCBORItem *pItemToConsume,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003162 bool *pbBreak,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003163 uint8_t *puNextNestLevel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003164{
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003165 QCBORError uReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003166 QCBORItem Item;
Laurence Lundblade9b334962020-08-27 10:55:53 -07003167
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003168 /* If it is a map or array, this will tell if it is empty. */
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003169 const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel);
3170
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003171 if(QCBORItem_IsMapOrArray(*pItemToConsume) && !bIsEmpty) {
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003172 /* There is only real work to do for non-empty maps and arrays */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003173
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003174 /* This works for definite- and indefinite-length maps and
3175 * arrays by using the nesting level
Laurence Lundblade1341c592020-04-11 14:19:05 -07003176 */
3177 do {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003178 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pbBreak, &Item);
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003179 if(QCBORDecode_IsUnrecoverableError(uReturn) ||
3180 uReturn == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003181 goto Done;
3182 }
3183 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003184
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003185 *puNextNestLevel = Item.uNextNestLevel;
3186
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003187 uReturn = QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003188
Laurence Lundblade1341c592020-04-11 14:19:05 -07003189 } else {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003190 /* pItemToConsume is not a map or array. Just pass the nesting
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003191 * level through. */
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003192 *puNextNestLevel = pItemToConsume->uNextNestLevel;
3193
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003194 uReturn = QCBOR_SUCCESS;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003195 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003196
3197Done:
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003198 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003199}
3200
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003201
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003202/*
3203 * Public function, see header qcbor/qcbor_decode.h file
3204 */
3205void
3206QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003207{
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003208 QCBORDecode_VGetNext(pMe, pDecodedItem);
3209
3210 if(pMe->uLastError == QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003211 pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL,
Máté Tóth-Pálc6d59682021-05-26 18:55:30 +02003212 &pDecodedItem->uNextNestLevel);
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003213 }
3214}
3215
3216
Laurence Lundblade11654912024-05-09 11:49:24 -07003217/*
3218 * Public function, see header qcbor/qcbor_decode.h file
3219 */
3220uint32_t
3221QCBORDecode_Tell(QCBORDecodeContext *pMe)
3222{
3223 size_t uCursorOffset;
3224
3225 if(pMe->uLastError != QCBOR_SUCCESS) {
3226 return UINT32_MAX;
3227 }
3228
3229 uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
3230
3231 if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
3232 return UINT32_MAX;
3233 } else {
3234 /* Cast is safe because decoder input size is restricted. */
3235 return (uint32_t)uCursorOffset;
3236 }
3237}
3238
3239
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003240/**
3241 * @brief Rewind cursor to start as if map or array were just entered.
3242 *
3243 * @param[in] pMe The decoding context
3244 *
3245 * This affects the nesting tracking and the UsefulInputBuf.
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003246 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003247static void
3248QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003249{
3250 /* Reset nesting tracking to the deepest bounded level */
3251 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3252
3253 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3254
3255 /* Reposition traversal cursor to the start of the map/array */
3256 UsefulInputBuf_Seek(&(pMe->InBuf),
3257 DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
3258}
3259
3260
3261/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003262 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003263 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003264void
3265QCBORDecode_Rewind(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003266{
3267 if(pMe->nesting.pCurrentBounded != NULL) {
3268 /* In a bounded map, array or bstr-wrapped CBOR */
3269
3270 if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
3271 /* In bstr-wrapped CBOR. */
3272
3273 /* Reposition traversal cursor to start of wrapping byte string */
3274 UsefulInputBuf_Seek(&(pMe->InBuf),
3275 pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
3276 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3277
3278 } else {
3279 /* In a map or array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003280 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003281 }
3282
3283 } else {
3284 /* Not in anything bounded */
3285
3286 /* Reposition traversal cursor to the start of input CBOR */
3287 UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
3288
3289 /* Reset nesting tracking to beginning of input. */
3290 DecodeNesting_Init(&(pMe->nesting));
3291 }
3292
3293 pMe->uLastError = QCBOR_SUCCESS;
3294}
3295
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003296
Laurence Lundblade9b334962020-08-27 10:55:53 -07003297
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003298
3299
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003300typedef struct {
3301 void *pCBContext;
3302 QCBORItemCallback pfCallback;
3303} MapSearchCallBack;
3304
3305typedef struct {
3306 size_t uStartOffset;
3307 uint16_t uItemCount;
3308} MapSearchInfo;
3309
3310
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003311/**
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003312 * @brief Search a map for a set of items.
3313 *
3314 * @param[in] pMe The decode context to search.
3315 * @param[in,out] pItemArray The items to search for and the items found.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003316 * @param[out] pInfo Several bits of meta-info returned by search.
3317 * @param[in] pCallBack Callback object or @c NULL.
3318 * TODO: fix params
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003319 *
3320 * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map.
3321 *
3322 * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label)
3323 * were found for one of the labels being
3324 * search for. This duplicate detection is
3325 * only performed for items in pItemArray,
3326 * not every item in the map.
3327 *
3328 * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was
3329 * wrong for the matchd label.
3330 *
3331 * @retval Also errors returned by QCBORDecode_GetNext().
3332 *
3333 * On input, \c pItemArray contains a list of labels and data types of
3334 * items to be found.
3335 *
3336 * On output, the fully retrieved items are filled in with values and
3337 * such. The label was matched, so it never changes.
3338 *
3339 * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE.
3340 *
3341 * This also finds the ends of maps and arrays when they are exited.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003342 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003343static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003344QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
3345 QCBORItem *pItemArray,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003346 MapSearchInfo *pInfo,
3347 MapSearchCallBack *pCallBack)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003348{
Laurence Lundbladee6f15112020-07-23 18:44:16 -07003349 QCBORError uReturn;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003350 uint64_t uFoundItemBitMap = 0;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07003351
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003352 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003353 uReturn = pMe->uLastError;
3354 goto Done2;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003355 }
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003356
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003357 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) &&
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003358 pItemArray->uLabelType != QCBOR_TYPE_NONE) {
3359 /* QCBOR_TYPE_NONE as first item indicates just looking
3360 for the end of an array, so don't give error. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003361 uReturn = QCBOR_ERR_MAP_NOT_ENTERED;
3362 goto Done2;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003363 }
3364
Laurence Lundblade085d7952020-07-24 10:26:30 -07003365 if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) {
3366 // It is an empty bounded array or map
3367 if(pItemArray->uLabelType == QCBOR_TYPE_NONE) {
3368 // Just trying to find the end of the map or array
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003369 pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003370 uReturn = QCBOR_SUCCESS;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003371 } else {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003372 // Nothing is ever found in an empty array or map. All items
3373 // are marked as not found below.
Laurence Lundblade085d7952020-07-24 10:26:30 -07003374 uReturn = QCBOR_SUCCESS;
3375 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003376 goto Done2;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003377 }
3378
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003379 QCBORDecodeNesting SaveNesting;
Laurence Lundblade11654912024-05-09 11:49:24 -07003380 size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003381 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3382
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003383 /* Reposition to search from the start of the map / array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003384 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundblade1341c592020-04-11 14:19:05 -07003385
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003386 /*
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003387 Loop over all the items in the map or array. Each item
3388 could be a map or array, but label matching is only at
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003389 the main level. This handles definite- and indefinite-
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003390 length maps and arrays. The only reason this is ever
3391 called on arrays is to find their end position.
3392
3393 This will always run over all items in order to do
3394 duplicate detection.
3395
3396 This will exit with failure if it encounters an
3397 unrecoverable error, but continue on for recoverable
3398 errors.
3399
3400 If a recoverable error occurs on a matched item, then
3401 that error code is returned.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003402 */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07003403 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003404 if(pInfo) {
3405 pInfo->uItemCount = 0;
3406 }
Máté Tóth-Pál2f2aa5f2021-05-17 21:35:09 +02003407 uint8_t uNextNestLevel;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003408 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003409 /* Remember offset of the item because sometimes it has to be returned */
Laurence Lundblade1341c592020-04-11 14:19:05 -07003410 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003411
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003412 /* Get the item */
3413 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003414 QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003415 if(QCBORDecode_IsUnrecoverableError(uResult)) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003416 /* The map/array can't be decoded when unrecoverable errors occur */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003417 uReturn = uResult;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003418 goto Done;
3419 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003420 if(uResult == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003421 /* Unexpected end of map or array. */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003422 uReturn = uResult;
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003423 goto Done;
3424 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003425
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003426 /* See if item has one of the labels that are of interest */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003427 bool bMatched = false;
3428 for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003429 if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003430 /* A label match has been found */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003431 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
3432 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003433 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003434 }
Laurence Lundblade63926052021-03-29 16:05:51 -07003435 if(uResult != QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003436 /* The label matches, but the data item is in error.
3437 * It is OK to have recoverable errors on items that are not
3438 * matched. */
Laurence Lundblade63926052021-03-29 16:05:51 -07003439 uReturn = uResult;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003440 goto Done;
3441 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003442 if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) {
Laurence Lundblade63926052021-03-29 16:05:51 -07003443 /* The data item is not of the type(s) requested */
3444 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003445 goto Done;
3446 }
3447
Laurence Lundblade1341c592020-04-11 14:19:05 -07003448 /* Successful match. Return the item. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003449 pItemArray[nIndex] = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003450 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003451 if(pInfo) {
3452 pInfo->uStartOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003453 }
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003454 bMatched = true;
3455 }
3456 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003457
3458
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003459 if(!bMatched && pCallBack != NULL) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003460 /*
3461 Call the callback on unmatched labels.
3462 (It is tempting to do duplicate detection here, but that would
3463 require dynamic memory allocation because the number of labels
3464 that might be encountered is unbounded.)
3465 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003466 uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item);
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003467 if(uReturn != QCBOR_SUCCESS) {
3468 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003469 }
3470 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003471
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003472 /*
3473 Consume the item whether matched or not. This
3474 does the work of traversing maps and array and
3475 everything in them. In this loop only the
3476 items at the current nesting level are examined
3477 to match the labels.
3478 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003479 uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel);
Laurence Lundbladec7114722020-08-13 05:11:40 -07003480 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003481 goto Done;
3482 }
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003483
3484 if(pInfo) {
3485 pInfo->uItemCount++;
3486 }
3487
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003488 } while (uNextNestLevel >= uMapNestLevel);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003489
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003490 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003491
3492 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003493
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003494 // Check here makes sure that this won't accidentally be
3495 // QCBOR_MAP_OFFSET_CACHE_INVALID which is larger than
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003496 // QCBOR_MAX_DECODE_INPUT_SIZE.
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -08003497 // Cast to uint32_t to possibly address cases where SIZE_MAX < UINT32_MAX
3498 if((uint32_t)uEndOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003499 uReturn = QCBOR_ERR_INPUT_TOO_LARGE;
3500 goto Done;
3501 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003502 /* Cast OK because encoded CBOR is limited to UINT32_MAX */
3503 pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003504
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003505 Done:
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003506 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade11654912024-05-09 11:49:24 -07003507 UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos);
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003508
3509 Done2:
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003510 /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */
Laurence Lundbladec7114722020-08-13 05:11:40 -07003511 for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003512 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003513 pItemArray[i].uDataType = QCBOR_TYPE_NONE;
3514 pItemArray[i].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003515 }
3516 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003517
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003518 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003519}
3520
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003521
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003522/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003523 * Public function, see header qcbor/qcbor_decode.h file
3524 */
3525void
3526QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
3527 int64_t nLabel,
3528 uint8_t uQcborType,
3529 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003530{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003531 if(pMe->uLastError != QCBOR_SUCCESS) {
3532 return;
3533 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003534
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003535 QCBORItem OneItemSeach[2];
3536 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3537 OneItemSeach[0].label.int64 = nLabel;
3538 OneItemSeach[0].uDataType = uQcborType;
3539 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003540
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003541 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003542
3543 *pItem = OneItemSeach[0];
3544
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003545 if(uReturn != QCBOR_SUCCESS) {
3546 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003547 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003548 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003549 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003550 }
3551
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003552 Done:
3553 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003554}
3555
3556
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003557/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003558 * Public function, see header qcbor/qcbor_decode.h file
3559 */
3560void
3561QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
3562 const char *szLabel,
3563 uint8_t uQcborType,
3564 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003565{
Laurence Lundbladeda095972020-06-06 18:35:33 -07003566 if(pMe->uLastError != QCBOR_SUCCESS) {
3567 return;
3568 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003569
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003570#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003571 QCBORItem OneItemSeach[2];
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003572 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3573 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3574 OneItemSeach[0].uDataType = uQcborType;
3575 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003576
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003577 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
3578
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003579 if(uReturn != QCBOR_SUCCESS) {
3580 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003581 }
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003582 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003583 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003584 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003585 }
3586
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003587 *pItem = OneItemSeach[0];
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003588Done:
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003589
3590#else
3591 (void)pMe;
3592 (void)szLabel;
3593 (void)uQcborType;
3594 (void)pItem;
3595 QCBORError uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
3596#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
3597
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003598 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003599}
3600
3601
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003602
3603/**
3604 * @brief Semi-private. Get pointer, length and item for an array or map.
3605 *
3606 * @param[in] pMe The decode context.
3607 * @param[in] uType CBOR major type, either array/map.
3608 * @param[out] pItem The item for the array/map.
3609 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3610 *
3611 * The next item to be decoded must be a map or array as specified by \c uType.
3612 *
3613 * \c pItem will be filled in with the label and tags of the array or map
3614 * in addition to \c pEncodedCBOR giving the pointer and length of the
3615 * encoded CBOR.
3616 *
3617 * When this is complete, the traversal cursor is at the end of the array or
3618 * map that was retrieved.
3619 */
3620void
3621QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe,
3622 const uint8_t uType,
3623 QCBORItem *pItem,
3624 UsefulBufC *pEncodedCBOR)
3625{
3626 QCBORError uErr;
3627 uint8_t uNestLevel;
3628 size_t uStartingCursor;
3629 size_t uStartOfReturned;
3630 size_t uEndOfReturned;
3631 size_t uTempSaveCursor;
3632 bool bInMap;
3633 QCBORItem LabelItem;
3634 bool EndedByBreak;
3635
3636 uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3637 bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting));
3638
3639 /* Could call GetNext here, but don't need to because this
3640 * is only interested in arrays and maps. */
3641 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem);
3642 if(uErr != QCBOR_SUCCESS) {
3643 pMe->uLastError = (uint8_t)uErr;
3644 return;
3645 }
3646
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003647 uint8_t uItemDataType = pItem->uDataType;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003648#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003649 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
3650 uItemDataType = QCBOR_TYPE_ARRAY;
3651 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003652#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003653
3654 if(uItemDataType != uType) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003655 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
3656 return;
3657 }
3658
3659 if(bInMap) {
3660 /* If the item is in a map, the start of the array/map
3661 * itself, not the label, must be found. Do this by
3662 * rewinding to the starting position and fetching
3663 * just the label data item. QCBORDecode_Private_GetNextTagNumber()
3664 * doesn't do any of the array/map item counting or nesting
3665 * level tracking. Used here it will just fetech the label
3666 * data item.
3667 *
3668 * Have to save the cursor and put it back to the position
3669 * after the full item once the label as been fetched by
3670 * itself.
3671 */
3672 uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3673 UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor);
3674
3675 /* Item has been fetched once so safe to ignore error */
3676 (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem);
3677
3678 uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3679 UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor);
3680 } else {
3681 uStartOfReturned = uStartingCursor;
3682 }
3683
3684 /* Consume the entire array/map to find the end */
3685 uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel);
3686 if(uErr != QCBOR_SUCCESS) {
3687 pMe->uLastError = (uint8_t)uErr;
3688 goto Done;
3689 }
3690
3691 /* Fill in returned values */
3692 uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3693 if(EndedByBreak) {
3694 /* When ascending nesting levels, a break for the level above
3695 * was consumed. That break is not a part of what is consumed here. */
3696 uEndOfReturned--;
3697 }
3698 pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned);
3699 pEncodedCBOR->len = uEndOfReturned - uStartOfReturned;
3700
3701Done:
3702 return;
3703}
3704
3705
3706/**
3707 * @brief Semi-private. Get pointer, length and item count of an array or map.
3708 *
3709 * @param[in] pMe The decode context.
3710 * @param[in] pTarget The label and type of the array or map to retrieve.
3711 * @param[out] pItem The item for the array/map.
3712 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3713 *
3714 * The next item to be decoded must be a map or array as specified by \c uType.
3715 *
3716 * When this is complete, the traversal cursor is unchanged.
3717 */void
3718QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe,
3719 QCBORItem *pTarget,
3720 QCBORItem *pItem,
3721 UsefulBufC *pEncodedCBOR)
3722{
3723 MapSearchInfo Info;
3724 QCBORDecodeNesting SaveNesting;
3725 size_t uSaveCursor;
3726
3727 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL);
3728 if(pMe->uLastError != QCBOR_SUCCESS) {
3729 return;
3730 }
3731
3732 /* Save the whole position of things so they can be restored.
3733 * so the cursor position is unchanged by this operation, like
3734 * all the other GetXxxxInMap() operations. */
3735 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3736 uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3737
3738 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3739 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
3740 QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR);
3741
3742 UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor);
3743 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
3744}
3745
3746
3747
3748
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003749/**
3750 * @brief Is a QCBOR_TYPE in the type list?
3751 *
3752 * @param[in] uDataType Type to check for.
3753 * @param[in] puTypeList List to check.
3754 *
3755 * @retval QCBOR_SUCCESS If in the list.
3756 * @retval QCBOR_ERR_UNEXPECTED_TYPE Not in the list.
3757 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07003758static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003759QCBOR_Private_CheckTypeList(const int uDataType,
3760 const uint8_t puTypeList[QCBOR_TAGSPEC_NUM_TYPES])
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003761{
3762 for(size_t i = 0; i < QCBOR_TAGSPEC_NUM_TYPES; i++) {
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003763 if(uDataType == puTypeList[i]) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003764 return QCBOR_SUCCESS;
3765 }
3766 }
3767 return QCBOR_ERR_UNEXPECTED_TYPE;
3768}
3769
Laurence Lundblade67257dc2020-07-27 03:33:37 -07003770
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003771/**
Laurence Lundblade37286c02022-09-03 10:05:02 -07003772 * Match a tag/type specification against the type of the item.
3773 *
3774 * @param[in] TagSpec Specification for matching tags.
3775 * @param[in] pItem The item to check.
3776 *
3777 * @retval QCBOR_SUCCESS \c uDataType is allowed by @c TagSpec
3778 * @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec
3779 *
3780 * This checks the item data type of untagged items as well as of
3781 * tagged items against a specification to see if decoding should
3782 * proceed.
3783 *
3784 * This relies on the automatic tag decoding done by QCBOR that turns
3785 * tag numbers into particular QCBOR_TYPEs so there is no actual
3786 * comparsion of tag numbers, just of QCBOR_TYPEs.
3787 *
3788 * This checks the data item type as possibly representing the tag
3789 * number or as the tag content type.
3790 *
3791 * If QCBOR_DISABLE_TAGS is #defined, this primarily checks the item
3792 * data type against the allowed tag content types. It will also error out
3793 * if the caller tries to require a tag because there is no way that can
3794 * ever be fulfilled.
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003795 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07003796static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003797QCBOR_Private_CheckTagRequirement(const QCBOR_Private_TagSpec TagSpec,
3798 const QCBORItem *pItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07003799{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003800 const int nItemType = pItem->uDataType; /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade37286c02022-09-03 10:05:02 -07003801 const int nTagReq = TagSpec.uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
3802
3803#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003804 /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003805 if(!(TagSpec.uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS) &&
3806 pItem->uTags[0] != CBOR_TAG_INVALID16) {
3807 /* There are tags that QCBOR couldn't process on this item and
Laurence Lundblade37286c02022-09-03 10:05:02 -07003808 * the caller has told us there should not be.
3809 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003810 return QCBOR_ERR_UNEXPECTED_TYPE;
3811 }
3812
Laurence Lundblade9b334962020-08-27 10:55:53 -07003813 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
Laurence Lundblade37286c02022-09-03 10:05:02 -07003814 /* Must match the tag number and only the tag */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003815 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003816 }
3817
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003818 QCBORError uReturn = QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003819 if(uReturn == QCBOR_SUCCESS) {
3820 return QCBOR_SUCCESS;
3821 }
3822
3823 if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
3824 /* Must match the content type and only the content type.
Laurence Lundblade37286c02022-09-03 10:05:02 -07003825 * There was no match just above so it is a fail. */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003826 return QCBOR_ERR_UNEXPECTED_TYPE;
3827 }
3828
Laurence Lundblade37286c02022-09-03 10:05:02 -07003829 /* QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG: If here it can match either the tag or the content
3830 * and it hasn't matched the content, so the end
3831 * result is whether it matches the tag. This is
3832 * the tag optional case that the CBOR standard discourages.
3833 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003834
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003835 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003836
Laurence Lundblade37286c02022-09-03 10:05:02 -07003837#else /* QCBOR_DISABLE_TAGS */
3838 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
3839 return QCBOR_ERR_UNEXPECTED_TYPE;
3840 }
3841
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07003842 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade37286c02022-09-03 10:05:02 -07003843
3844#endif /* QCBOR_DISABLE_TAGS */
3845}
Laurence Lundblade9b334962020-08-27 10:55:53 -07003846
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003847
3848/**
3849 * @brief Get an item by label to match a tag specification.
3850 *
3851 * @param[in] pMe The decode context.
3852 * @param[in] nLabel The label to search map for.
3853 * @param[in] TagSpec The tag number specification to match.
3854 * @param[out] pItem The item found.
3855 *
3856 * This finds the item with the given label in currently open
3857 * map. Then checks that its tag number and types matches the tag
3858 * specification. If not, an error is set in the decode context.
3859 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003860static void
3861QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
3862 const int64_t nLabel,
3863 const QCBOR_Private_TagSpec TagSpec,
3864 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003865{
3866 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
3867 if(pMe->uLastError != QCBOR_SUCCESS) {
3868 return;
3869 }
3870
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003871 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003872}
3873
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07003874
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003875/**
3876 * @brief Get an item by label to match a tag specification.
3877 *
3878 * @param[in] pMe The decode context.
3879 * @param[in] szLabel The label to search map for.
3880 * @param[in] TagSpec The tag number specification to match.
3881 * @param[out] pItem The item found.
3882 *
3883 * This finds the item with the given label in currently open
3884 * map. Then checks that its tag number and types matches the tag
3885 * specification. If not, an error is set in the decode context.
3886 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003887static void
3888QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
3889 const char *szLabel,
3890 const QCBOR_Private_TagSpec TagSpec,
3891 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003892{
3893 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
3894 if(pMe->uLastError != QCBOR_SUCCESS) {
3895 return;
3896 }
3897
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003898 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003899}
3900
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003901
3902/**
3903 * @brief Semi-private to get an string by label to match a tag specification.
3904 *
3905 * @param[in] pMe The decode context.
3906 * @param[in] nLabel The label to search map for.
3907 * @param[in] TagSpec The tag number specification to match.
3908 * @param[out] pString The string found.
3909 *
3910 * This finds the string with the given label in currently open
3911 * map. Then checks that its tag number and types matches the tag
3912 * specification. If not, an error is set in the decode context.
3913 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003914void
3915QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
3916 const int64_t nLabel,
3917 const QCBOR_Private_TagSpec TagSpec,
3918 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003919{
3920 QCBORItem Item;
3921 QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
3922 if(pMe->uLastError == QCBOR_SUCCESS) {
3923 *pString = Item.val.string;
3924 }
3925}
3926
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003927
3928/**
3929 * @brief Semi-private to get an string by label to match a tag specification.
3930 *
3931 * @param[in] pMe The decode context.
3932 * @param[in] szLabel The label to search map for.
3933 * @param[in] TagSpec The tag number specification to match.
3934 * @param[out] pString The string found.
3935 *
3936 * This finds the string with the given label in currently open
3937 * map. Then checks that its tag number and types matches the tag
3938 * specification. If not, an error is set in the decode context.
3939 */void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003940QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
3941 const char * szLabel,
3942 const QCBOR_Private_TagSpec TagSpec,
3943 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003944{
3945 QCBORItem Item;
3946 QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
3947 if(pMe->uLastError == QCBOR_SUCCESS) {
3948 *pString = Item.val.string;
3949 }
3950}
Laurence Lundblade1341c592020-04-11 14:19:05 -07003951
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003952
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003953/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003954 * Public function, see header qcbor/qcbor_decode.h file
3955 */
3956void
3957QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003958{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003959 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL);
Laurence Lundblade5f53f832020-09-03 12:00:14 -07003960 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003961}
3962
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003963/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003964 * Public function, see header qcbor/qcbor_decode.h file
3965 */
3966void
3967QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe,
3968 QCBORItem *pItemList,
3969 void *pCallbackCtx,
3970 QCBORItemCallback pfCB)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003971{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003972 MapSearchCallBack CallBack;
3973 CallBack.pCBContext = pCallbackCtx;
3974 CallBack.pfCallback = pfCB;
3975
3976 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack);
3977
Laurence Lundblade5f53f832020-09-03 12:00:14 -07003978 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003979}
3980
3981
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08003982/**
3983 * @brief Search for a map/array by label and enter it
3984 *
3985 * @param[in] pMe The decode context.
3986 * @param[in] pSearch The map/array to search for.
3987 *
3988 * @c pSearch is expected to contain one item of type map or array
3989 * with the label specified. The current bounded map will be searched for
3990 * this and if found will be entered.
3991 *
3992 * If the label is not found, or the item found is not a map or array,
3993 * the error state is set.
3994 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003995static void
3996QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07003997{
Laurence Lundblade323f8a92020-09-06 19:43:09 -07003998 // The first item in pSearch is the one that is to be
3999 // entered. It should be the only one filled in. Any other
4000 // will be ignored unless it causes an error.
Laurence Lundblade34691b92020-05-18 22:25:25 -07004001 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07004002 return;
4003 }
4004
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004005 MapSearchInfo Info;
4006 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pSearch, &Info, NULL);
Laurence Lundblade34691b92020-05-18 22:25:25 -07004007 if(pMe->uLastError != QCBOR_SUCCESS) {
4008 return;
4009 }
4010
Laurence Lundblade9b334962020-08-27 10:55:53 -07004011 if(pSearch->uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004012 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004013 return;
4014 }
4015
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004016
4017 /* The map or array was found. Now enter it.
4018 *
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004019 * QCBORDecode_EnterBoundedMapOrArray() used here, requires the
4020 * next item for the pre-order traversal cursor to be the map/array
4021 * found by MapSearch(). The next few lines of code force the
4022 * cursor to that.
4023 *
4024 * There is no need to retain the old cursor because
4025 * QCBORDecode_EnterBoundedMapOrArray() will set it to the
4026 * beginning of the map/array being entered.
4027 *
4028 * The cursor is forced by: 1) setting the input buffer position to
4029 * the item offset found by MapSearch(), 2) setting the map/array
4030 * counter to the total in the map/array, 3) setting the nesting
4031 * level. Setting the map/array counter to the total is not
4032 * strictly correct, but this is OK because this cursor only needs
4033 * to be used to get one item and MapSearch() has already found it
4034 * confirming it exists.
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004035 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004036 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004037
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004038 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
4039
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004040 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07004041
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004042 QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004043}
4044
4045
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004046/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004047 * Public function, see header qcbor/qcbor_decode.h file
4048 */
4049void
4050QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004051{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004052 QCBORItem OneItemSeach[2];
4053 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4054 OneItemSeach[0].label.int64 = nLabel;
4055 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4056 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004057
Laurence Lundblade9b334962020-08-27 10:55:53 -07004058 /* The map to enter was found, now finish off entering it. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004059 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004060}
4061
4062
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004063/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004064 * Public function, see header qcbor/qcbor_decode.h file
4065 */
4066void
4067QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004068{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004069#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004070 QCBORItem OneItemSeach[2];
4071 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4072 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4073 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4074 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004075
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004076 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004077#else
4078 (void)szLabel;
4079 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
4080#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004081}
4082
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004083/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004084 * Public function, see header qcbor/qcbor_decode.h file
4085 */
4086void
4087QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07004088{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004089 QCBORItem OneItemSeach[2];
4090 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4091 OneItemSeach[0].label.int64 = nLabel;
4092 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4093 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004094
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004095 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07004096}
4097
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004098/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004099 * Public function, see header qcbor/qcbor_decode.h file
4100 */
4101void
4102QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundblade34691b92020-05-18 22:25:25 -07004103{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004104#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004105 QCBORItem OneItemSeach[2];
4106 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4107 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4108 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4109 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004110
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004111 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004112#else
4113 (void)szLabel;
4114 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
4115#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade1341c592020-04-11 14:19:05 -07004116}
4117
4118
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004119/**
4120 * @brief Semi-private to do the the work for EnterMap() and EnterArray().
4121 *
4122 * @param[in] pMe The decode context
4123 * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY.
4124 * @param[out] pItem The data item for the map or array entered.
4125 *
4126 * The next item in the traversal must be a map or array. This
4127 * consumes that item and does the book keeping to enter the map or
4128 * array.
4129 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004130void
4131QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe,
4132 const uint8_t uType,
4133 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004134{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004135 QCBORError uErr;
4136
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004137 /* Must only be called on maps and arrays. */
Laurence Lundblade34691b92020-05-18 22:25:25 -07004138 if(pMe->uLastError != QCBOR_SUCCESS) {
4139 // Already in error state; do nothing.
4140 return;
4141 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07004142
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004143 /* Get the data item that is the map or array being entered. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004144 QCBORItem Item;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004145 uErr = QCBORDecode_GetNext(pMe, &Item);
4146 if(uErr != QCBOR_SUCCESS) {
4147 goto Done;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07004148 }
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004149
4150 uint8_t uItemDataType = Item.uDataType;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004151
4152#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004153 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) {
4154 uItemDataType = QCBOR_TYPE_ARRAY;
4155 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004156#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
4157
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004158 if(uItemDataType != uType) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004159 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
4160 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004161 }
4162
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004163 QCBORDecode_Private_CopyTags(pMe, &Item);
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004164
4165
Laurence Lundbladef0499502020-08-01 11:55:57 -07004166 const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
Laurence Lundblade085d7952020-07-24 10:26:30 -07004167 if(bIsEmpty) {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004168 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
4169 // Undo decrement done by QCBORDecode_GetNext() so the the
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004170 // the decrement when exiting the map/array works correctly
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004171 pMe->nesting.pCurrent->u.ma.uCountCursor++;
4172 }
Laurence Lundblade93d89472020-10-03 22:30:50 -07004173 // Special case to increment nesting level for zero-length maps
4174 // and arrays entered in bounded mode.
Laurence Lundbladee6f15112020-07-23 18:44:16 -07004175 DecodeNesting_Descend(&(pMe->nesting), uType);
4176 }
4177
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004178 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004179
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004180 uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty,
4181 UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004182
Laurence Lundblade6545d1b2020-10-14 11:13:13 -07004183 if(pItem != NULL) {
4184 *pItem = Item;
4185 }
4186
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004187Done:
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004188 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004189}
4190
Laurence Lundblade02625d42020-06-25 14:41:41 -07004191
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004192/**
4193 * @brief Exit a bounded map, array or bstr (semi-private).
4194 *
4195 * @param[in] pMe Decode context.
4196 * @param[in] uEndOffset The input buffer offset of the end of item exited.
4197 *
4198 * @returns QCBOR_SUCCESS or an error code.
4199 *
4200 * This is the common work for exiting a level that is a bounded map,
4201 * array or bstr wrapped CBOR.
4202 *
4203 * One chunk of work is to set up the pre-order traversal so it is at
4204 * the item just after the bounded map, array or bstr that is being
4205 * exited. This is somewhat complex.
4206 *
4207 * The other work is to level-up the bounded mode to next higest
4208 * bounded mode or the top level if there isn't one.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004209 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004210static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004211QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
4212 const uint32_t uEndOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004213{
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004214 QCBORError uErr;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004215
Laurence Lundblade02625d42020-06-25 14:41:41 -07004216 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004217 * First the pre-order-traversal byte offset is positioned to the
4218 * item just after the bounded mode item that was just consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004219 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004220 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
4221
Laurence Lundblade02625d42020-06-25 14:41:41 -07004222 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004223 * Next, set the current nesting level to one above the bounded
4224 * level that was just exited.
4225 *
4226 * DecodeNesting_CheckBoundedType() is always called before this
4227 * and makes sure pCurrentBounded is valid.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004228 */
4229 DecodeNesting_LevelUpCurrent(&(pMe->nesting));
4230
4231 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004232 * This does the complex work of leveling up the pre-order
4233 * traversal when the end of a map or array or another bounded
4234 * level is reached. It may do nothing, or ascend all the way to
4235 * the top level.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004236 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004237 uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004238 if(uErr != QCBOR_SUCCESS) {
4239 goto Done;
4240 }
4241
Laurence Lundblade02625d42020-06-25 14:41:41 -07004242 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004243 * This makes the next highest bounded level the current bounded
4244 * level. If there is no next highest level, then no bounded mode
4245 * is in effect.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004246 */
4247 DecodeNesting_LevelUpBounded(&(pMe->nesting));
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004248
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004249 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004250
4251Done:
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004252 return uErr;
4253}
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004254
Laurence Lundblade02625d42020-06-25 14:41:41 -07004255
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004256/**
4257 * @brief Get started exiting a map or array (semi-private)
4258 *
4259 * @param[in] pMe The decode context
4260 * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP
4261 *
4262 * This does some work for map and array exiting (but not
4263 * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel()
4264 * is called to do the rest.
4265 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004266void
4267QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe,
4268 const uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004269{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004270 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07004271 /* Already in error state; do nothing. */
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004272 return;
4273 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004274
Laurence Lundblade02625d42020-06-25 14:41:41 -07004275 QCBORError uErr;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004276
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004277 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004278 uErr = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004279 goto Done;
4280 }
4281
Laurence Lundblade02625d42020-06-25 14:41:41 -07004282 /*
4283 Have to set the offset to the end of the map/array
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004284 that is being exited. If there is no cached value,
Laurence Lundblade02625d42020-06-25 14:41:41 -07004285 from previous map search, then do a dummy search.
4286 */
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004287 if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004288 QCBORItem Dummy;
4289 Dummy.uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004290 uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL);
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004291 if(uErr != QCBOR_SUCCESS) {
4292 goto Done;
4293 }
4294 }
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004295
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004296 uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004297
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004298Done:
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004299 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004300}
4301
4302
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004303/**
4304 * @brief The main work of entering some byte-string wrapped CBOR.
4305 *
4306 * @param[in] pMe The decode context.
4307 * @param[in] pItem The byte string item.
4308 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX
4309 * @param[out] pBstr Pointer and length of byte string entered.
4310 *
4311 * This is called once the byte string item has been decoded to do all
4312 * the book keeping work for descending a nesting level into the
4313 * nested CBOR.
4314 *
4315 * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement.
4316 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004317static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004318QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe,
4319 const QCBORItem *pItem,
4320 const uint8_t uTagRequirement,
4321 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004322{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004323 if(pBstr) {
4324 *pBstr = NULLUsefulBufC;
4325 }
4326
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004327 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004328 /* Already in error state; do nothing. */
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004329 return pMe->uLastError;
4330 }
4331
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004332 QCBORError uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004333
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004334 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004335 {
4336 uTagRequirement,
4337 {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE},
4338 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4339 };
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004340
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004341 uError = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004342 if(uError != QCBOR_SUCCESS) {
4343 goto Done;
4344 }
4345
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004346 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004347 /* Reverse the decrement done by GetNext() for the bstr so the
4348 * increment in QCBORDecode_NestLevelAscender() called by
4349 * ExitBoundedLevel() will work right.
4350 */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004351 DecodeNesting_ReverseDecrement(&(pMe->nesting));
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07004352 }
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004353
4354 if(pBstr) {
4355 *pBstr = pItem->val.string;
4356 }
4357
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004358 /* This saves the current length of the UsefulInputBuf and then
4359 * narrows the UsefulInputBuf to start and length of the wrapped
4360 * CBOR that is being entered.
4361 *
4362 * Most of these calls are simple inline accessors so this doesn't
4363 * amount to much code.
4364 */
4365
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004366 const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004367 /* This check makes the cast of uPreviousLength to uint32_t below safe. */
4368 if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004369 uError = QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladef76a2622020-08-06 19:51:03 -07004370 goto Done;
4371 }
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004372
4373 const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
4374 pItem->val.string.ptr);
4375 /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
4376 if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
4377 /* This should never happen because pItem->val.string.ptr should
4378 * always be valid since it was just returned.
4379 */
4380 uError = QCBOR_ERR_INPUT_TOO_LARGE;
4381 goto Done;
4382 }
4383
4384 const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
4385
4386 UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004387 UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004388
Laurence Lundblade02625d42020-06-25 14:41:41 -07004389 uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004390 (uint32_t)uPreviousLength,
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004391 (uint32_t)uStartOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004392Done:
4393 return uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004394}
4395
4396
Laurence Lundblade02625d42020-06-25 14:41:41 -07004397/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004398 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004399 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004400void
4401QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe,
4402 const uint8_t uTagRequirement,
4403 UsefulBufC *pBstr)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004404{
4405 if(pMe->uLastError != QCBOR_SUCCESS) {
4406 // Already in error state; do nothing.
4407 return;
4408 }
4409
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004410 /* Get the data item that is the byte string being entered */
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004411 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004412 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4413 if(pMe->uLastError != QCBOR_SUCCESS) {
4414 return;
4415 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004416
Laurence Lundblade31fddb72024-05-13 13:03:35 -07004417 if(Item.uDataAlloc) {
4418 pMe->uLastError = QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
4419 return;
4420 }
4421
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004422 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4423 &Item,
4424 uTagRequirement,
4425 pBstr);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004426}
4427
4428
Laurence Lundblade02625d42020-06-25 14:41:41 -07004429/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004430 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004431 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004432void
4433QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe,
4434 const int64_t nLabel,
4435 const uint8_t uTagRequirement,
4436 UsefulBufC *pBstr)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004437{
4438 QCBORItem Item;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004439 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004440
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004441 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4442 &Item,
4443 uTagRequirement,
4444 pBstr);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004445}
4446
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004447
Laurence Lundblade02625d42020-06-25 14:41:41 -07004448/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004449 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004450 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004451void
4452QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe,
4453 const char *szLabel,
4454 const uint8_t uTagRequirement,
4455 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004456{
4457 QCBORItem Item;
4458 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4459
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004460 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4461 &Item,
4462 uTagRequirement,
4463 pBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004464}
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004465
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004466
Laurence Lundblade02625d42020-06-25 14:41:41 -07004467/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004468 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004469 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004470void
4471QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004472{
Laurence Lundblade02625d42020-06-25 14:41:41 -07004473 if(pMe->uLastError != QCBOR_SUCCESS) {
4474 // Already in error state; do nothing.
4475 return;
4476 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004477
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004478 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004479 pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade02625d42020-06-25 14:41:41 -07004480 return;
4481 }
4482
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004483 const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
4484
Laurence Lundblade02625d42020-06-25 14:41:41 -07004485 /*
4486 Reset the length of the UsefulInputBuf to what it was before
4487 the bstr wrapped CBOR was entered.
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004488 */
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004489 UsefulInputBuf_SetBufferLength(&(pMe->InBuf),
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004490 DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004491
4492
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004493 QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004494 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004495}
4496
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004497
Laurence Lundbladee6430642020-03-14 21:15:44 -07004498
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004499/**
4500 * @brief Process simple type true and false, a boolean
4501 *
4502 * @param[in] pMe The decode context.
4503 * @param[in] pItem The item with either true or false.
4504 * @param[out] pBool The boolean value output.
4505 *
4506 * Sets the internal error if the item isn't a true or a false. Also
4507 * records any tag numbers as the tag numbers of the last item.
4508 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004509static void
4510QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe,
4511 const QCBORItem *pItem,
4512 bool *pBool)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004513{
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004514 if(pMe->uLastError != QCBOR_SUCCESS) {
4515 /* Already in error state, do nothing */
4516 return;
4517 }
4518
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004519 switch(pItem->uDataType) {
4520 case QCBOR_TYPE_TRUE:
4521 *pBool = true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004522 break;
4523
4524 case QCBOR_TYPE_FALSE:
4525 *pBool = false;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004526 break;
4527
4528 default:
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004529 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004530 break;
4531 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004532 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004533}
Laurence Lundbladee6430642020-03-14 21:15:44 -07004534
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004535
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004536/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004537 * Public function, see header qcbor/qcbor_decode.h file
4538 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004539void
4540QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004541{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004542 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004543 /* Already in error state, do nothing */
Laurence Lundbladee6430642020-03-14 21:15:44 -07004544 return;
4545 }
4546
Laurence Lundbladec4537442020-04-14 18:53:22 -07004547 QCBORItem Item;
4548
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004549 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4550
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004551 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004552}
4553
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004554
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004555/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004556 * Public function, see header qcbor/qcbor_decode.h file
4557 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004558void
4559QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe,
4560 const int64_t nLabel,
4561 bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004562{
4563 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004564 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004565
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004566 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004567}
4568
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004569
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004570/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004571 * Public function, see header qcbor/qcbor_decode.h file
4572 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004573void
4574QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe,
4575 const char *szLabel,
4576 bool *pValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004577{
4578 QCBORItem Item;
4579 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4580
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004581 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004582}
4583
4584
Laurence Lundblade3888f002024-06-12 21:20:56 -07004585/**
4586 * @brief Process simple values.
4587 *
4588 * @param[in] pMe The decode context.
4589 * @param[in] pItem The item with the simple value.
4590 * @param[out] puSimple The simple value output.
4591 *
4592 * Sets the internal error if the item isn't a true or a false. Also
4593 * records any tag numbers as the tag numbers of the last item.
4594 */
4595static void
4596QCBORDecode_Private_ProcessSimple(QCBORDecodeContext *pMe,
4597 const QCBORItem *pItem,
4598 uint8_t *puSimple)
4599{
4600 if(pMe->uLastError != QCBOR_SUCCESS) {
4601 return;
4602 }
4603
4604 /* It's kind of lame to remap true...undef back to simple values, but
4605 * this function isn't used much and to not do it would require
4606 * changing GetNext() behavior in an incompatible way.
4607 */
4608 switch(pItem->uDataType) {
4609 case QCBOR_TYPE_UKNOWN_SIMPLE:
4610 *puSimple = pItem->val.uSimple;
4611 break;
4612
4613 case QCBOR_TYPE_TRUE:
4614 *puSimple = CBOR_SIMPLEV_TRUE;
4615 break;
4616
4617 case QCBOR_TYPE_FALSE:
4618 *puSimple = CBOR_SIMPLEV_FALSE;
4619 break;
4620
4621 case QCBOR_TYPE_NULL:
4622 *puSimple = CBOR_SIMPLEV_NULL;
4623 break;
4624
4625 case QCBOR_TYPE_UNDEF:
4626 *puSimple = CBOR_SIMPLEV_UNDEF;
4627 break;
4628
4629 default:
4630 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4631 return;
4632 }
4633 QCBORDecode_Private_CopyTags(pMe, pItem);
4634}
4635
4636/*
4637 * Public function, see header qcbor/qcbor_decode.h file
4638 */
4639void
4640QCBORDecode_GetSimple(QCBORDecodeContext *pMe, uint8_t *puSimple)
4641{
4642 QCBORItem Item;
4643
4644 QCBORDecode_VGetNext(pMe, &Item);
4645 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimple);
4646}
4647
4648/*
4649 * Public function, see header qcbor/qcbor_decode.h file
4650 */
4651void
4652QCBORDecode_GetSimpleInMapN(QCBORDecodeContext *pMe,
4653 int64_t nLabel,
4654 uint8_t *puSimpleValue)
4655{
4656 QCBORItem Item;
4657 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
4658
4659 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
4660}
4661
4662/*
4663 * Public function, see header qcbor/qcbor_decode.h file
4664 */
4665void
4666QCBORDecode_GetSimpleInMapSZ(QCBORDecodeContext *pMe,
4667 const char *szLabel,
4668 uint8_t *puSimpleValue)
4669{
4670 QCBORItem Item;
4671 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4672
4673 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
4674}
4675
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004676
Laurence Lundbladec7114722020-08-13 05:11:40 -07004677
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004678/**
4679 * @brief Common processing for an epoch date.
4680 *
4681 * @param[in] pMe The decode context.
4682 * @param[in] pItem The item with the date.
4683 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4684 * @param[out] pnTime The returned date.
4685 *
4686 * Common processing for the date tag. Mostly make sure the tag
4687 * content is correct and copy forward any further other tag numbers.
4688 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004689static void
4690QCBORDecode_Private_ProcessEpochDate(QCBORDecodeContext *pMe,
4691 QCBORItem *pItem,
4692 const uint8_t uTagRequirement,
4693 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004694{
4695 if(pMe->uLastError != QCBOR_SUCCESS) {
4696 // Already in error state, do nothing
4697 return;
4698 }
4699
4700 QCBORError uErr;
4701
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004702 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladec7114722020-08-13 05:11:40 -07004703 {
4704 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004705 {QCBOR_TYPE_DATE_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4706 {QCBOR_TYPE_INT64, QCBOR_TYPE_DOUBLE, QCBOR_TYPE_FLOAT, QCBOR_TYPE_UINT64}
Laurence Lundbladec7114722020-08-13 05:11:40 -07004707 };
4708
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004709 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004710 if(uErr != QCBOR_SUCCESS) {
4711 goto Done;
4712 }
4713
4714 if(pItem->uDataType != QCBOR_TYPE_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004715 uErr = QCBOR_Private_DecodeDateEpoch(pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004716 if(uErr != QCBOR_SUCCESS) {
4717 goto Done;
4718 }
4719 }
4720
Laurence Lundblade9b334962020-08-27 10:55:53 -07004721 // Save the tags in the last item's tags in the decode context
4722 // for QCBORDecode_GetNthTagOfLast()
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004723 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07004724
Laurence Lundbladec7114722020-08-13 05:11:40 -07004725 *pnTime = pItem->val.epochDate.nSeconds;
4726
4727Done:
4728 pMe->uLastError = (uint8_t)uErr;
4729}
4730
4731
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004732
4733/*
4734 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4735 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004736void
4737QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
4738 uint8_t uTagRequirement,
4739 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004740{
4741 if(pMe->uLastError != QCBOR_SUCCESS) {
4742 // Already in error state, do nothing
4743 return;
4744 }
4745
4746 QCBORItem Item;
4747 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4748
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004749 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004750}
4751
4752
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004753/*
4754 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4755 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07004756void
4757QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
4758 int64_t nLabel,
4759 uint8_t uTagRequirement,
4760 int64_t *pnTime)
4761{
4762 QCBORItem Item;
4763 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004764 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004765}
4766
4767
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004768/*
4769 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4770 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07004771void
4772QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
4773 const char *szLabel,
4774 uint8_t uTagRequirement,
4775 int64_t *pnTime)
4776{
4777 QCBORItem Item;
4778 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004779 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004780}
4781
4782
4783
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004784/**
4785 * @brief Common processing for an epoch date.
4786 *
4787 * @param[in] pMe The decode context.
4788 * @param[in] pItem The item with the date.
4789 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4790 * @param[out] pnDays The returned day count.
4791 *
4792 * Common processing for the RFC 8943 day-count tag. Mostly make sure
4793 * the tag content is correct and copy forward any further other tag
4794 * numbers.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004795 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004796static void
4797QCBORDecode_Private_ProcessEpochDays(QCBORDecodeContext *pMe,
4798 QCBORItem *pItem,
4799 uint8_t uTagRequirement,
4800 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004801{
4802 if(pMe->uLastError != QCBOR_SUCCESS) {
4803 /* Already in error state, do nothing */
4804 return;
4805 }
4806
4807 QCBORError uErr;
4808
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004809 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004810 {
4811 uTagRequirement,
4812 {QCBOR_TYPE_DAYS_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4813 {QCBOR_TYPE_INT64, QCBOR_TYPE_UINT64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4814 };
4815
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004816 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004817 if(uErr != QCBOR_SUCCESS) {
4818 goto Done;
4819 }
4820
4821 if(pItem->uDataType != QCBOR_TYPE_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004822 uErr = QCBOR_Private_DecodeDaysEpoch(pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004823 if(uErr != QCBOR_SUCCESS) {
4824 goto Done;
4825 }
4826 }
4827
4828 /* Save the tags in the last item's tags in the decode context
4829 * for QCBORDecode_GetNthTagOfLast()
4830 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004831 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004832
4833 *pnDays = pItem->val.epochDays;
4834
4835Done:
4836 pMe->uLastError = (uint8_t)uErr;
4837}
4838
4839
4840/*
4841 * Public function, see header qcbor/qcbor_decode.h
4842 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004843void
4844QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe,
4845 uint8_t uTagRequirement,
4846 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004847{
4848 if(pMe->uLastError != QCBOR_SUCCESS) {
4849 /* Already in error state, do nothing */
4850 return;
4851 }
4852
4853 QCBORItem Item;
4854 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4855
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004856 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004857}
4858
4859
4860/*
4861 * Public function, see header qcbor/qcbor_decode.h
4862 */
4863void
4864QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe,
4865 int64_t nLabel,
4866 uint8_t uTagRequirement,
4867 int64_t *pnDays)
4868{
4869 QCBORItem Item;
4870 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004871 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004872}
4873
4874
4875/*
4876 * Public function, see header qcbor/qcbor_decode.h
4877 */
4878void
4879QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe,
4880 const char *szLabel,
4881 uint8_t uTagRequirement,
4882 int64_t *pnDays)
4883{
4884 QCBORItem Item;
4885 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004886 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004887}
4888
4889
4890
Laurence Lundblade37286c02022-09-03 10:05:02 -07004891/*
4892 * @brief Get a string that matches the type/tag specification.
4893 */
4894void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004895QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
4896 const QCBOR_Private_TagSpec TagSpec,
4897 UsefulBufC *pBstr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004898{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004899 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade37286c02022-09-03 10:05:02 -07004900 /* Already in error state, do nothing */
Laurence Lundbladec4537442020-04-14 18:53:22 -07004901 return;
4902 }
4903
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004904 QCBORError uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004905 QCBORItem Item;
4906
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004907 uError = QCBORDecode_GetNext(pMe, &Item);
4908 if(uError != QCBOR_SUCCESS) {
4909 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004910 return;
4911 }
4912
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004913 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004914
4915 if(pMe->uLastError == QCBOR_SUCCESS) {
4916 *pBstr = Item.val.string;
Laurence Lundbladeab40c6f2020-08-28 11:24:58 -07004917 } else {
4918 *pBstr = NULLUsefulBufC;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004919 }
4920}
4921
Laurence Lundbladec4537442020-04-14 18:53:22 -07004922
4923
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004924
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004925/**
4926 * @brief Common processing for a big number tag.
4927 *
4928 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4929 * @param[in] pItem The item with the date.
4930 * @param[out] pValue The returned big number
4931 * @param[out] pbIsNegative The returned sign of the big number.
4932 *
4933 * Common processing for the big number tag. Mostly make sure
4934 * the tag content is correct and copy forward any further other tag
4935 * numbers.
4936 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004937static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004938QCBOR_Private_ProcessBigNum(const uint8_t uTagRequirement,
4939 const QCBORItem *pItem,
4940 UsefulBufC *pValue,
4941 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004942{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004943 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004944 {
4945 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004946 {QCBOR_TYPE_POSBIGNUM, QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4947 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004948 };
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004949
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004950 QCBORError uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004951 if(uErr != QCBOR_SUCCESS) {
4952 return uErr;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004953 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004954
4955 *pValue = pItem->val.string;
4956
4957 if(pItem->uDataType == QCBOR_TYPE_POSBIGNUM) {
4958 *pbIsNegative = false;
4959 } else if(pItem->uDataType == QCBOR_TYPE_NEGBIGNUM) {
4960 *pbIsNegative = true;
4961 }
4962
4963 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004964}
4965
4966
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004967/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004968 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004969 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004970void
4971QCBORDecode_GetBignum(QCBORDecodeContext *pMe,
4972 const uint8_t uTagRequirement,
4973 UsefulBufC *pValue,
4974 bool *pbIsNegative)
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004975{
4976 if(pMe->uLastError != QCBOR_SUCCESS) {
4977 // Already in error state, do nothing
4978 return;
4979 }
4980
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004981 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004982 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
4983 if(uError != QCBOR_SUCCESS) {
4984 pMe->uLastError = (uint8_t)uError;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004985 return;
4986 }
4987
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004988 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4989 &Item,
4990 pValue,
4991 pbIsNegative);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004992}
4993
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004994
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004995/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004996 * Public function, see header qcbor/qcbor_spiffy_decode.h
4997 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004998void
4999QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe,
5000 const int64_t nLabel,
5001 const uint8_t uTagRequirement,
5002 UsefulBufC *pValue,
5003 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005004{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005005 QCBORItem Item;
5006 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005007 if(pMe->uLastError != QCBOR_SUCCESS) {
5008 return;
5009 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005010
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005011 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
5012 &Item,
5013 pValue,
5014 pbIsNegative);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005015}
5016
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005017
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005018/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005019 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005020 */
5021void
5022QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe,
5023 const char *szLabel,
5024 const uint8_t uTagRequirement,
5025 UsefulBufC *pValue,
5026 bool *pbIsNegative)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005027{
5028 QCBORItem Item;
5029 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005030 if(pMe->uLastError != QCBOR_SUCCESS) {
5031 return;
5032 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005033
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005034 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
5035 &Item,
5036 pValue,
5037 pbIsNegative);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005038}
5039
5040
5041
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005042/**
5043 * @brief Common processing for MIME tag (semi-private).
5044 *
5045 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
5046 * @param[in] pItem The item with the date.
5047 * @param[out] pMessage The returned MIME message.
5048 * @param[out] pbIsTag257 If true, binary MIME, if not, text MIME.
5049 *
5050 * Common processing for the MIME tag. Mostly make sure the tag
5051 * content is correct and copy forward any further other tag
5052 * numbers. See QCBORDecode_GetMIMEMessage().
5053 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07005054QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005055QCBORDecode_Private_GetMIME(const uint8_t uTagRequirement,
Laurence Lundblade37286c02022-09-03 10:05:02 -07005056 const QCBORItem *pItem,
5057 UsefulBufC *pMessage,
5058 bool *pbIsTag257)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005059{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005060 const QCBOR_Private_TagSpec TagSpecText =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005061 {
5062 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07005063 {QCBOR_TYPE_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
5064 {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005065 };
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005066 const QCBOR_Private_TagSpec TagSpecBinary =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005067 {
5068 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07005069 {QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
5070 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005071 };
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005072
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005073 QCBORError uReturn;
Laurence Lundblade9b334962020-08-27 10:55:53 -07005074
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005075 if(QCBOR_Private_CheckTagRequirement(TagSpecText, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005076 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07005077 if(pbIsTag257 != NULL) {
5078 *pbIsTag257 = false;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005079 }
5080 uReturn = QCBOR_SUCCESS;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005081 } else if(QCBOR_Private_CheckTagRequirement(TagSpecBinary, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005082 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07005083 if(pbIsTag257 != NULL) {
5084 *pbIsTag257 = true;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005085 }
5086 uReturn = QCBOR_SUCCESS;
5087
5088 } else {
5089 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
5090 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07005091
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005092 return uReturn;
5093}
5094
Laurence Lundblade93d89472020-10-03 22:30:50 -07005095// Improvement: add methods for wrapped CBOR, a simple alternate
5096// to EnterBstrWrapped
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005097
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005098
5099
5100
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005101#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundbladee6430642020-03-14 21:15:44 -07005102
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005103/**
5104 * @brief Prototype for conversion of exponent and mantissa to unsigned integer.
5105 *
5106 * @param[in] uMantissa The mantissa.
5107 * @param[in] nExponent The exponent.
5108 * @param[out] puResult The resulting integer.
5109 *
5110 * Concrete implementations of this are for exponent base 10 and 2 supporting
5111 * decimal fractions and big floats.
5112 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005113typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005114
5115
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005116/**
5117 * @brief Base 10 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5118 *
5119 * @param[in] uMantissa The unsigned integer mantissa.
5120 * @param[in] nExponent The signed integer exponent.
5121 * @param[out] puResult Place to return the unsigned integer result.
5122 *
5123 * This computes: mantissa * 10 ^^ exponent as for a decimal fraction. The output is a 64-bit
5124 * unsigned integer.
5125 *
5126 * There are many inputs for which the result will not fit in the
5127 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5128 * be returned.
5129 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005130static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005131QCBOR_Private_Exponentitate10(const uint64_t uMantissa,
5132 int64_t nExponent,
5133 uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005134{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005135 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005136
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005137 if(uResult != 0) {
5138 /* This loop will run a maximum of 19 times because
5139 * UINT64_MAX < 10 ^^ 19. More than that will cause
5140 * exit with the overflow error
5141 */
5142 for(; nExponent > 0; nExponent--) {
5143 if(uResult > UINT64_MAX / 10) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005144 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005145 }
5146 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005147 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005148
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005149 for(; nExponent < 0; nExponent++) {
5150 uResult = uResult / 10;
5151 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005152 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005153 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005154 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005155 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005156 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07005157
5158 *puResult = uResult;
5159
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005160 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005161}
5162
5163
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005164/**
5165 * @brief Base 2 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5166 *
5167 * @param[in] uMantissa The unsigned integer mantissa.
5168 * @param[in] nExponent The signed integer exponent.
5169 * @param[out] puResult Place to return the unsigned integer result.
5170 *
5171 * This computes: mantissa * 2 ^^ exponent as for a big float. The
5172 * output is a 64-bit unsigned integer.
5173 *
5174 * There are many inputs for which the result will not fit in the
5175 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5176 * be returned.
5177 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005178static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005179QCBOR_Private_Exponentitate2(const uint64_t uMantissa,
5180 int64_t nExponent,
5181 uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005182{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005183 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005184
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005185 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005186
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005187 /* This loop will run a maximum of 64 times because INT64_MAX <
5188 * 2^31. More than that will cause exit with the overflow error
Laurence Lundbladee6430642020-03-14 21:15:44 -07005189 */
5190 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005191 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005192 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005193 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005194 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005195 nExponent--;
5196 }
5197
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005198 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005199 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005200 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005201 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005202 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005203 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005204 }
5205
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005206 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005207
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005208 return QCBOR_SUCCESS;
5209}
5210
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005211
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005212/**
5213 * @brief Exponentiate a signed mantissa and signed exponent to produce a signed result.
5214 *
5215 * @param[in] nMantissa Signed integer mantissa.
5216 * @param[in] nExponent Signed integer exponent.
5217 * @param[out] pnResult Place to put the signed integer result.
5218 * @param[in] pfExp Exponentiation function.
5219 *
5220 * @returns Error code
5221 *
5222 * \c pfExp performs exponentiation on and unsigned mantissa and
5223 * produces an unsigned result. This converts the mantissa from signed
5224 * and converts the result to signed. The exponentiation function is
5225 * either for base 2 or base 10 (and could be other if needed).
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005226 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005227static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005228QCBOR_Private_ExponentiateNN(const int64_t nMantissa,
5229 const int64_t nExponent,
5230 int64_t *pnResult,
5231 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005232{
5233 uint64_t uResult;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005234 uint64_t uMantissa;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005235
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005236 /* Take the absolute value and put it into an unsigned. */
5237 if(nMantissa >= 0) {
5238 /* Positive case is straightforward */
5239 uMantissa = (uint64_t)nMantissa;
5240 } else if(nMantissa != INT64_MIN) {
5241 /* The common negative case. See next. */
5242 uMantissa = (uint64_t)-nMantissa;
5243 } else {
5244 /* int64_t and uint64_t are always two's complement per the
5245 * C standard (and since QCBOR uses these it only works with
5246 * two's complement, which is pretty much universal these
5247 * days). The range of a negative two's complement integer is
5248 * one more that than a positive, so the simple code above might
5249 * not work all the time because you can't simply negate the
5250 * value INT64_MIN because it can't be represented in an
5251 * int64_t. -INT64_MIN can however be represented in a
5252 * uint64_t. Some compilers seem to recognize this case for the
5253 * above code and put the correct value in uMantissa, however
5254 * they are not required to do this by the C standard. This next
5255 * line does however work for all compilers.
5256 *
5257 * This does assume two's complement where -INT64_MIN ==
5258 * INT64_MAX + 1 (which wouldn't be true for one's complement or
5259 * sign and magnitude (but we know we're using two's complement
5260 * because int64_t requires it)).
5261 *
5262 * See these, particularly the detailed commentary:
5263 * https://stackoverflow.com/questions/54915742/does-c99-mandate-a-int64-t-type-be-available-always
5264 * https://stackoverflow.com/questions/37301078/is-negating-int-min-undefined-behaviour
5265 */
5266 uMantissa = (uint64_t)INT64_MAX+1;
5267 }
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005268
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005269 /* Call the exponentiator passed for either base 2 or base 10.
5270 * Here is where most of the overflow errors are caught. */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005271 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
5272 if(uReturn) {
5273 return uReturn;
5274 }
5275
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005276 /* Convert back to the sign of the original mantissa */
5277 if(nMantissa >= 0) {
5278 if(uResult > INT64_MAX) {
5279 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5280 }
5281 *pnResult = (int64_t)uResult;
5282 } else {
5283 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
5284 * of INT64_MIN. This assumes two's compliment representation
5285 * where INT64_MIN is one increment farther from 0 than
5286 * INT64_MAX. Trying to write -INT64_MIN doesn't work to get
5287 * this because the compiler makes it an int64_t which can't
5288 * represent -INT64_MIN. Also see above.
5289 */
5290 if(uResult > (uint64_t)INT64_MAX+1) {
5291 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5292 }
5293 *pnResult = -(int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005294 }
5295
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005296 return QCBOR_SUCCESS;
5297}
5298
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005299
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005300/**
5301 * @brief Exponentiate an unsigned mantissa and signed exponent to produce an unsigned result.
5302 *
5303 * @param[in] nMantissa Signed integer mantissa.
5304 * @param[in] nExponent Signed integer exponent.
5305 * @param[out] puResult Place to put the signed integer result.
5306 * @param[in] pfExp Exponentiation function.
5307 *
5308 * @returns Error code
5309 *
5310 * \c pfExp performs exponentiation on and unsigned mantissa and
5311 * produces an unsigned result. This errors out if the mantissa
5312 * is negative because the output is unsigned.
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005313 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005314static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005315QCBOR_Private_ExponentitateNU(const int64_t nMantissa,
5316 const int64_t nExponent,
5317 uint64_t *puResult,
5318 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005319{
5320 if(nMantissa < 0) {
5321 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5322 }
5323
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005324 /* Cast to unsigned is OK because of check for negative.
5325 * Cast to unsigned is OK because UINT64_MAX > INT64_MAX.
5326 * Exponentiation is straight forward
5327 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005328 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
5329}
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005330
5331
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005332/**
5333 * @brief Exponentiate an usnigned mantissa and unsigned exponent to produce an unsigned result.
5334 *
5335 * @param[in] uMantissa Unsigned integer mantissa.
5336 * @param[in] nExponent Unsigned integer exponent.
5337 * @param[out] puResult Place to put the unsigned integer result.
5338 * @param[in] pfExp Exponentiation function.
5339 *
5340 * @returns Error code
5341 *
5342 * \c pfExp performs exponentiation on and unsigned mantissa and
5343 * produces an unsigned result so this is just a wrapper that does
5344 * nothing (and is likely inlined).
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005345 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005346static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005347QCBOR_Private_ExponentitateUU(const uint64_t uMantissa,
5348 const int64_t nExponent,
5349 uint64_t *puResult,
5350 fExponentiator pfExp)
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005351{
5352 return (*pfExp)(uMantissa, nExponent, puResult);
5353}
5354
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005355#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005356
5357
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005358
5359
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005360/**
5361 * @brief Convert a CBOR big number to a uint64_t.
5362 *
5363 * @param[in] BigNum Bytes of the big number to convert.
5364 * @param[in] uMax Maximum value allowed for the result.
5365 * @param[out] pResult Place to put the unsigned integer result.
5366 *
5367 * @returns Error code
5368 *
5369 * Many values will overflow because a big num can represent a much
5370 * larger range than uint64_t.
5371 */
5372static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005373QCBOR_Private_ConvertBigNumToUnsigned(const UsefulBufC BigNum,
5374 const uint64_t uMax,
5375 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005376{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005377 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005378
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005379 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005380 const uint8_t *pByte = BigNum.ptr;
5381 size_t uLen = BigNum.len;
5382 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07005383 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005384 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005385 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07005386 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005387 }
5388
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005389 *pResult = uResult;
5390 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005391}
5392
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005393
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005394/**
5395 * @brief Convert a CBOR postive big number to a uint64_t.
5396 *
5397 * @param[in] BigNum Bytes of the big number to convert.
5398 * @param[out] pResult Place to put the unsigned integer result.
5399 *
5400 * @returns Error code
5401 *
5402 * Many values will overflow because a big num can represent a much
5403 * larger range than uint64_t.
5404 */
5405static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005406QCBOR_Private_ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum,
5407 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005408{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005409 return QCBOR_Private_ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005410}
5411
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005412
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005413/**
5414 * @brief Convert a CBOR positive big number to an int64_t.
5415 *
5416 * @param[in] BigNum Bytes of the big number to convert.
5417 * @param[out] pResult Place to put the signed integer result.
5418 *
5419 * @returns Error code
5420 *
5421 * Many values will overflow because a big num can represent a much
5422 * larger range than int64_t.
5423 */
5424static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005425QCBOR_Private_ConvertPositiveBigNumToSigned(const UsefulBufC BigNum,
5426 int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005427{
5428 uint64_t uResult;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005429 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5430 INT64_MAX,
5431 &uResult);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005432 if(uError) {
5433 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005434 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005435 /* Cast is safe because ConvertBigNumToUnsigned limits to INT64_MAX */
Laurence Lundbladee6430642020-03-14 21:15:44 -07005436 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005437 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005438}
5439
5440
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005441/**
5442 * @brief Convert a CBOR negative big number to an int64_t.
5443 *
5444 * @param[in] BigNum Bytes of the big number to convert.
5445 * @param[out] pnResult Place to put the signed integer result.
5446 *
5447 * @returns Error code
5448 *
5449 * Many values will overflow because a big num can represent a much
5450 * larger range than int64_t.
5451 */
5452static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005453QCBOR_Private_ConvertNegativeBigNumToSigned(const UsefulBufC BigNum,
5454 int64_t *pnResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005455{
5456 uint64_t uResult;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005457 /* The negative integer furthest from zero for a C int64_t is
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005458 * INT64_MIN which is expressed as -INT64_MAX - 1. The value of a
5459 * negative number in CBOR is computed as -n - 1 where n is the
5460 * encoded integer, where n is what is in the variable BigNum. When
5461 * converting BigNum to a uint64_t, the maximum value is thus
5462 * INT64_MAX, so that when it -n - 1 is applied to it the result
5463 * will never be further from 0 than INT64_MIN.
5464 *
5465 * -n - 1 <= INT64_MIN.
5466 * -n - 1 <= -INT64_MAX - 1
5467 * n <= INT64_MAX.
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005468 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005469 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5470 INT64_MAX,
5471 &uResult);
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005472 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005473 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005474 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005475
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005476 /* Now apply -n - 1. The cast is safe because
5477 * ConvertBigNumToUnsigned() is limited to INT64_MAX which does fit
5478 * is the largest positive integer that an int64_t can
5479 * represent. */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005480 *pnResult = -(int64_t)uResult - 1;
5481
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005482 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005483}
5484
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005485
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005486
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005487
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005488/**
5489 * @brief Convert integers and floats to an int64_t.
5490 *
5491 * @param[in] pItem The item to convert.
5492 * @param[in] uConvertTypes Bit mask list of conversion options.
5493 * @param[out] pnValue The resulting converted value.
5494 *
5495 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5496 * in uConvertTypes.
5497 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5498 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5499 * or too small.
5500 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005501static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005502QCBOR_Private_ConvertInt64(const QCBORItem *pItem,
5503 const uint32_t uConvertTypes,
5504 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005505{
5506 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005507 case QCBOR_TYPE_FLOAT:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005508 case QCBOR_TYPE_DOUBLE:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005509#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005510 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005511 /* https://pubs.opengroup.org/onlinepubs/009695399/functions/llround.html
5512 http://www.cplusplus.com/reference/cmath/llround/
5513 */
5514 // Not interested in FE_INEXACT
5515 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005516 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5517 *pnValue = llround(pItem->val.dfnum);
5518 } else {
5519 *pnValue = lroundf(pItem->val.fnum);
5520 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005521 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5522 // llround() shouldn't result in divide by zero, but catch
5523 // it here in case it unexpectedly does. Don't try to
5524 // distinguish between the various exceptions because it seems
5525 // they vary by CPU, compiler and OS.
5526 return QCBOR_ERR_FLOAT_EXCEPTION;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005527 }
5528 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005529 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005530 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005531#else
5532 return QCBOR_ERR_HW_FLOAT_DISABLED;
5533#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005534 break;
5535
5536 case QCBOR_TYPE_INT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005537 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005538 *pnValue = pItem->val.int64;
5539 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005540 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005541 }
5542 break;
5543
5544 case QCBOR_TYPE_UINT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005545 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005546 if(pItem->val.uint64 < INT64_MAX) {
5547 *pnValue = pItem->val.int64;
5548 } else {
5549 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5550 }
5551 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005552 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005553 }
5554 break;
5555
Laurence Lundblade2d493002024-02-01 11:09:17 -07005556 case QCBOR_TYPE_65BIT_NEG_INT:
5557 /* This type occurs if the value won't fit into int64_t
5558 * so this is always an error. */
5559 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5560 break;
5561
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005562 default:
5563 return QCBOR_ERR_UNEXPECTED_TYPE;
5564 }
5565 return QCBOR_SUCCESS;
5566}
5567
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005568
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005569/**
5570 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5571 *
5572 * @param[in] pMe The decode context.
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_GetInt64Convert().
5578 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005579void
5580QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pMe,
5581 uint32_t uConvertTypes,
5582 int64_t *pnValue,
5583 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005584{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07005585 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005586 return;
5587 }
5588
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005589 QCBORError uError = QCBORDecode_GetNext(pMe, pItem);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005590 if(uError) {
5591 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005592 return;
5593 }
5594
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005595 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005596 uConvertTypes,
5597 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005598}
5599
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005600/**
5601 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5602 *
5603 * @param[in] pMe The decode context.
5604 * @param[in] nLabel Label to find in map.
5605 * @param[in] uConvertTypes Bit mask list of conversion options.
5606 * @param[out] pnValue Result of the conversion.
5607 * @param[in,out] pItem Temporary space to store Item, returned item.
5608 *
5609 * See QCBORDecode_GetInt64ConvertInMapN().
5610 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005611void
5612QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pMe,
5613 int64_t nLabel,
5614 uint32_t uConvertTypes,
5615 int64_t *pnValue,
5616 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005617{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005618 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005619 if(pMe->uLastError != QCBOR_SUCCESS) {
5620 return;
5621 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005622
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005623 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5624 uConvertTypes,
5625 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005626}
5627
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005628/**
5629 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5630 *
5631 * @param[in] pMe The decode context.
5632 * @param[in] szLabel Label to find in map.
5633 * @param[in] uConvertTypes Bit mask list of conversion options.
5634 * @param[out] pnValue Result of the conversion.
5635 * @param[in,out] pItem Temporary space to store Item, returned item.
5636 *
5637 * See QCBORDecode_GetInt64ConvertInMapSZ().
5638 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005639void
5640QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5641 const char * szLabel,
5642 uint32_t uConvertTypes,
5643 int64_t *pnValue,
5644 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005645{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005646 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005647 if(pMe->uLastError != QCBOR_SUCCESS) {
5648 return;
5649 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005650
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005651 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5652 uConvertTypes,
5653 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005654}
5655
5656
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005657/**
5658 * @brief Convert many number types to an int64_t.
5659 *
5660 * @param[in] pItem The item to convert.
5661 * @param[in] uConvertTypes Bit mask list of conversion options.
5662 * @param[out] pnValue The resulting converted value.
5663 *
5664 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5665 * in uConvertTypes.
5666 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5667 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5668 * or too small.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005669 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005670static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005671QCBOR_Private_Int64ConvertAll(const QCBORItem *pItem,
5672 const uint32_t uConvertTypes,
5673 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005674{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005675 switch(pItem->uDataType) {
5676
5677 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005678 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005679 return QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005680 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005681 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005682 }
5683 break;
5684
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005685 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005686 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005687 return QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005688 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005689 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005690 }
5691 break;
5692
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005693#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005694 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005695 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005696 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005697 pItem->val.expAndMantissa.nExponent,
5698 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005699 &QCBOR_Private_Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005700 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005701 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005702 }
5703 break;
5704
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005705 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005706 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005707 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005708 pItem->val.expAndMantissa.nExponent,
5709 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005710 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005711 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005712 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005713 }
5714 break;
5715
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005716 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005717 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005718 int64_t nMantissa;
5719 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005720 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005721 if(uErr) {
5722 return uErr;
5723 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005724 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005725 pItem->val.expAndMantissa.nExponent,
5726 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005727 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005728 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005729 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005730 }
5731 break;
5732
5733 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005734 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005735 int64_t nMantissa;
5736 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005737 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005738 if(uErr) {
5739 return uErr;
5740 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005741 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005742 pItem->val.expAndMantissa.nExponent,
5743 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005744 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005745 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005746 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005747 }
5748 break;
5749
5750 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005751 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005752 int64_t nMantissa;
5753 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005754 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005755 if(uErr) {
5756 return uErr;
5757 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005758 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005759 pItem->val.expAndMantissa.nExponent,
5760 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005761 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005762 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005763 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005764 }
5765 break;
5766
5767 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005768 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005769 int64_t nMantissa;
5770 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005771 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005772 if(uErr) {
5773 return uErr;
5774 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005775 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005776 pItem->val.expAndMantissa.nExponent,
5777 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005778 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005779 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005780 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005781 }
5782 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005783#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005784
Laurence Lundbladee6430642020-03-14 21:15:44 -07005785
Laurence Lundbladec4537442020-04-14 18:53:22 -07005786 default:
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005787 return QCBOR_ERR_UNEXPECTED_TYPE; }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005788}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005789
5790
Laurence Lundbladec4537442020-04-14 18:53:22 -07005791/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005792 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005793 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005794void
5795QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe,
5796 const uint32_t uConvertTypes,
5797 int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005798{
5799 QCBORItem Item;
5800
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005801 QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005802
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005803 if(pMe->uLastError == QCBOR_SUCCESS) {
5804 // The above conversion succeeded
5805 return;
5806 }
5807
Laurence Lundbladef6c86662020-05-12 02:08:00 -07005808 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005809 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07005810 return;
5811 }
5812
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005813 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5814 uConvertTypes,
5815 pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005816}
5817
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005818
5819/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005820 * Public function, see header qcbor/qcbor_decode.h file
5821 */
5822void
5823QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
5824 const int64_t nLabel,
5825 const uint32_t uConvertTypes,
5826 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005827{
5828 QCBORItem Item;
5829
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005830 QCBORDecode_Private_GetInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07005831 nLabel,
5832 uConvertTypes,
5833 pnValue,
5834 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005835
5836 if(pMe->uLastError == QCBOR_SUCCESS) {
5837 // The above conversion succeeded
5838 return;
5839 }
5840
5841 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5842 // The above conversion failed in a way that code below can't correct
5843 return;
5844 }
5845
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005846 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5847 uConvertTypes,
5848 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005849}
5850
5851
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005852/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005853 * Public function, see header qcbor/qcbor_decode.h file
5854 */
5855void
5856QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
5857 const char *szLabel,
5858 const uint32_t uConvertTypes,
5859 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005860{
5861 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005862 QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07005863 szLabel,
5864 uConvertTypes,
5865 pnValue,
5866 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005867
5868 if(pMe->uLastError == QCBOR_SUCCESS) {
5869 // The above conversion succeeded
5870 return;
5871 }
5872
5873 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5874 // The above conversion failed in a way that code below can't correct
5875 return;
5876 }
5877
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005878 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5879 uConvertTypes,
5880 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005881}
5882
5883
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005884/**
5885 * @brief Convert many number types to an uint64_t.
5886 *
5887 * @param[in] pItem The item to convert.
5888 * @param[in] uConvertTypes Bit mask list of conversion options.
5889 * @param[out] puValue The resulting converted value.
5890 *
5891 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5892 * in uConvertTypes.
5893 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5894 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5895 * or too small.
5896 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005897static QCBORError
5898QCBOR_Private_ConvertUInt64(const QCBORItem *pItem,
5899 const uint32_t uConvertTypes,
5900 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005901{
5902 switch(pItem->uDataType) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005903 case QCBOR_TYPE_DOUBLE:
5904 case QCBOR_TYPE_FLOAT:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005905#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005906 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005907 // Can't use llround here because it will not convert values
5908 // greater than INT64_MAX and less than UINT64_MAX that
5909 // need to be converted so it is more complicated.
5910 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
5911 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5912 if(isnan(pItem->val.dfnum)) {
5913 return QCBOR_ERR_FLOAT_EXCEPTION;
5914 } else if(pItem->val.dfnum < 0) {
5915 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5916 } else {
5917 double dRounded = round(pItem->val.dfnum);
5918 // See discussion in DecodeDateEpoch() for
5919 // explanation of - 0x7ff
5920 if(dRounded > (double)(UINT64_MAX- 0x7ff)) {
5921 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5922 }
5923 *puValue = (uint64_t)dRounded;
5924 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005925 } else {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005926 if(isnan(pItem->val.fnum)) {
5927 return QCBOR_ERR_FLOAT_EXCEPTION;
5928 } else if(pItem->val.fnum < 0) {
5929 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5930 } else {
5931 float fRounded = roundf(pItem->val.fnum);
5932 // See discussion in DecodeDateEpoch() for
5933 // explanation of - 0x7ff
5934 if(fRounded > (float)(UINT64_MAX- 0x7ff)) {
5935 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5936 }
5937 *puValue = (uint64_t)fRounded;
5938 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005939 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005940 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5941 // round() and roundf() shouldn't result in exceptions here, but
5942 // catch them to be robust and thorough. Don't try to
5943 // distinguish between the various exceptions because it seems
5944 // they vary by CPU, compiler and OS.
5945 return QCBOR_ERR_FLOAT_EXCEPTION;
5946 }
5947
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005948 } else {
5949 return QCBOR_ERR_UNEXPECTED_TYPE;
5950 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005951#else
5952 return QCBOR_ERR_HW_FLOAT_DISABLED;
5953#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005954 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005955
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005956 case QCBOR_TYPE_INT64:
5957 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
5958 if(pItem->val.int64 >= 0) {
5959 *puValue = (uint64_t)pItem->val.int64;
5960 } else {
5961 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5962 }
5963 } else {
5964 return QCBOR_ERR_UNEXPECTED_TYPE;
5965 }
5966 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005967
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005968 case QCBOR_TYPE_UINT64:
5969 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade2d493002024-02-01 11:09:17 -07005970 *puValue = pItem->val.uint64;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005971 } else {
5972 return QCBOR_ERR_UNEXPECTED_TYPE;
5973 }
5974 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005975
Laurence Lundblade2d493002024-02-01 11:09:17 -07005976 case QCBOR_TYPE_65BIT_NEG_INT:
5977 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5978
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005979 default:
5980 return QCBOR_ERR_UNEXPECTED_TYPE;
5981 }
5982
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005983 return QCBOR_SUCCESS;
5984}
Laurence Lundbladec4537442020-04-14 18:53:22 -07005985
5986
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005987/**
5988 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5989 *
5990 * @param[in] pMe The decode context.
5991 * @param[in] uConvertTypes Bit mask list of conversion options.
5992 * @param[out] puValue Result of the conversion.
5993 * @param[in,out] pItem Temporary space to store Item, returned item.
5994 *
5995 * See QCBORDecode_GetUInt64Convert().
5996 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005997void
5998QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pMe,
5999 const uint32_t uConvertTypes,
6000 uint64_t *puValue,
6001 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07006002{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006003 if(pMe->uLastError != QCBOR_SUCCESS) {
6004 return;
6005 }
6006
Laurence Lundbladec4537442020-04-14 18:53:22 -07006007 QCBORItem Item;
Laurence Lundbladec4537442020-04-14 18:53:22 -07006008
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07006009 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
6010 if(uError) {
6011 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07006012 return;
6013 }
6014
Laurence Lundbladea826c502020-05-10 21:07:00 -07006015 if(pItem) {
6016 *pItem = Item;
6017 }
6018
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006019 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(&Item,
6020 uConvertTypes,
6021 puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07006022}
6023
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006024
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006025/**
6026 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
6027 *
6028 * @param[in] pMe The decode context.
6029 * @param[in] nLabel Label to find in map.
6030 * @param[in] uConvertTypes Bit mask list of conversion options.
6031 * @param[out] puValue Result of the conversion.
6032 * @param[in,out] pItem Temporary space to store Item, returned item.
6033 *
6034 * See QCBORDecode_GetUInt64ConvertInMapN().
6035 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006036void
6037QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe,
6038 const int64_t nLabel,
6039 const uint32_t uConvertTypes,
6040 uint64_t *puValue,
6041 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006042{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006043 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006044 if(pMe->uLastError != QCBOR_SUCCESS) {
6045 return;
6046 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006047
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006048 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
6049 uConvertTypes,
6050 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006051}
6052
6053
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006054/**
6055 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
6056 *
6057 * @param[in] pMe The decode context.
6058 * @param[in] szLabel Label to find in map.
6059 * @param[in] uConvertTypes Bit mask list of conversion options.
6060 * @param[out] puValue Result of the conversion.
6061 * @param[in,out] pItem Temporary space to store Item, returned item.
6062 *
6063 * See QCBORDecode_GetUInt64ConvertInMapSZ().
6064 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006065void
6066QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
6067 const char *szLabel,
6068 const uint32_t uConvertTypes,
6069 uint64_t *puValue,
6070 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006071{
6072 if(pMe->uLastError != QCBOR_SUCCESS) {
6073 return;
6074 }
6075
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006076 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006077 if(pMe->uLastError != QCBOR_SUCCESS) {
6078 return;
6079 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006080
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006081 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
6082 uConvertTypes,
6083 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006084}
6085
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006086
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006087/**
6088 * @brief Convert many number types to an unt64_t.
6089 *
6090 * @param[in] pItem The item to convert.
6091 * @param[in] uConvertTypes Bit mask list of conversion options.
6092 * @param[out] puValue The resulting converted value.
6093 *
6094 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6095 * in uConvertTypes.
6096 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6097 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6098 * or too small.
6099 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006100static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006101QCBOR_Private_UInt64ConvertAll(const QCBORItem *pItem,
6102 const uint32_t uConvertTypes,
6103 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006104{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08006105 switch(pItem->uDataType) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006106
6107 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006108 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006109 return QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006110 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006111 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006112 }
6113 break;
6114
6115 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006116 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006117 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6118 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006119 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006120 }
6121 break;
6122
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006123#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006124
6125 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006126 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006127 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006128 pItem->val.expAndMantissa.nExponent,
6129 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006130 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006131 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006132 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006133 }
6134 break;
6135
6136 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006137 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006138 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006139 pItem->val.expAndMantissa.nExponent,
6140 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006141 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006142 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006143 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006144 }
6145 break;
6146
6147 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006148 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006149 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006150 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006151 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006152 if(uErr != QCBOR_SUCCESS) {
6153 return uErr;
6154 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006155 return QCBOR_Private_ExponentitateUU(uMantissa,
6156 pItem->val.expAndMantissa.nExponent,
6157 puValue,
6158 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006159 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006160 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006161 }
6162 break;
6163
6164 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006165 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006166 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6167 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006168 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006169 }
6170 break;
6171
6172 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006173 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006174 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006175 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006176 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum,
6177 &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006178 if(uErr != QCBOR_SUCCESS) {
6179 return uErr;
6180 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006181 return QCBOR_Private_ExponentitateUU(uMantissa,
6182 pItem->val.expAndMantissa.nExponent,
6183 puValue,
6184 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006185 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006186 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006187 }
6188 break;
6189
6190 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006191 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006192 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6193 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006194 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006195 }
6196 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006197#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006198 default:
6199 return QCBOR_ERR_UNEXPECTED_TYPE;
6200 }
6201}
6202
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006203
Laurence Lundblade4e2da002020-06-13 23:08:31 -07006204/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006205 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006206 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006207void
6208QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe,
6209 const uint32_t uConvertTypes,
6210 uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006211{
6212 QCBORItem Item;
6213
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006214 QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006215
Laurence Lundbladef6c86662020-05-12 02:08:00 -07006216 if(pMe->uLastError == QCBOR_SUCCESS) {
6217 // The above conversion succeeded
6218 return;
6219 }
6220
6221 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6222 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07006223 return;
6224 }
6225
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006226 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6227 uConvertTypes,
6228 puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006229}
6230
Laurence Lundbladec4537442020-04-14 18:53:22 -07006231
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006232/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006233 * Public function, see header qcbor/qcbor_decode.h file
6234 */
6235void
6236QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
6237 const int64_t nLabel,
6238 const uint32_t uConvertTypes,
6239 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006240{
6241 QCBORItem Item;
6242
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006243 QCBORDecode_Private_GetUInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006244 nLabel,
6245 uConvertTypes,
6246 puValue,
6247 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006248
6249 if(pMe->uLastError == QCBOR_SUCCESS) {
6250 // The above conversion succeeded
6251 return;
6252 }
6253
6254 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6255 // The above conversion failed in a way that code below can't correct
6256 return;
6257 }
6258
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006259 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6260 uConvertTypes,
6261 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006262}
6263
6264
6265/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006266 * Public function, see header qcbor/qcbor_decode.h file
6267 */
6268void
6269QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
6270 const char *szLabel,
6271 const uint32_t uConvertTypes,
6272 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006273{
6274 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006275 QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006276 szLabel,
6277 uConvertTypes,
6278 puValue,
6279 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006280
6281 if(pMe->uLastError == QCBOR_SUCCESS) {
6282 // The above conversion succeeded
6283 return;
6284 }
6285
6286 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6287 // The above conversion failed in a way that code below can't correct
6288 return;
6289 }
6290
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006291 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6292 uConvertTypes,
6293 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006294}
6295
6296
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006297
6298
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006299#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006300/**
6301 * @brief Basic conversions to a double.
6302 *
6303 * @param[in] pItem The item to convert
6304 * @param[in] uConvertTypes Bit flags indicating source types for conversion
6305 * @param[out] pdValue The value converted to a double
6306 *
6307 * This does the conversions that don't need much object code,
6308 * the conversions from int, uint and float to double.
6309 *
6310 * See QCBOR_Private_DoubleConvertAll() for the full set
6311 * of conversions.
6312 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006313static QCBORError
6314QCBOR_Private_ConvertDouble(const QCBORItem *pItem,
6315 const uint32_t uConvertTypes,
6316 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006317{
6318 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006319 case QCBOR_TYPE_FLOAT:
6320#ifndef QCBOR_DISABLE_FLOAT_HW_USE
6321 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6322 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006323 // Simple cast does the job.
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006324 *pdValue = (double)pItem->val.fnum;
6325 } else {
6326 return QCBOR_ERR_UNEXPECTED_TYPE;
6327 }
6328 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006329#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006330 return QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006331#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006332 break;
6333
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006334 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006335 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6336 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006337 *pdValue = pItem->val.dfnum;
6338 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006339 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006340 }
6341 }
6342 break;
6343
6344 case QCBOR_TYPE_INT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006345#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006346 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006347 // A simple cast seems to do the job with no worry of exceptions.
6348 // There will be precision loss for some values.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006349 *pdValue = (double)pItem->val.int64;
6350
6351 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006352 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006353 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006354#else
6355 return QCBOR_ERR_HW_FLOAT_DISABLED;
6356#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006357 break;
6358
6359 case QCBOR_TYPE_UINT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006360#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006361 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006362 // A simple cast seems to do the job with no worry of exceptions.
6363 // There will be precision loss for some values.
6364 *pdValue = (double)pItem->val.uint64;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006365 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006366 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006367 }
6368 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006369#else
6370 return QCBOR_ERR_HW_FLOAT_DISABLED;
6371#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006372
Laurence Lundblade2d493002024-02-01 11:09:17 -07006373 case QCBOR_TYPE_65BIT_NEG_INT:
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -08006374#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade2d493002024-02-01 11:09:17 -07006375 *pdValue = -(double)pItem->val.uint64 - 1;
6376 break;
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -08006377#else
6378 return QCBOR_ERR_HW_FLOAT_DISABLED;
6379#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade2d493002024-02-01 11:09:17 -07006380
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006381 default:
6382 return QCBOR_ERR_UNEXPECTED_TYPE;
6383 }
6384
6385 return QCBOR_SUCCESS;
6386}
6387
6388
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006389/**
6390 * @brief Almost-public method to decode a number and convert to double (semi-private).
6391 *
6392 * @param[in] pMe The decode context.
6393 * @param[in] uConvertTypes Bit mask list of conversion options
6394 * @param[out] pdValue The output of the conversion.
6395 * @param[in,out] pItem Temporary space to store Item, returned item.
6396 *
6397 * See QCBORDecode_GetDoubleConvert().
6398 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006399void
6400QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pMe,
6401 const uint32_t uConvertTypes,
6402 double *pdValue,
6403 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07006404{
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006405 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07006406 return;
6407 }
6408
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006409 QCBORError uError = QCBORDecode_GetNext(pMe, pItem);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006410 if(uError) {
6411 pMe->uLastError = (uint8_t)uError;
6412 return;
6413 }
6414
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006415 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006416 uConvertTypes,
6417 pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006418}
Laurence Lundbladec4537442020-04-14 18:53:22 -07006419
Laurence Lundbladec4537442020-04-14 18:53:22 -07006420
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006421/**
6422 * @brief Almost-public method to decode a number and convert to double (semi-private).
6423 *
6424 * @param[in] pMe The decode context.
6425 * @param[in] nLabel Label to find in map.
6426 * @param[in] uConvertTypes Bit mask list of conversion options
6427 * @param[out] pdValue The output of the conversion.
6428 * @param[in,out] pItem Temporary space to store Item, returned item.
6429 *
6430 * See QCBORDecode_GetDoubleConvertInMapN().
6431 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006432void
6433QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pMe,
6434 const int64_t nLabel,
6435 const uint32_t uConvertTypes,
6436 double *pdValue,
6437 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006438{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006439 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006440 if(pMe->uLastError != QCBOR_SUCCESS) {
6441 return;
6442 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006443
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006444 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6445 uConvertTypes,
6446 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006447}
6448
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006449
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006450/**
6451 * @brief Almost-public method to decode a number and convert to double (semi-private).
6452 *
6453 * @param[in] pMe The decode context.
6454 * @param[in] szLabel Label to find in map.
6455 * @param[in] uConvertTypes Bit mask list of conversion options
6456 * @param[out] pdValue The output of the conversion.
6457 * @param[in,out] pItem Temporary space to store Item, returned item.
6458 *
6459 * See QCBORDecode_GetDoubleConvertInMapSZ().
6460 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006461void
6462QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe,
6463 const char *szLabel,
6464 const uint32_t uConvertTypes,
6465 double *pdValue,
6466 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006467{
6468 if(pMe->uLastError != QCBOR_SUCCESS) {
6469 return;
6470 }
6471
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006472 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006473 if(pMe->uLastError != QCBOR_SUCCESS) {
6474 return;
6475 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006476
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006477 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6478 uConvertTypes,
6479 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006480}
6481
6482
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006483#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006484/**
6485 * @brief Convert a big number to double-precision float.
6486 *
6487 * @param[in] BigNum The big number to convert
6488 *
6489 * @returns The double value.
6490 *
6491 * This will always succeed. It will lose precision for larger
6492 * numbers. If the big number is too large to fit (more than
6493 * 1.7976931348623157E+308) infinity will be returned. NaN is never
6494 * returned.
6495 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006496static double
6497QCBOR_Private_ConvertBigNumToDouble(const UsefulBufC BigNum)
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006498{
6499 double dResult;
6500
6501 dResult = 0.0;
6502 const uint8_t *pByte = BigNum.ptr;
6503 size_t uLen = BigNum.len;
6504 /* This will overflow and become the float value INFINITY if the number
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006505 * is too large to fit. */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006506 while(uLen--) {
6507 dResult = (dResult * 256.0) + (double)*pByte++;
6508 }
6509
6510 return dResult;
6511}
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006512#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6513
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006514
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006515
6516
6517/**
6518 * @brief Convert many number types to a double.
6519 *
6520 * @param[in] pItem The item to convert.
6521 * @param[in] uConvertTypes Bit mask list of conversion options.
6522 * @param[out] pdValue The resulting converted value.
6523 *
6524 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6525 * in uConvertTypes.
6526 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6527 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6528 * or too small.
6529 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006530static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006531QCBOR_Private_DoubleConvertAll(const QCBORItem *pItem,
6532 const uint32_t uConvertTypes,
6533 double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006534{
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006535#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07006536 /*
Laurence Lundblade16a207a2021-09-18 17:22:46 -07006537 * What Every Computer Scientist Should Know About Floating-Point Arithmetic
6538 * https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
6539 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006540 switch(pItem->uDataType) {
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006541
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006542#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006543 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006544 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006545 // Underflow gives 0, overflow gives infinity
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006546 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6547 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
6548 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006549 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006550 }
6551 break;
6552
6553 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006554 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006555 // Underflow gives 0, overflow gives infinity
6556 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6557 exp2((double)pItem->val.expAndMantissa.nExponent);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006558 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006559 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006560 }
6561 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006562#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006563
6564 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006565 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006566 *pdValue = QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006567 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006568 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006569 }
6570 break;
6571
6572 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006573 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006574 *pdValue = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006575 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006576 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006577 }
6578 break;
6579
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006580#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006581 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006582 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006583 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006584 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6585 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006586 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006587 }
6588 break;
6589
6590 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006591 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006592 double dMantissa = -QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006593 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6594 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006595 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006596 }
6597 break;
6598
6599 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006600 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006601 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006602 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6603 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006604 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006605 }
6606 break;
6607
6608 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006609 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006610 double dMantissa = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006611 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6612 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006613 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006614 }
6615 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006616#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006617
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006618 default:
6619 return QCBOR_ERR_UNEXPECTED_TYPE;
6620 }
6621
6622 return QCBOR_SUCCESS;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006623
6624#else
6625 (void)pItem;
6626 (void)uConvertTypes;
6627 (void)pdValue;
6628 return QCBOR_ERR_HW_FLOAT_DISABLED;
6629#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6630
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006631}
6632
6633
6634/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006635 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006636 */
6637void
6638QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe,
6639 const uint32_t uConvertTypes,
6640 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006641{
6642
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006643 QCBORItem Item;
6644
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006645 QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006646
6647 if(pMe->uLastError == QCBOR_SUCCESS) {
6648 // The above conversion succeeded
6649 return;
6650 }
6651
6652 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6653 // The above conversion failed in a way that code below can't correct
6654 return;
6655 }
6656
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006657 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6658 uConvertTypes,
6659 pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006660}
6661
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006662
6663/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006664 * Public function, see header qcbor/qcbor_decode.h file
6665 */
6666void
6667QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe,
6668 const int64_t nLabel,
6669 const uint32_t uConvertTypes,
6670 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006671{
6672 QCBORItem Item;
6673
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006674 QCBORDecode_Private_GetDoubleConvertInMapN(pMe,
6675 nLabel,
6676 uConvertTypes,
6677 pdValue,
6678 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006679
6680 if(pMe->uLastError == QCBOR_SUCCESS) {
6681 // The above conversion succeeded
6682 return;
6683 }
6684
6685 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6686 // The above conversion failed in a way that code below can't correct
6687 return;
6688 }
6689
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006690 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6691 uConvertTypes,
6692 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006693}
6694
6695
6696/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006697 * Public function, see header qcbor/qcbor_decode.h file
6698 */
6699void
6700QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe,
6701 const char *szLabel,
6702 const uint32_t uConvertTypes,
6703 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006704{
6705 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006706 QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe,
6707 szLabel,
6708 uConvertTypes,
6709 pdValue,
6710 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006711
6712 if(pMe->uLastError == QCBOR_SUCCESS) {
6713 // The above conversion succeeded
6714 return;
6715 }
6716
6717 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6718 // The above conversion failed in a way that code below can't correct
6719 return;
6720 }
6721
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006722 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6723 uConvertTypes,
6724 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006725}
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006726#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006727
6728
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006729
6730
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006731#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006732/**
6733 * @brief Convert an integer to a big number
6734 *
6735 * @param[in] uInt The integer to convert.
6736 * @param[in] Buffer The buffer to output the big number to.
6737 *
6738 * @returns The big number or NULLUsefulBufC is the buffer is to small.
6739 *
6740 * This always succeeds unless the buffer is too small.
6741 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006742static UsefulBufC
6743QCBOR_Private_ConvertIntToBigNum(uint64_t uInt, const UsefulBuf Buffer)
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006744{
6745 while((uInt & 0xff00000000000000UL) == 0) {
6746 uInt = uInt << 8;
6747 };
6748
6749 UsefulOutBuf UOB;
6750
6751 UsefulOutBuf_Init(&UOB, Buffer);
6752
6753 while(uInt) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006754 UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff00000000000000UL) >> 56));
6755 uInt = uInt << 8;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006756 }
6757
6758 return UsefulOutBuf_OutUBuf(&UOB);
6759}
6760
6761
Laurence Lundblade37286c02022-09-03 10:05:02 -07006762/**
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006763 * @brief Check and/or complete exponent and mantissa item.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006764 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006765 * @param[in] pMe The decoder context.
6766 * @param[in] TagSpec Expected type(s).
6767 * @param[in,out] pItem See below.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006768 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006769 * This is for decimal fractions and big floats, both of which are an
6770 * exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006771 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006772 * If the item item had a tag number indicating it was a
6773 * decimal fraction or big float, then the input @c pItem will
6774 * have been decoded as exponent and mantissa. If there was
6775 * no tag number, the caller is asking this be decoded as a
6776 * big float or decimal fraction and @c pItem just has the
6777 * first item in an exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006778 *
6779 * On output, the item is always a fully decoded decimal fraction or
6780 * big float.
6781 *
6782 * This errors out if the input type does not meet the TagSpec.
6783 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07006784static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006785QCBOR_Private_ExpMantissaTypeHandler(QCBORDecodeContext *pMe,
6786 const QCBOR_Private_TagSpec TagSpec,
6787 QCBORItem *pItem)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006788{
6789 QCBORError uErr;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006790
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006791 /* pItem could either be a decoded exponent and mantissa or
6792 * the opening array of an undecoded exponent and mantissa. This
Laurence Lundblade37286c02022-09-03 10:05:02 -07006793 * check will succeed on either, but doesn't say which it was.
6794 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006795 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07006796 if(uErr != QCBOR_SUCCESS) {
6797 goto Done;
6798 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006799
Laurence Lundblade37286c02022-09-03 10:05:02 -07006800 if(pItem->uDataType == QCBOR_TYPE_ARRAY) {
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006801 /* The item is an array, which means is is an undecoded exponent
6802 * and mantissa. This call consumes the items in the array and
6803 * results in a decoded exponent and mantissa in pItem. This is
Laurence Lundblade37286c02022-09-03 10:05:02 -07006804 * the case where there was no tag.
6805 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006806 uErr = QCBORDecode_Private_ExpMantissa(pMe, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006807 if(uErr != QCBOR_SUCCESS) {
6808 goto Done;
6809 }
6810
Laurence Lundblade37286c02022-09-03 10:05:02 -07006811 /* The above decode didn't determine whether it is a decimal
6812 * fraction or big num. Which of these two depends on what the
6813 * caller wants it decoded as since there is no tag, so fish the
6814 * type out of the TagSpec. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006815 pItem->uDataType = QCBOR_Private_ExpMantissaDataType(TagSpec.uTaggedTypes[0], pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07006816
6817 /* No need to check the type again. All that we need to know was
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006818 * that it decoded correctly as a exponent and mantissa. The
Laurence Lundblade37286c02022-09-03 10:05:02 -07006819 * QCBOR type is set out by what was requested.
6820 */
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006821 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07006822
6823 /* If the item was not an array and the check passed, then
6824 * it is a fully decoded big float or decimal fraction and
6825 * matches what is requested.
6826 */
6827
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006828Done:
6829 return uErr;
6830}
6831
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006832
Laurence Lundblade37286c02022-09-03 10:05:02 -07006833/* Some notes from the work to disable tags.
6834 *
6835 * The API for big floats and decimal fractions seems good.
6836 * If there's any issue with it it's that the code size to
6837 * implement is a bit large because of the conversion
6838 * to/from int and bignum that is required. There is no API
6839 * that doesn't do the conversion so dead stripping will never
6840 * leave that code out.
6841 *
6842 * The implementation itself seems correct, but not as clean
6843 * and neat as it could be. It could probably be smaller too.
6844 *
6845 * The implementation has three main parts / functions
6846 * - The decoding of the array of two
6847 * - All the tag and type checking for the various API functions
6848 * - Conversion to/from bignum and int
6849 *
6850 * The type checking seems like it wastes the most code for
6851 * what it needs to do.
6852 *
6853 * The inlining for the conversion is probably making the
6854 * overall code base larger.
6855 *
6856 * The tests cases could be organized a lot better and be
6857 * more thorough.
6858 *
6859 * Seems also like there could be more common code in the
6860 * first tier part of the public API. Some functions only
6861 * vary by a TagSpec.
6862 */
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006863
6864/**
6865 * @brief Common processor for exponent and mantissa.
6866 *
6867 * @param[in] pMe The decode context.
6868 * @param[in] TagSpec The expected/allowed tags.
6869 * @param[in] pItem The data item to process.
6870 * @param[out] pnMantissa The returned mantissa as an int64_t.
6871 * @param[out] pnExponent The returned exponent as an int64_t.
6872 *
6873 * This handles exponent and mantissa for base 2 and 10. This
6874 * is limited to a mantissa that is an int64_t. See also
6875 * QCBORDecode_Private_ProcessExpMantissaBig().
6876 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006877static void
6878QCBOR_Private_ProcessExpMantissa(QCBORDecodeContext *pMe,
6879 const QCBOR_Private_TagSpec TagSpec,
6880 QCBORItem *pItem,
6881 int64_t *pnMantissa,
6882 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006883{
6884 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006885
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006886 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006887 if(uErr != QCBOR_SUCCESS) {
6888 goto Done;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006889 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006890
Laurence Lundblade9b334962020-08-27 10:55:53 -07006891 switch (pItem->uDataType) {
6892
6893 case QCBOR_TYPE_DECIMAL_FRACTION:
6894 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade9b334962020-08-27 10:55:53 -07006895 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006896 *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
Laurence Lundblade9b334962020-08-27 10:55:53 -07006897 break;
6898
Laurence Lundblade37286c02022-09-03 10:05:02 -07006899#ifndef QCBOR_DISABLE_TAGS
6900 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006901 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
6902 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
6903 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006904 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006905 break;
6906
6907 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
6908 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
6909 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006910 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006911 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006912#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006913
6914 default:
6915 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
6916 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006917
6918 Done:
6919 pMe->uLastError = (uint8_t)uErr;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006920}
6921
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006922
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006923/**
6924 * @brief Decode exponent and mantissa into a big number.
6925 *
6926 * @param[in] pMe The decode context.
6927 * @param[in] TagSpec The expected/allowed tags.
6928 * @param[in] pItem Item to decode and convert.
6929 * @param[in] BufferForMantissa Buffer to output mantissa into.
6930 * @param[out] pMantissa The output mantissa.
6931 * @param[out] pbIsNegative The sign of the output.
6932 * @param[out] pnExponent The mantissa of the output.
6933 *
6934 * This is the common processing of a decimal fraction or a big float
6935 * into a big number. This will decode and consume all the CBOR items
6936 * that make up the decimal fraction or big float.
6937 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006938static void
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006939QCBORDecode_Private_ProcessExpMantissaBig(QCBORDecodeContext *pMe,
6940 const QCBOR_Private_TagSpec TagSpec,
6941 QCBORItem *pItem,
6942 const UsefulBuf BufferForMantissa,
6943 UsefulBufC *pMantissa,
6944 bool *pbIsNegative,
6945 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006946{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006947 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006948
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006949 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006950 if(uErr != QCBOR_SUCCESS) {
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006951 goto Done;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006952 }
6953
6954 uint64_t uMantissa;
6955
6956 switch (pItem->uDataType) {
6957
6958 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006959 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006960 /* See comments in ExponentiateNN() on handling INT64_MIN */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006961 if(pItem->val.expAndMantissa.Mantissa.nInt >= 0) {
6962 uMantissa = (uint64_t)pItem->val.expAndMantissa.Mantissa.nInt;
6963 *pbIsNegative = false;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006964 } else if(pItem->val.expAndMantissa.Mantissa.nInt != INT64_MIN) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006965 uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt;
6966 *pbIsNegative = true;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006967 } else {
6968 uMantissa = (uint64_t)INT64_MAX+1;
6969 *pbIsNegative = true;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006970 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006971 *pMantissa = QCBOR_Private_ConvertIntToBigNum(uMantissa,
6972 BufferForMantissa);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006973 *pnExponent = pItem->val.expAndMantissa.nExponent;
6974 break;
6975
Laurence Lundblade37286c02022-09-03 10:05:02 -07006976#ifndef QCBOR_DISABLE_TAGS
6977 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006978 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006979 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006980 *pnExponent = pItem->val.expAndMantissa.nExponent;
6981 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6982 *pbIsNegative = false;
6983 break;
6984
6985 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006986 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006987 *pnExponent = pItem->val.expAndMantissa.nExponent;
6988 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6989 *pbIsNegative = true;
6990 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006991#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006992
6993 default:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006994 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006995 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006996
6997Done:
6998 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006999}
7000
7001
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007002/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007003 * Public function, see header qcbor/qcbor_decode.h file
7004 */
7005void
7006QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe,
7007 const uint8_t uTagRequirement,
7008 int64_t *pnMantissa,
7009 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007010{
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007011 if(pMe->uLastError != QCBOR_SUCCESS) {
7012 return;
7013 }
7014
7015 QCBORItem Item;
7016 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
7017 if(uError) {
7018 pMe->uLastError = (uint8_t)uError;
7019 return;
7020 }
7021
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007022 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007023 {
7024 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007025 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7026 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7027 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007028 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007029
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007030 QCBOR_Private_ProcessExpMantissa(pMe,
7031 TagSpec,
7032 &Item,
7033 pnMantissa,
7034 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007035}
7036
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007037
7038/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007039 * Public function, see header qcbor/qcbor_decode.h file
7040 */
7041void
7042QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe,
7043 const int64_t nLabel,
7044 const uint8_t uTagRequirement,
7045 int64_t *pnMantissa,
7046 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007047{
7048 if(pMe->uLastError != QCBOR_SUCCESS) {
7049 return;
7050 }
7051
7052 QCBORItem Item;
7053 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7054
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007055 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007056 {
7057 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007058 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7059 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7060 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007061 };
7062
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007063 QCBOR_Private_ProcessExpMantissa(pMe,
7064 TagSpec,
7065 &Item,
7066 pnMantissa,
7067 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007068}
7069
7070
7071/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007072 * Public function, see header qcbor/qcbor_decode.h file
7073 */
7074void
7075QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
7076 const char *szLabel,
7077 const uint8_t uTagRequirement,
7078 int64_t *pnMantissa,
7079 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007080{
7081 if(pMe->uLastError != QCBOR_SUCCESS) {
7082 return;
7083 }
7084
7085 QCBORItem Item;
7086 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7087
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007088 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007089 {
7090 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007091 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7092 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7093 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007094 };
Laurence Lundblade9b334962020-08-27 10:55:53 -07007095
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007096 QCBOR_Private_ProcessExpMantissa(pMe,
7097 TagSpec,
7098 &Item,
7099 pnMantissa,
7100 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007101}
7102
7103
7104/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007105 * Public function, see header qcbor/qcbor_decode.h file
7106 */
7107void
7108QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe,
7109 const uint8_t uTagRequirement,
7110 const UsefulBuf MantissaBuffer,
7111 UsefulBufC *pMantissa,
7112 bool *pbMantissaIsNegative,
7113 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007114{
7115 if(pMe->uLastError != QCBOR_SUCCESS) {
7116 return;
7117 }
7118
7119 QCBORItem Item;
7120 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
7121 if(uError) {
7122 pMe->uLastError = (uint8_t)uError;
7123 return;
7124 }
7125
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007126 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007127 {
7128 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007129 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7130 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7131 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007132 };
7133
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007134 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7135 TagSpec,
7136 &Item,
7137 MantissaBuffer,
7138 pMantissa,
7139 pbMantissaIsNegative,
7140 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007141}
7142
7143
7144/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007145 * Public function, see header qcbor/qcbor_decode.h file
7146 */
7147void
7148QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe,
7149 const int64_t nLabel,
7150 const uint8_t uTagRequirement,
7151 const UsefulBuf BufferForMantissa,
7152 UsefulBufC *pMantissa,
7153 bool *pbIsNegative,
7154 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007155{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007156 if(pMe->uLastError != QCBOR_SUCCESS) {
7157 return;
7158 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007159
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007160 QCBORItem Item;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007161 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007162 if(pMe->uLastError != QCBOR_SUCCESS) {
7163 return;
7164 }
7165
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007166 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007167 {
7168 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007169 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7170 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7171 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007172 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007173
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007174 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7175 TagSpec,
7176 &Item,
7177 BufferForMantissa,
7178 pMantissa,
7179 pbIsNegative,
7180 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007181}
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007182
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007183
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007184/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007185 * Public function, see header qcbor/qcbor_decode.h file
7186 */
7187void
7188QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe,
7189 const char *szLabel,
7190 const uint8_t uTagRequirement,
7191 const UsefulBuf BufferForMantissa,
7192 UsefulBufC *pMantissa,
7193 bool *pbIsNegative,
7194 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007195{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007196 if(pMe->uLastError != QCBOR_SUCCESS) {
7197 return;
7198 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007199
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007200 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007201 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7202 if(pMe->uLastError != QCBOR_SUCCESS) {
7203 return;
7204 }
7205
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007206 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007207 {
7208 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007209 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7210 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7211 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007212 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007213
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007214 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7215 TagSpec,
7216 &Item,
7217 BufferForMantissa,
7218 pMantissa,
7219 pbIsNegative,
7220 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007221}
7222
7223
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007224/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007225 * Public function, see header qcbor/qcbor_decode.h file
7226 */
7227void
7228QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe,
7229 const uint8_t uTagRequirement,
7230 int64_t *pnMantissa,
7231 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007232{
7233 if(pMe->uLastError != QCBOR_SUCCESS) {
7234 return;
7235 }
7236
7237 QCBORItem Item;
7238 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
7239 if(uError) {
7240 pMe->uLastError = (uint8_t)uError;
7241 return;
7242 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007243 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007244 {
7245 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007246 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7247 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7248 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007249 };
7250
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007251 QCBOR_Private_ProcessExpMantissa(pMe,
7252 TagSpec,
7253 &Item,
7254 pnMantissa,
7255 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007256}
7257
7258
7259/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007260 * Public function, see header qcbor/qcbor_decode.h file
7261 */
7262void
7263QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe,
7264 const int64_t nLabel,
7265 const uint8_t uTagRequirement,
7266 int64_t *pnMantissa,
7267 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007268{
7269 if(pMe->uLastError != QCBOR_SUCCESS) {
7270 return;
7271 }
7272
7273 QCBORItem Item;
7274 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7275 if(pMe->uLastError != QCBOR_SUCCESS) {
7276 return;
7277 }
7278
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007279 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007280 {
7281 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007282 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7283 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7284 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007285 };
7286
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007287 QCBOR_Private_ProcessExpMantissa(pMe,
7288 TagSpec,
7289 &Item,
7290 pnMantissa,
7291 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007292}
7293
7294
7295/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007296 * Public function, see header qcbor/qcbor_decode.h file
7297 */
7298void
7299QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe,
7300 const char *szLabel,
7301 const uint8_t uTagRequirement,
7302 int64_t *pnMantissa,
7303 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007304{
7305 if(pMe->uLastError != QCBOR_SUCCESS) {
7306 return;
7307 }
7308
7309 QCBORItem Item;
7310 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7311 if(pMe->uLastError != QCBOR_SUCCESS) {
7312 return;
7313 }
7314
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007315 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007316 {
7317 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007318 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7319 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7320 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007321 };
7322
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007323 QCBOR_Private_ProcessExpMantissa(pMe,
7324 TagSpec,
7325 &Item,
7326 pnMantissa,
7327 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007328}
7329
7330
7331/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007332 * Public function, see header qcbor/qcbor_decode.h file
7333 */
7334void
7335QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe,
7336 const uint8_t uTagRequirement,
7337 const UsefulBuf MantissaBuffer,
7338 UsefulBufC *pMantissa,
7339 bool *pbMantissaIsNegative,
7340 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007341{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007342 if(pMe->uLastError != QCBOR_SUCCESS) {
7343 return;
7344 }
7345
7346 QCBORItem Item;
7347 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
7348 if(uError) {
7349 pMe->uLastError = (uint8_t)uError;
7350 return;
7351 }
7352
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007353 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007354 {
7355 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007356 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7357 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7358 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007359 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007360
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007361 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7362 TagSpec,
7363 &Item,
7364 MantissaBuffer,
7365 pMantissa,
7366 pbMantissaIsNegative,
7367 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007368}
7369
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007370
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007371/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007372 * Public function, see header qcbor/qcbor_decode.h file
7373 */
7374void
7375QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe,
7376 const int64_t nLabel,
7377 const uint8_t uTagRequirement,
7378 const UsefulBuf BufferForMantissa,
7379 UsefulBufC *pMantissa,
7380 bool *pbIsNegative,
7381 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007382{
7383 if(pMe->uLastError != QCBOR_SUCCESS) {
7384 return;
7385 }
7386
7387 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007388 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7389 if(pMe->uLastError != QCBOR_SUCCESS) {
7390 return;
7391 }
7392
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007393 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007394 {
7395 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007396 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7397 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7398 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007399 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007400
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007401 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7402 TagSpec,
7403 &Item,
7404 BufferForMantissa,
7405 pMantissa,
7406 pbIsNegative,
7407 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007408}
7409
7410
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007411/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007412 * Public function, see header qcbor/qcbor_decode.h file
7413 */
7414void
7415QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe,
7416 const char *szLabel,
7417 const uint8_t uTagRequirement,
7418 const UsefulBuf BufferForMantissa,
7419 UsefulBufC *pMantissa,
7420 bool *pbIsNegative,
7421 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007422{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007423 if(pMe->uLastError != QCBOR_SUCCESS) {
7424 return;
7425 }
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007426
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007427 QCBORItem Item;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007428 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7429 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007430 return;
7431 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007432
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007433 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007434 {
7435 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007436 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7437 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7438 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007439 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007440
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007441 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7442 TagSpec,
7443 &Item,
7444 BufferForMantissa,
7445 pMantissa,
7446 pbIsNegative,
7447 pnExponent);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007448}
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007449
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07007450#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007451
7452
7453#if !defined(USEFULBUF_DISABLE_ALL_FLOAT) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
7454/*
7455 * Public function, see header qcbor/qcbor_spiffy_decode.h file
7456 */
7457void
7458QCBORDecode_GetNumberConvertPrecisely(QCBORDecodeContext *pMe,
7459 QCBORItem *pNumber)
7460{
7461 QCBORItem Item;
7462 struct IEEE754_ToInt ToInt;
7463 double d;
7464 QCBORError uError;
7465
7466 if(pMe->uLastError != QCBOR_SUCCESS) {
7467 return;
7468 }
7469
7470 uError = QCBORDecode_GetNext(pMe, &Item);
7471 if(uError != QCBOR_SUCCESS) {
7472 pMe->uLastError = (uint8_t)uError;
7473 return;
7474 }
7475
7476 switch(Item.uDataType) {
7477 case QCBOR_TYPE_INT64:
7478 case QCBOR_TYPE_UINT64:
7479 *pNumber = Item;
7480 break;
7481
7482 case QCBOR_TYPE_DOUBLE:
7483 ToInt = IEEE754_DoubleToInt(Item.val.dfnum);
7484 if(ToInt.type == IEEE754_ToInt_IS_INT) {
7485 pNumber->uDataType = QCBOR_TYPE_INT64;
7486 pNumber->val.int64 = ToInt.integer.is_signed;
7487 } else if(ToInt.type == IEEE754_ToInt_IS_UINT) {
7488 if(ToInt.integer.un_signed <= INT64_MAX) {
7489 /* Do the same as base QCBOR integer decoding */
7490 pNumber->uDataType = QCBOR_TYPE_INT64;
7491 pNumber->val.int64 = (int64_t)ToInt.integer.un_signed;
7492 } else {
7493 pNumber->uDataType = QCBOR_TYPE_UINT64;
7494 pNumber->val.uint64 = ToInt.integer.un_signed;
7495 }
7496 } else {
7497 *pNumber = Item;
7498 }
7499 break;
7500
7501 case QCBOR_TYPE_FLOAT:
7502 ToInt = IEEE754_SingleToInt(Item.val.fnum);
7503 if(ToInt.type == IEEE754_ToInt_IS_INT) {
7504 pNumber->uDataType = QCBOR_TYPE_INT64;
7505 pNumber->val.int64 = ToInt.integer.is_signed;
7506 } else if(ToInt.type == IEEE754_ToInt_IS_UINT) {
7507 if(ToInt.integer.un_signed <= INT64_MAX) {
7508 /* Do the same as base QCBOR integer decoding */
7509 pNumber->uDataType = QCBOR_TYPE_INT64;
7510 pNumber->val.int64 = (int64_t)ToInt.integer.un_signed;
7511 } else {
7512 pNumber->uDataType = QCBOR_TYPE_UINT64;
7513 pNumber->val.uint64 = ToInt.integer.un_signed;
7514 }
7515 } else {
7516 *pNumber = Item;
7517 }
7518 break;
7519
7520
7521 case QCBOR_TYPE_65BIT_NEG_INT:
7522 d = IEEE754_UintToDouble(Item.val.uint64, 1);
7523 if(d == IEEE754_UINT_TO_DOUBLE_OOB) {
7524 *pNumber = Item;
7525 } else {
7526 pNumber->uDataType = QCBOR_TYPE_DOUBLE;
7527 /* -1 is because of CBOR offset of negative numbers */
7528 pNumber->val.dfnum = d - 1;
7529 }
7530 break;
7531
7532 default:
7533 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
7534 pNumber->uDataType = QCBOR_TYPE_NONE;
7535 break;
7536 }
7537}
7538
7539#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT && ! QCBOR_DISABLE_PREFERRED_FLOAT */