blob: 6e6acea09f8cd3a48746a5376e0d481088e879c0 [file] [log] [blame]
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001/*==============================================================================
Laurence Lundbladed92a6162018-11-01 11:38:35 +07002 Copyright (c) 2016-2018, The Linux Foundation.
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003 Copyright (c) 2018-2024, Laurence Lundblade.
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02004 Copyright (c) 2021, Arm Limited.
Laurence Lundbladed92a6162018-11-01 11:38:35 +07005 All rights reserved.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08006
Laurence Lundblade0dbc9172018-11-01 14:17:21 +07007Redistribution and use in source and binary forms, with or without
8modification, are permitted provided that the following conditions are
9met:
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above
13 copyright notice, this list of conditions and the following
14 disclaimer in the documentation and/or other materials provided
15 with the distribution.
16 * Neither the name of The Linux Foundation nor the names of its
17 contributors, nor the name "Laurence Lundblade" may be used to
18 endorse or promote products derived from this software without
19 specific prior written permission.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080020
Laurence Lundblade0dbc9172018-11-01 14:17:21 +070021THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
22WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
24ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
25BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
30OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Laurence Lundbladeee851742020-01-08 08:37:05 -080032 =============================================================================*/
Laurence Lundblade624405d2018-09-18 20:10:47 -070033
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080034
Laurence Lundblade844bb5c2020-03-01 17:27:25 -080035#include "qcbor/qcbor_decode.h"
Laurence Lundblade67257dc2020-07-27 03:33:37 -070036#include "qcbor/qcbor_spiffy_decode.h"
Laurence Lundblade3f1318a2021-01-04 18:26:44 -080037#include "ieee754.h" /* Does not use math.h */
Laurence Lundbladec7114722020-08-13 05:11:40 -070038
39#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade3f1318a2021-01-04 18:26:44 -080040
41#include <math.h> /* For isnan(), llround(), llroudf(), round(), roundf(),
42 * pow(), exp2()
43 */
44#include <fenv.h> /* feclearexcept(), fetestexcept() */
45
Laurence Lundbladee2c893c2020-12-26 17:41:53 -080046#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070047
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070048
Laurence Lundblade68cb61c2023-02-12 13:21:44 -080049#if (defined(__GNUC__) && !defined(__clang__))
Laurence Lundblade8e36f812024-01-26 10:59:29 -070050/*
Laurence Lundblade68cb61c2023-02-12 13:21:44 -080051 * This is how the -Wmaybe-uninitialized compiler warning is
52 * handled. It can’t be ignored because some version of gcc enable it
53 * with -Wall which is a common and useful gcc warning option. It also
54 * can’t be ignored because it is the goal of QCBOR to compile clean
55 * out of the box in all environments.
56 *
57 * The big problem with -Wmaybe-uninitialized is that it generates
58 * false positives. It complains things are uninitialized when they
59 * are not. This is because it is not a thorough static analyzer. This
60 * is why “maybe” is in its name. The problem is it is just not
61 * thorough enough to understand all the code (and someone saw fit to
62 * put it in gcc and worse to enable it with -Wall).
63 *
64 * One solution would be to change the code so -Wmaybe-uninitialized
65 * doesn’t get confused, for example adding an unnecessary extra
66 * initialization to zero. (If variables were truly uninitialized, the
67 * correct path is to understand the code thoroughly and set them to
68 * the correct value at the correct time; in essence this is already
69 * done; -Wmaybe-uninitialized just can’t tell). This path is not
70 * taken because it makes the code bigger and is kind of the tail
71 * wagging the dog.
72 *
73 * The solution here is to just use a pragma to disable it for the
74 * whole file. Disabling it for each line makes the code fairly ugly
75 * requiring #pragma to push, pop and ignore. Another reason is the
76 * warnings issues vary by version of gcc and which optimization
77 * optimizations are selected. Another reason is that compilers other
78 * than gcc don’t have -Wmaybe-uninitialized.
79 *
80 * One may ask how to be sure these warnings are false positives and
81 * not real issues. 1) The code has been read carefully to check. 2)
82 * Testing is pretty thorough. 3) This code has been run through
83 * thorough high-quality static analyzers.
84 *
85 * In particularly, most of the warnings are about
86 * Item.Item->uDataType being uninitialized. QCBORDecode_GetNext()
87 * *always* sets this value and test case confirm
88 * this. -Wmaybe-uninitialized just can't tell.
89 *
90 * https://stackoverflow.com/questions/5080848/disable-gcc-may-be-used-uninitialized-on-a-particular-variable
91 */
92#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
Laurence Lundblade8e36f812024-01-26 10:59:29 -070093#endif
Laurence Lundblade68cb61c2023-02-12 13:21:44 -080094
95
96
Laurence Lundblade3f1318a2021-01-04 18:26:44 -080097
Laurence Lundbladea9489f82020-09-12 13:50:56 -070098#define SIZEOF_C_ARRAY(array,type) (sizeof(array)/sizeof(type))
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070099
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700100
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800101
102
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700103static bool
104QCBORItem_IsMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700105{
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700106 const uint8_t uDataType = Item.uDataType;
Laurence Lundblade02625d42020-06-25 14:41:41 -0700107 return uDataType == QCBOR_TYPE_MAP ||
Laurence Lundblade62cae932024-06-03 13:16:17 -0700108#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
109 uDataType == QCBOR_TYPE_MAP_AS_ARRAY ||
Laurence Lundblade78a66132024-06-06 12:19:59 -0700110#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade62cae932024-06-03 13:16:17 -0700111 uDataType == QCBOR_TYPE_ARRAY;
Laurence Lundblade02625d42020-06-25 14:41:41 -0700112}
113
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700114static bool
115QCBORItem_IsEmptyDefiniteLengthMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700116{
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700117 if(!QCBORItem_IsMapOrArray(Item)){
Laurence Lundblade02625d42020-06-25 14:41:41 -0700118 return false;
119 }
120
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700121 if(Item.val.uCount != 0) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700122 return false;
123 }
124 return true;
125}
126
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700127static bool
128QCBORItem_IsIndefiniteLengthMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700129{
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800130#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700131 if(!QCBORItem_IsMapOrArray(Item)){
Laurence Lundblade02625d42020-06-25 14:41:41 -0700132 return false;
133 }
134
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700135 if(Item.val.uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700136 return false;
137 }
138 return true;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800139#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700140 (void)Item;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800141 return false;
142#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700143}
144
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700145/* Return true if the labels in Item1 and Item2 are the same.
146 Works only for integer and string labels. Returns false
147 for any other type. */
148static bool
149QCBORItem_MatchLabel(const QCBORItem Item1, const QCBORItem Item2)
150{
151 if(Item1.uLabelType == QCBOR_TYPE_INT64) {
152 if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
153 return true;
154 }
Laurence Lundblade78a66132024-06-06 12:19:59 -0700155#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700156 } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
157 if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
158 return true;
159 }
160 } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
161 if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
162 return true;
163 }
164 } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
165 if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
166 return true;
167 }
Laurence Lundblade78a66132024-06-06 12:19:59 -0700168#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700169 }
170
171 /* Other label types are never matched */
172 return false;
173}
174
175
176/*
177 Returns true if Item1 and Item2 are the same type
178 or if either are of QCBOR_TYPE_ANY.
179 */
180static bool
181QCBORItem_MatchType(const QCBORItem Item1, const QCBORItem Item2)
182{
183 if(Item1.uDataType == Item2.uDataType) {
184 return true;
185 } else if(Item1.uDataType == QCBOR_TYPE_ANY) {
186 return true;
187 } else if(Item2.uDataType == QCBOR_TYPE_ANY) {
188 return true;
189 }
190 return false;
191}
192
Laurence Lundblade02625d42020-06-25 14:41:41 -0700193
Laurence Lundbladeee851742020-01-08 08:37:05 -0800194/*===========================================================================
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700195 DecodeNesting -- Tracking array/map/sequence/bstr-wrapped nesting
Laurence Lundbladeee851742020-01-08 08:37:05 -0800196 ===========================================================================*/
197
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700198/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800199 * See comments about and typedef of QCBORDecodeNesting in qcbor_private.h,
200 * the data structure all these functions work on.
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700201 */
202
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700203
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700204static uint8_t
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700205DecodeNesting_GetCurrentLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700206{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700207 const ptrdiff_t nLevel = pNesting->pCurrent - &(pNesting->pLevels[0]);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800208 /* Limit in DecodeNesting_Descend against more than
209 * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
Laurence Lundblade02625d42020-06-25 14:41:41 -0700210 */
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700211 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700212}
213
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700214
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700215static uint8_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700216DecodeNesting_GetBoundedModeLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700217{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700218 const ptrdiff_t nLevel = pNesting->pCurrentBounded - &(pNesting->pLevels[0]);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800219 /* Limit in DecodeNesting_Descend against more than
220 * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
Laurence Lundblade02625d42020-06-25 14:41:41 -0700221 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700222 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700223}
224
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700225
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700226static uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700227DecodeNesting_GetMapOrArrayStart(const QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700228{
229 return pNesting->pCurrentBounded->u.ma.uStartOffset;
230}
231
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700232
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700233static bool
Laurence Lundblade085d7952020-07-24 10:26:30 -0700234DecodeNesting_IsBoundedEmpty(const QCBORDecodeNesting *pNesting)
235{
236 if(pNesting->pCurrentBounded->u.ma.uCountCursor == QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
237 return true;
238 } else {
239 return false;
240 }
241}
242
243
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700244static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700245DecodeNesting_IsCurrentAtTop(const QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700246{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700247 if(pNesting->pCurrent == &(pNesting->pLevels[0])) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700248 return true;
249 } else {
250 return false;
251 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700252}
253
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700254
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700255static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700256DecodeNesting_IsCurrentDefiniteLength(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700257{
258 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800259 /* Not a map or array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700260 return false;
261 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800262
263#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700264 if(pNesting->pCurrent->u.ma.uCountTotal == QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800265 /* Is indefinite */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700266 return false;
267 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800268
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800269#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
270
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800271 /* All checks passed; is a definte length map or array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700272 return true;
273}
274
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700275static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700276DecodeNesting_IsCurrentBstrWrapped(const QCBORDecodeNesting *pNesting)
Laurence Lundblade642282a2020-06-23 12:00:33 -0700277{
278 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800279 /* is a byte string */
Laurence Lundblade642282a2020-06-23 12:00:33 -0700280 return true;
281 }
282 return false;
283}
284
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700285
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700286static bool
287DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700288{
289 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
290 return true;
291 }
Laurence Lundblade02625d42020-06-25 14:41:41 -0700292 if(pNesting->pCurrent->u.ma.uStartOffset != QCBOR_NON_BOUNDED_OFFSET) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700293 return true;
294 }
295 return false;
296}
297
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700298
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700299static void
300DecodeNesting_SetMapOrArrayBoundedMode(QCBORDecodeNesting *pNesting, bool bIsEmpty, size_t uStart)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700301{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800302 /* Should be only called on maps and arrays */
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700303 /*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800304 * DecodeNesting_EnterBoundedMode() checks to be sure uStart is not
305 * larger than DecodeNesting_EnterBoundedMode which keeps it less than
306 * uin32_t so the cast is safe.
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700307 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700308 pNesting->pCurrent->u.ma.uStartOffset = (uint32_t)uStart;
Laurence Lundblade085d7952020-07-24 10:26:30 -0700309
310 if(bIsEmpty) {
311 pNesting->pCurrent->u.ma.uCountCursor = QCBOR_COUNT_INDICATES_ZERO_LENGTH;
312 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700313}
314
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700315
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700316static void
317DecodeNesting_ClearBoundedMode(QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700318{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700319 pNesting->pCurrent->u.ma.uStartOffset = QCBOR_NON_BOUNDED_OFFSET;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700320}
321
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700322
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700323static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700324DecodeNesting_IsAtEndOfBoundedLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700325{
326 if(pNesting->pCurrentBounded == NULL) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800327 /* No bounded map or array set up */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700328 return false;
329 }
330 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800331 /* Not a map or array; end of those is by byte count */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700332 return false;
333 }
Laurence Lundblade6ab01fb2020-10-01 13:04:49 -0700334 if(!DecodeNesting_IsCurrentBounded(pNesting)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800335 /* In a traveral at a level deeper than the bounded level */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700336 return false;
337 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800338 /* Works for both definite- and indefinitelength maps/arrays */
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800339 if(pNesting->pCurrentBounded->u.ma.uCountCursor != 0 &&
340 pNesting->pCurrentBounded->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800341 /* Count is not zero, still unconsumed item */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700342 return false;
343 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800344 /* All checks passed, got to the end of an array or map*/
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700345 return true;
346}
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700347
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700348
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700349static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700350DecodeNesting_IsEndOfDefiniteLengthMapOrArray(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700351{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800352 /* Must only be called on map / array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700353 if(pNesting->pCurrent->u.ma.uCountCursor == 0) {
354 return true;
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700355 } else {
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700356 return false;
357 }
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700358}
359
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700360
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700361static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700362DecodeNesting_IsCurrentTypeMap(const QCBORDecodeNesting *pNesting)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700363{
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700364 if(pNesting->pCurrent->uLevelType == CBOR_MAJOR_TYPE_MAP) {
365 return true;
366 } else {
367 return false;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700368 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700369}
370
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700371
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700372static bool
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700373DecodeNesting_IsBoundedType(const QCBORDecodeNesting *pNesting, uint8_t uType)
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700374{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700375 if(pNesting->pCurrentBounded == NULL) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700376 return false;
377 }
Laurence Lundblade02625d42020-06-25 14:41:41 -0700378
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700379 uint8_t uItemDataType = pNesting->pCurrentBounded->uLevelType;
Laurence Lundblade62cae932024-06-03 13:16:17 -0700380#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700381 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
382 uItemDataType = QCBOR_TYPE_ARRAY;
383 }
Laurence Lundblade78a66132024-06-06 12:19:59 -0700384#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700385
386 if(uItemDataType != uType) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700387 return false;
388 }
389
390 return true;
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700391}
392
Laurence Lundblade02625d42020-06-25 14:41:41 -0700393
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700394static void
Laurence Lundblade6c8a4442020-06-22 22:16:11 -0700395DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700396{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800397 /* Only call on a definite-length array / map */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700398 pNesting->pCurrent->u.ma.uCountCursor--;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700399}
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700400
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700401
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700402static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700403DecodeNesting_ReverseDecrement(QCBORDecodeNesting *pNesting)
404{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800405 /* Only call on a definite-length array / map */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700406 pNesting->pCurrent->u.ma.uCountCursor++;
407}
408
409
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700410static void
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700411DecodeNesting_Ascend(QCBORDecodeNesting *pNesting)
412{
413 pNesting->pCurrent--;
414}
415
Laurence Lundblade02625d42020-06-25 14:41:41 -0700416
417static QCBORError
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700418DecodeNesting_Descend(QCBORDecodeNesting *pNesting, uint8_t uType)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700419{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800420 /* Error out if nesting is too deep */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700421 if(pNesting->pCurrent >= &(pNesting->pLevels[QCBOR_MAX_ARRAY_NESTING])) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700422 return QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP;
Laurence Lundblade02625d42020-06-25 14:41:41 -0700423 }
424
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800425 /* The actual descend */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700426 pNesting->pCurrent++;
427
428 pNesting->pCurrent->uLevelType = uType;
429
430 return QCBOR_SUCCESS;
431}
432
433
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700434static QCBORError
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800435DecodeNesting_EnterBoundedMapOrArray(QCBORDecodeNesting *pNesting,
436 bool bIsEmpty,
437 size_t uOffset)
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700438{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700439 /*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800440 * Should only be called on map/array.
441 *
442 * Have descended into this before this is called. The job here is
443 * just to mark it in bounded mode.
444 *
445 * Check against QCBOR_MAX_DECODE_INPUT_SIZE make sure that
446 * uOffset doesn't collide with QCBOR_NON_BOUNDED_OFFSET.
447 *
448 * Cast of uOffset to uint32_t for cases where SIZE_MAX < UINT32_MAX.
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700449 */
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -0800450 if((uint32_t)uOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700451 return QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700452 }
453
Laurence Lundblade0750fc42020-06-20 21:02:34 -0700454 pNesting->pCurrentBounded = pNesting->pCurrent;
Laurence Lundblade085d7952020-07-24 10:26:30 -0700455
456 DecodeNesting_SetMapOrArrayBoundedMode(pNesting, bIsEmpty, uOffset);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700457
458 return QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700459}
460
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700461
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700462static QCBORError
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700463DecodeNesting_DescendMapOrArray(QCBORDecodeNesting *pNesting,
Laurence Lundblade02625d42020-06-25 14:41:41 -0700464 uint8_t uQCBORType,
465 uint64_t uCount)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700466{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700467 QCBORError uError = QCBOR_SUCCESS;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700468
469 if(uCount == 0) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800470 /* Nothing to do for empty definite-length arrays. They are just are
471 * effectively the same as an item that is not a map or array.
472 */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700473 goto Done;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800474 /* Empty indefinite-length maps and arrays are handled elsewhere */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700475 }
476
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800477 /* Error out if arrays is too long to handle */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700478 if(uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH &&
479 uCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700480 uError = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700481 goto Done;
482 }
483
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700484 uError = DecodeNesting_Descend(pNesting, uQCBORType);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700485 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700486 goto Done;
487 }
488
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800489 /* Fill in the new map/array level. Check above makes casts OK. */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -0700490 pNesting->pCurrent->u.ma.uCountCursor = (uint16_t)uCount;
491 pNesting->pCurrent->u.ma.uCountTotal = (uint16_t)uCount;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700492
493 DecodeNesting_ClearBoundedMode(pNesting);
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700494
495Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700496 return uError;;
497}
498
499
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700500static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700501DecodeNesting_LevelUpCurrent(QCBORDecodeNesting *pNesting)
502{
503 pNesting->pCurrent = pNesting->pCurrentBounded - 1;
504}
505
506
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700507static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700508DecodeNesting_LevelUpBounded(QCBORDecodeNesting *pNesting)
509{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700510 while(pNesting->pCurrentBounded != &(pNesting->pLevels[0])) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700511 pNesting->pCurrentBounded--;
512 if(DecodeNesting_IsCurrentBounded(pNesting)) {
513 break;
514 }
515 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700516}
517
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800518
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700519static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700520DecodeNesting_SetCurrentToBoundedLevel(QCBORDecodeNesting *pNesting)
521{
522 pNesting->pCurrent = pNesting->pCurrentBounded;
523}
524
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700525
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700526static QCBORError
Laurence Lundblade02625d42020-06-25 14:41:41 -0700527DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting,
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700528 uint32_t uEndOffset,
529 uint32_t uStartOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700530{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700531 QCBORError uError;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700532
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700533 uError = DecodeNesting_Descend(pNesting, QCBOR_TYPE_BYTE_STRING);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700534 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700535 goto Done;
536 }
537
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800538 /* Fill in the new byte string level */
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700539 pNesting->pCurrent->u.bs.uSavedEndOffset = uEndOffset;
540 pNesting->pCurrent->u.bs.uBstrStartOffset = uStartOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700541
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800542 /* Bstr wrapped levels are always bounded */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700543 pNesting->pCurrentBounded = pNesting->pCurrent;
544
545Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700546 return uError;;
547}
548
Laurence Lundbladed0304932020-06-27 10:59:38 -0700549
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700550static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700551DecodeNesting_ZeroMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700552{
553 pNesting->pCurrent->u.ma.uCountCursor = 0;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700554}
555
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700556
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700557static void
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800558DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting)
559{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700560 if(pNesting->pCurrent->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
561 pNesting->pCurrentBounded->u.ma.uCountCursor = pNesting->pCurrentBounded->u.ma.uCountTotal;
562 }
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800563}
564
565
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700566static void
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700567DecodeNesting_Init(QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700568{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700569 /* Assumes that *pNesting has been zero'd before this call. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700570 pNesting->pLevels[0].uLevelType = QCBOR_TYPE_BYTE_STRING;
571 pNesting->pCurrent = &(pNesting->pLevels[0]);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700572}
573
574
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700575static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800576DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting,
577 QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700578{
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700579 *pSave = *pNesting;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700580}
581
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700582
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700583static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800584DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting,
585 const QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700586{
587 *pNesting = *pSave;
588}
589
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700590
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700591static uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700592DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700593{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700594 return pMe->pCurrentBounded->u.bs.uSavedEndOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700595}
596
597
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800598
599
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800600#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladeee851742020-01-08 08:37:05 -0800601/*===========================================================================
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800602 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
603
604 The following four functions are pretty wrappers for invocation of
605 the string allocator supplied by the caller.
606
Laurence Lundbladeee851742020-01-08 08:37:05 -0800607 ===========================================================================*/
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800608
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700609static void
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800610StringAllocator_Free(const QCBORInternalAllocator *pMe, const void *pMem)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800611{
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300612 /* This cast to uintptr_t suppresses the "-Wcast-qual" warnings.
613 * This is the one place where the const needs to be cast away so const can
614 * be use in the rest of the code.
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800615 */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300616 (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, 0);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800617}
618
Laurence Lundbladeee851742020-01-08 08:37:05 -0800619// StringAllocator_Reallocate called with pMem NULL is
620// equal to StringAllocator_Allocate()
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700621static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800622StringAllocator_Reallocate(const QCBORInternalAllocator *pMe,
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800623 const void *pMem,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800624 size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800625{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800626 /* See comment in StringAllocator_Free() */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300627 return (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, uSize);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800628}
629
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700630static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800631StringAllocator_Allocate(const QCBORInternalAllocator *pMe, size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800632{
633 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
634}
635
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700636static void
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800637StringAllocator_Destruct(const QCBORInternalAllocator *pMe)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800638{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800639 /* See comment in StringAllocator_Free() */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800640 if(pMe->pfAllocator) {
641 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
642 }
643}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800644#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800645
646
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800647
648
Laurence Lundbladeee851742020-01-08 08:37:05 -0800649/*===========================================================================
650 QCBORDecode -- The main implementation of CBOR decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700651
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800652 See qcbor/qcbor_decode.h for definition of the object
653 used here: QCBORDecodeContext
Laurence Lundbladeee851742020-01-08 08:37:05 -0800654 ===========================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700655/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800656 * Public function, see header file
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700657 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700658void
659QCBORDecode_Init(QCBORDecodeContext *pMe,
660 UsefulBufC EncodedCBOR,
661 QCBORDecodeMode nDecodeMode)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700662{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800663 memset(pMe, 0, sizeof(QCBORDecodeContext));
664 UsefulInputBuf_Init(&(pMe->InBuf), EncodedCBOR);
665 /* Don't bother with error check on decode mode. If a bad value is
666 * passed it will just act as if the default normal mode of 0 was set.
667 */
668 pMe->uDecodeMode = (uint8_t)nDecodeMode;
669 DecodeNesting_Init(&(pMe->nesting));
670
671 /* Inialize me->auMappedTags to CBOR_TAG_INVALID16. See
672 * GetNext_TaggedItem() and MapTagNumber(). */
673 memset(pMe->auMappedTags, 0xff, sizeof(pMe->auMappedTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700674}
675
676
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800677#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
678
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700679/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800680 * Public function, see header file
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700681 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700682void
683QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
684 QCBORStringAllocate pfAllocateFunction,
685 void *pAllocateContext,
686 bool bAllStrings)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700687{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800688 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
689 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
690 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700691}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800692#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700693
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800694
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800695
696
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800697/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800698 * Deprecated public function, see header file
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800699 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700700void
701QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pMe,
702 const QCBORTagListIn *pTagList)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700703{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800704 /* This does nothing now. It is retained for backwards compatibility */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700705 (void)pMe;
706 (void)pTagList;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700707}
708
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700709
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800710
711
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700712/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800713 * Decoding items is done in six layers, one calling the next one
714 * down. If a layer has no work to do for a particular item, it
715 * returns quickly.
716 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700717 * 1. QCBORDecode_Private_GetNextTagContent - The top layer processes
718 * tagged data items, turning them into the local C representation.
719 * For the most simple it is just associating a QCBOR_TYPE with the
720 * data. For the complex ones that an aggregate of data items, there
721 * is some further decoding and some limited recursion.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800722 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700723 * 2. QCBORDecode_Private_GetNextMapOrArray - This manages the
724 * beginnings and ends of maps and arrays. It tracks descending into
725 * and ascending out of maps/arrays. It processes breaks that
726 * terminate indefinite-length maps and arrays.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800727 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700728 * 3. QCBORDecode_Private_GetNextMapEntry - This handles the combining
729 * of two items, the label and the data, that make up a map entry. It
730 * only does work on maps. It combines the label and data items into
731 * one labeled item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800732 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700733 * 4. QCBORDecode_Private_GetNextTagNumber - This decodes type 6 tag
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800734 * numbers. It turns the tag numbers into bit flags associated with
735 * the data item. No actual decoding of the contents of the tag is
736 * performed here.
737 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700738 * 5. QCBORDecode_Private_GetNextFullString - This assembles the
739 * sub-items that make up an indefinite-length string into one string
740 * item. It uses the string allocator to create contiguous space for
741 * the item. It processes all breaks that are part of
742 * indefinite-length strings.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800743 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700744 * 6. QCBOR_Private_DecodeAtomicDataItem - This decodes the atomic
745 * data items in CBOR. Each atomic data item has a "major type", an
746 * integer "argument" and optionally some content. For text and byte
747 * strings, the content is the bytes that make up the string. These
748 * are the smallest data items that are considered to be well-formed.
749 * The content may also be other data items in the case of aggregate
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800750 * types. They are not handled in this layer.
751 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700752 * This uses about 350 bytes of stack. This number comes from
753 * instrumenting (printf address of stack variables) the code on x86
754 * compiled for size optimization.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700755 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800756
757
758/*
759 * Note about use of int and unsigned variables.
760 *
761 * See http://www.unix.org/whitepapers/64bit.html for reasons int is
762 * used carefully here, and in particular why it isn't used in the
763 * public interface. Also see
764 * https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers
765 *
766 * Int is used for values that need less than 16-bits and would be
767 * subject to integer promotion and result in complaining from static
768 * analyzers.
769 */
770
771
772/**
773 * @brief Decode the CBOR head, the type and argument.
774 *
775 * @param[in] pUInBuf The input buffer to read from.
776 * @param[out] pnMajorType The decoded major type.
777 * @param[out] puArgument The decoded argument.
778 * @param[out] pnAdditionalInfo The decoded Lower 5 bits of initial byte.
779 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -0700780 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved features
781 * @retval QCBOR_ERR_HIT_END Unexpected end of input
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800782 *
783 * This decodes the CBOR "head" that every CBOR data item has. See
784 * longer explaination of the head in documentation for
785 * QCBOREncode_EncodeHead().
786 *
787 * This does the network->host byte order conversion. The conversion
788 * here also results in the conversion for floats in addition to that
789 * for lengths, tags and integer values.
790 *
791 * The int type is preferred to uint8_t for some variables as this
792 * avoids integer promotions, can reduce code size and makes static
793 * analyzers happier.
794 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700795static QCBORError
796QCBOR_Private_DecodeHead(UsefulInputBuf *pUInBuf,
797 int *pnMajorType,
798 uint64_t *puArgument,
799 int *pnAdditionalInfo)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700800{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800801 QCBORError uReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800802
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800803 /* Get the initial byte that every CBOR data item has and break it
804 * down. */
805 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800806 const int nTmpMajorType = nInitialByte >> 5;
807 const int nAdditionalInfo = nInitialByte & 0x1f;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800808
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800809 /* Where the argument accumulates */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800810 uint64_t uArgument;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800811
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800812 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800813 /* Need to get 1,2,4 or 8 additional argument bytes. Map
814 * LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length.
815 */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800816 static const uint8_t aIterate[] = {1,2,4,8};
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800817
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800818 /* Loop getting all the bytes in the argument */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800819 uArgument = 0;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800820 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800821 /* This shift and add gives the endian conversion. */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800822 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
823 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800824 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800825 /* The reserved and thus-far unused additional info values */
826 uReturn = QCBOR_ERR_UNSUPPORTED;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800827 goto Done;
828 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800829 /* Less than 24, additional info is argument or 31, an
830 * indefinite-length. No more bytes to get.
831 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800832 uArgument = (uint64_t)nAdditionalInfo;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700833 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800834
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700835 if(UsefulInputBuf_GetError(pUInBuf)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800836 uReturn = QCBOR_ERR_HIT_END;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700837 goto Done;
838 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800839
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800840 /* All successful if arrived here. */
841 uReturn = QCBOR_SUCCESS;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800842 *pnMajorType = nTmpMajorType;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800843 *puArgument = uArgument;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800844 *pnAdditionalInfo = nAdditionalInfo;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800845
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700846Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800847 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700848}
849
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800850
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800851/**
852 * @brief Decode integer types, major types 0 and 1.
853 *
854 * @param[in] nMajorType The CBOR major type (0 or 1).
855 * @param[in] uArgument The argument from the head.
856 * @param[out] pDecodedItem The filled in decoded item.
857 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -0700858 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800859 *
860 * Must only be called when major type is 0 or 1.
861 *
862 * CBOR doesn't explicitly specify two's compliment for integers but
863 * all CPUs use it these days and the test vectors in the RFC are
864 * so. All integers in the CBOR structure are positive and the major
865 * type indicates positive or negative. CBOR can express positive
866 * integers up to 2^x - 1 where x is the number of bits and negative
867 * integers down to 2^x. Note that negative numbers can be one more
868 * away from zero than positive. Stdint, as far as I can tell, uses
869 * two's compliment to represent negative integers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700870 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700871static QCBORError
872QCBOR_Private_DecodeInteger(const int nMajorType,
873 const uint64_t uArgument,
Laurence Lundblade62cae932024-06-03 13:16:17 -0700874 const int nAdditionalInfo,
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700875 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700876{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800877 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800878
Laurence Lundblade62cae932024-06-03 13:16:17 -0700879 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
880 uReturn = QCBOR_ERR_BAD_INT;
881 goto Done;
882 }
883
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700884 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800885 if (uArgument <= INT64_MAX) {
886 pDecodedItem->val.int64 = (int64_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700887 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800888
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700889 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800890 pDecodedItem->val.uint64 = uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700891 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700892 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800893
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700894 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800895 if(uArgument <= INT64_MAX) {
896 /* CBOR's representation of negative numbers lines up with
897 * the two-compliment representation. A negative integer has
898 * one more in range than a positive integer. INT64_MIN is
899 * equal to (-INT64_MAX) - 1.
900 */
901 pDecodedItem->val.int64 = (-(int64_t)uArgument) - 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700902 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800903
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700904 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800905 /* C can't represent a negative integer in this range so it
906 * is an error.
907 */
908 uReturn = QCBOR_ERR_INT_OVERFLOW;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700909 }
910 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800911
Laurence Lundblade62cae932024-06-03 13:16:17 -0700912Done:
913 return uReturn;
914}
915
916
917static QCBORError
918QCBOR_Private_DecodeTag(const int nAdditionalInfo,
919 const uint64_t uArgument,
920 QCBORItem *pDecodedItem)
921{
922 QCBORError uReturn;
923
924#ifndef QCBOR_DISABLE_TAGS
925 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
926 uReturn = QCBOR_ERR_BAD_INT;
927 } else {
928 pDecodedItem->val.uTagV = uArgument;
929 pDecodedItem->uDataType = QCBOR_TYPE_TAG;
930 uReturn = QCBOR_SUCCESS;
931 }
932#else /* QCBOR_DISABLE_TAGS */
933 uReturn = QCBOR_ERR_TAGS_DISABLED;
934#endif /* QCBOR_DISABLE_TAGS */
935
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800936 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700937}
938
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800939
940/* Make sure #define value line up as DecodeSimple counts on this. */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700941#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
942#error QCBOR_TYPE_FALSE macro value wrong
943#endif
944
945#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
946#error QCBOR_TYPE_TRUE macro value wrong
947#endif
948
949#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
950#error QCBOR_TYPE_NULL macro value wrong
951#endif
952
953#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
954#error QCBOR_TYPE_UNDEF macro value wrong
955#endif
956
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700957#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
958#error QCBOR_TYPE_BREAK macro value wrong
959#endif
960
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700961#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
962#error QCBOR_TYPE_DOUBLE macro value wrong
963#endif
964
965#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
966#error QCBOR_TYPE_FLOAT macro value wrong
967#endif
968
Laurence Lundblade9b334962020-08-27 10:55:53 -0700969
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800970/**
971 * @brief Decode major type 7 -- true, false, floating-point, break...
972 *
973 * @param[in] nAdditionalInfo The lower five bits from the initial byte.
974 * @param[in] uArgument The argument from the head.
975 * @param[out] pDecodedItem The filled in decoded item.
976 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -0700977 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
978 * of half-precision disabled
979 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all float
980 * decode is disabled.
981 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of simple
982 * type in input.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700983 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700984static QCBORError
985QCBOR_Private_DecodeType7(const int nAdditionalInfo,
986 const uint64_t uArgument,
987 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800988{
989 QCBORError uReturn = QCBOR_SUCCESS;
990
991 /* uAdditionalInfo is 5 bits from the initial byte. Compile time
992 * checks above make sure uAdditionalInfo values line up with
993 * uDataType values. DecodeHead() never returns an AdditionalInfo
994 * > 0x1f so cast is safe.
995 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800996 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800997
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800998 switch(nAdditionalInfo) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800999 /* No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they
1000 * are caught before this is called.
1001 */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001002
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001003 case HALF_PREC_FLOAT: /* 25 */
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -07001004#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001005 /* Half-precision is returned as a double. The cast to
1006 * uint16_t is safe because the encoded value was 16 bits. It
1007 * was widened to 64 bits to be passed in here.
1008 */
1009 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uArgument);
Laurence Lundblade67bd5512018-11-02 21:44:06 +07001010 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001011#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001012 uReturn = FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001013 break;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001014 case SINGLE_PREC_FLOAT: /* 26 */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001015#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001016 /* Single precision is normally returned as a double since
1017 * double is widely supported, there is no loss of precision,
1018 * it makes it easy for the caller in most cases and it can
1019 * be converted back to single with no loss of precision
1020 *
1021 * The cast to uint32_t is safe because the encoded value was
1022 * 32 bits. It was widened to 64 bits to be passed in here.
1023 */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001024 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001025 const float f = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uArgument);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001026#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001027 /* In the normal case, use HW to convert float to
1028 * double. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001029 pDecodedItem->val.dfnum = (double)f;
1030 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001031#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001032 /* Use of float HW is disabled, return as a float. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001033 pDecodedItem->val.fnum = f;
1034 pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
1035
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001036 /* IEEE754_FloatToDouble() could be used here to return as
1037 * a double, but it adds object code and most likely
1038 * anyone disabling FLOAT HW use doesn't care about floats
1039 * and wants to save object code.
1040 */
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001041#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001042 }
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001043#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1044 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001045 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001046
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001047 case DOUBLE_PREC_FLOAT: /* 27 */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001048#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001049 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uArgument);
Laurence Lundblade67bd5512018-11-02 21:44:06 +07001050 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001051#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1052 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001053 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001054
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001055 case CBOR_SIMPLEV_FALSE: /* 20 */
1056 case CBOR_SIMPLEV_TRUE: /* 21 */
1057 case CBOR_SIMPLEV_NULL: /* 22 */
1058 case CBOR_SIMPLEV_UNDEF: /* 23 */
1059 case CBOR_SIMPLE_BREAK: /* 31 */
1060 break; /* nothing to do */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001061
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001062 case CBOR_SIMPLEV_ONEBYTE: /* 24 */
1063 if(uArgument <= CBOR_SIMPLE_BREAK) {
1064 /* This takes out f8 00 ... f8 1f which should be encoded
1065 * as e0 … f7
1066 */
1067 uReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001068 goto Done;
1069 }
Laurence Lundblade5e390822019-01-06 12:35:01 -08001070 /* FALLTHROUGH */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001071
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001072 default: /* 0-19 */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001073 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001074 /* DecodeHead() will make uArgument equal to
1075 * nAdditionalInfo when nAdditionalInfo is < 24. This cast is
1076 * safe because the 2, 4 and 8 byte lengths of uNumber are in
1077 * the double/float cases above
Laurence Lundbladeee851742020-01-08 08:37:05 -08001078 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001079 pDecodedItem->val.uSimple = (uint8_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001080 break;
1081 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001082
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001083Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001084 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001085}
1086
1087
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001088/**
1089 * @brief Decode text and byte strings
1090 *
Laurence Lundblade78a66132024-06-06 12:19:59 -07001091 * @param[in] pMe Decoder context.
1092 * @param[in] bAllocate Whether to allocate and copy string.
1093 * @param[in] nMajorType Whether it is a byte or text string.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001094 * @param[in] uStrLen The length of the string.
Laurence Lundblade78a66132024-06-06 12:19:59 -07001095 * @param[in] nAdditionalInfo Whether it is an indefinite-length string.
1096 * @param[out] pDecodedItem The filled-in decoded item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001097 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001098 * @retval QCBOR_ERR_HIT_END Unexpected end of input.
1099 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1100 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
Laurence Lundblade78a66132024-06-06 12:19:59 -07001101 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001102 *
Laurence Lundblade78a66132024-06-06 12:19:59 -07001103 * This reads @c uStrlen bytes from the input and fills in @c
1104 * pDecodedItem. If @c bAllocate is true, then memory for the string
1105 * is allocated.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001106 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001107static QCBORError
Laurence Lundblade78a66132024-06-06 12:19:59 -07001108QCBOR_Private_DecodeString(QCBORDecodeContext *pMe,
1109 const bool bAllocate,
1110 const int nMajorType,
1111 const uint64_t uStrLen,
1112 const int nAdditionalInfo,
1113 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001114{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001115 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001116
Laurence Lundblade78a66132024-06-06 12:19:59 -07001117 /* ---- Figure out the major type ---- */
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001118 #if CBOR_MAJOR_TYPE_BYTE_STRING + 4 != QCBOR_TYPE_BYTE_STRING
Laurence Lundblade78a66132024-06-06 12:19:59 -07001119 #error QCBOR_TYPE_BYTE_STRING not lined up with major type
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001120 #endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001121
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001122 #if CBOR_MAJOR_TYPE_TEXT_STRING + 4 != QCBOR_TYPE_TEXT_STRING
Laurence Lundblade78a66132024-06-06 12:19:59 -07001123 #error QCBOR_TYPE_TEXT_STRING not lined up with major type
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001124 #endif
Laurence Lundblade62cae932024-06-03 13:16:17 -07001125 pDecodedItem->uDataType = (uint8_t)(nMajorType + 4);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001126
Laurence Lundblade62cae932024-06-03 13:16:17 -07001127 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundblade78a66132024-06-06 12:19:59 -07001128 /* --- Just the head of an indefinite-length string --- */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001129 pDecodedItem->val.string = (UsefulBufC){NULL, QCBOR_STRING_LENGTH_INDEFINITE};
1130
1131 } else {
Laurence Lundblade78a66132024-06-06 12:19:59 -07001132 /* --- A definite-length string --- */
1133 /* --- (which might be a chunk of an indefinte-length string) --- */
1134
Laurence Lundblade62cae932024-06-03 13:16:17 -07001135 /* CBOR lengths can be 64 bits, but size_t is not 64 bits on all
1136 * CPUs. This check makes the casts to size_t below safe.
1137 *
1138 * The max is 4 bytes less than the largest sizeof() so this can be
1139 * tested by putting a SIZE_MAX length in the CBOR test input (no
1140 * one will care the limit on strings is 4 bytes shorter).
1141 */
1142 if(uStrLen > SIZE_MAX-4) {
1143 uReturn = QCBOR_ERR_STRING_TOO_LONG;
1144 goto Done;
1145 }
1146
Laurence Lundblade78a66132024-06-06 12:19:59 -07001147 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(&(pMe->InBuf), (size_t)uStrLen);
Laurence Lundblade62cae932024-06-03 13:16:17 -07001148 if(UsefulBuf_IsNULLC(Bytes)) {
1149 /* Failed to get the bytes for this string item */
1150 uReturn = QCBOR_ERR_HIT_END;
1151 goto Done;
1152 }
1153
1154#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade78a66132024-06-06 12:19:59 -07001155 if(bAllocate) {
1156 /* --- Put string in allocated memory --- */
1157
1158 /* Note that this is not where allocation to coalesce
1159 * indefinite-length strings is done. This is for when the
1160 * caller has requested all strings be allocated. Disabling
1161 * indefinite length strings also disables this allocate-all
1162 * option.
1163 */
1164
1165 if(pMe->StringAllocator.pfAllocator == NULL) {
1166 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1167 goto Done;
1168 }
1169 UsefulBuf NewMem = StringAllocator_Allocate(&(pMe->StringAllocator), (size_t)uStrLen);
Laurence Lundblade62cae932024-06-03 13:16:17 -07001170 if(UsefulBuf_IsNULL(NewMem)) {
1171 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1172 goto Done;
1173 }
1174 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
1175 pDecodedItem->uDataAlloc = 1;
1176 goto Done;
1177 }
Laurence Lundblade62cae932024-06-03 13:16:17 -07001178#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1179
Laurence Lundblade78a66132024-06-06 12:19:59 -07001180 /* --- Normal case with no string allocator --- */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001181 pDecodedItem->val.string = Bytes;
1182 }
1183
1184Done:
1185 return uReturn;
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001186}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001187
1188
Laurence Lundblade62cae932024-06-03 13:16:17 -07001189
1190
Laurence Lundblade78a66132024-06-06 12:19:59 -07001191/**
1192 * @brief Decode array or map.
1193 *
1194 * @param[in] uMode Decoder mode.
1195 * @param[in] nMajorType Whether it is a byte or text string.
1196 * @param[in] uItemCount The length of the string.
1197 * @param[in] nAdditionalInfo Whether it is an indefinite-length.
1198 * @param[out] pDecodedItem The filled-in decoded item.
1199 *
1200 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinites disabled.
1201 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map.
1202 *
1203 * Not much to do for arrays and maps. Just the type
1204 * item count.
1205 *
1206 * This also does the bulk of the work for QCBOR_DECODE_MODE_MAP_AS_ARRAY,
1207 * a special mode to handle arbitrarily complex map labels. This
1208 * ifdefs out with QCBOR_DISABLE_NON_INTEGER_LABELS.
1209 */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001210static QCBORError
1211QCBOR_Private_DecodeArrayOrMap(const uint8_t uMode,
1212 const int nMajorType,
1213 const uint64_t uItemCount,
1214 const int nAdditionalInfo,
1215 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001216{
Laurence Lundblade62cae932024-06-03 13:16:17 -07001217 QCBORError uReturn;
1218
1219 /* ------ Sort out the data type ------ */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001220 #if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
1221 #error QCBOR_TYPE_ARRAY value not lined up with major type
1222 #endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001223
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001224 #if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
1225 #error QCBOR_TYPE_MAP value not lined up with major type
1226 #endif
Laurence Lundblade62cae932024-06-03 13:16:17 -07001227 pDecodedItem->uDataType = (uint8_t)nMajorType;
1228#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1229 if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
1230 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
1231 }
Laurence Lundblade78a66132024-06-06 12:19:59 -07001232#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001233
Laurence Lundblade62cae932024-06-03 13:16:17 -07001234 uReturn = QCBOR_SUCCESS;
1235
1236 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundblade78a66132024-06-06 12:19:59 -07001237 /* ------ Indefinite-length array/map ----- */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001238#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
1239 pDecodedItem->val.uCount = QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH;
1240#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1241 uReturn = QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED;
1242#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1243 } else {
1244
1245#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1246 if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
1247 /* ------ Definite-length map as array ------ */
1248
1249 if(uItemCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
1250 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
1251 } else {
1252 /* cast OK because of check above */
1253 pDecodedItem->val.uCount = (uint16_t)uItemCount*2;
1254 }
1255
1256 } else
Laurence Lundblade78a66132024-06-06 12:19:59 -07001257#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001258 {
1259 /* ------ Definite-length array/map ------ */
1260 if(uItemCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
1261 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
1262 } else {
1263 /* cast OK because of check above */
1264 pDecodedItem->val.uCount = (uint16_t)uItemCount;
1265 }
1266 }
1267 }
1268
1269 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001270}
1271
1272
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001273/**
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001274 * @brief Decode a single primitive data item (decode layer 6).
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001275 *
Laurence Lundblade62cae932024-06-03 13:16:17 -07001276 * param[in] pUInBuf Input buffer to read data item from.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001277 * @param[out] pDecodedItem The filled-in decoded item.
Laurence Lundblade78a66132024-06-06 12:19:59 -07001278 * param[in] pAllocator The allocator to use for strings or NULL.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001279 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001280 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1281 * features
1282 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1283 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1284 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1285 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1286 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1287 * of half-precision disabled
1288 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1289 * float decode is disabled.
1290 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1291 * simple type in input.
1292 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1293 * in input, but indefinite
1294 * lengths disabled.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001295 *
1296 * This decodes the most primitive / atomic data item. It does
1297 * no combing of data items.
1298 */
1299static QCBORError
Laurence Lundblade62cae932024-06-03 13:16:17 -07001300QCBOR_Private_DecodeAtomicDataItem(QCBORDecodeContext *pMe,
Laurence Lundblade78a66132024-06-06 12:19:59 -07001301 const bool bAllocateStrings,
1302 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001303{
1304 QCBORError uReturn;
1305
1306 /* Get the major type and the argument. The argument could be
1307 * length of more bytes or the value depending on the major
1308 * type. nAdditionalInfo is an encoding of the length of the
1309 * uNumber and is needed to decode floats and doubles.
1310 */
1311 int nMajorType = 0;
1312 uint64_t uArgument = 0;
1313 int nAdditionalInfo = 0;
1314
1315 memset(pDecodedItem, 0, sizeof(QCBORItem));
1316
Laurence Lundblade62cae932024-06-03 13:16:17 -07001317 uReturn = QCBOR_Private_DecodeHead(&(pMe->InBuf), &nMajorType, &uArgument, &nAdditionalInfo);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001318 if(uReturn) {
1319 goto Done;
1320 }
1321
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001322 switch (nMajorType) {
1323 case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
1324 case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001325 uReturn = QCBOR_Private_DecodeInteger(nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001326 break;
1327
1328 case CBOR_MAJOR_TYPE_BYTE_STRING: /* Major type 2 */
1329 case CBOR_MAJOR_TYPE_TEXT_STRING: /* Major type 3 */
Laurence Lundblade78a66132024-06-06 12:19:59 -07001330 uReturn = QCBOR_Private_DecodeString(pMe, bAllocateStrings, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001331 break;
1332
1333 case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */
1334 case CBOR_MAJOR_TYPE_MAP: /* Major type 5 */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001335 uReturn = QCBOR_Private_DecodeArrayOrMap(pMe->uDecodeMode, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001336 break;
1337
1338 case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001339 uReturn = QCBOR_Private_DecodeTag(nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001340 break;
1341
1342 case CBOR_MAJOR_TYPE_SIMPLE:
1343 /* Major type 7: float, double, true, false, null... */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001344 uReturn = QCBOR_Private_DecodeType7(nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001345 break;
1346
1347 default:
1348 /* Never happens because DecodeHead() should never return > 7 */
1349 uReturn = QCBOR_ERR_UNSUPPORTED;
1350 break;
1351 }
1352
1353Done:
1354 return uReturn;
1355}
1356
1357
1358/**
1359 * @brief Process indefinite-length strings (decode layer 5).
1360 *
1361 * @param[in] pMe Decoder context
1362 * @param[out] pDecodedItem The decoded item that work is done on.
1363 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001364 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1365 * features
1366 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1367 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1368 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1369 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1370 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1371 * of half-precision disabled
1372 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1373 * float decode is disabled.
1374 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1375 * simple type in input.
1376 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1377 * in input, but indefinite
1378 * lengths disabled.
1379 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1380 * but no string allocator.
1381 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1382 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1383 * input, but indefinite-length
1384 * strings are disabled.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001385 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001386 * If @c pDecodedItem is not an indefinite-length string, this does nothing.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001387 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001388 * If it is, this loops getting the subsequent chunk data items that
1389 * make up the string. The string allocator is used to make a
1390 * contiguous buffer for the chunks. When this completes @c
1391 * pDecodedItem contains the put-together string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001392 *
1393 * Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001394 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001395static QCBORError
1396QCBORDecode_Private_GetNextFullString(QCBORDecodeContext *pMe,
1397 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001398{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001399 /* Aproximate stack usage
1400 * 64-bit 32-bit
1401 * local vars 32 16
1402 * 2 UsefulBufs 32 16
1403 * QCBORItem 56 52
1404 * TOTAL 120 74
1405 */
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001406 QCBORError uReturn;
Laurence Lundblade78a66132024-06-06 12:19:59 -07001407
1408 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, pMe->bStringAllocateAll, pDecodedItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001409 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001410 goto Done;
1411 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001412
Laurence Lundblade78a66132024-06-06 12:19:59 -07001413 /* Skip out if not an indefinite-length string */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001414 const uint8_t uStringType = pDecodedItem->uDataType;
Laurence Lundblade78a66132024-06-06 12:19:59 -07001415 if(uStringType != QCBOR_TYPE_BYTE_STRING &&
1416 uStringType != QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001417 goto Done;
1418 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001419 if(pDecodedItem->val.string.len != QCBOR_STRING_LENGTH_INDEFINITE) {
1420 goto Done;
1421 }
1422
1423#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001424 /* Can't decode indefinite-length strings without a string allocator */
Laurence Lundblade78a66132024-06-06 12:19:59 -07001425 if(!pMe->StringAllocator.pfAllocator) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001426 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1427 goto Done;
1428 }
1429
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001430 /* Loop getting chunks of the indefinite-length string */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001431 UsefulBufC FullString = NULLUsefulBufC;
1432
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001433 for(;;) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001434 /* Get QCBORItem for next chunk */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001435 QCBORItem StringChunkItem;
Laurence Lundblade78a66132024-06-06 12:19:59 -07001436 /* Pass a false to DecodeAtomicDataItem() because the
1437 * individual string chunks in an indefinite-length must not
1438 * be allocated. They are always copied into the allocated contiguous
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001439 * buffer allocated here.
1440 */
Laurence Lundblade78a66132024-06-06 12:19:59 -07001441 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &StringChunkItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001442 if(uReturn) {
1443 break;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001444 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001445
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001446 /* Is item is the marker for end of the indefinite-length string? */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001447 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001448 /* String is complete */
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001449 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301450 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001451 break;
1452 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001453
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001454 /* All chunks must be of the same type, the type of the item
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001455 * that introduces the indefinite-length string. This also
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001456 * catches errors where the chunk is not a string at all and an
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001457 * indefinite-length string inside an indefinite-length string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001458 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001459 if(StringChunkItem.uDataType != uStringType ||
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001460 StringChunkItem.val.string.len == QCBOR_STRING_LENGTH_INDEFINITE) {
1461 uReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001462 break;
1463 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001464
David Navarro9123e5b2022-03-28 16:04:03 +02001465 if (StringChunkItem.val.string.len > 0) {
1466 /* The first time throurgh FullString.ptr is NULL and this is
1467 * equivalent to StringAllocator_Allocate(). Subsequently it is
1468 * not NULL and a reallocation happens.
1469 */
Laurence Lundblade78a66132024-06-06 12:19:59 -07001470 UsefulBuf NewMem = StringAllocator_Reallocate(&(pMe->StringAllocator),
David Navarro9123e5b2022-03-28 16:04:03 +02001471 FullString.ptr,
1472 FullString.len + StringChunkItem.val.string.len);
David Navarro9123e5b2022-03-28 16:04:03 +02001473 if(UsefulBuf_IsNULL(NewMem)) {
1474 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1475 break;
1476 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001477
David Navarro9123e5b2022-03-28 16:04:03 +02001478 /* Copy new string chunk to the end of accumulated string */
1479 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001480 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001481 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001482
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001483 if(uReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
1484 /* Getting the item failed, clean up the allocated memory */
Laurence Lundblade78a66132024-06-06 12:19:59 -07001485 StringAllocator_Free(&(pMe->StringAllocator), FullString.ptr);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001486 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001487#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1488 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1489#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001490
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001491Done:
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001492 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001493}
1494
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001495
Laurence Lundblade37286c02022-09-03 10:05:02 -07001496#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001497/**
1498 * @brief This converts a tag number to a shorter mapped value for storage.
1499 *
1500 * @param[in] pMe The decode context.
1501 * @param[in] uUnMappedTag The tag number to map
1502 * @param[out] puMappedTagNumer The stored tag number.
1503 *
1504 * @return error code.
1505 *
1506 * The main point of mapping tag numbers is make QCBORItem
1507 * smaller. With this mapping storage of 4 tags takes up 8
1508 * bytes. Without, it would take up 32 bytes.
1509 *
1510 * This maps tag numbers greater than QCBOR_LAST_UNMAPPED_TAG.
1511 * QCBOR_LAST_UNMAPPED_TAG is a little smaller than MAX_UINT16.
1512 *
1513 * See also UnMapTagNumber() and @ref QCBORItem.
1514 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001515static QCBORError
1516QCBORDecode_Private_MapTagNumber(QCBORDecodeContext *pMe,
1517 const uint64_t uUnMappedTag,
1518 uint16_t *puMappedTagNumer)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001519{
1520 if(uUnMappedTag > QCBOR_LAST_UNMAPPED_TAG) {
1521 unsigned uTagMapIndex;
1522 /* Is there room in the tag map, or is it in it already? */
1523 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
1524 if(pMe->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID64) {
1525 break;
1526 }
1527 if(pMe->auMappedTags[uTagMapIndex] == uUnMappedTag) {
1528 break;
1529 }
1530 }
1531 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
1532 return QCBOR_ERR_TOO_MANY_TAGS;
1533 }
1534
1535 /* Covers the cases where tag is new and were it is already in the map */
1536 pMe->auMappedTags[uTagMapIndex] = uUnMappedTag;
1537 *puMappedTagNumer = (uint16_t)(uTagMapIndex + QCBOR_LAST_UNMAPPED_TAG + 1);
1538
1539 } else {
1540 *puMappedTagNumer = (uint16_t)uUnMappedTag;
1541 }
1542
1543 return QCBOR_SUCCESS;
1544}
1545
1546
1547/**
1548 * @brief This converts a mapped tag number to the actual tag number.
1549 *
1550 * @param[in] pMe The decode context.
1551 * @param[in] uMappedTagNumber The stored tag number.
1552 *
1553 * @return The actual tag number is returned or
1554 * @ref CBOR_TAG_INVALID64 on error.
1555 *
1556 * This is the reverse of MapTagNumber()
1557 */
1558static uint64_t
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001559QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe,
1560 const uint16_t uMappedTagNumber)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001561{
1562 if(uMappedTagNumber <= QCBOR_LAST_UNMAPPED_TAG) {
1563 return uMappedTagNumber;
1564 } else if(uMappedTagNumber == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07001565 return CBOR_TAG_INVALID64;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001566 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001567 /* This won't be negative because of code below in
1568 * MapTagNumber()
1569 */
1570 const unsigned uIndex = uMappedTagNumber - (QCBOR_LAST_UNMAPPED_TAG + 1);
1571 return pMe->auMappedTags[uIndex];
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001572 }
1573}
Laurence Lundblade37286c02022-09-03 10:05:02 -07001574#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001575
Laurence Lundblade9b334962020-08-27 10:55:53 -07001576
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001577/**
1578 * @brief Aggregate all tags wrapping a data item (decode layer 4).
1579 *
1580 * @param[in] pMe Decoder context
1581 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001582 *
1583 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1584 * features
1585 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1586 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1587 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1588 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1589 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1590 * of half-precision disabled
1591 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1592 * float decode is disabled.
1593 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1594 * simple type in input.
1595 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1596 * in input, but indefinite
1597 * lengths disabled.
1598 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1599 * but no string allocator.
1600 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1601 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1602 * input, but indefinite-length
1603 * strings are disabled.
1604 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001605 *
1606 * This loops getting atomic data items until one is not a tag
1607 * number. Usually this is largely pass-through because most
1608 * item are not tag numbers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001609 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001610static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001611QCBORDecode_Private_GetNextTagNumber(QCBORDecodeContext *pMe,
1612 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001613{
Laurence Lundblade37286c02022-09-03 10:05:02 -07001614#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001615 /* Accummulate the tags from multiple items here and then copy them
1616 * into the last item, the non-tag item.
1617 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001618 uint16_t auItemsTags[QCBOR_MAX_TAGS_PER_ITEM];
1619
1620 /* Initialize to CBOR_TAG_INVALID16 */
1621 #if CBOR_TAG_INVALID16 != 0xffff
1622 /* Be sure the memset does the right thing. */
1623 #err CBOR_TAG_INVALID16 tag not defined as expected
1624 #endif
1625 memset(auItemsTags, 0xff, sizeof(auItemsTags));
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001626
Laurence Lundblade9b334962020-08-27 10:55:53 -07001627 QCBORError uReturn = QCBOR_SUCCESS;
1628
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001629 /* Loop fetching data items until the item fetched is not a tag */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001630 for(;;) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001631 QCBORError uErr = QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07001632 if(uErr != QCBOR_SUCCESS) {
1633 uReturn = uErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001634 goto Done;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001635 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001636
Laurence Lundblade9b334962020-08-27 10:55:53 -07001637 if(pDecodedItem->uDataType != QCBOR_TYPE_TAG) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001638 /* Successful exit from loop; maybe got some tags, maybe not */
1639 memcpy(pDecodedItem->uTags, auItemsTags, sizeof(auItemsTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001640 break;
1641 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001642
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001643 if(auItemsTags[QCBOR_MAX_TAGS_PER_ITEM - 1] != CBOR_TAG_INVALID16) {
1644 /* No room in the tag list */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001645 uReturn = QCBOR_ERR_TOO_MANY_TAGS;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001646 /* Continue on to get all tags wrapping this item even though
1647 * it is erroring out in the end. This allows decoding to
1648 * continue. This is a resource limit error, not a problem
1649 * with being well-formed CBOR.
1650 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001651 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001652 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001653 /* Slide tags over one in the array to make room at index 0.
1654 * Must use memmove because the move source and destination
1655 * overlap.
1656 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001657 memmove(&auItemsTags[1],
1658 auItemsTags,
1659 sizeof(auItemsTags) - sizeof(auItemsTags[0]));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001660
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001661 /* Map the tag */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001662 uint16_t uMappedTagNumber = 0;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001663 uReturn = QCBORDecode_Private_MapTagNumber(pMe, pDecodedItem->val.uTagV, &uMappedTagNumber);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001664 /* Continue even on error so as to consume all tags wrapping
1665 * this data item so decoding can go on. If MapTagNumber()
1666 * errors once it will continue to error.
1667 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001668 auItemsTags[0] = uMappedTagNumber;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001669 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001670
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001671Done:
Laurence Lundblade9b334962020-08-27 10:55:53 -07001672 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001673
Laurence Lundblade37286c02022-09-03 10:05:02 -07001674#else /* QCBOR_DISABLE_TAGS */
1675
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07001676 return QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07001677
1678#endif /* QCBOR_DISABLE_TAGS */
1679}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001680
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001681
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001682/**
1683 * @brief Combine a map entry label and value into one item (decode layer 3).
1684 *
1685 * @param[in] pMe Decoder context
1686 * @param[out] pDecodedItem The decoded item that work is done on.
1687 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001688 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1689 * features
1690 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1691 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1692 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1693 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1694 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1695 * of half-precision disabled
1696 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1697 * float decode is disabled.
1698 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1699 * simple type in input.
1700 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1701 * in input, but indefinite
1702 * lengths disabled.
1703 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1704 * but no string allocator.
1705 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1706 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1707 * input, but indefinite-length
1708 * strings are disabled.
1709 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1710 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1711 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001712 *
Laurence Lundblade62cae932024-06-03 13:16:17 -07001713 * If the current nesting level is a map, then this
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001714 * combines pairs of items into one data item with a label
1715 * and value.
1716 *
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07001717 * This is passthrough if the current nesting level is
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001718 * not a map.
1719 *
1720 * This also implements maps-as-array mode where a map
1721 * is treated like an array to allow caller to do their
1722 * own label processing.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001723 */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001724
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001725static QCBORError
1726QCBORDecode_Private_GetNextMapEntry(QCBORDecodeContext *pMe,
1727 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001728{
Laurence Lundblade62cae932024-06-03 13:16:17 -07001729 QCBORItem LabelItem;
1730 QCBORError uErr;
1731
1732 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1733 if(QCBORDecode_IsUnrecoverableError(uErr)) {
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001734 goto Done;
1735 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001736
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001737 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
1738 /* Break can't be a map entry */
1739 goto Done;
1740 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001741
Laurence Lundblade62cae932024-06-03 13:16:17 -07001742 if(!DecodeNesting_IsCurrentTypeMap(&(pMe->nesting))) {
1743 /* Not decoding a map; nothing to do */
1744 /* This is where maps-as-arrays is effected too */
1745 goto Done;
1746 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001747
Laurence Lundblade62cae932024-06-03 13:16:17 -07001748 /* Decoding a map entry, so the item so far is the label; must get value */
1749 LabelItem = *pDecodedItem;
1750 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1751 if(QCBORDecode_IsUnrecoverableError(uErr)) {
1752 goto Done;
1753 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001754
Laurence Lundblade62cae932024-06-03 13:16:17 -07001755 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
1756 pDecodedItem->uLabelType = LabelItem.uDataType;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001757
Laurence Lundblade62cae932024-06-03 13:16:17 -07001758#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1759 /* QCBOR_DECODE_MODE_MAP_STRINGS_ONLY was a bad idea. Maybe
1760 * get rid of it in QCBOR 2.0
1761 */
1762 if(pMe->uDecodeMode == QCBOR_DECODE_MODE_MAP_STRINGS_ONLY &&
1763 LabelItem.uDataType != QCBOR_TYPE_TEXT_STRING) {
1764 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
1765 goto Done;
1766 }
1767#endif /* !QCBOR_DISABLE_NON_INTEGER_LABELS */
1768
1769 switch(LabelItem.uDataType) {
1770 case QCBOR_TYPE_INT64:
1771 pDecodedItem->label.int64 = LabelItem.val.int64;
1772 break;
1773
1774#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1775 case QCBOR_TYPE_UINT64:
1776 pDecodedItem->label.uint64 = LabelItem.val.uint64;
1777 break;
1778
1779 case QCBOR_TYPE_TEXT_STRING:
1780 case QCBOR_TYPE_BYTE_STRING:
1781 pDecodedItem->label.string = LabelItem.val.string;
1782 break;
1783#endif /* !QCBOR_DISABLE_NON_INTEGER_LABELS */
1784
1785 /* case QCBOR_TYPE_BREAK:
1786 uErr = 99;
1787 goto Done; */
1788
1789 default:
1790 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
1791 goto Done;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001792 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001793
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001794Done:
Laurence Lundblade62cae932024-06-03 13:16:17 -07001795 return uErr;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001796}
1797
1798
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001799#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001800/**
1801 * @brief Peek and see if next data item is a break;
1802 *
Laurence Lundblade62cae932024-06-03 13:16:17 -07001803 * param[in] pUIB UsefulInputBuf to read from.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001804 * @param[out] pbNextIsBreak Indicate if next was a break or not.
1805 *
1806 * @return Any decoding error.
1807 *
1808 * See if next item is a CBOR break. If it is, it is consumed,
1809 * if not it is not consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07001810*/
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001811static QCBORError
Laurence Lundblade62cae932024-06-03 13:16:17 -07001812QCBOR_Private_NextIsBreak(QCBORDecodeContext *pMe, bool *pbNextIsBreak)
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001813{
1814 *pbNextIsBreak = false;
Laurence Lundblade62cae932024-06-03 13:16:17 -07001815 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) != 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001816 QCBORItem Peek;
Laurence Lundblade62cae932024-06-03 13:16:17 -07001817 size_t uPeek = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade78a66132024-06-06 12:19:59 -07001818 QCBORError uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &Peek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001819 if(uReturn != QCBOR_SUCCESS) {
1820 return uReturn;
1821 }
1822 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001823 /* It is not a break, rewind so it can be processed normally. */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001824 UsefulInputBuf_Seek(&(pMe->InBuf), uPeek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001825 } else {
1826 *pbNextIsBreak = true;
1827 }
1828 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001829
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001830 return QCBOR_SUCCESS;
1831}
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001832#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001833
1834
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001835/**
1836 * @brief Ascend up nesting levels if all items in them have been consumed.
1837 *
1838 * @param[in] pMe The decode context.
1839 * @param[in] bMarkEnd If true mark end of maps/arrays with count of zero.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001840 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001841 *
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001842 * An item was just consumed, now figure out if it was the
1843 * end of an array/map map that can be closed out. That
1844 * may in turn close out the above array/map...
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001845 *
1846 * When ascending indefinite-length arrays and maps, this will correctly
1847 * consume the break for the level above. This is a problem for the
1848 * implementation of QCBORDecode_GetArray() that must not return
1849 * that break. @c pbBreak is set to true to indicate that one
1850 * byte should be removed.
1851 *
1852 * Improvement: this could reduced further if indef is disabled
1853 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001854static QCBORError
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001855QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd, bool *pbBreak)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001856{
1857 QCBORError uReturn;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001858
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001859 /* Loop ascending nesting levels as long as there is ascending to do */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001860 while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001861 if(pbBreak) {
1862 *pbBreak = false;
1863 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001864
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001865 if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) {
1866 /* Nesting level is bstr-wrapped CBOR */
1867
1868 /* Ascent for bstr-wrapped CBOR is always by explicit call
1869 * so no further ascending can happen.
1870 */
1871 break;
1872
1873 } else if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
1874 /* Level is a definite-length array/map */
1875
1876 /* Decrement the item count the definite-length array/map */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001877 DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(&(pMe->nesting));
1878 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001879 /* Didn't close out array/map, so all work here is done */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001880 break;
1881 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001882 /* All items in a definite-length array were consumed so it
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001883 * is time to ascend one level. This happens below.
1884 */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001885
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001886#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001887 } else {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001888 /* Level is an indefinite-length array/map. */
1889
1890 /* Check for a break which is what ends indefinite-length arrays/maps */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001891 bool bIsBreak = false;
Laurence Lundblade62cae932024-06-03 13:16:17 -07001892 uReturn = QCBOR_Private_NextIsBreak(pMe, &bIsBreak);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001893 if(uReturn != QCBOR_SUCCESS) {
1894 goto Done;
1895 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001896
1897 if(!bIsBreak) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001898 /* Not a break so array/map does not close out. All work is done */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001899 break;
1900 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001901
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001902 /* It was a break in an indefinitelength map / array so
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001903 * it is time to ascend one level.
1904 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001905 if(pbBreak) {
1906 *pbBreak = true;
1907 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001908
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001909#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001910 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001911
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001912
1913 /* All items in the array/map have been consumed. */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001914
Laurence Lundblade93d89472020-10-03 22:30:50 -07001915 /* But ascent in bounded mode is only by explicit call to
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001916 * QCBORDecode_ExitBoundedMode().
1917 */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07001918 if(DecodeNesting_IsCurrentBounded(&(pMe->nesting))) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001919 /* Set the count to zero for definite-length arrays to indicate
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001920 * cursor is at end of bounded array/map */
Laurence Lundbladed0304932020-06-27 10:59:38 -07001921 if(bMarkEnd) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001922 /* Used for definite and indefinite to signal end */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07001923 DecodeNesting_ZeroMapOrArrayCount(&(pMe->nesting));
Laurence Lundbladed0304932020-06-27 10:59:38 -07001924
Laurence Lundblade2c1faf92020-06-26 22:43:56 -07001925 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001926 break;
1927 }
1928
1929 /* Finally, actually ascend one level. */
1930 DecodeNesting_Ascend(&(pMe->nesting));
1931 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001932
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001933 uReturn = QCBOR_SUCCESS;
1934
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001935#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001936Done:
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001937#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1938
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001939 return uReturn;
1940}
1941
1942
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001943/**
1944 * @brief Ascending & Descending out of nesting levels (decode layer 2).
1945 *
1946 * @param[in] pMe Decoder context
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001947 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001948 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001949
1950 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1951 * features
1952 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1953 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1954 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1955 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1956 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1957 * of half-precision disabled
1958 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1959 * float decode is disabled.
1960 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1961 * simple type in input.
1962 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1963 * in input, but indefinite
1964 * lengths disabled.
1965 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1966 * but no string allocator.
1967 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1968 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1969 * input, but indefinite-length
1970 * strings are disabled.
1971 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1972 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1973 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
1974 * @retval QCBOR_ERR_NO_MORE_ITEMS Need more items for map or array.
1975 * @retval QCBOR_ERR_BAD_BREAK Indefinite-length break in wrong
1976 * place.
1977 * @retval QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP Nesting deeper than QCBOR
1978 * can handle.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001979 *
1980 * This handles the traversal descending into and asecnding out of
1981 * maps, arrays and bstr-wrapped CBOR. It figures out the ends of
1982 * definite- and indefinte-length maps and arrays by looking at the
1983 * item count or finding CBOR breaks. It detects the ends of the
1984 * top-level sequence and of bstr-wrapped CBOR by byte count.
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001985 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001986static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001987QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001988 bool *pbBreak,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001989 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001990{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001991 QCBORError uReturn;
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07001992 /* ==== First: figure out if at the end of a traversal ==== */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001993
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001994 /* If out of bytes to consume, it is either the end of the
1995 * top-level sequence of some bstr-wrapped CBOR that was entered.
1996 *
1997 * In the case of bstr-wrapped CBOR, the length of the
1998 * UsefulInputBuf was set to that of the bstr-wrapped CBOR. When
1999 * the bstr-wrapped CBOR is exited, the length is set back to the
2000 * top-level's length or to the next highest bstr-wrapped CBOR.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002001 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002002 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) == 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002003 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002004 goto Done;
2005 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07002006
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002007 /* Check to see if at the end of a bounded definite-length map or
2008 * array. The check for a break ending indefinite-length array is
2009 * later in QCBORDecode_NestLevelAscender().
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002010 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002011 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002012 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002013 goto Done;
2014 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002015
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002016 /* ==== Next: not at the end, so get another item ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002017 uReturn = QCBORDecode_Private_GetNextMapEntry(pMe, pDecodedItem);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002018 if(QCBORDecode_IsUnrecoverableError(uReturn)) {
2019 /* Error is so bad that traversal is not possible. */
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002020 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002021 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05302022
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002023 /* Breaks ending arrays/maps are processed later in the call to
2024 * QCBORDecode_NestLevelAscender(). They should never show up here.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002025 */
Laurence Lundblade6de37062018-10-15 12:22:42 +05302026 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002027 uReturn = QCBOR_ERR_BAD_BREAK;
Laurence Lundblade6de37062018-10-15 12:22:42 +05302028 goto Done;
Laurence Lundblade5b8c5852018-10-14 21:11:42 +05302029 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002030
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002031 /* Record the nesting level for this data item before processing
2032 * any of decrementing and descending.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002033 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002034 pDecodedItem->uNestingLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002035
Laurence Lundblade642282a2020-06-23 12:00:33 -07002036
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002037 /* ==== Next: Process the item for descent, ascent, decrement... ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002038 if(QCBORItem_IsMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002039 /* If the new item is a map or array, descend.
2040 *
2041 * Empty indefinite-length maps and arrays are descended into,
2042 * but then ascended out of in the next chunk of code.
2043 *
2044 * Maps and arrays do count as items in the map/array that
2045 * encloses them so a decrement needs to be done for them too,
2046 * but that is done only when all the items in them have been
2047 * processed, not when they are opened with the exception of an
2048 * empty map or array.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002049 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002050 QCBORError uDescendErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002051 uDescendErr = DecodeNesting_DescendMapOrArray(&(pMe->nesting),
Laurence Lundblade642282a2020-06-23 12:00:33 -07002052 pDecodedItem->uDataType,
2053 pDecodedItem->val.uCount);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002054 if(uDescendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002055 /* This error is probably a traversal error and it overrides
2056 * the non-traversal error.
2057 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002058 uReturn = uDescendErr;
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002059 goto Done;
2060 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002061 }
2062
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002063 if(!QCBORItem_IsMapOrArray(*pDecodedItem) ||
2064 QCBORItem_IsEmptyDefiniteLengthMapOrArray(*pDecodedItem) ||
2065 QCBORItem_IsIndefiniteLengthMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002066 /* The following cases are handled here:
2067 * - A non-aggregate item like an integer or string
2068 * - An empty definite-length map or array
2069 * - An indefinite-length map or array that might be empty or might not.
2070 *
2071 * QCBORDecode_NestLevelAscender() does the work of decrementing the count
2072 * for an definite-length map/array and break detection for an
2073 * indefinite-0length map/array. If the end of the map/array was
2074 * reached, then it ascends nesting levels, possibly all the way
2075 * to the top level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002076 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002077 QCBORError uAscendErr;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002078 uAscendErr = QCBORDecode_Private_NestLevelAscender(pMe, true, pbBreak);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002079 if(uAscendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002080 /* This error is probably a traversal error and it overrides
2081 * the non-traversal error.
2082 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002083 uReturn = uAscendErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002084 goto Done;
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002085 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05302086 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002087
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002088 /* ==== Last: tell the caller the nest level of the next item ==== */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002089 /* Tell the caller what level is next. This tells them what
2090 * maps/arrays were closed out and makes it possible for them to
2091 * reconstruct the tree with just the information returned in a
2092 * QCBORItem.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002093 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002094 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07002095 /* At end of a bounded map/array; uNextNestLevel 0 to indicate this */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002096 pDecodedItem->uNextNestLevel = 0;
2097 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002098 pDecodedItem->uNextNestLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002099 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002100
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002101Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002102 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002103}
2104
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002105
Laurence Lundblade37286c02022-09-03 10:05:02 -07002106#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002107/**
2108 * @brief Shift 0th tag out of the tag list.
2109 *
2110 * pDecodedItem[in,out] The data item to convert.
2111 *
2112 * The 0th tag is discarded. \ref CBOR_TAG_INVALID16 is
2113 * shifted into empty slot at the end of the tag list.
2114 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002115static void
2116QCBOR_Private_ShiftTags(QCBORItem *pDecodedItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002117{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002118 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM-1; i++) {
2119 pDecodedItem->uTags[i] = pDecodedItem->uTags[i+1];
2120 }
2121 pDecodedItem->uTags[QCBOR_MAX_TAGS_PER_ITEM-1] = CBOR_TAG_INVALID16;
Laurence Lundblade9b334962020-08-27 10:55:53 -07002122}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002123#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002124
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002125
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002126/**
2127 * @brief Convert different epoch date formats in to the QCBOR epoch date format
2128 *
2129 * pDecodedItem[in,out] The data item to convert.
2130 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002131 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2132 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2133 * floating-point date disabled.
2134 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2135 * all floating-point disabled.
2136 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2137 * error decoding date.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002138 *
2139 * The epoch date tag defined in QCBOR allows for floating-point
2140 * dates. It even allows a protocol to flop between date formats when
2141 * ever it wants. Floating-point dates aren't that useful as they are
2142 * only needed for dates beyond the age of the earth.
2143 *
2144 * This converts all the date formats into one format of an unsigned
2145 * integer plus a floating-point fraction.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002146 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002147static QCBORError
2148QCBOR_Private_DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002149{
Laurence Lundbladec7114722020-08-13 05:11:40 -07002150 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002151
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002152#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade59289e52019-12-30 13:44:37 -08002153 pDecodedItem->val.epochDate.fSecondsFraction = 0;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002154#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002155
2156 switch (pDecodedItem->uDataType) {
2157
2158 case QCBOR_TYPE_INT64:
2159 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
2160 break;
2161
2162 case QCBOR_TYPE_UINT64:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002163 /* This only happens for CBOR type 0 > INT64_MAX so it is
2164 * always an overflow.
2165 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07002166 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2167 goto Done;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002168 break;
2169
2170 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade9682a532020-06-06 18:33:04 -07002171 case QCBOR_TYPE_FLOAT:
2172#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade59289e52019-12-30 13:44:37 -08002173 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002174 /* Convert working value to double if input was a float */
Laurence Lundblade3ed0bca2020-07-14 22:50:10 -07002175 const double d = pDecodedItem->uDataType == QCBOR_TYPE_DOUBLE ?
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002176 pDecodedItem->val.dfnum :
2177 (double)pDecodedItem->val.fnum;
2178
2179 /* The conversion from float to integer requires overflow
2180 * detection since floats can be much larger than integers.
2181 * This implementation errors out on these large float values
2182 * since they are beyond the age of the earth.
2183 *
2184 * These constants for the overflow check are computed by the
2185 * compiler. They are not computed at run time.
2186 *
2187 * The factor of 0x7ff is added/subtracted to avoid a
2188 * rounding error in the wrong direction when the compiler
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002189 * computes these constants. There is rounding because a
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002190 * 64-bit integer has 63 bits of precision where a double
2191 * only has 53 bits. Without the 0x7ff factor, the compiler
2192 * may round up and produce a double for the bounds check
2193 * that is larger than can be stored in a 64-bit integer. The
2194 * amount of 0x7ff is picked because it has 11 bits set.
2195 *
2196 * Without the 0x7ff there is a ~30 minute range of time
2197 * values 10 billion years in the past and in the future
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002198 * where this code could go wrong. Some compilers
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002199 * generate a warning or error without the 0x7ff.
2200 */
2201 const double dDateMax = (double)(INT64_MAX - 0x7ff);
2202 const double dDateMin = (double)(INT64_MIN + 0x7ff);
2203
2204 if(isnan(d) || d > dDateMax || d < dDateMin) {
Laurence Lundbladec7114722020-08-13 05:11:40 -07002205 uReturn = QCBOR_ERR_DATE_OVERFLOW;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002206 goto Done;
2207 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002208
2209 /* The actual conversion */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002210 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
Laurence Lundblade2feb1e12020-07-15 03:50:45 -07002211 pDecodedItem->val.epochDate.fSecondsFraction =
2212 d - (double)pDecodedItem->val.epochDate.nSeconds;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002213 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002214#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade4b270642020-08-14 12:53:07 -07002215
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002216 uReturn = QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundblade4b270642020-08-14 12:53:07 -07002217 goto Done;
2218
Laurence Lundblade9682a532020-06-06 18:33:04 -07002219#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002220 break;
2221
2222 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002223 /* It's the arrays and maps that are unrecoverable because
2224 * they are not consumed here. Since this is just an error
2225 * condition, no extra code is added here to make the error
2226 * recoverable for non-arrays and maps like strings. */
2227 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002228 goto Done;
2229 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002230
Laurence Lundblade59289e52019-12-30 13:44:37 -08002231 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
2232
2233Done:
Laurence Lundbladec7114722020-08-13 05:11:40 -07002234 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002235}
2236
2237
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002238/**
2239 * @brief Convert the days epoch date.
2240 *
2241 * pDecodedItem[in,out] The data item to convert.
2242 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002243 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2244 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2245 * floating-point date disabled.
2246 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2247 * all floating-point disabled.
2248 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2249 * error decoding date.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002250 *
2251 * This is much simpler than the other epoch date format because
2252 * floating-porint is not allowed. This is mostly a simple type check.
2253 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002254static QCBORError
2255QCBOR_Private_DecodeDaysEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002256{
2257 QCBORError uReturn = QCBOR_SUCCESS;
2258
2259 switch (pDecodedItem->uDataType) {
2260
2261 case QCBOR_TYPE_INT64:
2262 pDecodedItem->val.epochDays = pDecodedItem->val.int64;
2263 break;
2264
2265 case QCBOR_TYPE_UINT64:
2266 /* This only happens for CBOR type 0 > INT64_MAX so it is
2267 * always an overflow.
2268 */
2269 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2270 goto Done;
2271 break;
2272
2273 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002274 /* It's the arrays and maps that are unrecoverable because
2275 * they are not consumed here. Since this is just an error
2276 * condition, no extra code is added here to make the error
2277 * recoverable for non-arrays and maps like strings. */
2278 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002279 goto Done;
2280 break;
2281 }
2282
2283 pDecodedItem->uDataType = QCBOR_TYPE_DAYS_EPOCH;
2284
2285Done:
2286 return uReturn;
2287}
2288
2289
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002290#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade37286c02022-09-03 10:05:02 -07002291
2292/* Forward declaration is necessary for
2293 * QCBORDecode_MantissaAndExponent(). to be able to decode bignum
2294 * tags in the mantissa. If the mantissa is a decimal fraction or big
2295 * float in error, this will result in a recurive call to
2296 * QCBORDecode_MantissaAndExponent(), but the recursion will unwined
2297 * correctly and the correct error is returned.
2298 */
2299static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002300QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2301 QCBORItem *pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002302
2303
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002304/**
2305 * @brief Decode decimal fractions and big floats.
2306 *
2307 * @param[in] pMe The decode context.
2308 * @param[in,out] pDecodedItem On input the array data item that
2309 * holds the mantissa and exponent. On
2310 * output the decoded mantissa and
2311 * exponent.
2312 *
2313 * @returns Decoding errors from getting primitive data items or
2314 * \ref QCBOR_ERR_BAD_EXP_AND_MANTISSA.
2315 *
Laurence Lundblade37286c02022-09-03 10:05:02 -07002316 * When called pDecodedItem must be the array with two members, the
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002317 * exponent and mantissa.
2318 *
2319 * This will fetch and decode the exponent and mantissa and put the
2320 * result back into pDecodedItem.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002321 *
2322 * This does no checking or processing of tag numbers. That is to be
2323 * done by the code that calls this.
2324 *
2325 * This stuffs the type of the mantissa into pDecodedItem with the expectation
2326 * the caller will process it.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002327 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002328static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002329QCBORDecode_Private_ExpMantissa(QCBORDecodeContext *pMe,
2330 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002331{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002332 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002333
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002334 /* --- Make sure it is an array; track nesting level of members --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002335 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002336 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002337 goto Done;
2338 }
2339
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002340 /* A check for pDecodedItem->val.uCount == 2 would work for
Laurence Lundblade37286c02022-09-03 10:05:02 -07002341 * definite-length arrays, but not for indefinite. Instead remember
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002342 * the nesting level the two integers must be at, which is one
2343 * deeper than that of the array.
2344 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002345 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
2346
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002347 /* --- Get the exponent --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002348 QCBORItem exponentItem;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002349 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, &exponentItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002350 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002351 goto Done;
2352 }
2353 if(exponentItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002354 /* Array is empty or a map/array encountered when expecting an int */
2355 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002356 goto Done;
2357 }
2358 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002359 /* Data arriving as an unsigned int < INT64_MAX has been
2360 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2361 * also means that the only data arriving here of type
2362 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2363 * and thus an error that will get handled in the next else.
2364 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002365 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
2366 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002367 /* Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX */
2368 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002369 goto Done;
2370 }
2371
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002372 /* --- Get the mantissa --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002373 QCBORItem mantissaItem;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002374 uReturn = QCBORDecode_Private_GetNextTagContent(pMe, &mantissaItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002375 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002376 goto Done;
2377 }
2378 if(mantissaItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002379 /* Mantissa missing or map/array encountered when expecting number */
2380 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002381 goto Done;
2382 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002383 /* Stuff the mantissa data type into the item to send it up to the
2384 * the next level. */
2385 pDecodedItem->uDataType = mantissaItem.uDataType;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002386 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002387 /* Data arriving as an unsigned int < INT64_MAX has been
2388 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2389 * also means that the only data arriving here of type
2390 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2391 * and thus an error that will get handled in an else below.
2392 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002393 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002394#ifndef QCBOR_DISABLE_TAGS
2395 /* With tags fully disabled a big number mantissa will error out
2396 * in the call to QCBORDecode_GetNextWithTags() because it has
2397 * a tag number.
2398 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07002399 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM ||
2400 mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002401 /* Got a good big num mantissa */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002402 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002403#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002404 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002405 /* Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX */
2406 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002407 goto Done;
2408 }
2409
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002410 /* --- Check that array only has the two numbers --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002411 if(mantissaItem.uNextNestLevel == nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002412 /* Extra items in the decimal fraction / big float */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002413 /* Improvement: this should probably be an unrecoverable error. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002414 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002415 goto Done;
2416 }
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002417 pDecodedItem->uNextNestLevel = mantissaItem.uNextNestLevel;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002418
2419Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002420 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002421}
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002422#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002423
2424
Laurence Lundblade37286c02022-09-03 10:05:02 -07002425#ifndef QCBOR_DISABLE_TAGS
2426
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002427#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002428/**
2429 * @brief Decode the MIME type tag
2430 *
2431 * @param[in,out] pDecodedItem The item to decode.
2432 *
2433 * Handle the text and binary MIME type tags. Slightly too complicated
2434 * f or ProcessTaggedString() because the RFC 7049 MIME type was
2435 * incorreclty text-only.
2436 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002437static QCBORError
2438QCBOR_Private_DecodeMIME(QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002439{
2440 if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) {
2441 pDecodedItem->uDataType = QCBOR_TYPE_MIME;
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07002442 } else if(pDecodedItem->uDataType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002443 pDecodedItem->uDataType = QCBOR_TYPE_BINARY_MIME;
2444 } else {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002445 /* It's the arrays and maps that are unrecoverable because
2446 * they are not consumed here. Since this is just an error
2447 * condition, no extra code is added here to make the error
2448 * recoverable for non-arrays and maps like strings. */
2449 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002450 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002451
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002452 return QCBOR_SUCCESS;
2453}
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002454#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002455
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002456/**
Laurence Lundblade99615302020-11-29 11:19:47 -08002457 * Table of CBOR tags whose content is either a text string or a byte
2458 * string. The table maps the CBOR tag to the QCBOR type. The high-bit
2459 * of uQCBORtype indicates the content should be a byte string rather
2460 * than a text string
2461 */
2462struct StringTagMapEntry {
2463 uint16_t uTagNumber;
2464 uint8_t uQCBORtype;
2465};
2466
2467#define IS_BYTE_STRING_BIT 0x80
2468#define QCBOR_TYPE_MASK ~IS_BYTE_STRING_BIT
2469
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002470static const struct StringTagMapEntry QCBOR_Private_StringTagMap[] = {
Laurence Lundblade99615302020-11-29 11:19:47 -08002471 {CBOR_TAG_DATE_STRING, QCBOR_TYPE_DATE_STRING},
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002472 {CBOR_TAG_DAYS_STRING, QCBOR_TYPE_DAYS_STRING},
Laurence Lundblade99615302020-11-29 11:19:47 -08002473 {CBOR_TAG_POS_BIGNUM, QCBOR_TYPE_POSBIGNUM | IS_BYTE_STRING_BIT},
2474 {CBOR_TAG_NEG_BIGNUM, QCBOR_TYPE_NEGBIGNUM | IS_BYTE_STRING_BIT},
2475 {CBOR_TAG_CBOR, QBCOR_TYPE_WRAPPED_CBOR | IS_BYTE_STRING_BIT},
2476 {CBOR_TAG_URI, QCBOR_TYPE_URI},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002477#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002478 {CBOR_TAG_B64URL, QCBOR_TYPE_BASE64URL},
2479 {CBOR_TAG_B64, QCBOR_TYPE_BASE64},
2480 {CBOR_TAG_REGEX, QCBOR_TYPE_REGEX},
2481 {CBOR_TAG_BIN_UUID, QCBOR_TYPE_UUID | IS_BYTE_STRING_BIT},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002482#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade99615302020-11-29 11:19:47 -08002483 {CBOR_TAG_CBOR_SEQUENCE, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE | IS_BYTE_STRING_BIT},
2484 {CBOR_TAG_INVALID16, QCBOR_TYPE_NONE}
2485};
2486
2487
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002488/**
2489 * @brief Process standard CBOR tags whose content is a string
2490 *
2491 * @param[in] uTag The tag.
2492 * @param[in,out] pDecodedItem The data item.
2493 *
2494 * @returns This returns QCBOR_SUCCESS if the tag was procssed,
2495 * \ref QCBOR_ERR_UNSUPPORTED if the tag was not processed and
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002496 * \ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT if the content type was wrong for the tag.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002497 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002498 * Process the CBOR tags that whose content is a byte string or a text
2499 * string and for which the string is just passed on to the caller.
2500 *
2501 * This maps the CBOR tag to the QCBOR type and checks the content
2502 * type. Nothing more. It may not be the most important
Laurence Lundbladec02e13e2020-12-06 05:45:41 -08002503 * functionality, but it part of implementing as much of RFC 8949 as
Laurence Lundblade99615302020-11-29 11:19:47 -08002504 * possible.
Laurence Lundblade99615302020-11-29 11:19:47 -08002505 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002506static QCBORError
2507QCBOR_Private_ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002508{
Laurence Lundblade99615302020-11-29 11:19:47 -08002509 /* This only works on tags that were not mapped; no need for other yet */
2510 if(uTag > QCBOR_LAST_UNMAPPED_TAG) {
2511 return QCBOR_ERR_UNSUPPORTED;
2512 }
2513
2514 unsigned uIndex;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002515 for(uIndex = 0; QCBOR_Private_StringTagMap[uIndex].uTagNumber != CBOR_TAG_INVALID16; uIndex++) {
2516 if(QCBOR_Private_StringTagMap[uIndex].uTagNumber == uTag) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002517 break;
2518 }
2519 }
2520
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002521 const uint8_t uQCBORType = QCBOR_Private_StringTagMap[uIndex].uQCBORtype;
Laurence Lundblade99615302020-11-29 11:19:47 -08002522 if(uQCBORType == QCBOR_TYPE_NONE) {
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002523 /* repurpose this error to mean not handled here */
Laurence Lundblade99615302020-11-29 11:19:47 -08002524 return QCBOR_ERR_UNSUPPORTED;
2525 }
2526
2527 uint8_t uExpectedType = QCBOR_TYPE_TEXT_STRING;
2528 if(uQCBORType & IS_BYTE_STRING_BIT) {
2529 uExpectedType = QCBOR_TYPE_BYTE_STRING;
2530 }
2531
2532 if(pDecodedItem->uDataType != uExpectedType) {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002533 /* It's the arrays and maps that are unrecoverable because
2534 * they are not consumed here. Since this is just an error
2535 * condition, no extra code is added here to make the error
2536 * recoverable for non-arrays and maps like strings. */
2537 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002538 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002539
Laurence Lundblade99615302020-11-29 11:19:47 -08002540 pDecodedItem->uDataType = (uint8_t)(uQCBORType & QCBOR_TYPE_MASK);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002541 return QCBOR_SUCCESS;
2542}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002543#endif /* QCBOR_DISABLE_TAGS */
2544
2545
2546#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002547/**
2548 * @brief Figures out data type for exponent mantissa tags.
2549 *
2550 * @param[in] uTagToProcess Either @ref CBOR_TAG_DECIMAL_FRACTION or
2551 * @ref CBOR_TAG_BIG_FLOAT.
2552 * @param[in] pDecodedItem Item being decoded.
2553 *
2554 * @returns One of the 6 values between \ref QCBOR_TYPE_DECIMAL_FRACTION
2555 * and @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM.
2556 *
2557 * Does mapping between a CBOR tag number and a QCBOR type. with a
2558 * little bit of logic and arithmatic.
2559 *
2560 * Used in serveral contexts. Does the work where sometimes the data
2561 * item is explicitly tagged and sometimes not.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002562 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002563static uint8_t
2564QCBOR_Private_ExpMantissaDataType(const uint16_t uTagToProcess,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002565 const QCBORItem *pDecodedItem)
Laurence Lundblade37286c02022-09-03 10:05:02 -07002566{
2567 uint8_t uBase = uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ?
2568 QCBOR_TYPE_DECIMAL_FRACTION :
2569 QCBOR_TYPE_BIGFLOAT;
2570 if(pDecodedItem->uDataType != QCBOR_TYPE_INT64) {
2571 uBase = (uint8_t)(uBase + pDecodedItem->uDataType - QCBOR_TYPE_POSBIGNUM + 1);
2572 }
2573 return uBase;
2574}
2575#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002576
2577
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002578/**
2579 * @brief Decode tag content for select tags (decoding layer 1).
2580 *
2581 * @param[in] pMe The decode context.
2582 * @param[out] pDecodedItem The decoded item.
2583 *
2584 * @return Decoding error code.
2585 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002586 * CBOR tag numbers for the item were decoded in GetNext_TaggedItem(),
2587 * but the whole tag was not decoded. Here, the whole tags (tag number
2588 * and tag content) that are supported by QCBOR are decoded. This is a
2589 * quick pass through for items that are not tags.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002590 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002591static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002592QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2593 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002594{
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002595 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002596
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002597 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pDecodedItem);
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002598 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002599 goto Done;
2600 }
2601
Laurence Lundblade37286c02022-09-03 10:05:02 -07002602#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002603 /* When there are no tag numbers for the item, this exits first
2604 * thing and effectively does nothing.
2605 *
2606 * This loops over all the tag numbers accumulated for this item
2607 * trying to decode and interpret them. This stops at the end of
2608 * the list or at the first tag number that can't be interpreted by
2609 * this code. This is effectively a recursive processing of the
2610 * tags number list that handles nested tags.
2611 */
2612 while(1) {
2613 /* Don't bother to unmap tags via QCBORITem.uTags since this
2614 * code only works on tags less than QCBOR_LAST_UNMAPPED_TAG.
2615 */
2616 const uint16_t uTagToProcess = pDecodedItem->uTags[0];
Laurence Lundblade59289e52019-12-30 13:44:37 -08002617
Laurence Lundblade99615302020-11-29 11:19:47 -08002618 if(uTagToProcess == CBOR_TAG_INVALID16) {
2619 /* Hit the end of the tag list. A successful exit. */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002620 break;
2621
Laurence Lundblade99615302020-11-29 11:19:47 -08002622 } else if(uTagToProcess == CBOR_TAG_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002623 uReturn = QCBOR_Private_DecodeDateEpoch(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002624
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002625 } else if(uTagToProcess == CBOR_TAG_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002626 uReturn = QCBOR_Private_DecodeDaysEpoch(pDecodedItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002627
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002628#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade99615302020-11-29 11:19:47 -08002629 } else if(uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ||
2630 uTagToProcess == CBOR_TAG_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002631 uReturn = QCBORDecode_Private_ExpMantissa(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002632 /* --- Which is it, decimal fraction or a bigfloat? --- */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002633 pDecodedItem->uDataType = QCBOR_Private_ExpMantissaDataType(uTagToProcess, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002634
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002635#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002636#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002637 } else if(uTagToProcess == CBOR_TAG_MIME ||
2638 uTagToProcess == CBOR_TAG_BINARY_MIME) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002639 uReturn = QCBOR_Private_DecodeMIME(pDecodedItem);
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002640#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002641
Laurence Lundblade99615302020-11-29 11:19:47 -08002642 } else {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002643 /* See if it is a passthrough byte/text string tag; process if so */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002644 uReturn = QCBOR_Private_ProcessTaggedString(pDecodedItem->uTags[0], pDecodedItem);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002645
Laurence Lundblade99615302020-11-29 11:19:47 -08002646 if(uReturn == QCBOR_ERR_UNSUPPORTED) {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002647 /* It wasn't a passthrough byte/text string tag so it is
Laurence Lundblade99615302020-11-29 11:19:47 -08002648 * an unknown tag. This is the exit from the loop on the
2649 * first unknown tag. It is a successful exit.
2650 */
2651 uReturn = QCBOR_SUCCESS;
2652 break;
2653 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002654 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002655
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002656 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002657 /* Error exit from the loop */
2658 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002659 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002660
2661 /* A tag was successfully processed, shift it out of the list of
2662 * tags returned. This is the loop increment.
2663 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002664 QCBOR_Private_ShiftTags(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002665 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002666#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002667
2668Done:
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002669 return uReturn;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002670}
2671
2672
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002673/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002674 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002675 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002676QCBORError
2677QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2678{
2679 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002680 uErr = QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002681 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002682 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2683 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
2684 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002685 return uErr;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002686}
2687
2688
2689/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002690 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08002691 */
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002692QCBORError
2693QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2694{
2695 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2696 const UsefulInputBuf Save = pMe->InBuf;
2697
2698 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
2699
2700 pMe->nesting = SaveNesting;
2701 pMe->InBuf = Save;
2702
2703 return uErr;
2704}
2705
2706
2707/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002708 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002709 */
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002710void
2711QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2712{
2713 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002714 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2715 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002716 return;
2717 }
2718
2719 pMe->uLastError = (uint8_t)QCBORDecode_PeekNext(pMe, pDecodedItem);
2720}
2721
2722
2723/*
2724 * Public function, see header qcbor/qcbor_decode.h file
2725 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002726void
2727QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002728{
2729 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002730 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2731 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002732 return;
2733 }
2734
2735 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem);
2736}
2737
2738
2739/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002740 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002741 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002742QCBORError
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002743QCBORDecode_GetNextWithTags(QCBORDecodeContext *pMe,
2744 QCBORItem *pDecodedItem,
2745 QCBORTagListOut *pTags)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002746{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002747#ifndef QCBOR_DISABLE_TAGS
2748
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002749 QCBORError uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002750
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002751 uReturn = QCBORDecode_GetNext(pMe, pDecodedItem);
2752 if(uReturn != QCBOR_SUCCESS) {
2753 return uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002754 }
2755
2756 if(pTags != NULL) {
2757 pTags->uNumUsed = 0;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002758 /* Reverse the order because pTags is reverse of QCBORItem.uTags. */
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002759 for(int nTagIndex = QCBOR_MAX_TAGS_PER_ITEM-1; nTagIndex >=0; nTagIndex--) {
2760 if(pDecodedItem->uTags[nTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07002761 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002762 }
2763 if(pTags->uNumUsed >= pTags->uNumAllocated) {
2764 return QCBOR_ERR_TOO_MANY_TAGS;
2765 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002766 pTags->puTags[pTags->uNumUsed] = QCBORDecode_Private_UnMapTagNumber(pMe,pDecodedItem->uTags[nTagIndex]);
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002767 pTags->uNumUsed++;
2768 }
2769 }
2770
2771 return QCBOR_SUCCESS;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002772
2773#else /* QCBOR_DISABLE_TAGS */
2774 (void)pMe;
2775 (void)pDecodedItem;
2776 (void)pTags;
2777 return QCBOR_ERR_TAGS_DISABLED;
2778#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002779}
2780
2781
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002782/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002783 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05302784 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002785bool
2786QCBORDecode_IsTagged(QCBORDecodeContext *pMe,
2787 const QCBORItem *pItem,
2788 uint64_t uTag)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002789{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002790#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002791 for(unsigned uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) {
2792 if(pItem->uTags[uTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002793 break;
2794 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002795 if(QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uTagIndex]) == uTag) {
Laurence Lundbladef71e1622020-08-06 18:52:13 -07002796 return true;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002797 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002798 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002799#else /* QCBOR_TAGS_DISABLED */
2800 (void)pMe;
2801 (void)pItem;
2802 (void)uTag;
2803#endif /* QCBOR_TAGS_DISABLED */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002804
Laurence Lundbladef71e1622020-08-06 18:52:13 -07002805 return false;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002806}
2807
2808
2809/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002810 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002811 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002812QCBORError
2813QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002814{
Laurence Lundblade87495732021-02-26 10:05:55 -07002815 if(puConsumed != NULL) {
2816 *puConsumed = pMe->InBuf.cursor;
2817 }
2818
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002819 QCBORError uReturn = pMe->uLastError;
Laurence Lundblade085d7952020-07-24 10:26:30 -07002820
2821 if(uReturn != QCBOR_SUCCESS) {
2822 goto Done;
2823 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002824
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002825 /* Error out if all the maps/arrays are not closed out */
2826 if(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002827 uReturn = QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002828 goto Done;
2829 }
2830
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002831 /* Error out if not all the bytes are consumed */
2832 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf))) {
Laurence Lundblade085d7952020-07-24 10:26:30 -07002833 uReturn = QCBOR_ERR_EXTRA_BYTES;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002834 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002835
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002836Done:
Laurence Lundblade87495732021-02-26 10:05:55 -07002837 return uReturn;
2838}
2839
2840
2841/*
2842 * Public function, see header qcbor/qcbor_decode.h file
2843 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002844QCBORError
2845QCBORDecode_Finish(QCBORDecodeContext *pMe)
Laurence Lundblade87495732021-02-26 10:05:55 -07002846{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002847#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002848 /* Call the destructor for the string allocator if there is one.
2849 * Always called, even if there are errors; always have to clean up.
2850 */
2851 StringAllocator_Destruct(&(pMe->StringAllocator));
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002852#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002853
Laurence Lundblade87495732021-02-26 10:05:55 -07002854 return QCBORDecode_PartialFinish(pMe, NULL);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002855}
2856
2857
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002858/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002859 * Public function, see header qcbor/qcbor_decode.h file
2860 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002861uint64_t
2862QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
2863 const QCBORItem *pItem,
2864 uint32_t uIndex)
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002865{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002866#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002867 if(pItem->uDataType == QCBOR_TYPE_NONE) {
2868 return CBOR_TAG_INVALID64;
2869 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002870 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2871 return CBOR_TAG_INVALID64;
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002872 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002873 return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uIndex]);
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002874 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002875#else /* QCBOR_DISABLE_TAGS */
2876 (void)pMe;
2877 (void)pItem;
2878 (void)uIndex;
2879
2880 return CBOR_TAG_INVALID64;
2881#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002882}
2883
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002884
Laurence Lundblade9b334962020-08-27 10:55:53 -07002885/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002886 * Public function, see header qcbor/qcbor_decode.h file
2887 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002888uint64_t
2889QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe,
2890 uint32_t uIndex)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002891{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002892#ifndef QCBOR_DISABLE_TAGS
2893
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002894 if(pMe->uLastError != QCBOR_SUCCESS) {
2895 return CBOR_TAG_INVALID64;
2896 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002897 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2898 return CBOR_TAG_INVALID64;
2899 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002900 return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->uLastTags[uIndex]);
Laurence Lundblade9b334962020-08-27 10:55:53 -07002901 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002902#else /* QCBOR_DISABLE_TAGS */
2903 (void)pMe;
2904 (void)uIndex;
2905
2906 return CBOR_TAG_INVALID64;
2907#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07002908}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002909
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002910
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002911
2912
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002913#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladef6531662018-12-04 10:42:22 +09002914
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002915/* ===========================================================================
2916 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002917
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002918 This implements a simple sting allocator for indefinite-length
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002919 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
2920 implements the function type QCBORStringAllocate and allows easy
2921 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09002922
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002923 This particular allocator is built-in for convenience. The caller
2924 can implement their own. All of this following code will get
2925 dead-stripped if QCBORDecode_SetMemPool() is not called.
2926
2927 This is a very primitive memory allocator. It does not track
2928 individual allocations, only a high-water mark. A free or
2929 reallocation must be of the last chunk allocated.
2930
2931 The size of the pool and offset to free memory are packed into the
2932 first 8 bytes of the memory pool so we don't have to keep them in
2933 the decode context. Since the address of the pool may not be
2934 aligned, they have to be packed and unpacked as if they were
2935 serialized data of the wire or such.
2936
2937 The sizes packed in are uint32_t to be the same on all CPU types
2938 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08002939 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002940
2941
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002942static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08002943MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002944{
2945 // Use of UsefulInputBuf is overkill, but it is convenient.
2946 UsefulInputBuf UIB;
2947
Laurence Lundbladeee851742020-01-08 08:37:05 -08002948 // Just assume the size here. It was checked during SetUp so
2949 // the assumption is safe.
Laurence Lundblade93d89472020-10-03 22:30:50 -07002950 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem,QCBOR_DECODE_MIN_MEM_POOL_SIZE});
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002951 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
2952 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
2953 return UsefulInputBuf_GetError(&UIB);
2954}
2955
2956
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002957static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08002958MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002959{
2960 // Use of UsefulOutBuf is overkill, but convenient. The
2961 // length check performed here is useful.
2962 UsefulOutBuf UOB;
2963
2964 UsefulOutBuf_Init(&UOB, Pool);
2965 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
2966 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
2967 return UsefulOutBuf_GetError(&UOB);
2968}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002969
2970
2971/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002972 Internal function for an allocation, reallocation free and destuct.
2973
2974 Having only one function rather than one each per mode saves space in
2975 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002976
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002977 Code Reviewers: THIS FUNCTION DOES POINTER MATH
2978 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08002979static UsefulBuf
2980MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002981{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002982 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002983
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002984 uint32_t uPoolSize;
2985 uint32_t uFreeOffset;
2986
2987 if(uNewSize > UINT32_MAX) {
2988 // This allocator is only good up to 4GB. This check should
2989 // optimize out if sizeof(size_t) == sizeof(uint32_t)
2990 goto Done;
2991 }
2992 const uint32_t uNewSize32 = (uint32_t)uNewSize;
2993
2994 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
2995 goto Done;
2996 }
2997
2998 if(uNewSize) {
2999 if(pMem) {
3000 // REALLOCATION MODE
3001 // Calculate pointer to the end of the memory pool. It is
3002 // assumed that pPool + uPoolSize won't wrap around by
3003 // assuming the caller won't pass a pool buffer in that is
3004 // not in legitimate memory space.
3005 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
3006
3007 // Check that the pointer for reallocation is in the range of the
3008 // pool. This also makes sure that pointer math further down
3009 // doesn't wrap under or over.
3010 if(pMem >= pPool && pMem < pPoolEnd) {
3011 // Offset to start of chunk for reallocation. This won't
3012 // wrap under because of check that pMem >= pPool. Cast
3013 // is safe because the pool is always less than UINT32_MAX
3014 // because of check in QCBORDecode_SetMemPool().
3015 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3016
3017 // Check to see if the allocation will fit. uPoolSize -
3018 // uMemOffset will not wrap under because of check that
3019 // pMem is in the range of the uPoolSize by check above.
3020 if(uNewSize <= uPoolSize - uMemOffset) {
3021 ReturnValue.ptr = pMem;
3022 ReturnValue.len = uNewSize;
3023
3024 // Addition won't wrap around over because uNewSize was
3025 // checked to be sure it is less than the pool size.
3026 uFreeOffset = uMemOffset + uNewSize32;
3027 }
3028 }
3029 } else {
3030 // ALLOCATION MODE
3031 // uPoolSize - uFreeOffset will not underflow because this
3032 // pool implementation makes sure uFreeOffset is always
3033 // smaller than uPoolSize through this check here and
3034 // reallocation case.
3035 if(uNewSize <= uPoolSize - uFreeOffset) {
3036 ReturnValue.len = uNewSize;
3037 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08003038 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003039 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003040 }
3041 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003042 if(pMem) {
3043 // FREE MODE
3044 // Cast is safe because of limit on pool size in
3045 // QCBORDecode_SetMemPool()
3046 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3047 } else {
3048 // DESTRUCT MODE
3049 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003050 }
3051 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003052
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003053 UsefulBuf Pool = {pPool, uPoolSize};
3054 MemPool_Pack(Pool, uFreeOffset);
3055
3056Done:
3057 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003058}
3059
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003060
Laurence Lundbladef6531662018-12-04 10:42:22 +09003061/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003062 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09003063 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003064QCBORError
3065QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
3066 UsefulBuf Pool,
3067 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003068{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003069 // The pool size and free mem offset are packed into the beginning
Dave Thaler93c01182022-08-06 15:08:35 -04003070 // of the pool memory. This compile time check makes sure the
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003071 // constant in the header is correct. This check should optimize
3072 // down to nothing.
Dave Thaler93c01182022-08-06 15:08:35 -04003073#ifdef _MSC_VER
3074#pragma warning(push)
3075#pragma warning(disable:4127) // conditional expression is constant
3076#endif
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003077 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003078 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003079 }
Dave Thaler93c01182022-08-06 15:08:35 -04003080#ifdef _MSC_VER
3081#pragma warning(pop)
3082#endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003083
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003084 // The pool size and free offset packed in to the beginning of pool
3085 // memory are only 32-bits. This check will optimize out on 32-bit
3086 // machines.
3087 if(Pool.len > UINT32_MAX) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003088 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003089 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003090
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003091 // This checks that the pool buffer given is big enough.
3092 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003093 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003094 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003095
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003096 QCBORDecode_SetUpAllocator(pMe, MemPool_Function, Pool.ptr, bAllStrings);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003097
Laurence Lundblade30816f22018-11-10 13:40:22 +07003098 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003099}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003100#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003101
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003102
3103
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003104static void
3105QCBORDecode_Private_CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07003106{
Laurence Lundblade37286c02022-09-03 10:05:02 -07003107#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade9b334962020-08-27 10:55:53 -07003108 memcpy(pMe->uLastTags, pItem->uTags, sizeof(pItem->uTags));
Laurence Lundblade37286c02022-09-03 10:05:02 -07003109#else
3110 (void)pMe;
3111 (void)pItem;
3112#endif
Laurence Lundblade9b334962020-08-27 10:55:53 -07003113}
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003114
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003115
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003116/**
3117 * @brief Consume an entire map or array including its contents.
3118 *
3119 * @param[in] pMe The decoder context.
3120 * @param[in] pItemToConsume The array/map whose contents are to be
3121 * consumed.
3122 * @param[out] puNextNestLevel The next nesting level after the item was
3123 * fully consumed.
3124 *
3125 * This may be called when @c pItemToConsume is not an array or
3126 * map. In that case, this is just a pass through for @c puNextNestLevel
3127 * since there is nothing to do.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003128 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003129static QCBORError
3130QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
3131 const QCBORItem *pItemToConsume,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003132 bool *pbBreak,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003133 uint8_t *puNextNestLevel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003134{
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003135 QCBORError uReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003136 QCBORItem Item;
Laurence Lundblade9b334962020-08-27 10:55:53 -07003137
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003138 /* If it is a map or array, this will tell if it is empty. */
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003139 const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel);
3140
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003141 if(QCBORItem_IsMapOrArray(*pItemToConsume) && !bIsEmpty) {
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003142 /* There is only real work to do for non-empty maps and arrays */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003143
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003144 /* This works for definite- and indefinite-length maps and
3145 * arrays by using the nesting level
Laurence Lundblade1341c592020-04-11 14:19:05 -07003146 */
3147 do {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003148 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pbBreak, &Item);
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003149 if(QCBORDecode_IsUnrecoverableError(uReturn) ||
3150 uReturn == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003151 goto Done;
3152 }
3153 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003154
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003155 *puNextNestLevel = Item.uNextNestLevel;
3156
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003157 uReturn = QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003158
Laurence Lundblade1341c592020-04-11 14:19:05 -07003159 } else {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003160 /* pItemToConsume is not a map or array. Just pass the nesting
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003161 * level through. */
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003162 *puNextNestLevel = pItemToConsume->uNextNestLevel;
3163
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003164 uReturn = QCBOR_SUCCESS;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003165 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003166
3167Done:
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003168 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003169}
3170
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003171
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003172/*
3173 * Public function, see header qcbor/qcbor_decode.h file
3174 */
3175void
3176QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003177{
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003178 QCBORDecode_VGetNext(pMe, pDecodedItem);
3179
3180 if(pMe->uLastError == QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003181 pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL,
Máté Tóth-Pálc6d59682021-05-26 18:55:30 +02003182 &pDecodedItem->uNextNestLevel);
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003183 }
3184}
3185
3186
Laurence Lundblade11654912024-05-09 11:49:24 -07003187/*
3188 * Public function, see header qcbor/qcbor_decode.h file
3189 */
3190uint32_t
3191QCBORDecode_Tell(QCBORDecodeContext *pMe)
3192{
3193 size_t uCursorOffset;
3194
3195 if(pMe->uLastError != QCBOR_SUCCESS) {
3196 return UINT32_MAX;
3197 }
3198
3199 uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
3200
3201 if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
3202 return UINT32_MAX;
3203 } else {
3204 /* Cast is safe because decoder input size is restricted. */
3205 return (uint32_t)uCursorOffset;
3206 }
3207}
3208
3209
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003210/**
3211 * @brief Rewind cursor to start as if map or array were just entered.
3212 *
3213 * @param[in] pMe The decoding context
3214 *
3215 * This affects the nesting tracking and the UsefulInputBuf.
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003216 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003217static void
3218QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003219{
3220 /* Reset nesting tracking to the deepest bounded level */
3221 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3222
3223 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3224
3225 /* Reposition traversal cursor to the start of the map/array */
3226 UsefulInputBuf_Seek(&(pMe->InBuf),
3227 DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
3228}
3229
3230
3231/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003232 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003233 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003234void
3235QCBORDecode_Rewind(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003236{
3237 if(pMe->nesting.pCurrentBounded != NULL) {
3238 /* In a bounded map, array or bstr-wrapped CBOR */
3239
3240 if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
3241 /* In bstr-wrapped CBOR. */
3242
3243 /* Reposition traversal cursor to start of wrapping byte string */
3244 UsefulInputBuf_Seek(&(pMe->InBuf),
3245 pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
3246 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3247
3248 } else {
3249 /* In a map or array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003250 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003251 }
3252
3253 } else {
3254 /* Not in anything bounded */
3255
3256 /* Reposition traversal cursor to the start of input CBOR */
3257 UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
3258
3259 /* Reset nesting tracking to beginning of input. */
3260 DecodeNesting_Init(&(pMe->nesting));
3261 }
3262
3263 pMe->uLastError = QCBOR_SUCCESS;
3264}
3265
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003266
Laurence Lundblade9b334962020-08-27 10:55:53 -07003267
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003268
3269
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003270typedef struct {
3271 void *pCBContext;
3272 QCBORItemCallback pfCallback;
3273} MapSearchCallBack;
3274
3275typedef struct {
3276 size_t uStartOffset;
3277 uint16_t uItemCount;
3278} MapSearchInfo;
3279
3280
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003281/**
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003282 * @brief Search a map for a set of items.
3283 *
3284 * @param[in] pMe The decode context to search.
3285 * @param[in,out] pItemArray The items to search for and the items found.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003286 * @param[out] pInfo Several bits of meta-info returned by search.
3287 * @param[in] pCallBack Callback object or @c NULL.
3288 * TODO: fix params
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003289 *
3290 * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map.
3291 *
3292 * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label)
3293 * were found for one of the labels being
3294 * search for. This duplicate detection is
3295 * only performed for items in pItemArray,
3296 * not every item in the map.
3297 *
3298 * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was
3299 * wrong for the matchd label.
3300 *
3301 * @retval Also errors returned by QCBORDecode_GetNext().
3302 *
3303 * On input, \c pItemArray contains a list of labels and data types of
3304 * items to be found.
3305 *
3306 * On output, the fully retrieved items are filled in with values and
3307 * such. The label was matched, so it never changes.
3308 *
3309 * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE.
3310 *
3311 * This also finds the ends of maps and arrays when they are exited.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003312 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003313static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003314QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
3315 QCBORItem *pItemArray,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003316 MapSearchInfo *pInfo,
3317 MapSearchCallBack *pCallBack)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003318{
Laurence Lundbladee6f15112020-07-23 18:44:16 -07003319 QCBORError uReturn;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003320 uint64_t uFoundItemBitMap = 0;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07003321
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003322 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003323 uReturn = pMe->uLastError;
3324 goto Done2;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003325 }
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003326
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003327 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) &&
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003328 pItemArray->uLabelType != QCBOR_TYPE_NONE) {
3329 /* QCBOR_TYPE_NONE as first item indicates just looking
3330 for the end of an array, so don't give error. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003331 uReturn = QCBOR_ERR_MAP_NOT_ENTERED;
3332 goto Done2;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003333 }
3334
Laurence Lundblade085d7952020-07-24 10:26:30 -07003335 if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) {
3336 // It is an empty bounded array or map
3337 if(pItemArray->uLabelType == QCBOR_TYPE_NONE) {
3338 // Just trying to find the end of the map or array
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003339 pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003340 uReturn = QCBOR_SUCCESS;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003341 } else {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003342 // Nothing is ever found in an empty array or map. All items
3343 // are marked as not found below.
Laurence Lundblade085d7952020-07-24 10:26:30 -07003344 uReturn = QCBOR_SUCCESS;
3345 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003346 goto Done2;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003347 }
3348
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003349 QCBORDecodeNesting SaveNesting;
Laurence Lundblade11654912024-05-09 11:49:24 -07003350 size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003351 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3352
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003353 /* Reposition to search from the start of the map / array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003354 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundblade1341c592020-04-11 14:19:05 -07003355
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003356 /*
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003357 Loop over all the items in the map or array. Each item
3358 could be a map or array, but label matching is only at
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003359 the main level. This handles definite- and indefinite-
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003360 length maps and arrays. The only reason this is ever
3361 called on arrays is to find their end position.
3362
3363 This will always run over all items in order to do
3364 duplicate detection.
3365
3366 This will exit with failure if it encounters an
3367 unrecoverable error, but continue on for recoverable
3368 errors.
3369
3370 If a recoverable error occurs on a matched item, then
3371 that error code is returned.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003372 */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07003373 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003374 if(pInfo) {
3375 pInfo->uItemCount = 0;
3376 }
Máté Tóth-Pál2f2aa5f2021-05-17 21:35:09 +02003377 uint8_t uNextNestLevel;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003378 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003379 /* Remember offset of the item because sometimes it has to be returned */
Laurence Lundblade1341c592020-04-11 14:19:05 -07003380 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003381
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003382 /* Get the item */
3383 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003384 QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003385 if(QCBORDecode_IsUnrecoverableError(uResult)) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003386 /* The map/array can't be decoded when unrecoverable errors occur */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003387 uReturn = uResult;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003388 goto Done;
3389 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003390 if(uResult == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003391 /* Unexpected end of map or array. */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003392 uReturn = uResult;
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003393 goto Done;
3394 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003395
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003396 /* See if item has one of the labels that are of interest */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003397 bool bMatched = false;
3398 for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003399 if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003400 /* A label match has been found */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003401 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
3402 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003403 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003404 }
Laurence Lundblade63926052021-03-29 16:05:51 -07003405 if(uResult != QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003406 /* The label matches, but the data item is in error.
3407 * It is OK to have recoverable errors on items that are not
3408 * matched. */
Laurence Lundblade63926052021-03-29 16:05:51 -07003409 uReturn = uResult;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003410 goto Done;
3411 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003412 if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) {
Laurence Lundblade63926052021-03-29 16:05:51 -07003413 /* The data item is not of the type(s) requested */
3414 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003415 goto Done;
3416 }
3417
Laurence Lundblade1341c592020-04-11 14:19:05 -07003418 /* Successful match. Return the item. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003419 pItemArray[nIndex] = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003420 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003421 if(pInfo) {
3422 pInfo->uStartOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003423 }
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003424 bMatched = true;
3425 }
3426 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003427
3428
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003429 if(!bMatched && pCallBack != NULL) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003430 /*
3431 Call the callback on unmatched labels.
3432 (It is tempting to do duplicate detection here, but that would
3433 require dynamic memory allocation because the number of labels
3434 that might be encountered is unbounded.)
3435 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003436 uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item);
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003437 if(uReturn != QCBOR_SUCCESS) {
3438 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003439 }
3440 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003441
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003442 /*
3443 Consume the item whether matched or not. This
3444 does the work of traversing maps and array and
3445 everything in them. In this loop only the
3446 items at the current nesting level are examined
3447 to match the labels.
3448 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003449 uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel);
Laurence Lundbladec7114722020-08-13 05:11:40 -07003450 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003451 goto Done;
3452 }
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003453
3454 if(pInfo) {
3455 pInfo->uItemCount++;
3456 }
3457
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003458 } while (uNextNestLevel >= uMapNestLevel);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003459
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003460 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003461
3462 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003463
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003464 // Check here makes sure that this won't accidentally be
3465 // QCBOR_MAP_OFFSET_CACHE_INVALID which is larger than
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003466 // QCBOR_MAX_DECODE_INPUT_SIZE.
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -08003467 // Cast to uint32_t to possibly address cases where SIZE_MAX < UINT32_MAX
3468 if((uint32_t)uEndOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003469 uReturn = QCBOR_ERR_INPUT_TOO_LARGE;
3470 goto Done;
3471 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003472 /* Cast OK because encoded CBOR is limited to UINT32_MAX */
3473 pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003474
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003475 Done:
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003476 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade11654912024-05-09 11:49:24 -07003477 UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos);
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003478
3479 Done2:
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003480 /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */
Laurence Lundbladec7114722020-08-13 05:11:40 -07003481 for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003482 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003483 pItemArray[i].uDataType = QCBOR_TYPE_NONE;
3484 pItemArray[i].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003485 }
3486 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003487
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003488 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003489}
3490
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003491
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003492/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003493 * Public function, see header qcbor/qcbor_decode.h file
3494 */
3495void
3496QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
3497 int64_t nLabel,
3498 uint8_t uQcborType,
3499 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003500{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003501 if(pMe->uLastError != QCBOR_SUCCESS) {
3502 return;
3503 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003504
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003505 QCBORItem OneItemSeach[2];
3506 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3507 OneItemSeach[0].label.int64 = nLabel;
3508 OneItemSeach[0].uDataType = uQcborType;
3509 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003510
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003511 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003512
3513 *pItem = OneItemSeach[0];
3514
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003515 if(uReturn != QCBOR_SUCCESS) {
3516 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003517 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003518 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003519 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003520 }
3521
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003522 Done:
3523 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003524}
3525
3526
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003527/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003528 * Public function, see header qcbor/qcbor_decode.h file
3529 */
3530void
3531QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
3532 const char *szLabel,
3533 uint8_t uQcborType,
3534 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003535{
Laurence Lundbladeda095972020-06-06 18:35:33 -07003536 if(pMe->uLastError != QCBOR_SUCCESS) {
3537 return;
3538 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003539
Laurence Lundblade78a66132024-06-06 12:19:59 -07003540#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003541 QCBORItem OneItemSeach[2];
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003542 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3543 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3544 OneItemSeach[0].uDataType = uQcborType;
3545 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003546
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003547 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
3548
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003549 if(uReturn != QCBOR_SUCCESS) {
3550 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003551 }
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003552 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003553 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003554 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003555 }
3556
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003557 *pItem = OneItemSeach[0];
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003558Done:
Laurence Lundblade78a66132024-06-06 12:19:59 -07003559
3560#else
3561 QCBORError uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
3562#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
3563
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003564 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003565}
3566
3567
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003568
3569/**
3570 * @brief Semi-private. Get pointer, length and item for an array or map.
3571 *
3572 * @param[in] pMe The decode context.
3573 * @param[in] uType CBOR major type, either array/map.
3574 * @param[out] pItem The item for the array/map.
3575 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3576 *
3577 * The next item to be decoded must be a map or array as specified by \c uType.
3578 *
3579 * \c pItem will be filled in with the label and tags of the array or map
3580 * in addition to \c pEncodedCBOR giving the pointer and length of the
3581 * encoded CBOR.
3582 *
3583 * When this is complete, the traversal cursor is at the end of the array or
3584 * map that was retrieved.
3585 */
3586void
3587QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe,
3588 const uint8_t uType,
3589 QCBORItem *pItem,
3590 UsefulBufC *pEncodedCBOR)
3591{
3592 QCBORError uErr;
3593 uint8_t uNestLevel;
3594 size_t uStartingCursor;
3595 size_t uStartOfReturned;
3596 size_t uEndOfReturned;
3597 size_t uTempSaveCursor;
3598 bool bInMap;
3599 QCBORItem LabelItem;
3600 bool EndedByBreak;
3601
3602 uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3603 bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting));
3604
3605 /* Could call GetNext here, but don't need to because this
3606 * is only interested in arrays and maps. */
3607 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem);
3608 if(uErr != QCBOR_SUCCESS) {
3609 pMe->uLastError = (uint8_t)uErr;
3610 return;
3611 }
3612
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003613 uint8_t uItemDataType = pItem->uDataType;
Laurence Lundblade62cae932024-06-03 13:16:17 -07003614#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003615 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
3616 uItemDataType = QCBOR_TYPE_ARRAY;
3617 }
Laurence Lundblade78a66132024-06-06 12:19:59 -07003618#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003619
3620 if(uItemDataType != uType) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003621 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
3622 return;
3623 }
3624
3625 if(bInMap) {
3626 /* If the item is in a map, the start of the array/map
3627 * itself, not the label, must be found. Do this by
3628 * rewinding to the starting position and fetching
3629 * just the label data item. QCBORDecode_Private_GetNextTagNumber()
3630 * doesn't do any of the array/map item counting or nesting
3631 * level tracking. Used here it will just fetech the label
3632 * data item.
3633 *
3634 * Have to save the cursor and put it back to the position
3635 * after the full item once the label as been fetched by
3636 * itself.
3637 */
3638 uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3639 UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor);
3640
3641 /* Item has been fetched once so safe to ignore error */
3642 (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem);
3643
3644 uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3645 UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor);
3646 } else {
3647 uStartOfReturned = uStartingCursor;
3648 }
3649
3650 /* Consume the entire array/map to find the end */
3651 uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel);
3652 if(uErr != QCBOR_SUCCESS) {
3653 pMe->uLastError = (uint8_t)uErr;
3654 goto Done;
3655 }
3656
3657 /* Fill in returned values */
3658 uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3659 if(EndedByBreak) {
3660 /* When ascending nesting levels, a break for the level above
3661 * was consumed. That break is not a part of what is consumed here. */
3662 uEndOfReturned--;
3663 }
3664 pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned);
3665 pEncodedCBOR->len = uEndOfReturned - uStartOfReturned;
3666
3667Done:
3668 return;
3669}
3670
3671
3672/**
3673 * @brief Semi-private. Get pointer, length and item count of an array or map.
3674 *
3675 * @param[in] pMe The decode context.
3676 * @param[in] pTarget The label and type of the array or map to retrieve.
3677 * @param[out] pItem The item for the array/map.
3678 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3679 *
3680 * The next item to be decoded must be a map or array as specified by \c uType.
3681 *
3682 * When this is complete, the traversal cursor is unchanged.
3683 */void
3684QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe,
3685 QCBORItem *pTarget,
3686 QCBORItem *pItem,
3687 UsefulBufC *pEncodedCBOR)
3688{
3689 MapSearchInfo Info;
3690 QCBORDecodeNesting SaveNesting;
3691 size_t uSaveCursor;
3692
3693 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL);
3694 if(pMe->uLastError != QCBOR_SUCCESS) {
3695 return;
3696 }
3697
3698 /* Save the whole position of things so they can be restored.
3699 * so the cursor position is unchanged by this operation, like
3700 * all the other GetXxxxInMap() operations. */
3701 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3702 uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3703
3704 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3705 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
3706 QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR);
3707
3708 UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor);
3709 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
3710}
3711
3712
3713
3714
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003715/**
3716 * @brief Is a QCBOR_TYPE in the type list?
3717 *
3718 * @param[in] uDataType Type to check for.
3719 * @param[in] puTypeList List to check.
3720 *
3721 * @retval QCBOR_SUCCESS If in the list.
3722 * @retval QCBOR_ERR_UNEXPECTED_TYPE Not in the list.
3723 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07003724static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003725QCBOR_Private_CheckTypeList(const int uDataType,
3726 const uint8_t puTypeList[QCBOR_TAGSPEC_NUM_TYPES])
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003727{
3728 for(size_t i = 0; i < QCBOR_TAGSPEC_NUM_TYPES; i++) {
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003729 if(uDataType == puTypeList[i]) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003730 return QCBOR_SUCCESS;
3731 }
3732 }
3733 return QCBOR_ERR_UNEXPECTED_TYPE;
3734}
3735
Laurence Lundblade67257dc2020-07-27 03:33:37 -07003736
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003737/**
Laurence Lundblade37286c02022-09-03 10:05:02 -07003738 * Match a tag/type specification against the type of the item.
3739 *
3740 * @param[in] TagSpec Specification for matching tags.
3741 * @param[in] pItem The item to check.
3742 *
3743 * @retval QCBOR_SUCCESS \c uDataType is allowed by @c TagSpec
3744 * @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec
3745 *
3746 * This checks the item data type of untagged items as well as of
3747 * tagged items against a specification to see if decoding should
3748 * proceed.
3749 *
3750 * This relies on the automatic tag decoding done by QCBOR that turns
3751 * tag numbers into particular QCBOR_TYPEs so there is no actual
3752 * comparsion of tag numbers, just of QCBOR_TYPEs.
3753 *
3754 * This checks the data item type as possibly representing the tag
3755 * number or as the tag content type.
3756 *
3757 * If QCBOR_DISABLE_TAGS is #defined, this primarily checks the item
3758 * data type against the allowed tag content types. It will also error out
3759 * if the caller tries to require a tag because there is no way that can
3760 * ever be fulfilled.
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003761 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07003762static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003763QCBOR_Private_CheckTagRequirement(const QCBOR_Private_TagSpec TagSpec,
3764 const QCBORItem *pItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07003765{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003766 const int nItemType = pItem->uDataType; /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade37286c02022-09-03 10:05:02 -07003767 const int nTagReq = TagSpec.uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
3768
3769#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003770 /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003771 if(!(TagSpec.uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS) &&
3772 pItem->uTags[0] != CBOR_TAG_INVALID16) {
3773 /* There are tags that QCBOR couldn't process on this item and
Laurence Lundblade37286c02022-09-03 10:05:02 -07003774 * the caller has told us there should not be.
3775 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003776 return QCBOR_ERR_UNEXPECTED_TYPE;
3777 }
3778
Laurence Lundblade9b334962020-08-27 10:55:53 -07003779 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
Laurence Lundblade37286c02022-09-03 10:05:02 -07003780 /* Must match the tag number and only the tag */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003781 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003782 }
3783
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003784 QCBORError uReturn = QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003785 if(uReturn == QCBOR_SUCCESS) {
3786 return QCBOR_SUCCESS;
3787 }
3788
3789 if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
3790 /* Must match the content type and only the content type.
Laurence Lundblade37286c02022-09-03 10:05:02 -07003791 * There was no match just above so it is a fail. */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003792 return QCBOR_ERR_UNEXPECTED_TYPE;
3793 }
3794
Laurence Lundblade37286c02022-09-03 10:05:02 -07003795 /* QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG: If here it can match either the tag or the content
3796 * and it hasn't matched the content, so the end
3797 * result is whether it matches the tag. This is
3798 * the tag optional case that the CBOR standard discourages.
3799 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003800
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003801 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003802
Laurence Lundblade37286c02022-09-03 10:05:02 -07003803#else /* QCBOR_DISABLE_TAGS */
3804 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
3805 return QCBOR_ERR_UNEXPECTED_TYPE;
3806 }
3807
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07003808 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade37286c02022-09-03 10:05:02 -07003809
3810#endif /* QCBOR_DISABLE_TAGS */
3811}
Laurence Lundblade9b334962020-08-27 10:55:53 -07003812
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003813
3814/**
3815 * @brief Get an item by label to match a tag specification.
3816 *
3817 * @param[in] pMe The decode context.
3818 * @param[in] nLabel The label to search map for.
3819 * @param[in] TagSpec The tag number specification to match.
3820 * @param[out] pItem The item found.
3821 *
3822 * This finds the item with the given label in currently open
3823 * map. Then checks that its tag number and types matches the tag
3824 * specification. If not, an error is set in the decode context.
3825 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003826static void
3827QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
3828 const int64_t nLabel,
3829 const QCBOR_Private_TagSpec TagSpec,
3830 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003831{
3832 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
3833 if(pMe->uLastError != QCBOR_SUCCESS) {
3834 return;
3835 }
3836
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003837 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003838}
3839
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07003840
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003841/**
3842 * @brief Get an item by label to match a tag specification.
3843 *
3844 * @param[in] pMe The decode context.
3845 * @param[in] szLabel The label to search map for.
3846 * @param[in] TagSpec The tag number specification to match.
3847 * @param[out] pItem The item found.
3848 *
3849 * This finds the item with the given label in currently open
3850 * map. Then checks that its tag number and types matches the tag
3851 * specification. If not, an error is set in the decode context.
3852 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003853static void
3854QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
3855 const char *szLabel,
3856 const QCBOR_Private_TagSpec TagSpec,
3857 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003858{
3859 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
3860 if(pMe->uLastError != QCBOR_SUCCESS) {
3861 return;
3862 }
3863
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003864 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003865}
3866
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003867
3868/**
3869 * @brief Semi-private to get an string by label to match a tag specification.
3870 *
3871 * @param[in] pMe The decode context.
3872 * @param[in] nLabel The label to search map for.
3873 * @param[in] TagSpec The tag number specification to match.
3874 * @param[out] pString The string found.
3875 *
3876 * This finds the string with the given label in currently open
3877 * map. Then checks that its tag number and types matches the tag
3878 * specification. If not, an error is set in the decode context.
3879 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003880void
3881QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
3882 const int64_t nLabel,
3883 const QCBOR_Private_TagSpec TagSpec,
3884 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003885{
3886 QCBORItem Item;
3887 QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
3888 if(pMe->uLastError == QCBOR_SUCCESS) {
3889 *pString = Item.val.string;
3890 }
3891}
3892
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003893
3894/**
3895 * @brief Semi-private to get an string by label to match a tag specification.
3896 *
3897 * @param[in] pMe The decode context.
3898 * @param[in] szLabel The label to search map for.
3899 * @param[in] TagSpec The tag number specification to match.
3900 * @param[out] pString The string found.
3901 *
3902 * This finds the string with the given label in currently open
3903 * map. Then checks that its tag number and types matches the tag
3904 * specification. If not, an error is set in the decode context.
3905 */void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003906QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
3907 const char * szLabel,
3908 const QCBOR_Private_TagSpec TagSpec,
3909 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003910{
3911 QCBORItem Item;
3912 QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
3913 if(pMe->uLastError == QCBOR_SUCCESS) {
3914 *pString = Item.val.string;
3915 }
3916}
Laurence Lundblade1341c592020-04-11 14:19:05 -07003917
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003918
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003919/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003920 * Public function, see header qcbor/qcbor_decode.h file
3921 */
3922void
3923QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003924{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003925 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL);
Laurence Lundblade5f53f832020-09-03 12:00:14 -07003926 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003927}
3928
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003929/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003930 * Public function, see header qcbor/qcbor_decode.h file
3931 */
3932void
3933QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe,
3934 QCBORItem *pItemList,
3935 void *pCallbackCtx,
3936 QCBORItemCallback pfCB)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003937{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003938 MapSearchCallBack CallBack;
3939 CallBack.pCBContext = pCallbackCtx;
3940 CallBack.pfCallback = pfCB;
3941
3942 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack);
3943
Laurence Lundblade5f53f832020-09-03 12:00:14 -07003944 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003945}
3946
3947
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08003948/**
3949 * @brief Search for a map/array by label and enter it
3950 *
3951 * @param[in] pMe The decode context.
3952 * @param[in] pSearch The map/array to search for.
3953 *
3954 * @c pSearch is expected to contain one item of type map or array
3955 * with the label specified. The current bounded map will be searched for
3956 * this and if found will be entered.
3957 *
3958 * If the label is not found, or the item found is not a map or array,
3959 * the error state is set.
3960 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003961static void
3962QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07003963{
Laurence Lundblade323f8a92020-09-06 19:43:09 -07003964 // The first item in pSearch is the one that is to be
3965 // entered. It should be the only one filled in. Any other
3966 // will be ignored unless it causes an error.
Laurence Lundblade34691b92020-05-18 22:25:25 -07003967 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07003968 return;
3969 }
3970
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003971 MapSearchInfo Info;
3972 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pSearch, &Info, NULL);
Laurence Lundblade34691b92020-05-18 22:25:25 -07003973 if(pMe->uLastError != QCBOR_SUCCESS) {
3974 return;
3975 }
3976
Laurence Lundblade9b334962020-08-27 10:55:53 -07003977 if(pSearch->uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003978 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade9b334962020-08-27 10:55:53 -07003979 return;
3980 }
3981
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003982
3983 /* The map or array was found. Now enter it.
3984 *
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08003985 * QCBORDecode_EnterBoundedMapOrArray() used here, requires the
3986 * next item for the pre-order traversal cursor to be the map/array
3987 * found by MapSearch(). The next few lines of code force the
3988 * cursor to that.
3989 *
3990 * There is no need to retain the old cursor because
3991 * QCBORDecode_EnterBoundedMapOrArray() will set it to the
3992 * beginning of the map/array being entered.
3993 *
3994 * The cursor is forced by: 1) setting the input buffer position to
3995 * the item offset found by MapSearch(), 2) setting the map/array
3996 * counter to the total in the map/array, 3) setting the nesting
3997 * level. Setting the map/array counter to the total is not
3998 * strictly correct, but this is OK because this cursor only needs
3999 * to be used to get one item and MapSearch() has already found it
4000 * confirming it exists.
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004001 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004002 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004003
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004004 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
4005
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004006 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07004007
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004008 QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004009}
4010
4011
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004012/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004013 * Public function, see header qcbor/qcbor_decode.h file
4014 */
4015void
4016QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004017{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004018 QCBORItem OneItemSeach[2];
4019 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4020 OneItemSeach[0].label.int64 = nLabel;
4021 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4022 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004023
Laurence Lundblade9b334962020-08-27 10:55:53 -07004024 /* The map to enter was found, now finish off entering it. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004025 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004026}
4027
4028
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004029/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004030 * Public function, see header qcbor/qcbor_decode.h file
4031 */
4032void
4033QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundblade78a66132024-06-06 12:19:59 -07004034 {
4035#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
4036 QCBORItem OneItemSeach[2];
4037 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4038 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4039 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4040 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004041
Laurence Lundblade78a66132024-06-06 12:19:59 -07004042 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
4043#else
4044 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
4045#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
4046 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004047
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004048/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004049 * Public function, see header qcbor/qcbor_decode.h file
4050 */
4051void
4052QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07004053{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004054 QCBORItem OneItemSeach[2];
4055 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4056 OneItemSeach[0].label.int64 = nLabel;
4057 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4058 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004059
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004060 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07004061}
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_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundblade34691b92020-05-18 22:25:25 -07004068{
Laurence Lundblade78a66132024-06-06 12:19:59 -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_ARRAY;
4074 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004075
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004076 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade78a66132024-06-06 12:19:59 -07004077#else
4078 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
4079#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade1341c592020-04-11 14:19:05 -07004080}
4081
4082
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004083/**
4084 * @brief Semi-private to do the the work for EnterMap() and EnterArray().
4085 *
4086 * @param[in] pMe The decode context
4087 * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY.
4088 * @param[out] pItem The data item for the map or array entered.
4089 *
4090 * The next item in the traversal must be a map or array. This
4091 * consumes that item and does the book keeping to enter the map or
4092 * array.
4093 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004094void
4095QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe,
4096 const uint8_t uType,
4097 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004098{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004099 QCBORError uErr;
4100
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004101 /* Must only be called on maps and arrays. */
Laurence Lundblade34691b92020-05-18 22:25:25 -07004102 if(pMe->uLastError != QCBOR_SUCCESS) {
4103 // Already in error state; do nothing.
4104 return;
4105 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07004106
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004107 /* Get the data item that is the map or array being entered. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004108 QCBORItem Item;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004109 uErr = QCBORDecode_GetNext(pMe, &Item);
4110 if(uErr != QCBOR_SUCCESS) {
4111 goto Done;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07004112 }
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004113
4114 uint8_t uItemDataType = Item.uDataType;
Laurence Lundblade78a66132024-06-06 12:19:59 -07004115
Laurence Lundblade62cae932024-06-03 13:16:17 -07004116#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004117 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) {
4118 uItemDataType = QCBOR_TYPE_ARRAY;
4119 }
Laurence Lundblade78a66132024-06-06 12:19:59 -07004120#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
4121
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004122 if(uItemDataType != uType) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004123 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
4124 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004125 }
4126
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004127 QCBORDecode_Private_CopyTags(pMe, &Item);
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004128
4129
Laurence Lundbladef0499502020-08-01 11:55:57 -07004130 const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
Laurence Lundblade085d7952020-07-24 10:26:30 -07004131 if(bIsEmpty) {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004132 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
4133 // Undo decrement done by QCBORDecode_GetNext() so the the
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004134 // the decrement when exiting the map/array works correctly
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004135 pMe->nesting.pCurrent->u.ma.uCountCursor++;
4136 }
Laurence Lundblade93d89472020-10-03 22:30:50 -07004137 // Special case to increment nesting level for zero-length maps
4138 // and arrays entered in bounded mode.
Laurence Lundbladee6f15112020-07-23 18:44:16 -07004139 DecodeNesting_Descend(&(pMe->nesting), uType);
4140 }
4141
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004142 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004143
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004144 uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty,
4145 UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004146
Laurence Lundblade6545d1b2020-10-14 11:13:13 -07004147 if(pItem != NULL) {
4148 *pItem = Item;
4149 }
4150
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004151Done:
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004152 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004153}
4154
Laurence Lundblade02625d42020-06-25 14:41:41 -07004155
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004156/**
4157 * @brief Exit a bounded map, array or bstr (semi-private).
4158 *
4159 * @param[in] pMe Decode context.
4160 * @param[in] uEndOffset The input buffer offset of the end of item exited.
4161 *
4162 * @returns QCBOR_SUCCESS or an error code.
4163 *
4164 * This is the common work for exiting a level that is a bounded map,
4165 * array or bstr wrapped CBOR.
4166 *
4167 * One chunk of work is to set up the pre-order traversal so it is at
4168 * the item just after the bounded map, array or bstr that is being
4169 * exited. This is somewhat complex.
4170 *
4171 * The other work is to level-up the bounded mode to next higest
4172 * bounded mode or the top level if there isn't one.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004173 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004174static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004175QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
4176 const uint32_t uEndOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004177{
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004178 QCBORError uErr;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004179
Laurence Lundblade02625d42020-06-25 14:41:41 -07004180 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004181 * First the pre-order-traversal byte offset is positioned to the
4182 * item just after the bounded mode item that was just consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004183 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004184 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
4185
Laurence Lundblade02625d42020-06-25 14:41:41 -07004186 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004187 * Next, set the current nesting level to one above the bounded
4188 * level that was just exited.
4189 *
4190 * DecodeNesting_CheckBoundedType() is always called before this
4191 * and makes sure pCurrentBounded is valid.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004192 */
4193 DecodeNesting_LevelUpCurrent(&(pMe->nesting));
4194
4195 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004196 * This does the complex work of leveling up the pre-order
4197 * traversal when the end of a map or array or another bounded
4198 * level is reached. It may do nothing, or ascend all the way to
4199 * the top level.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004200 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004201 uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004202 if(uErr != QCBOR_SUCCESS) {
4203 goto Done;
4204 }
4205
Laurence Lundblade02625d42020-06-25 14:41:41 -07004206 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004207 * This makes the next highest bounded level the current bounded
4208 * level. If there is no next highest level, then no bounded mode
4209 * is in effect.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004210 */
4211 DecodeNesting_LevelUpBounded(&(pMe->nesting));
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004212
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004213 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004214
4215Done:
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004216 return uErr;
4217}
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004218
Laurence Lundblade02625d42020-06-25 14:41:41 -07004219
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004220/**
4221 * @brief Get started exiting a map or array (semi-private)
4222 *
4223 * @param[in] pMe The decode context
4224 * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP
4225 *
4226 * This does some work for map and array exiting (but not
4227 * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel()
4228 * is called to do the rest.
4229 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004230void
4231QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe,
4232 const uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004233{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004234 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07004235 /* Already in error state; do nothing. */
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004236 return;
4237 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004238
Laurence Lundblade02625d42020-06-25 14:41:41 -07004239 QCBORError uErr;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004240
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004241 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004242 uErr = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004243 goto Done;
4244 }
4245
Laurence Lundblade02625d42020-06-25 14:41:41 -07004246 /*
4247 Have to set the offset to the end of the map/array
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004248 that is being exited. If there is no cached value,
Laurence Lundblade02625d42020-06-25 14:41:41 -07004249 from previous map search, then do a dummy search.
4250 */
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004251 if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004252 QCBORItem Dummy;
4253 Dummy.uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004254 uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL);
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004255 if(uErr != QCBOR_SUCCESS) {
4256 goto Done;
4257 }
4258 }
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004259
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004260 uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004261
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004262Done:
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004263 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004264}
4265
4266
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004267/**
4268 * @brief The main work of entering some byte-string wrapped CBOR.
4269 *
4270 * @param[in] pMe The decode context.
4271 * @param[in] pItem The byte string item.
4272 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX
4273 * @param[out] pBstr Pointer and length of byte string entered.
4274 *
4275 * This is called once the byte string item has been decoded to do all
4276 * the book keeping work for descending a nesting level into the
4277 * nested CBOR.
4278 *
4279 * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement.
4280 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004281static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004282QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe,
4283 const QCBORItem *pItem,
4284 const uint8_t uTagRequirement,
4285 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004286{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004287 if(pBstr) {
4288 *pBstr = NULLUsefulBufC;
4289 }
4290
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004291 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004292 /* Already in error state; do nothing. */
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004293 return pMe->uLastError;
4294 }
4295
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004296 QCBORError uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004297
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004298 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004299 {
4300 uTagRequirement,
4301 {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE},
4302 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4303 };
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004304
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004305 uError = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004306 if(uError != QCBOR_SUCCESS) {
4307 goto Done;
4308 }
4309
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004310 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004311 /* Reverse the decrement done by GetNext() for the bstr so the
4312 * increment in QCBORDecode_NestLevelAscender() called by
4313 * ExitBoundedLevel() will work right.
4314 */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004315 DecodeNesting_ReverseDecrement(&(pMe->nesting));
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07004316 }
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004317
4318 if(pBstr) {
4319 *pBstr = pItem->val.string;
4320 }
4321
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004322 /* This saves the current length of the UsefulInputBuf and then
4323 * narrows the UsefulInputBuf to start and length of the wrapped
4324 * CBOR that is being entered.
4325 *
4326 * Most of these calls are simple inline accessors so this doesn't
4327 * amount to much code.
4328 */
4329
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004330 const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004331 /* This check makes the cast of uPreviousLength to uint32_t below safe. */
4332 if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004333 uError = QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladef76a2622020-08-06 19:51:03 -07004334 goto Done;
4335 }
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004336
4337 const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
4338 pItem->val.string.ptr);
4339 /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
4340 if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
4341 /* This should never happen because pItem->val.string.ptr should
4342 * always be valid since it was just returned.
4343 */
4344 uError = QCBOR_ERR_INPUT_TOO_LARGE;
4345 goto Done;
4346 }
4347
4348 const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
4349
4350 UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004351 UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004352
Laurence Lundblade02625d42020-06-25 14:41:41 -07004353 uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004354 (uint32_t)uPreviousLength,
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004355 (uint32_t)uStartOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004356Done:
4357 return uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004358}
4359
4360
Laurence Lundblade02625d42020-06-25 14:41:41 -07004361/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004362 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004363 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004364void
4365QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe,
4366 const uint8_t uTagRequirement,
4367 UsefulBufC *pBstr)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004368{
4369 if(pMe->uLastError != QCBOR_SUCCESS) {
4370 // Already in error state; do nothing.
4371 return;
4372 }
4373
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004374 /* Get the data item that is the byte string being entered */
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004375 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004376 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4377 if(pMe->uLastError != QCBOR_SUCCESS) {
4378 return;
4379 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004380
Laurence Lundblade31fddb72024-05-13 13:03:35 -07004381 if(Item.uDataAlloc) {
4382 pMe->uLastError = QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
4383 return;
4384 }
4385
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004386 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4387 &Item,
4388 uTagRequirement,
4389 pBstr);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004390}
4391
4392
Laurence Lundblade02625d42020-06-25 14:41:41 -07004393/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004394 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004395 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004396void
4397QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe,
4398 const int64_t nLabel,
4399 const uint8_t uTagRequirement,
4400 UsefulBufC *pBstr)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004401{
4402 QCBORItem Item;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004403 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004404
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004405 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4406 &Item,
4407 uTagRequirement,
4408 pBstr);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004409}
4410
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004411
Laurence Lundblade02625d42020-06-25 14:41:41 -07004412/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004413 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004414 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004415void
4416QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe,
4417 const char *szLabel,
4418 const uint8_t uTagRequirement,
4419 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004420{
4421 QCBORItem Item;
4422 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4423
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004424 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4425 &Item,
4426 uTagRequirement,
4427 pBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004428}
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004429
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004430
Laurence Lundblade02625d42020-06-25 14:41:41 -07004431/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004432 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004433 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004434void
4435QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004436{
Laurence Lundblade02625d42020-06-25 14:41:41 -07004437 if(pMe->uLastError != QCBOR_SUCCESS) {
4438 // Already in error state; do nothing.
4439 return;
4440 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004441
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004442 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004443 pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade02625d42020-06-25 14:41:41 -07004444 return;
4445 }
4446
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004447 const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
4448
Laurence Lundblade02625d42020-06-25 14:41:41 -07004449 /*
4450 Reset the length of the UsefulInputBuf to what it was before
4451 the bstr wrapped CBOR was entered.
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004452 */
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004453 UsefulInputBuf_SetBufferLength(&(pMe->InBuf),
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004454 DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004455
4456
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004457 QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004458 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004459}
4460
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004461
Laurence Lundbladee6430642020-03-14 21:15:44 -07004462
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004463/**
4464 * @brief Process simple type true and false, a boolean
4465 *
4466 * @param[in] pMe The decode context.
4467 * @param[in] pItem The item with either true or false.
4468 * @param[out] pBool The boolean value output.
4469 *
4470 * Sets the internal error if the item isn't a true or a false. Also
4471 * records any tag numbers as the tag numbers of the last item.
4472 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004473static void
4474QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe,
4475 const QCBORItem *pItem,
4476 bool *pBool)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004477{
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004478 if(pMe->uLastError != QCBOR_SUCCESS) {
4479 /* Already in error state, do nothing */
4480 return;
4481 }
4482
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004483 switch(pItem->uDataType) {
4484 case QCBOR_TYPE_TRUE:
4485 *pBool = true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004486 break;
4487
4488 case QCBOR_TYPE_FALSE:
4489 *pBool = false;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004490 break;
4491
4492 default:
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004493 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004494 break;
4495 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004496 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004497}
Laurence Lundbladee6430642020-03-14 21:15:44 -07004498
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004499
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004500/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004501 * Public function, see header qcbor/qcbor_decode.h file
4502 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004503void
4504QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004505{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004506 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004507 /* Already in error state, do nothing */
Laurence Lundbladee6430642020-03-14 21:15:44 -07004508 return;
4509 }
4510
Laurence Lundbladec4537442020-04-14 18:53:22 -07004511 QCBORItem Item;
4512
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004513 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4514
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004515 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004516}
4517
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004518
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004519/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004520 * Public function, see header qcbor/qcbor_decode.h file
4521 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004522void
4523QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe,
4524 const int64_t nLabel,
4525 bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004526{
4527 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004528 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004529
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004530 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004531}
4532
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004533
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004534/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004535 * Public function, see header qcbor/qcbor_decode.h file
4536 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004537void
4538QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe,
4539 const char *szLabel,
4540 bool *pValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004541{
4542 QCBORItem Item;
4543 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4544
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004545 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004546}
4547
4548
4549
Laurence Lundbladec7114722020-08-13 05:11:40 -07004550
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004551/**
4552 * @brief Common processing for an epoch date.
4553 *
4554 * @param[in] pMe The decode context.
4555 * @param[in] pItem The item with the date.
4556 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4557 * @param[out] pnTime The returned date.
4558 *
4559 * Common processing for the date tag. Mostly make sure the tag
4560 * content is correct and copy forward any further other tag numbers.
4561 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004562static void
4563QCBORDecode_Private_ProcessEpochDate(QCBORDecodeContext *pMe,
4564 QCBORItem *pItem,
4565 const uint8_t uTagRequirement,
4566 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004567{
4568 if(pMe->uLastError != QCBOR_SUCCESS) {
4569 // Already in error state, do nothing
4570 return;
4571 }
4572
4573 QCBORError uErr;
4574
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004575 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladec7114722020-08-13 05:11:40 -07004576 {
4577 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004578 {QCBOR_TYPE_DATE_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4579 {QCBOR_TYPE_INT64, QCBOR_TYPE_DOUBLE, QCBOR_TYPE_FLOAT, QCBOR_TYPE_UINT64}
Laurence Lundbladec7114722020-08-13 05:11:40 -07004580 };
4581
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004582 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004583 if(uErr != QCBOR_SUCCESS) {
4584 goto Done;
4585 }
4586
4587 if(pItem->uDataType != QCBOR_TYPE_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004588 uErr = QCBOR_Private_DecodeDateEpoch(pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004589 if(uErr != QCBOR_SUCCESS) {
4590 goto Done;
4591 }
4592 }
4593
Laurence Lundblade9b334962020-08-27 10:55:53 -07004594 // Save the tags in the last item's tags in the decode context
4595 // for QCBORDecode_GetNthTagOfLast()
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004596 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07004597
Laurence Lundbladec7114722020-08-13 05:11:40 -07004598 *pnTime = pItem->val.epochDate.nSeconds;
4599
4600Done:
4601 pMe->uLastError = (uint8_t)uErr;
4602}
4603
4604
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004605
4606/*
4607 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4608 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004609void
4610QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
4611 uint8_t uTagRequirement,
4612 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004613{
4614 if(pMe->uLastError != QCBOR_SUCCESS) {
4615 // Already in error state, do nothing
4616 return;
4617 }
4618
4619 QCBORItem Item;
4620 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4621
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004622 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004623}
4624
4625
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004626/*
4627 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4628 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07004629void
4630QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
4631 int64_t nLabel,
4632 uint8_t uTagRequirement,
4633 int64_t *pnTime)
4634{
4635 QCBORItem Item;
4636 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004637 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004638}
4639
4640
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004641/*
4642 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4643 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07004644void
4645QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
4646 const char *szLabel,
4647 uint8_t uTagRequirement,
4648 int64_t *pnTime)
4649{
4650 QCBORItem Item;
4651 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004652 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004653}
4654
4655
4656
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004657/**
4658 * @brief Common processing for an epoch date.
4659 *
4660 * @param[in] pMe The decode context.
4661 * @param[in] pItem The item with the date.
4662 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4663 * @param[out] pnDays The returned day count.
4664 *
4665 * Common processing for the RFC 8943 day-count tag. Mostly make sure
4666 * the tag content is correct and copy forward any further other tag
4667 * numbers.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004668 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004669static void
4670QCBORDecode_Private_ProcessEpochDays(QCBORDecodeContext *pMe,
4671 QCBORItem *pItem,
4672 uint8_t uTagRequirement,
4673 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004674{
4675 if(pMe->uLastError != QCBOR_SUCCESS) {
4676 /* Already in error state, do nothing */
4677 return;
4678 }
4679
4680 QCBORError uErr;
4681
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004682 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004683 {
4684 uTagRequirement,
4685 {QCBOR_TYPE_DAYS_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4686 {QCBOR_TYPE_INT64, QCBOR_TYPE_UINT64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4687 };
4688
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004689 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004690 if(uErr != QCBOR_SUCCESS) {
4691 goto Done;
4692 }
4693
4694 if(pItem->uDataType != QCBOR_TYPE_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004695 uErr = QCBOR_Private_DecodeDaysEpoch(pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004696 if(uErr != QCBOR_SUCCESS) {
4697 goto Done;
4698 }
4699 }
4700
4701 /* Save the tags in the last item's tags in the decode context
4702 * for QCBORDecode_GetNthTagOfLast()
4703 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004704 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004705
4706 *pnDays = pItem->val.epochDays;
4707
4708Done:
4709 pMe->uLastError = (uint8_t)uErr;
4710}
4711
4712
4713/*
4714 * Public function, see header qcbor/qcbor_decode.h
4715 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004716void
4717QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe,
4718 uint8_t uTagRequirement,
4719 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004720{
4721 if(pMe->uLastError != QCBOR_SUCCESS) {
4722 /* Already in error state, do nothing */
4723 return;
4724 }
4725
4726 QCBORItem Item;
4727 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4728
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004729 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004730}
4731
4732
4733/*
4734 * Public function, see header qcbor/qcbor_decode.h
4735 */
4736void
4737QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe,
4738 int64_t nLabel,
4739 uint8_t uTagRequirement,
4740 int64_t *pnDays)
4741{
4742 QCBORItem Item;
4743 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004744 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004745}
4746
4747
4748/*
4749 * Public function, see header qcbor/qcbor_decode.h
4750 */
4751void
4752QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe,
4753 const char *szLabel,
4754 uint8_t uTagRequirement,
4755 int64_t *pnDays)
4756{
4757 QCBORItem Item;
4758 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004759 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004760}
4761
4762
4763
Laurence Lundblade37286c02022-09-03 10:05:02 -07004764/*
4765 * @brief Get a string that matches the type/tag specification.
4766 */
4767void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004768QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
4769 const QCBOR_Private_TagSpec TagSpec,
4770 UsefulBufC *pBstr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004771{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004772 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade37286c02022-09-03 10:05:02 -07004773 /* Already in error state, do nothing */
Laurence Lundbladec4537442020-04-14 18:53:22 -07004774 return;
4775 }
4776
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004777 QCBORError uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004778 QCBORItem Item;
4779
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004780 uError = QCBORDecode_GetNext(pMe, &Item);
4781 if(uError != QCBOR_SUCCESS) {
4782 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004783 return;
4784 }
4785
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004786 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004787
4788 if(pMe->uLastError == QCBOR_SUCCESS) {
4789 *pBstr = Item.val.string;
Laurence Lundbladeab40c6f2020-08-28 11:24:58 -07004790 } else {
4791 *pBstr = NULLUsefulBufC;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004792 }
4793}
4794
Laurence Lundbladec4537442020-04-14 18:53:22 -07004795
4796
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004797
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004798/**
4799 * @brief Common processing for a big number tag.
4800 *
4801 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4802 * @param[in] pItem The item with the date.
4803 * @param[out] pValue The returned big number
4804 * @param[out] pbIsNegative The returned sign of the big number.
4805 *
4806 * Common processing for the big number tag. Mostly make sure
4807 * the tag content is correct and copy forward any further other tag
4808 * numbers.
4809 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004810static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004811QCBOR_Private_ProcessBigNum(const uint8_t uTagRequirement,
4812 const QCBORItem *pItem,
4813 UsefulBufC *pValue,
4814 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004815{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004816 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004817 {
4818 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004819 {QCBOR_TYPE_POSBIGNUM, QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4820 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004821 };
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004822
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004823 QCBORError uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004824 if(uErr != QCBOR_SUCCESS) {
4825 return uErr;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004826 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004827
4828 *pValue = pItem->val.string;
4829
4830 if(pItem->uDataType == QCBOR_TYPE_POSBIGNUM) {
4831 *pbIsNegative = false;
4832 } else if(pItem->uDataType == QCBOR_TYPE_NEGBIGNUM) {
4833 *pbIsNegative = true;
4834 }
4835
4836 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004837}
4838
4839
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004840/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004841 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004842 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004843void
4844QCBORDecode_GetBignum(QCBORDecodeContext *pMe,
4845 const uint8_t uTagRequirement,
4846 UsefulBufC *pValue,
4847 bool *pbIsNegative)
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004848{
4849 if(pMe->uLastError != QCBOR_SUCCESS) {
4850 // Already in error state, do nothing
4851 return;
4852 }
4853
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004854 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004855 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
4856 if(uError != QCBOR_SUCCESS) {
4857 pMe->uLastError = (uint8_t)uError;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004858 return;
4859 }
4860
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004861 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4862 &Item,
4863 pValue,
4864 pbIsNegative);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004865}
4866
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004867
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004868/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004869 * Public function, see header qcbor/qcbor_spiffy_decode.h
4870 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004871void
4872QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe,
4873 const int64_t nLabel,
4874 const uint8_t uTagRequirement,
4875 UsefulBufC *pValue,
4876 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004877{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004878 QCBORItem Item;
4879 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004880 if(pMe->uLastError != QCBOR_SUCCESS) {
4881 return;
4882 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004883
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004884 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4885 &Item,
4886 pValue,
4887 pbIsNegative);
Laurence Lundbladec4537442020-04-14 18:53:22 -07004888}
4889
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004890
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004891/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004892 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004893 */
4894void
4895QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe,
4896 const char *szLabel,
4897 const uint8_t uTagRequirement,
4898 UsefulBufC *pValue,
4899 bool *pbIsNegative)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004900{
4901 QCBORItem Item;
4902 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004903 if(pMe->uLastError != QCBOR_SUCCESS) {
4904 return;
4905 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004906
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004907 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4908 &Item,
4909 pValue,
4910 pbIsNegative);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004911}
4912
4913
4914
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004915/**
4916 * @brief Common processing for MIME tag (semi-private).
4917 *
4918 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4919 * @param[in] pItem The item with the date.
4920 * @param[out] pMessage The returned MIME message.
4921 * @param[out] pbIsTag257 If true, binary MIME, if not, text MIME.
4922 *
4923 * Common processing for the MIME tag. Mostly make sure the tag
4924 * content is correct and copy forward any further other tag
4925 * numbers. See QCBORDecode_GetMIMEMessage().
4926 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004927QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004928QCBORDecode_Private_GetMIME(const uint8_t uTagRequirement,
Laurence Lundblade37286c02022-09-03 10:05:02 -07004929 const QCBORItem *pItem,
4930 UsefulBufC *pMessage,
4931 bool *pbIsTag257)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004932{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004933 const QCBOR_Private_TagSpec TagSpecText =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004934 {
4935 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004936 {QCBOR_TYPE_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4937 {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004938 };
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004939 const QCBOR_Private_TagSpec TagSpecBinary =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004940 {
4941 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004942 {QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4943 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004944 };
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004945
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004946 QCBORError uReturn;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004947
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004948 if(QCBOR_Private_CheckTagRequirement(TagSpecText, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004949 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07004950 if(pbIsTag257 != NULL) {
4951 *pbIsTag257 = false;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004952 }
4953 uReturn = QCBOR_SUCCESS;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004954 } else if(QCBOR_Private_CheckTagRequirement(TagSpecBinary, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004955 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07004956 if(pbIsTag257 != NULL) {
4957 *pbIsTag257 = true;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004958 }
4959 uReturn = QCBOR_SUCCESS;
4960
4961 } else {
4962 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
4963 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07004964
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004965 return uReturn;
4966}
4967
Laurence Lundblade93d89472020-10-03 22:30:50 -07004968// Improvement: add methods for wrapped CBOR, a simple alternate
4969// to EnterBstrWrapped
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004970
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004971
4972
4973
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07004974#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundbladee6430642020-03-14 21:15:44 -07004975
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004976/**
4977 * @brief Prototype for conversion of exponent and mantissa to unsigned integer.
4978 *
4979 * @param[in] uMantissa The mantissa.
4980 * @param[in] nExponent The exponent.
4981 * @param[out] puResult The resulting integer.
4982 *
4983 * Concrete implementations of this are for exponent base 10 and 2 supporting
4984 * decimal fractions and big floats.
4985 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004986typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004987
4988
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004989/**
4990 * @brief Base 10 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
4991 *
4992 * @param[in] uMantissa The unsigned integer mantissa.
4993 * @param[in] nExponent The signed integer exponent.
4994 * @param[out] puResult Place to return the unsigned integer result.
4995 *
4996 * This computes: mantissa * 10 ^^ exponent as for a decimal fraction. The output is a 64-bit
4997 * unsigned integer.
4998 *
4999 * There are many inputs for which the result will not fit in the
5000 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5001 * be returned.
5002 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005003static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005004QCBOR_Private_Exponentitate10(const uint64_t uMantissa,
5005 int64_t nExponent,
5006 uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005007{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005008 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005009
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005010 if(uResult != 0) {
5011 /* This loop will run a maximum of 19 times because
5012 * UINT64_MAX < 10 ^^ 19. More than that will cause
5013 * exit with the overflow error
5014 */
5015 for(; nExponent > 0; nExponent--) {
5016 if(uResult > UINT64_MAX / 10) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005017 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005018 }
5019 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005020 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005021
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005022 for(; nExponent < 0; nExponent++) {
5023 uResult = uResult / 10;
5024 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005025 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005026 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005027 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005028 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005029 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07005030
5031 *puResult = uResult;
5032
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005033 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005034}
5035
5036
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005037/**
5038 * @brief Base 2 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5039 *
5040 * @param[in] uMantissa The unsigned integer mantissa.
5041 * @param[in] nExponent The signed integer exponent.
5042 * @param[out] puResult Place to return the unsigned integer result.
5043 *
5044 * This computes: mantissa * 2 ^^ exponent as for a big float. The
5045 * output is a 64-bit unsigned integer.
5046 *
5047 * There are many inputs for which the result will not fit in the
5048 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5049 * be returned.
5050 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005051static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005052QCBOR_Private_Exponentitate2(const uint64_t uMantissa,
5053 int64_t nExponent,
5054 uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005055{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005056 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005057
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005058 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005059
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005060 /* This loop will run a maximum of 64 times because INT64_MAX <
5061 * 2^31. More than that will cause exit with the overflow error
Laurence Lundbladee6430642020-03-14 21:15:44 -07005062 */
5063 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005064 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005065 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005066 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005067 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005068 nExponent--;
5069 }
5070
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005071 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005072 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005073 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005074 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005075 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005076 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005077 }
5078
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005079 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005080
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005081 return QCBOR_SUCCESS;
5082}
5083
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005084
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005085/**
5086 * @brief Exponentiate a signed mantissa and signed exponent to produce a signed result.
5087 *
5088 * @param[in] nMantissa Signed integer mantissa.
5089 * @param[in] nExponent Signed integer exponent.
5090 * @param[out] pnResult Place to put the signed integer result.
5091 * @param[in] pfExp Exponentiation function.
5092 *
5093 * @returns Error code
5094 *
5095 * \c pfExp performs exponentiation on and unsigned mantissa and
5096 * produces an unsigned result. This converts the mantissa from signed
5097 * and converts the result to signed. The exponentiation function is
5098 * either for base 2 or base 10 (and could be other if needed).
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005099 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005100static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005101QCBOR_Private_ExponentiateNN(const int64_t nMantissa,
5102 const int64_t nExponent,
5103 int64_t *pnResult,
5104 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005105{
5106 uint64_t uResult;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005107 uint64_t uMantissa;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005108
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005109 /* Take the absolute value and put it into an unsigned. */
5110 if(nMantissa >= 0) {
5111 /* Positive case is straightforward */
5112 uMantissa = (uint64_t)nMantissa;
5113 } else if(nMantissa != INT64_MIN) {
5114 /* The common negative case. See next. */
5115 uMantissa = (uint64_t)-nMantissa;
5116 } else {
5117 /* int64_t and uint64_t are always two's complement per the
5118 * C standard (and since QCBOR uses these it only works with
5119 * two's complement, which is pretty much universal these
5120 * days). The range of a negative two's complement integer is
5121 * one more that than a positive, so the simple code above might
5122 * not work all the time because you can't simply negate the
5123 * value INT64_MIN because it can't be represented in an
5124 * int64_t. -INT64_MIN can however be represented in a
5125 * uint64_t. Some compilers seem to recognize this case for the
5126 * above code and put the correct value in uMantissa, however
5127 * they are not required to do this by the C standard. This next
5128 * line does however work for all compilers.
5129 *
5130 * This does assume two's complement where -INT64_MIN ==
5131 * INT64_MAX + 1 (which wouldn't be true for one's complement or
5132 * sign and magnitude (but we know we're using two's complement
5133 * because int64_t requires it)).
5134 *
5135 * See these, particularly the detailed commentary:
5136 * https://stackoverflow.com/questions/54915742/does-c99-mandate-a-int64-t-type-be-available-always
5137 * https://stackoverflow.com/questions/37301078/is-negating-int-min-undefined-behaviour
5138 */
5139 uMantissa = (uint64_t)INT64_MAX+1;
5140 }
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005141
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005142 /* Call the exponentiator passed for either base 2 or base 10.
5143 * Here is where most of the overflow errors are caught. */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005144 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
5145 if(uReturn) {
5146 return uReturn;
5147 }
5148
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005149 /* Convert back to the sign of the original mantissa */
5150 if(nMantissa >= 0) {
5151 if(uResult > INT64_MAX) {
5152 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5153 }
5154 *pnResult = (int64_t)uResult;
5155 } else {
5156 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
5157 * of INT64_MIN. This assumes two's compliment representation
5158 * where INT64_MIN is one increment farther from 0 than
5159 * INT64_MAX. Trying to write -INT64_MIN doesn't work to get
5160 * this because the compiler makes it an int64_t which can't
5161 * represent -INT64_MIN. Also see above.
5162 */
5163 if(uResult > (uint64_t)INT64_MAX+1) {
5164 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5165 }
5166 *pnResult = -(int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005167 }
5168
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005169 return QCBOR_SUCCESS;
5170}
5171
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005172
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005173/**
5174 * @brief Exponentiate an unsigned mantissa and signed exponent to produce an unsigned result.
5175 *
5176 * @param[in] nMantissa Signed integer mantissa.
5177 * @param[in] nExponent Signed integer exponent.
5178 * @param[out] puResult Place to put the signed integer result.
5179 * @param[in] pfExp Exponentiation function.
5180 *
5181 * @returns Error code
5182 *
5183 * \c pfExp performs exponentiation on and unsigned mantissa and
5184 * produces an unsigned result. This errors out if the mantissa
5185 * is negative because the output is unsigned.
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005186 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005187static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005188QCBOR_Private_ExponentitateNU(const int64_t nMantissa,
5189 const int64_t nExponent,
5190 uint64_t *puResult,
5191 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005192{
5193 if(nMantissa < 0) {
5194 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5195 }
5196
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005197 /* Cast to unsigned is OK because of check for negative.
5198 * Cast to unsigned is OK because UINT64_MAX > INT64_MAX.
5199 * Exponentiation is straight forward
5200 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005201 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
5202}
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005203
5204
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005205/**
5206 * @brief Exponentiate an usnigned mantissa and unsigned exponent to produce an unsigned result.
5207 *
5208 * @param[in] uMantissa Unsigned integer mantissa.
5209 * @param[in] nExponent Unsigned integer exponent.
5210 * @param[out] puResult Place to put the unsigned integer result.
5211 * @param[in] pfExp Exponentiation function.
5212 *
5213 * @returns Error code
5214 *
5215 * \c pfExp performs exponentiation on and unsigned mantissa and
5216 * produces an unsigned result so this is just a wrapper that does
5217 * nothing (and is likely inlined).
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005218 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005219static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005220QCBOR_Private_ExponentitateUU(const uint64_t uMantissa,
5221 const int64_t nExponent,
5222 uint64_t *puResult,
5223 fExponentiator pfExp)
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005224{
5225 return (*pfExp)(uMantissa, nExponent, puResult);
5226}
5227
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005228#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005229
5230
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005231
5232
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005233/**
5234 * @brief Convert a CBOR big number to a uint64_t.
5235 *
5236 * @param[in] BigNum Bytes of the big number to convert.
5237 * @param[in] uMax Maximum value allowed for the result.
5238 * @param[out] pResult Place to put the unsigned integer result.
5239 *
5240 * @returns Error code
5241 *
5242 * Many values will overflow because a big num can represent a much
5243 * larger range than uint64_t.
5244 */
5245static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005246QCBOR_Private_ConvertBigNumToUnsigned(const UsefulBufC BigNum,
5247 const uint64_t uMax,
5248 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005249{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005250 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005251
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005252 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005253 const uint8_t *pByte = BigNum.ptr;
5254 size_t uLen = BigNum.len;
5255 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07005256 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005257 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005258 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07005259 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005260 }
5261
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005262 *pResult = uResult;
5263 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005264}
5265
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005266
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005267/**
5268 * @brief Convert a CBOR postive big number to a uint64_t.
5269 *
5270 * @param[in] BigNum Bytes of the big number to convert.
5271 * @param[out] pResult Place to put the unsigned integer result.
5272 *
5273 * @returns Error code
5274 *
5275 * Many values will overflow because a big num can represent a much
5276 * larger range than uint64_t.
5277 */
5278static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005279QCBOR_Private_ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum,
5280 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005281{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005282 return QCBOR_Private_ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005283}
5284
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005285
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005286/**
5287 * @brief Convert a CBOR positive big number to an int64_t.
5288 *
5289 * @param[in] BigNum Bytes of the big number to convert.
5290 * @param[out] pResult Place to put the signed integer result.
5291 *
5292 * @returns Error code
5293 *
5294 * Many values will overflow because a big num can represent a much
5295 * larger range than int64_t.
5296 */
5297static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005298QCBOR_Private_ConvertPositiveBigNumToSigned(const UsefulBufC BigNum,
5299 int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005300{
5301 uint64_t uResult;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005302 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5303 INT64_MAX,
5304 &uResult);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005305 if(uError) {
5306 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005307 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005308 /* Cast is safe because ConvertBigNumToUnsigned limits to INT64_MAX */
Laurence Lundbladee6430642020-03-14 21:15:44 -07005309 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005310 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005311}
5312
5313
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005314/**
5315 * @brief Convert a CBOR negative big number to an int64_t.
5316 *
5317 * @param[in] BigNum Bytes of the big number to convert.
5318 * @param[out] pnResult Place to put the signed integer result.
5319 *
5320 * @returns Error code
5321 *
5322 * Many values will overflow because a big num can represent a much
5323 * larger range than int64_t.
5324 */
5325static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005326QCBOR_Private_ConvertNegativeBigNumToSigned(const UsefulBufC BigNum,
5327 int64_t *pnResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005328{
5329 uint64_t uResult;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005330 /* The negative integer furthest from zero for a C int64_t is
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005331 * INT64_MIN which is expressed as -INT64_MAX - 1. The value of a
5332 * negative number in CBOR is computed as -n - 1 where n is the
5333 * encoded integer, where n is what is in the variable BigNum. When
5334 * converting BigNum to a uint64_t, the maximum value is thus
5335 * INT64_MAX, so that when it -n - 1 is applied to it the result
5336 * will never be further from 0 than INT64_MIN.
5337 *
5338 * -n - 1 <= INT64_MIN.
5339 * -n - 1 <= -INT64_MAX - 1
5340 * n <= INT64_MAX.
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005341 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005342 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5343 INT64_MAX,
5344 &uResult);
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005345 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005346 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005347 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005348
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005349 /* Now apply -n - 1. The cast is safe because
5350 * ConvertBigNumToUnsigned() is limited to INT64_MAX which does fit
5351 * is the largest positive integer that an int64_t can
5352 * represent. */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005353 *pnResult = -(int64_t)uResult - 1;
5354
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005355 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005356}
5357
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005358
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005359
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005360
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005361/**
5362 * @brief Convert integers and floats to an int64_t.
5363 *
5364 * @param[in] pItem The item to convert.
5365 * @param[in] uConvertTypes Bit mask list of conversion options.
5366 * @param[out] pnValue The resulting converted value.
5367 *
5368 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5369 * in uConvertTypes.
5370 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5371 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5372 * or too small.
5373 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005374static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005375QCBOR_Private_ConvertInt64(const QCBORItem *pItem,
5376 const uint32_t uConvertTypes,
5377 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005378{
5379 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005380 case QCBOR_TYPE_FLOAT:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005381 case QCBOR_TYPE_DOUBLE:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005382#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005383 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005384 /* https://pubs.opengroup.org/onlinepubs/009695399/functions/llround.html
5385 http://www.cplusplus.com/reference/cmath/llround/
5386 */
5387 // Not interested in FE_INEXACT
5388 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005389 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5390 *pnValue = llround(pItem->val.dfnum);
5391 } else {
5392 *pnValue = lroundf(pItem->val.fnum);
5393 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005394 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5395 // llround() shouldn't result in divide by zero, but catch
5396 // it here in case it unexpectedly does. Don't try to
5397 // distinguish between the various exceptions because it seems
5398 // they vary by CPU, compiler and OS.
5399 return QCBOR_ERR_FLOAT_EXCEPTION;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005400 }
5401 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005402 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005403 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005404#else
5405 return QCBOR_ERR_HW_FLOAT_DISABLED;
5406#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005407 break;
5408
5409 case QCBOR_TYPE_INT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005410 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005411 *pnValue = pItem->val.int64;
5412 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005413 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005414 }
5415 break;
5416
5417 case QCBOR_TYPE_UINT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005418 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005419 if(pItem->val.uint64 < INT64_MAX) {
5420 *pnValue = pItem->val.int64;
5421 } else {
5422 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5423 }
5424 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005425 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005426 }
5427 break;
5428
5429 default:
5430 return QCBOR_ERR_UNEXPECTED_TYPE;
5431 }
5432 return QCBOR_SUCCESS;
5433}
5434
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005435
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005436/**
5437 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5438 *
5439 * @param[in] pMe The decode context.
5440 * @param[in] uConvertTypes Bit mask list of conversion options.
5441 * @param[out] pnValue Result of the conversion.
5442 * @param[in,out] pItem Temporary space to store Item, returned item.
5443 *
5444 * See QCBORDecode_GetInt64Convert().
5445 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005446void
5447QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pMe,
5448 uint32_t uConvertTypes,
5449 int64_t *pnValue,
5450 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005451{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07005452 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005453 return;
5454 }
5455
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005456 QCBORError uError = QCBORDecode_GetNext(pMe, pItem);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005457 if(uError) {
5458 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005459 return;
5460 }
5461
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005462 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005463 uConvertTypes,
5464 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005465}
5466
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005467/**
5468 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5469 *
5470 * @param[in] pMe The decode context.
5471 * @param[in] nLabel Label to find in map.
5472 * @param[in] uConvertTypes Bit mask list of conversion options.
5473 * @param[out] pnValue Result of the conversion.
5474 * @param[in,out] pItem Temporary space to store Item, returned item.
5475 *
5476 * See QCBORDecode_GetInt64ConvertInMapN().
5477 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005478void
5479QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pMe,
5480 int64_t nLabel,
5481 uint32_t uConvertTypes,
5482 int64_t *pnValue,
5483 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005484{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005485 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005486 if(pMe->uLastError != QCBOR_SUCCESS) {
5487 return;
5488 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005489
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005490 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5491 uConvertTypes,
5492 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005493}
5494
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005495/**
5496 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5497 *
5498 * @param[in] pMe The decode context.
5499 * @param[in] szLabel Label to find in map.
5500 * @param[in] uConvertTypes Bit mask list of conversion options.
5501 * @param[out] pnValue Result of the conversion.
5502 * @param[in,out] pItem Temporary space to store Item, returned item.
5503 *
5504 * See QCBORDecode_GetInt64ConvertInMapSZ().
5505 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005506void
5507QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5508 const char * szLabel,
5509 uint32_t uConvertTypes,
5510 int64_t *pnValue,
5511 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005512{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005513 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005514 if(pMe->uLastError != QCBOR_SUCCESS) {
5515 return;
5516 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005517
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005518 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5519 uConvertTypes,
5520 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005521}
5522
5523
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005524/**
5525 * @brief Convert many number types to an int64_t.
5526 *
5527 * @param[in] pItem The item to convert.
5528 * @param[in] uConvertTypes Bit mask list of conversion options.
5529 * @param[out] pnValue The resulting converted value.
5530 *
5531 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5532 * in uConvertTypes.
5533 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5534 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5535 * or too small.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005536 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005537static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005538QCBOR_Private_Int64ConvertAll(const QCBORItem *pItem,
5539 const uint32_t uConvertTypes,
5540 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005541{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005542 switch(pItem->uDataType) {
5543
5544 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005545 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005546 return QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005547 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005548 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005549 }
5550 break;
5551
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005552 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005553 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005554 return QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005555 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005556 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005557 }
5558 break;
5559
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005560#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005561 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005562 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005563 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005564 pItem->val.expAndMantissa.nExponent,
5565 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005566 &QCBOR_Private_Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005567 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005568 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005569 }
5570 break;
5571
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005572 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005573 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005574 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005575 pItem->val.expAndMantissa.nExponent,
5576 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005577 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005578 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005579 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005580 }
5581 break;
5582
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005583 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005584 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005585 int64_t nMantissa;
5586 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005587 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005588 if(uErr) {
5589 return uErr;
5590 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005591 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005592 pItem->val.expAndMantissa.nExponent,
5593 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005594 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005595 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005596 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005597 }
5598 break;
5599
5600 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005601 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005602 int64_t nMantissa;
5603 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005604 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005605 if(uErr) {
5606 return uErr;
5607 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005608 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005609 pItem->val.expAndMantissa.nExponent,
5610 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005611 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005612 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005613 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005614 }
5615 break;
5616
5617 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005618 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005619 int64_t nMantissa;
5620 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005621 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005622 if(uErr) {
5623 return uErr;
5624 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005625 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005626 pItem->val.expAndMantissa.nExponent,
5627 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005628 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005629 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005630 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005631 }
5632 break;
5633
5634 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005635 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005636 int64_t nMantissa;
5637 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005638 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005639 if(uErr) {
5640 return uErr;
5641 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005642 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005643 pItem->val.expAndMantissa.nExponent,
5644 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005645 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005646 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005647 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005648 }
5649 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005650#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005651
Laurence Lundbladee6430642020-03-14 21:15:44 -07005652
Laurence Lundbladec4537442020-04-14 18:53:22 -07005653 default:
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005654 return QCBOR_ERR_UNEXPECTED_TYPE; }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005655}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005656
5657
Laurence Lundbladec4537442020-04-14 18:53:22 -07005658/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005659 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005660 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005661void
5662QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe,
5663 const uint32_t uConvertTypes,
5664 int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005665{
5666 QCBORItem Item;
5667
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005668 QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005669
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005670 if(pMe->uLastError == QCBOR_SUCCESS) {
5671 // The above conversion succeeded
5672 return;
5673 }
5674
Laurence Lundbladef6c86662020-05-12 02:08:00 -07005675 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005676 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07005677 return;
5678 }
5679
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005680 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5681 uConvertTypes,
5682 pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005683}
5684
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005685
5686/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005687 * Public function, see header qcbor/qcbor_decode.h file
5688 */
5689void
5690QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
5691 const int64_t nLabel,
5692 const uint32_t uConvertTypes,
5693 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005694{
5695 QCBORItem Item;
5696
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005697 QCBORDecode_Private_GetInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07005698 nLabel,
5699 uConvertTypes,
5700 pnValue,
5701 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005702
5703 if(pMe->uLastError == QCBOR_SUCCESS) {
5704 // The above conversion succeeded
5705 return;
5706 }
5707
5708 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5709 // The above conversion failed in a way that code below can't correct
5710 return;
5711 }
5712
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005713 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5714 uConvertTypes,
5715 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005716}
5717
5718
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005719/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005720 * Public function, see header qcbor/qcbor_decode.h file
5721 */
5722void
5723QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
5724 const char *szLabel,
5725 const uint32_t uConvertTypes,
5726 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005727{
5728 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005729 QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07005730 szLabel,
5731 uConvertTypes,
5732 pnValue,
5733 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005734
5735 if(pMe->uLastError == QCBOR_SUCCESS) {
5736 // The above conversion succeeded
5737 return;
5738 }
5739
5740 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5741 // The above conversion failed in a way that code below can't correct
5742 return;
5743 }
5744
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005745 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5746 uConvertTypes,
5747 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005748}
5749
5750
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005751/**
5752 * @brief Convert many number types to an uint64_t.
5753 *
5754 * @param[in] pItem The item to convert.
5755 * @param[in] uConvertTypes Bit mask list of conversion options.
5756 * @param[out] puValue The resulting converted value.
5757 *
5758 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5759 * in uConvertTypes.
5760 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5761 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5762 * or too small.
5763 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005764static QCBORError
5765QCBOR_Private_ConvertUInt64(const QCBORItem *pItem,
5766 const uint32_t uConvertTypes,
5767 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005768{
5769 switch(pItem->uDataType) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005770 case QCBOR_TYPE_DOUBLE:
5771 case QCBOR_TYPE_FLOAT:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005772#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005773 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005774 // Can't use llround here because it will not convert values
5775 // greater than INT64_MAX and less than UINT64_MAX that
5776 // need to be converted so it is more complicated.
5777 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
5778 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5779 if(isnan(pItem->val.dfnum)) {
5780 return QCBOR_ERR_FLOAT_EXCEPTION;
5781 } else if(pItem->val.dfnum < 0) {
5782 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5783 } else {
5784 double dRounded = round(pItem->val.dfnum);
5785 // See discussion in DecodeDateEpoch() for
5786 // explanation of - 0x7ff
5787 if(dRounded > (double)(UINT64_MAX- 0x7ff)) {
5788 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5789 }
5790 *puValue = (uint64_t)dRounded;
5791 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005792 } else {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005793 if(isnan(pItem->val.fnum)) {
5794 return QCBOR_ERR_FLOAT_EXCEPTION;
5795 } else if(pItem->val.fnum < 0) {
5796 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5797 } else {
5798 float fRounded = roundf(pItem->val.fnum);
5799 // See discussion in DecodeDateEpoch() for
5800 // explanation of - 0x7ff
5801 if(fRounded > (float)(UINT64_MAX- 0x7ff)) {
5802 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5803 }
5804 *puValue = (uint64_t)fRounded;
5805 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005806 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005807 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5808 // round() and roundf() shouldn't result in exceptions here, but
5809 // catch them to be robust and thorough. Don't try to
5810 // distinguish between the various exceptions because it seems
5811 // they vary by CPU, compiler and OS.
5812 return QCBOR_ERR_FLOAT_EXCEPTION;
5813 }
5814
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005815 } else {
5816 return QCBOR_ERR_UNEXPECTED_TYPE;
5817 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005818#else
5819 return QCBOR_ERR_HW_FLOAT_DISABLED;
5820#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005821 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005822
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005823 case QCBOR_TYPE_INT64:
5824 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
5825 if(pItem->val.int64 >= 0) {
5826 *puValue = (uint64_t)pItem->val.int64;
5827 } else {
5828 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5829 }
5830 } else {
5831 return QCBOR_ERR_UNEXPECTED_TYPE;
5832 }
5833 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005834
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005835 case QCBOR_TYPE_UINT64:
5836 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
5837 *puValue = pItem->val.uint64;
5838 } else {
5839 return QCBOR_ERR_UNEXPECTED_TYPE;
5840 }
5841 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005842
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005843 default:
5844 return QCBOR_ERR_UNEXPECTED_TYPE;
5845 }
5846
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005847 return QCBOR_SUCCESS;
5848}
Laurence Lundbladec4537442020-04-14 18:53:22 -07005849
5850
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005851/**
5852 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5853 *
5854 * @param[in] pMe The decode context.
5855 * @param[in] uConvertTypes Bit mask list of conversion options.
5856 * @param[out] puValue Result of the conversion.
5857 * @param[in,out] pItem Temporary space to store Item, returned item.
5858 *
5859 * See QCBORDecode_GetUInt64Convert().
5860 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005861void
5862QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pMe,
5863 const uint32_t uConvertTypes,
5864 uint64_t *puValue,
5865 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005866{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005867 if(pMe->uLastError != QCBOR_SUCCESS) {
5868 return;
5869 }
5870
Laurence Lundbladec4537442020-04-14 18:53:22 -07005871 QCBORItem Item;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005872
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005873 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
5874 if(uError) {
5875 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005876 return;
5877 }
5878
Laurence Lundbladea826c502020-05-10 21:07:00 -07005879 if(pItem) {
5880 *pItem = Item;
5881 }
5882
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005883 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(&Item,
5884 uConvertTypes,
5885 puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005886}
5887
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005888
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005889/**
5890 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5891 *
5892 * @param[in] pMe The decode context.
5893 * @param[in] nLabel Label to find in map.
5894 * @param[in] uConvertTypes Bit mask list of conversion options.
5895 * @param[out] puValue Result of the conversion.
5896 * @param[in,out] pItem Temporary space to store Item, returned item.
5897 *
5898 * See QCBORDecode_GetUInt64ConvertInMapN().
5899 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005900void
5901QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe,
5902 const int64_t nLabel,
5903 const uint32_t uConvertTypes,
5904 uint64_t *puValue,
5905 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005906{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005907 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005908 if(pMe->uLastError != QCBOR_SUCCESS) {
5909 return;
5910 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005911
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005912 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
5913 uConvertTypes,
5914 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005915}
5916
5917
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005918/**
5919 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5920 *
5921 * @param[in] pMe The decode context.
5922 * @param[in] szLabel Label to find in map.
5923 * @param[in] uConvertTypes Bit mask list of conversion options.
5924 * @param[out] puValue Result of the conversion.
5925 * @param[in,out] pItem Temporary space to store Item, returned item.
5926 *
5927 * See QCBORDecode_GetUInt64ConvertInMapSZ().
5928 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005929void
5930QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5931 const char *szLabel,
5932 const uint32_t uConvertTypes,
5933 uint64_t *puValue,
5934 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005935{
5936 if(pMe->uLastError != QCBOR_SUCCESS) {
5937 return;
5938 }
5939
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005940 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005941 if(pMe->uLastError != QCBOR_SUCCESS) {
5942 return;
5943 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005944
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005945 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
5946 uConvertTypes,
5947 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005948}
5949
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005950
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005951/**
5952 * @brief Convert many number types to an unt64_t.
5953 *
5954 * @param[in] pItem The item to convert.
5955 * @param[in] uConvertTypes Bit mask list of conversion options.
5956 * @param[out] puValue The resulting converted value.
5957 *
5958 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5959 * in uConvertTypes.
5960 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5961 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5962 * or too small.
5963 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005964static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005965QCBOR_Private_UInt64ConvertAll(const QCBORItem *pItem,
5966 const uint32_t uConvertTypes,
5967 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005968{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08005969 switch(pItem->uDataType) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005970
5971 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005972 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005973 return QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005974 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005975 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005976 }
5977 break;
5978
5979 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005980 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005981 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5982 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005983 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005984 }
5985 break;
5986
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005987#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005988
5989 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005990 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005991 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005992 pItem->val.expAndMantissa.nExponent,
5993 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005994 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005995 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005996 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005997 }
5998 break;
5999
6000 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006001 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006002 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006003 pItem->val.expAndMantissa.nExponent,
6004 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006005 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006006 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006007 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006008 }
6009 break;
6010
6011 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006012 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006013 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006014 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006015 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006016 if(uErr != QCBOR_SUCCESS) {
6017 return uErr;
6018 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006019 return QCBOR_Private_ExponentitateUU(uMantissa,
6020 pItem->val.expAndMantissa.nExponent,
6021 puValue,
6022 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006023 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006024 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006025 }
6026 break;
6027
6028 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006029 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006030 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6031 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006032 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006033 }
6034 break;
6035
6036 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006037 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006038 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006039 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006040 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum,
6041 &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006042 if(uErr != QCBOR_SUCCESS) {
6043 return uErr;
6044 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006045 return QCBOR_Private_ExponentitateUU(uMantissa,
6046 pItem->val.expAndMantissa.nExponent,
6047 puValue,
6048 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006049 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006050 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006051 }
6052 break;
6053
6054 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006055 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006056 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6057 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006058 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006059 }
6060 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006061#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006062 default:
6063 return QCBOR_ERR_UNEXPECTED_TYPE;
6064 }
6065}
6066
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006067
Laurence Lundblade4e2da002020-06-13 23:08:31 -07006068/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006069 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006070 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006071void
6072QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe,
6073 const uint32_t uConvertTypes,
6074 uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006075{
6076 QCBORItem Item;
6077
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006078 QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006079
Laurence Lundbladef6c86662020-05-12 02:08:00 -07006080 if(pMe->uLastError == QCBOR_SUCCESS) {
6081 // The above conversion succeeded
6082 return;
6083 }
6084
6085 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6086 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07006087 return;
6088 }
6089
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006090 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6091 uConvertTypes,
6092 puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006093}
6094
Laurence Lundbladec4537442020-04-14 18:53:22 -07006095
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006096/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006097 * Public function, see header qcbor/qcbor_decode.h file
6098 */
6099void
6100QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
6101 const int64_t nLabel,
6102 const uint32_t uConvertTypes,
6103 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006104{
6105 QCBORItem Item;
6106
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006107 QCBORDecode_Private_GetUInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006108 nLabel,
6109 uConvertTypes,
6110 puValue,
6111 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006112
6113 if(pMe->uLastError == QCBOR_SUCCESS) {
6114 // The above conversion succeeded
6115 return;
6116 }
6117
6118 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6119 // The above conversion failed in a way that code below can't correct
6120 return;
6121 }
6122
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006123 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6124 uConvertTypes,
6125 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006126}
6127
6128
6129/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006130 * Public function, see header qcbor/qcbor_decode.h file
6131 */
6132void
6133QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
6134 const char *szLabel,
6135 const uint32_t uConvertTypes,
6136 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006137{
6138 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006139 QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006140 szLabel,
6141 uConvertTypes,
6142 puValue,
6143 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006144
6145 if(pMe->uLastError == QCBOR_SUCCESS) {
6146 // The above conversion succeeded
6147 return;
6148 }
6149
6150 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6151 // The above conversion failed in a way that code below can't correct
6152 return;
6153 }
6154
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006155 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6156 uConvertTypes,
6157 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006158}
6159
6160
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006161
6162
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006163#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006164/**
6165 * @brief Basic conversions to a double.
6166 *
6167 * @param[in] pItem The item to convert
6168 * @param[in] uConvertTypes Bit flags indicating source types for conversion
6169 * @param[out] pdValue The value converted to a double
6170 *
6171 * This does the conversions that don't need much object code,
6172 * the conversions from int, uint and float to double.
6173 *
6174 * See QCBOR_Private_DoubleConvertAll() for the full set
6175 * of conversions.
6176 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006177static QCBORError
6178QCBOR_Private_ConvertDouble(const QCBORItem *pItem,
6179 const uint32_t uConvertTypes,
6180 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006181{
6182 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006183 case QCBOR_TYPE_FLOAT:
6184#ifndef QCBOR_DISABLE_FLOAT_HW_USE
6185 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6186 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006187 // Simple cast does the job.
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006188 *pdValue = (double)pItem->val.fnum;
6189 } else {
6190 return QCBOR_ERR_UNEXPECTED_TYPE;
6191 }
6192 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006193#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006194 return QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006195#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006196 break;
6197
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006198 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006199 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6200 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006201 *pdValue = pItem->val.dfnum;
6202 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006203 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006204 }
6205 }
6206 break;
6207
6208 case QCBOR_TYPE_INT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006209#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006210 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006211 // A simple cast seems to do the job with no worry of exceptions.
6212 // There will be precision loss for some values.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006213 *pdValue = (double)pItem->val.int64;
6214
6215 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006216 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006217 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006218#else
6219 return QCBOR_ERR_HW_FLOAT_DISABLED;
6220#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006221 break;
6222
6223 case QCBOR_TYPE_UINT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006224#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006225 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006226 // A simple cast seems to do the job with no worry of exceptions.
6227 // There will be precision loss for some values.
6228 *pdValue = (double)pItem->val.uint64;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006229 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006230 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006231 }
6232 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006233#else
6234 return QCBOR_ERR_HW_FLOAT_DISABLED;
6235#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006236
6237 default:
6238 return QCBOR_ERR_UNEXPECTED_TYPE;
6239 }
6240
6241 return QCBOR_SUCCESS;
6242}
6243
6244
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006245/**
6246 * @brief Almost-public method to decode a number and convert to double (semi-private).
6247 *
6248 * @param[in] pMe The decode context.
6249 * @param[in] uConvertTypes Bit mask list of conversion options
6250 * @param[out] pdValue The output of the conversion.
6251 * @param[in,out] pItem Temporary space to store Item, returned item.
6252 *
6253 * See QCBORDecode_GetDoubleConvert().
6254 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006255void
6256QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pMe,
6257 const uint32_t uConvertTypes,
6258 double *pdValue,
6259 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07006260{
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006261 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07006262 return;
6263 }
6264
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006265 QCBORError uError = QCBORDecode_GetNext(pMe, pItem);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006266 if(uError) {
6267 pMe->uLastError = (uint8_t)uError;
6268 return;
6269 }
6270
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006271 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006272 uConvertTypes,
6273 pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006274}
Laurence Lundbladec4537442020-04-14 18:53:22 -07006275
Laurence Lundbladec4537442020-04-14 18:53:22 -07006276
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006277/**
6278 * @brief Almost-public method to decode a number and convert to double (semi-private).
6279 *
6280 * @param[in] pMe The decode context.
6281 * @param[in] nLabel Label to find in map.
6282 * @param[in] uConvertTypes Bit mask list of conversion options
6283 * @param[out] pdValue The output of the conversion.
6284 * @param[in,out] pItem Temporary space to store Item, returned item.
6285 *
6286 * See QCBORDecode_GetDoubleConvertInMapN().
6287 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006288void
6289QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pMe,
6290 const int64_t nLabel,
6291 const uint32_t uConvertTypes,
6292 double *pdValue,
6293 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006294{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006295 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006296 if(pMe->uLastError != QCBOR_SUCCESS) {
6297 return;
6298 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006299
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006300 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6301 uConvertTypes,
6302 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006303}
6304
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006305
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006306/**
6307 * @brief Almost-public method to decode a number and convert to double (semi-private).
6308 *
6309 * @param[in] pMe The decode context.
6310 * @param[in] szLabel Label to find in map.
6311 * @param[in] uConvertTypes Bit mask list of conversion options
6312 * @param[out] pdValue The output of the conversion.
6313 * @param[in,out] pItem Temporary space to store Item, returned item.
6314 *
6315 * See QCBORDecode_GetDoubleConvertInMapSZ().
6316 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006317void
6318QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe,
6319 const char *szLabel,
6320 const uint32_t uConvertTypes,
6321 double *pdValue,
6322 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006323{
6324 if(pMe->uLastError != QCBOR_SUCCESS) {
6325 return;
6326 }
6327
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006328 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006329 if(pMe->uLastError != QCBOR_SUCCESS) {
6330 return;
6331 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006332
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006333 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6334 uConvertTypes,
6335 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006336}
6337
6338
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006339#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006340/**
6341 * @brief Convert a big number to double-precision float.
6342 *
6343 * @param[in] BigNum The big number to convert
6344 *
6345 * @returns The double value.
6346 *
6347 * This will always succeed. It will lose precision for larger
6348 * numbers. If the big number is too large to fit (more than
6349 * 1.7976931348623157E+308) infinity will be returned. NaN is never
6350 * returned.
6351 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006352static double
6353QCBOR_Private_ConvertBigNumToDouble(const UsefulBufC BigNum)
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006354{
6355 double dResult;
6356
6357 dResult = 0.0;
6358 const uint8_t *pByte = BigNum.ptr;
6359 size_t uLen = BigNum.len;
6360 /* This will overflow and become the float value INFINITY if the number
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006361 * is too large to fit. */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006362 while(uLen--) {
6363 dResult = (dResult * 256.0) + (double)*pByte++;
6364 }
6365
6366 return dResult;
6367}
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006368#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6369
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006370
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006371
6372
6373/**
6374 * @brief Convert many number types to a double.
6375 *
6376 * @param[in] pItem The item to convert.
6377 * @param[in] uConvertTypes Bit mask list of conversion options.
6378 * @param[out] pdValue The resulting converted value.
6379 *
6380 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6381 * in uConvertTypes.
6382 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6383 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6384 * or too small.
6385 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006386static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006387QCBOR_Private_DoubleConvertAll(const QCBORItem *pItem,
6388 const uint32_t uConvertTypes,
6389 double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006390{
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006391#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07006392 /*
Laurence Lundblade16a207a2021-09-18 17:22:46 -07006393 * What Every Computer Scientist Should Know About Floating-Point Arithmetic
6394 * https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
6395 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006396 switch(pItem->uDataType) {
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006397
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006398#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006399 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006400 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006401 // Underflow gives 0, overflow gives infinity
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006402 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6403 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
6404 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006405 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006406 }
6407 break;
6408
6409 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006410 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006411 // Underflow gives 0, overflow gives infinity
6412 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6413 exp2((double)pItem->val.expAndMantissa.nExponent);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006414 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006415 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006416 }
6417 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006418#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006419
6420 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006421 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006422 *pdValue = QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006423 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006424 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006425 }
6426 break;
6427
6428 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006429 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006430 *pdValue = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006431 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006432 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006433 }
6434 break;
6435
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006436#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006437 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006438 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006439 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006440 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6441 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006442 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006443 }
6444 break;
6445
6446 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006447 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006448 double dMantissa = -QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006449 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6450 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006451 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006452 }
6453 break;
6454
6455 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006456 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006457 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006458 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6459 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006460 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006461 }
6462 break;
6463
6464 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006465 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006466 double dMantissa = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006467 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6468 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006469 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006470 }
6471 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006472#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006473
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006474 default:
6475 return QCBOR_ERR_UNEXPECTED_TYPE;
6476 }
6477
6478 return QCBOR_SUCCESS;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006479
6480#else
6481 (void)pItem;
6482 (void)uConvertTypes;
6483 (void)pdValue;
6484 return QCBOR_ERR_HW_FLOAT_DISABLED;
6485#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6486
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006487}
6488
6489
6490/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006491 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006492 */
6493void
6494QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe,
6495 const uint32_t uConvertTypes,
6496 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006497{
6498
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006499 QCBORItem Item;
6500
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006501 QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006502
6503 if(pMe->uLastError == QCBOR_SUCCESS) {
6504 // The above conversion succeeded
6505 return;
6506 }
6507
6508 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6509 // The above conversion failed in a way that code below can't correct
6510 return;
6511 }
6512
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006513 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6514 uConvertTypes,
6515 pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006516}
6517
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006518
6519/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006520 * Public function, see header qcbor/qcbor_decode.h file
6521 */
6522void
6523QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe,
6524 const int64_t nLabel,
6525 const uint32_t uConvertTypes,
6526 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006527{
6528 QCBORItem Item;
6529
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006530 QCBORDecode_Private_GetDoubleConvertInMapN(pMe,
6531 nLabel,
6532 uConvertTypes,
6533 pdValue,
6534 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006535
6536 if(pMe->uLastError == QCBOR_SUCCESS) {
6537 // The above conversion succeeded
6538 return;
6539 }
6540
6541 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6542 // The above conversion failed in a way that code below can't correct
6543 return;
6544 }
6545
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006546 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6547 uConvertTypes,
6548 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006549}
6550
6551
6552/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006553 * Public function, see header qcbor/qcbor_decode.h file
6554 */
6555void
6556QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe,
6557 const char *szLabel,
6558 const uint32_t uConvertTypes,
6559 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006560{
6561 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006562 QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe,
6563 szLabel,
6564 uConvertTypes,
6565 pdValue,
6566 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006567
6568 if(pMe->uLastError == QCBOR_SUCCESS) {
6569 // The above conversion succeeded
6570 return;
6571 }
6572
6573 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6574 // The above conversion failed in a way that code below can't correct
6575 return;
6576 }
6577
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006578 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6579 uConvertTypes,
6580 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006581}
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006582#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006583
6584
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006585
6586
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006587#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006588/**
6589 * @brief Convert an integer to a big number
6590 *
6591 * @param[in] uInt The integer to convert.
6592 * @param[in] Buffer The buffer to output the big number to.
6593 *
6594 * @returns The big number or NULLUsefulBufC is the buffer is to small.
6595 *
6596 * This always succeeds unless the buffer is too small.
6597 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006598static UsefulBufC
6599QCBOR_Private_ConvertIntToBigNum(uint64_t uInt, const UsefulBuf Buffer)
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006600{
6601 while((uInt & 0xff00000000000000UL) == 0) {
6602 uInt = uInt << 8;
6603 };
6604
6605 UsefulOutBuf UOB;
6606
6607 UsefulOutBuf_Init(&UOB, Buffer);
6608
6609 while(uInt) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006610 UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff00000000000000UL) >> 56));
6611 uInt = uInt << 8;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006612 }
6613
6614 return UsefulOutBuf_OutUBuf(&UOB);
6615}
6616
6617
Laurence Lundblade37286c02022-09-03 10:05:02 -07006618/**
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006619 * @brief Check and/or complete exponent and mantissa item.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006620 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006621 * @param[in] pMe The decoder context.
6622 * @param[in] TagSpec Expected type(s).
6623 * @param[in,out] pItem See below.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006624 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006625 * This is for decimal fractions and big floats, both of which are an
6626 * exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006627 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006628 * If the item item had a tag number indicating it was a
6629 * decimal fraction or big float, then the input @c pItem will
6630 * have been decoded as exponent and mantissa. If there was
6631 * no tag number, the caller is asking this be decoded as a
6632 * big float or decimal fraction and @c pItem just has the
6633 * first item in an exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006634 *
6635 * On output, the item is always a fully decoded decimal fraction or
6636 * big float.
6637 *
6638 * This errors out if the input type does not meet the TagSpec.
6639 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07006640static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006641QCBOR_Private_ExpMantissaTypeHandler(QCBORDecodeContext *pMe,
6642 const QCBOR_Private_TagSpec TagSpec,
6643 QCBORItem *pItem)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006644{
6645 QCBORError uErr;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006646
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006647 /* pItem could either be a decoded exponent and mantissa or
6648 * the opening array of an undecoded exponent and mantissa. This
Laurence Lundblade37286c02022-09-03 10:05:02 -07006649 * check will succeed on either, but doesn't say which it was.
6650 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006651 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07006652 if(uErr != QCBOR_SUCCESS) {
6653 goto Done;
6654 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006655
Laurence Lundblade37286c02022-09-03 10:05:02 -07006656 if(pItem->uDataType == QCBOR_TYPE_ARRAY) {
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006657 /* The item is an array, which means is is an undecoded exponent
6658 * and mantissa. This call consumes the items in the array and
6659 * results in a decoded exponent and mantissa in pItem. This is
Laurence Lundblade37286c02022-09-03 10:05:02 -07006660 * the case where there was no tag.
6661 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006662 uErr = QCBORDecode_Private_ExpMantissa(pMe, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006663 if(uErr != QCBOR_SUCCESS) {
6664 goto Done;
6665 }
6666
Laurence Lundblade37286c02022-09-03 10:05:02 -07006667 /* The above decode didn't determine whether it is a decimal
6668 * fraction or big num. Which of these two depends on what the
6669 * caller wants it decoded as since there is no tag, so fish the
6670 * type out of the TagSpec. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006671 pItem->uDataType = QCBOR_Private_ExpMantissaDataType(TagSpec.uTaggedTypes[0], pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07006672
6673 /* No need to check the type again. All that we need to know was
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006674 * that it decoded correctly as a exponent and mantissa. The
Laurence Lundblade37286c02022-09-03 10:05:02 -07006675 * QCBOR type is set out by what was requested.
6676 */
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006677 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07006678
6679 /* If the item was not an array and the check passed, then
6680 * it is a fully decoded big float or decimal fraction and
6681 * matches what is requested.
6682 */
6683
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006684Done:
6685 return uErr;
6686}
6687
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006688
Laurence Lundblade37286c02022-09-03 10:05:02 -07006689/* Some notes from the work to disable tags.
6690 *
6691 * The API for big floats and decimal fractions seems good.
6692 * If there's any issue with it it's that the code size to
6693 * implement is a bit large because of the conversion
6694 * to/from int and bignum that is required. There is no API
6695 * that doesn't do the conversion so dead stripping will never
6696 * leave that code out.
6697 *
6698 * The implementation itself seems correct, but not as clean
6699 * and neat as it could be. It could probably be smaller too.
6700 *
6701 * The implementation has three main parts / functions
6702 * - The decoding of the array of two
6703 * - All the tag and type checking for the various API functions
6704 * - Conversion to/from bignum and int
6705 *
6706 * The type checking seems like it wastes the most code for
6707 * what it needs to do.
6708 *
6709 * The inlining for the conversion is probably making the
6710 * overall code base larger.
6711 *
6712 * The tests cases could be organized a lot better and be
6713 * more thorough.
6714 *
6715 * Seems also like there could be more common code in the
6716 * first tier part of the public API. Some functions only
6717 * vary by a TagSpec.
6718 */
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006719
6720/**
6721 * @brief Common processor for exponent and mantissa.
6722 *
6723 * @param[in] pMe The decode context.
6724 * @param[in] TagSpec The expected/allowed tags.
6725 * @param[in] pItem The data item to process.
6726 * @param[out] pnMantissa The returned mantissa as an int64_t.
6727 * @param[out] pnExponent The returned exponent as an int64_t.
6728 *
6729 * This handles exponent and mantissa for base 2 and 10. This
6730 * is limited to a mantissa that is an int64_t. See also
6731 * QCBORDecode_Private_ProcessExpMantissaBig().
6732 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006733static void
6734QCBOR_Private_ProcessExpMantissa(QCBORDecodeContext *pMe,
6735 const QCBOR_Private_TagSpec TagSpec,
6736 QCBORItem *pItem,
6737 int64_t *pnMantissa,
6738 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006739{
6740 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006741
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006742 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006743 if(uErr != QCBOR_SUCCESS) {
6744 goto Done;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006745 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006746
Laurence Lundblade9b334962020-08-27 10:55:53 -07006747 switch (pItem->uDataType) {
6748
6749 case QCBOR_TYPE_DECIMAL_FRACTION:
6750 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade9b334962020-08-27 10:55:53 -07006751 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006752 *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
Laurence Lundblade9b334962020-08-27 10:55:53 -07006753 break;
6754
Laurence Lundblade37286c02022-09-03 10:05:02 -07006755#ifndef QCBOR_DISABLE_TAGS
6756 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006757 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
6758 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
6759 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006760 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006761 break;
6762
6763 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
6764 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
6765 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006766 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006767 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006768#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006769
6770 default:
6771 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
6772 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006773
6774 Done:
6775 pMe->uLastError = (uint8_t)uErr;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006776}
6777
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006778
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006779/**
6780 * @brief Decode exponent and mantissa into a big number.
6781 *
6782 * @param[in] pMe The decode context.
6783 * @param[in] TagSpec The expected/allowed tags.
6784 * @param[in] pItem Item to decode and convert.
6785 * @param[in] BufferForMantissa Buffer to output mantissa into.
6786 * @param[out] pMantissa The output mantissa.
6787 * @param[out] pbIsNegative The sign of the output.
6788 * @param[out] pnExponent The mantissa of the output.
6789 *
6790 * This is the common processing of a decimal fraction or a big float
6791 * into a big number. This will decode and consume all the CBOR items
6792 * that make up the decimal fraction or big float.
6793 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006794static void
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006795QCBORDecode_Private_ProcessExpMantissaBig(QCBORDecodeContext *pMe,
6796 const QCBOR_Private_TagSpec TagSpec,
6797 QCBORItem *pItem,
6798 const UsefulBuf BufferForMantissa,
6799 UsefulBufC *pMantissa,
6800 bool *pbIsNegative,
6801 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006802{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006803 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006804
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006805 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006806 if(uErr != QCBOR_SUCCESS) {
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006807 goto Done;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006808 }
6809
6810 uint64_t uMantissa;
6811
6812 switch (pItem->uDataType) {
6813
6814 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006815 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006816 /* See comments in ExponentiateNN() on handling INT64_MIN */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006817 if(pItem->val.expAndMantissa.Mantissa.nInt >= 0) {
6818 uMantissa = (uint64_t)pItem->val.expAndMantissa.Mantissa.nInt;
6819 *pbIsNegative = false;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006820 } else if(pItem->val.expAndMantissa.Mantissa.nInt != INT64_MIN) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006821 uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt;
6822 *pbIsNegative = true;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006823 } else {
6824 uMantissa = (uint64_t)INT64_MAX+1;
6825 *pbIsNegative = true;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006826 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006827 *pMantissa = QCBOR_Private_ConvertIntToBigNum(uMantissa,
6828 BufferForMantissa);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006829 *pnExponent = pItem->val.expAndMantissa.nExponent;
6830 break;
6831
Laurence Lundblade37286c02022-09-03 10:05:02 -07006832#ifndef QCBOR_DISABLE_TAGS
6833 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006834 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006835 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006836 *pnExponent = pItem->val.expAndMantissa.nExponent;
6837 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6838 *pbIsNegative = false;
6839 break;
6840
6841 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006842 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006843 *pnExponent = pItem->val.expAndMantissa.nExponent;
6844 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6845 *pbIsNegative = true;
6846 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006847#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006848
6849 default:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006850 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006851 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006852
6853Done:
6854 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006855}
6856
6857
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006858/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006859 * Public function, see header qcbor/qcbor_decode.h file
6860 */
6861void
6862QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe,
6863 const uint8_t uTagRequirement,
6864 int64_t *pnMantissa,
6865 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006866{
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006867 if(pMe->uLastError != QCBOR_SUCCESS) {
6868 return;
6869 }
6870
6871 QCBORItem Item;
6872 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
6873 if(uError) {
6874 pMe->uLastError = (uint8_t)uError;
6875 return;
6876 }
6877
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006878 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006879 {
6880 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006881 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6882 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6883 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006884 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006885
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006886 QCBOR_Private_ProcessExpMantissa(pMe,
6887 TagSpec,
6888 &Item,
6889 pnMantissa,
6890 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006891}
6892
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006893
6894/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006895 * Public function, see header qcbor/qcbor_decode.h file
6896 */
6897void
6898QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe,
6899 const int64_t nLabel,
6900 const uint8_t uTagRequirement,
6901 int64_t *pnMantissa,
6902 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006903{
6904 if(pMe->uLastError != QCBOR_SUCCESS) {
6905 return;
6906 }
6907
6908 QCBORItem Item;
6909 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
6910
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006911 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006912 {
6913 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006914 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6915 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6916 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006917 };
6918
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006919 QCBOR_Private_ProcessExpMantissa(pMe,
6920 TagSpec,
6921 &Item,
6922 pnMantissa,
6923 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006924}
6925
6926
6927/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006928 * Public function, see header qcbor/qcbor_decode.h file
6929 */
6930void
6931QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
6932 const char *szLabel,
6933 const uint8_t uTagRequirement,
6934 int64_t *pnMantissa,
6935 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006936{
6937 if(pMe->uLastError != QCBOR_SUCCESS) {
6938 return;
6939 }
6940
6941 QCBORItem Item;
6942 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
6943
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006944 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006945 {
6946 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006947 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6948 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6949 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006950 };
Laurence Lundblade9b334962020-08-27 10:55:53 -07006951
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006952 QCBOR_Private_ProcessExpMantissa(pMe,
6953 TagSpec,
6954 &Item,
6955 pnMantissa,
6956 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006957}
6958
6959
6960/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006961 * Public function, see header qcbor/qcbor_decode.h file
6962 */
6963void
6964QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe,
6965 const uint8_t uTagRequirement,
6966 const UsefulBuf MantissaBuffer,
6967 UsefulBufC *pMantissa,
6968 bool *pbMantissaIsNegative,
6969 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006970{
6971 if(pMe->uLastError != QCBOR_SUCCESS) {
6972 return;
6973 }
6974
6975 QCBORItem Item;
6976 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
6977 if(uError) {
6978 pMe->uLastError = (uint8_t)uError;
6979 return;
6980 }
6981
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006982 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006983 {
6984 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006985 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6986 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6987 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006988 };
6989
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006990 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
6991 TagSpec,
6992 &Item,
6993 MantissaBuffer,
6994 pMantissa,
6995 pbMantissaIsNegative,
6996 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006997}
6998
6999
7000/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007001 * Public function, see header qcbor/qcbor_decode.h file
7002 */
7003void
7004QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe,
7005 const int64_t nLabel,
7006 const uint8_t uTagRequirement,
7007 const UsefulBuf BufferForMantissa,
7008 UsefulBufC *pMantissa,
7009 bool *pbIsNegative,
7010 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007011{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007012 if(pMe->uLastError != QCBOR_SUCCESS) {
7013 return;
7014 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007015
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007016 QCBORItem Item;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007017 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007018 if(pMe->uLastError != QCBOR_SUCCESS) {
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 Lundblade4ae4ef92024-02-05 19:21:31 -07007030 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7031 TagSpec,
7032 &Item,
7033 BufferForMantissa,
7034 pMantissa,
7035 pbIsNegative,
7036 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007037}
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007038
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007039
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007040/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007041 * Public function, see header qcbor/qcbor_decode.h file
7042 */
7043void
7044QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe,
7045 const char *szLabel,
7046 const uint8_t uTagRequirement,
7047 const UsefulBuf BufferForMantissa,
7048 UsefulBufC *pMantissa,
7049 bool *pbIsNegative,
7050 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007051{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007052 if(pMe->uLastError != QCBOR_SUCCESS) {
7053 return;
7054 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007055
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007056 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007057 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7058 if(pMe->uLastError != QCBOR_SUCCESS) {
7059 return;
7060 }
7061
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007062 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007063 {
7064 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007065 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7066 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7067 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007068 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007069
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007070 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7071 TagSpec,
7072 &Item,
7073 BufferForMantissa,
7074 pMantissa,
7075 pbIsNegative,
7076 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007077}
7078
7079
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007080/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007081 * Public function, see header qcbor/qcbor_decode.h file
7082 */
7083void
7084QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe,
7085 const uint8_t uTagRequirement,
7086 int64_t *pnMantissa,
7087 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007088{
7089 if(pMe->uLastError != QCBOR_SUCCESS) {
7090 return;
7091 }
7092
7093 QCBORItem Item;
7094 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
7095 if(uError) {
7096 pMe->uLastError = (uint8_t)uError;
7097 return;
7098 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007099 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007100 {
7101 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007102 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7103 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7104 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007105 };
7106
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007107 QCBOR_Private_ProcessExpMantissa(pMe,
7108 TagSpec,
7109 &Item,
7110 pnMantissa,
7111 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007112}
7113
7114
7115/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007116 * Public function, see header qcbor/qcbor_decode.h file
7117 */
7118void
7119QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe,
7120 const int64_t nLabel,
7121 const uint8_t uTagRequirement,
7122 int64_t *pnMantissa,
7123 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007124{
7125 if(pMe->uLastError != QCBOR_SUCCESS) {
7126 return;
7127 }
7128
7129 QCBORItem Item;
7130 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7131 if(pMe->uLastError != QCBOR_SUCCESS) {
7132 return;
7133 }
7134
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007135 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007136 {
7137 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007138 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7139 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7140 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007141 };
7142
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007143 QCBOR_Private_ProcessExpMantissa(pMe,
7144 TagSpec,
7145 &Item,
7146 pnMantissa,
7147 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007148}
7149
7150
7151/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007152 * Public function, see header qcbor/qcbor_decode.h file
7153 */
7154void
7155QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe,
7156 const char *szLabel,
7157 const uint8_t uTagRequirement,
7158 int64_t *pnMantissa,
7159 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007160{
7161 if(pMe->uLastError != QCBOR_SUCCESS) {
7162 return;
7163 }
7164
7165 QCBORItem Item;
7166 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7167 if(pMe->uLastError != QCBOR_SUCCESS) {
7168 return;
7169 }
7170
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007171 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007172 {
7173 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007174 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7175 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7176 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007177 };
7178
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007179 QCBOR_Private_ProcessExpMantissa(pMe,
7180 TagSpec,
7181 &Item,
7182 pnMantissa,
7183 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007184}
7185
7186
7187/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007188 * Public function, see header qcbor/qcbor_decode.h file
7189 */
7190void
7191QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe,
7192 const uint8_t uTagRequirement,
7193 const UsefulBuf MantissaBuffer,
7194 UsefulBufC *pMantissa,
7195 bool *pbMantissaIsNegative,
7196 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007197{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007198 if(pMe->uLastError != QCBOR_SUCCESS) {
7199 return;
7200 }
7201
7202 QCBORItem Item;
7203 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
7204 if(uError) {
7205 pMe->uLastError = (uint8_t)uError;
7206 return;
7207 }
7208
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007209 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007210 {
7211 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007212 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7213 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7214 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007215 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007216
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007217 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7218 TagSpec,
7219 &Item,
7220 MantissaBuffer,
7221 pMantissa,
7222 pbMantissaIsNegative,
7223 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007224}
7225
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007226
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007227/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007228 * Public function, see header qcbor/qcbor_decode.h file
7229 */
7230void
7231QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe,
7232 const int64_t nLabel,
7233 const uint8_t uTagRequirement,
7234 const UsefulBuf BufferForMantissa,
7235 UsefulBufC *pMantissa,
7236 bool *pbIsNegative,
7237 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007238{
7239 if(pMe->uLastError != QCBOR_SUCCESS) {
7240 return;
7241 }
7242
7243 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007244 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7245 if(pMe->uLastError != QCBOR_SUCCESS) {
7246 return;
7247 }
7248
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007249 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007250 {
7251 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007252 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7253 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7254 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007255 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007256
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007257 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7258 TagSpec,
7259 &Item,
7260 BufferForMantissa,
7261 pMantissa,
7262 pbIsNegative,
7263 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007264}
7265
7266
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007267/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007268 * Public function, see header qcbor/qcbor_decode.h file
7269 */
7270void
7271QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe,
7272 const char *szLabel,
7273 const uint8_t uTagRequirement,
7274 const UsefulBuf BufferForMantissa,
7275 UsefulBufC *pMantissa,
7276 bool *pbIsNegative,
7277 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007278{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007279 if(pMe->uLastError != QCBOR_SUCCESS) {
7280 return;
7281 }
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007282
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007283 QCBORItem Item;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007284 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7285 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007286 return;
7287 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007288
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007289 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007290 {
7291 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007292 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7293 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7294 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007295 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007296
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007297 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7298 TagSpec,
7299 &Item,
7300 BufferForMantissa,
7301 pMantissa,
7302 pbIsNegative,
7303 pnExponent);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007304}
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007305
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07007306#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */