blob: 49af24a55e38d7bdc71f2fcfbdc7f7d3f4d84c2c [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 ||
110#endif
111 uDataType == QCBOR_TYPE_ARRAY;
Laurence Lundblade02625d42020-06-25 14:41:41 -0700112}
113
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700114static bool
115QCBORItem_IsEmptyDefiniteLengthMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700116{
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700117 if(!QCBORItem_IsMapOrArray(Item)){
Laurence Lundblade02625d42020-06-25 14:41:41 -0700118 return false;
119 }
120
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700121 if(Item.val.uCount != 0) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700122 return false;
123 }
124 return true;
125}
126
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700127static bool
128QCBORItem_IsIndefiniteLengthMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700129{
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800130#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700131 if(!QCBORItem_IsMapOrArray(Item)){
Laurence Lundblade02625d42020-06-25 14:41:41 -0700132 return false;
133 }
134
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700135 if(Item.val.uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700136 return false;
137 }
138 return true;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800139#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700140 (void)Item;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800141 return false;
142#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700143}
144
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700145/* Return true if the labels in Item1 and Item2 are the same.
146 Works only for integer and string labels. Returns false
147 for any other type. */
148static bool
149QCBORItem_MatchLabel(const QCBORItem Item1, const QCBORItem Item2)
150{
151 if(Item1.uLabelType == QCBOR_TYPE_INT64) {
152 if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
153 return true;
154 }
155 } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
156 if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
157 return true;
158 }
159 } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
160 if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
161 return true;
162 }
163 } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
164 if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
165 return true;
166 }
167 }
168
169 /* Other label types are never matched */
170 return false;
171}
172
173
174/*
175 Returns true if Item1 and Item2 are the same type
176 or if either are of QCBOR_TYPE_ANY.
177 */
178static bool
179QCBORItem_MatchType(const QCBORItem Item1, const QCBORItem Item2)
180{
181 if(Item1.uDataType == Item2.uDataType) {
182 return true;
183 } else if(Item1.uDataType == QCBOR_TYPE_ANY) {
184 return true;
185 } else if(Item2.uDataType == QCBOR_TYPE_ANY) {
186 return true;
187 }
188 return false;
189}
190
Laurence Lundblade02625d42020-06-25 14:41:41 -0700191
Laurence Lundbladeee851742020-01-08 08:37:05 -0800192/*===========================================================================
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700193 DecodeNesting -- Tracking array/map/sequence/bstr-wrapped nesting
Laurence Lundbladeee851742020-01-08 08:37:05 -0800194 ===========================================================================*/
195
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700196/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800197 * See comments about and typedef of QCBORDecodeNesting in qcbor_private.h,
198 * the data structure all these functions work on.
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700199 */
200
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700201
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700202static uint8_t
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700203DecodeNesting_GetCurrentLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700204{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700205 const ptrdiff_t nLevel = pNesting->pCurrent - &(pNesting->pLevels[0]);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800206 /* Limit in DecodeNesting_Descend against more than
207 * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
Laurence Lundblade02625d42020-06-25 14:41:41 -0700208 */
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700209 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700210}
211
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700212
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700213static uint8_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700214DecodeNesting_GetBoundedModeLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700215{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700216 const ptrdiff_t nLevel = pNesting->pCurrentBounded - &(pNesting->pLevels[0]);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800217 /* Limit in DecodeNesting_Descend against more than
218 * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
Laurence Lundblade02625d42020-06-25 14:41:41 -0700219 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700220 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700221}
222
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700223
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700224static uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700225DecodeNesting_GetMapOrArrayStart(const QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700226{
227 return pNesting->pCurrentBounded->u.ma.uStartOffset;
228}
229
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700230
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700231static bool
Laurence Lundblade085d7952020-07-24 10:26:30 -0700232DecodeNesting_IsBoundedEmpty(const QCBORDecodeNesting *pNesting)
233{
234 if(pNesting->pCurrentBounded->u.ma.uCountCursor == QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
235 return true;
236 } else {
237 return false;
238 }
239}
240
241
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700242static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700243DecodeNesting_IsCurrentAtTop(const QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700244{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700245 if(pNesting->pCurrent == &(pNesting->pLevels[0])) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700246 return true;
247 } else {
248 return false;
249 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700250}
251
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700252
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700253static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700254DecodeNesting_IsCurrentDefiniteLength(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700255{
256 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800257 /* Not a map or array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700258 return false;
259 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800260
261#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700262 if(pNesting->pCurrent->u.ma.uCountTotal == QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800263 /* Is indefinite */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700264 return false;
265 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800266
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800267#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
268
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800269 /* All checks passed; is a definte length map or array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700270 return true;
271}
272
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700273static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700274DecodeNesting_IsCurrentBstrWrapped(const QCBORDecodeNesting *pNesting)
Laurence Lundblade642282a2020-06-23 12:00:33 -0700275{
276 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800277 /* is a byte string */
Laurence Lundblade642282a2020-06-23 12:00:33 -0700278 return true;
279 }
280 return false;
281}
282
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700283
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700284static bool
285DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700286{
287 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
288 return true;
289 }
Laurence Lundblade02625d42020-06-25 14:41:41 -0700290 if(pNesting->pCurrent->u.ma.uStartOffset != QCBOR_NON_BOUNDED_OFFSET) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700291 return true;
292 }
293 return false;
294}
295
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700296
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700297static void
298DecodeNesting_SetMapOrArrayBoundedMode(QCBORDecodeNesting *pNesting, bool bIsEmpty, size_t uStart)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700299{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800300 /* Should be only called on maps and arrays */
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700301 /*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800302 * DecodeNesting_EnterBoundedMode() checks to be sure uStart is not
303 * larger than DecodeNesting_EnterBoundedMode which keeps it less than
304 * uin32_t so the cast is safe.
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700305 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700306 pNesting->pCurrent->u.ma.uStartOffset = (uint32_t)uStart;
Laurence Lundblade085d7952020-07-24 10:26:30 -0700307
308 if(bIsEmpty) {
309 pNesting->pCurrent->u.ma.uCountCursor = QCBOR_COUNT_INDICATES_ZERO_LENGTH;
310 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700311}
312
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700313
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700314static void
315DecodeNesting_ClearBoundedMode(QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700316{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700317 pNesting->pCurrent->u.ma.uStartOffset = QCBOR_NON_BOUNDED_OFFSET;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700318}
319
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700320
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700321static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700322DecodeNesting_IsAtEndOfBoundedLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700323{
324 if(pNesting->pCurrentBounded == NULL) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800325 /* No bounded map or array set up */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700326 return false;
327 }
328 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800329 /* Not a map or array; end of those is by byte count */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700330 return false;
331 }
Laurence Lundblade6ab01fb2020-10-01 13:04:49 -0700332 if(!DecodeNesting_IsCurrentBounded(pNesting)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800333 /* In a traveral at a level deeper than the bounded level */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700334 return false;
335 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800336 /* Works for both definite- and indefinitelength maps/arrays */
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800337 if(pNesting->pCurrentBounded->u.ma.uCountCursor != 0 &&
338 pNesting->pCurrentBounded->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800339 /* Count is not zero, still unconsumed item */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700340 return false;
341 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800342 /* All checks passed, got to the end of an array or map*/
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700343 return true;
344}
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700345
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700346
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700347static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700348DecodeNesting_IsEndOfDefiniteLengthMapOrArray(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700349{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800350 /* Must only be called on map / array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700351 if(pNesting->pCurrent->u.ma.uCountCursor == 0) {
352 return true;
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700353 } else {
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700354 return false;
355 }
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700356}
357
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700358
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700359static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700360DecodeNesting_IsCurrentTypeMap(const QCBORDecodeNesting *pNesting)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700361{
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700362 if(pNesting->pCurrent->uLevelType == CBOR_MAJOR_TYPE_MAP) {
363 return true;
364 } else {
365 return false;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700366 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700367}
368
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700369
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700370static bool
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700371DecodeNesting_IsBoundedType(const QCBORDecodeNesting *pNesting, uint8_t uType)
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700372{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700373 if(pNesting->pCurrentBounded == NULL) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700374 return false;
375 }
Laurence Lundblade02625d42020-06-25 14:41:41 -0700376
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700377 uint8_t uItemDataType = pNesting->pCurrentBounded->uLevelType;
Laurence Lundblade62cae932024-06-03 13:16:17 -0700378#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700379 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
380 uItemDataType = QCBOR_TYPE_ARRAY;
381 }
Laurence Lundblade62cae932024-06-03 13:16:17 -0700382#endif
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700383
384 if(uItemDataType != uType) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700385 return false;
386 }
387
388 return true;
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700389}
390
Laurence Lundblade02625d42020-06-25 14:41:41 -0700391
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700392static void
Laurence Lundblade6c8a4442020-06-22 22:16:11 -0700393DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700394{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800395 /* Only call on a definite-length array / map */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700396 pNesting->pCurrent->u.ma.uCountCursor--;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700397}
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700398
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700399
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700400static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700401DecodeNesting_ReverseDecrement(QCBORDecodeNesting *pNesting)
402{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800403 /* Only call on a definite-length array / map */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700404 pNesting->pCurrent->u.ma.uCountCursor++;
405}
406
407
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700408static void
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700409DecodeNesting_Ascend(QCBORDecodeNesting *pNesting)
410{
411 pNesting->pCurrent--;
412}
413
Laurence Lundblade02625d42020-06-25 14:41:41 -0700414
415static QCBORError
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700416DecodeNesting_Descend(QCBORDecodeNesting *pNesting, uint8_t uType)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700417{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800418 /* Error out if nesting is too deep */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700419 if(pNesting->pCurrent >= &(pNesting->pLevels[QCBOR_MAX_ARRAY_NESTING])) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700420 return QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP;
Laurence Lundblade02625d42020-06-25 14:41:41 -0700421 }
422
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800423 /* The actual descend */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700424 pNesting->pCurrent++;
425
426 pNesting->pCurrent->uLevelType = uType;
427
428 return QCBOR_SUCCESS;
429}
430
431
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700432static QCBORError
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800433DecodeNesting_EnterBoundedMapOrArray(QCBORDecodeNesting *pNesting,
434 bool bIsEmpty,
435 size_t uOffset)
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700436{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700437 /*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800438 * Should only be called on map/array.
439 *
440 * Have descended into this before this is called. The job here is
441 * just to mark it in bounded mode.
442 *
443 * Check against QCBOR_MAX_DECODE_INPUT_SIZE make sure that
444 * uOffset doesn't collide with QCBOR_NON_BOUNDED_OFFSET.
445 *
446 * Cast of uOffset to uint32_t for cases where SIZE_MAX < UINT32_MAX.
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700447 */
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -0800448 if((uint32_t)uOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700449 return QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700450 }
451
Laurence Lundblade0750fc42020-06-20 21:02:34 -0700452 pNesting->pCurrentBounded = pNesting->pCurrent;
Laurence Lundblade085d7952020-07-24 10:26:30 -0700453
454 DecodeNesting_SetMapOrArrayBoundedMode(pNesting, bIsEmpty, uOffset);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700455
456 return QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700457}
458
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700459
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700460static QCBORError
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700461DecodeNesting_DescendMapOrArray(QCBORDecodeNesting *pNesting,
Laurence Lundblade02625d42020-06-25 14:41:41 -0700462 uint8_t uQCBORType,
463 uint64_t uCount)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700464{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700465 QCBORError uError = QCBOR_SUCCESS;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700466
467 if(uCount == 0) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800468 /* Nothing to do for empty definite-length arrays. They are just are
469 * effectively the same as an item that is not a map or array.
470 */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700471 goto Done;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800472 /* Empty indefinite-length maps and arrays are handled elsewhere */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700473 }
474
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800475 /* Error out if arrays is too long to handle */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700476 if(uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH &&
477 uCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700478 uError = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700479 goto Done;
480 }
481
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700482 uError = DecodeNesting_Descend(pNesting, uQCBORType);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700483 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700484 goto Done;
485 }
486
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800487 /* Fill in the new map/array level. Check above makes casts OK. */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -0700488 pNesting->pCurrent->u.ma.uCountCursor = (uint16_t)uCount;
489 pNesting->pCurrent->u.ma.uCountTotal = (uint16_t)uCount;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700490
491 DecodeNesting_ClearBoundedMode(pNesting);
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700492
493Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700494 return uError;;
495}
496
497
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700498static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700499DecodeNesting_LevelUpCurrent(QCBORDecodeNesting *pNesting)
500{
501 pNesting->pCurrent = pNesting->pCurrentBounded - 1;
502}
503
504
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700505static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700506DecodeNesting_LevelUpBounded(QCBORDecodeNesting *pNesting)
507{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700508 while(pNesting->pCurrentBounded != &(pNesting->pLevels[0])) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700509 pNesting->pCurrentBounded--;
510 if(DecodeNesting_IsCurrentBounded(pNesting)) {
511 break;
512 }
513 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700514}
515
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800516
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700517static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700518DecodeNesting_SetCurrentToBoundedLevel(QCBORDecodeNesting *pNesting)
519{
520 pNesting->pCurrent = pNesting->pCurrentBounded;
521}
522
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700523
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700524static QCBORError
Laurence Lundblade02625d42020-06-25 14:41:41 -0700525DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting,
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700526 uint32_t uEndOffset,
527 uint32_t uStartOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700528{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700529 QCBORError uError;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700530
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700531 uError = DecodeNesting_Descend(pNesting, QCBOR_TYPE_BYTE_STRING);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700532 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700533 goto Done;
534 }
535
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800536 /* Fill in the new byte string level */
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700537 pNesting->pCurrent->u.bs.uSavedEndOffset = uEndOffset;
538 pNesting->pCurrent->u.bs.uBstrStartOffset = uStartOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700539
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800540 /* Bstr wrapped levels are always bounded */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700541 pNesting->pCurrentBounded = pNesting->pCurrent;
542
543Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700544 return uError;;
545}
546
Laurence Lundbladed0304932020-06-27 10:59:38 -0700547
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700548static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700549DecodeNesting_ZeroMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700550{
551 pNesting->pCurrent->u.ma.uCountCursor = 0;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700552}
553
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700554
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700555static void
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800556DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting)
557{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700558 if(pNesting->pCurrent->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
559 pNesting->pCurrentBounded->u.ma.uCountCursor = pNesting->pCurrentBounded->u.ma.uCountTotal;
560 }
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800561}
562
563
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700564static void
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700565DecodeNesting_Init(QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700566{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700567 /* Assumes that *pNesting has been zero'd before this call. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700568 pNesting->pLevels[0].uLevelType = QCBOR_TYPE_BYTE_STRING;
569 pNesting->pCurrent = &(pNesting->pLevels[0]);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700570}
571
572
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700573static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800574DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting,
575 QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700576{
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700577 *pSave = *pNesting;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700578}
579
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700580
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700581static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800582DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting,
583 const QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700584{
585 *pNesting = *pSave;
586}
587
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700588
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700589static uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700590DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700591{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700592 return pMe->pCurrentBounded->u.bs.uSavedEndOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700593}
594
595
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800596
597
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800598#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladeee851742020-01-08 08:37:05 -0800599/*===========================================================================
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800600 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
601
602 The following four functions are pretty wrappers for invocation of
603 the string allocator supplied by the caller.
604
Laurence Lundbladeee851742020-01-08 08:37:05 -0800605 ===========================================================================*/
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800606
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700607static void
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800608StringAllocator_Free(const QCBORInternalAllocator *pMe, const void *pMem)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800609{
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300610 /* This cast to uintptr_t suppresses the "-Wcast-qual" warnings.
611 * This is the one place where the const needs to be cast away so const can
612 * be use in the rest of the code.
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800613 */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300614 (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, 0);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800615}
616
Laurence Lundbladeee851742020-01-08 08:37:05 -0800617// StringAllocator_Reallocate called with pMem NULL is
618// equal to StringAllocator_Allocate()
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700619static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800620StringAllocator_Reallocate(const QCBORInternalAllocator *pMe,
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800621 const void *pMem,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800622 size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800623{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800624 /* See comment in StringAllocator_Free() */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300625 return (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, uSize);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800626}
627
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700628static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800629StringAllocator_Allocate(const QCBORInternalAllocator *pMe, size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800630{
631 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
632}
633
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700634static void
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800635StringAllocator_Destruct(const QCBORInternalAllocator *pMe)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800636{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800637 /* See comment in StringAllocator_Free() */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800638 if(pMe->pfAllocator) {
639 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
640 }
641}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800642#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800643
644
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800645
646
Laurence Lundbladeee851742020-01-08 08:37:05 -0800647/*===========================================================================
648 QCBORDecode -- The main implementation of CBOR decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700649
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800650 See qcbor/qcbor_decode.h for definition of the object
651 used here: QCBORDecodeContext
Laurence Lundbladeee851742020-01-08 08:37:05 -0800652 ===========================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700653/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800654 * Public function, see header file
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700655 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700656void
657QCBORDecode_Init(QCBORDecodeContext *pMe,
658 UsefulBufC EncodedCBOR,
659 QCBORDecodeMode nDecodeMode)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700660{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800661 memset(pMe, 0, sizeof(QCBORDecodeContext));
662 UsefulInputBuf_Init(&(pMe->InBuf), EncodedCBOR);
663 /* Don't bother with error check on decode mode. If a bad value is
664 * passed it will just act as if the default normal mode of 0 was set.
665 */
666 pMe->uDecodeMode = (uint8_t)nDecodeMode;
667 DecodeNesting_Init(&(pMe->nesting));
668
669 /* Inialize me->auMappedTags to CBOR_TAG_INVALID16. See
670 * GetNext_TaggedItem() and MapTagNumber(). */
671 memset(pMe->auMappedTags, 0xff, sizeof(pMe->auMappedTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700672}
673
674
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800675#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
676
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700677/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800678 * Public function, see header file
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700679 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700680void
681QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
682 QCBORStringAllocate pfAllocateFunction,
683 void *pAllocateContext,
684 bool bAllStrings)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700685{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800686 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
687 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
688 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700689}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800690#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700691
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800692
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800693
694
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800695/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800696 * Deprecated public function, see header file
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800697 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700698void
699QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pMe,
700 const QCBORTagListIn *pTagList)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700701{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800702 /* This does nothing now. It is retained for backwards compatibility */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700703 (void)pMe;
704 (void)pTagList;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700705}
706
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700707
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800708
709
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700710/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800711 * Decoding items is done in six layers, one calling the next one
712 * down. If a layer has no work to do for a particular item, it
713 * returns quickly.
714 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700715 * 1. QCBORDecode_Private_GetNextTagContent - The top layer processes
716 * tagged data items, turning them into the local C representation.
717 * For the most simple it is just associating a QCBOR_TYPE with the
718 * data. For the complex ones that an aggregate of data items, there
719 * is some further decoding and some limited recursion.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800720 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700721 * 2. QCBORDecode_Private_GetNextMapOrArray - This manages the
722 * beginnings and ends of maps and arrays. It tracks descending into
723 * and ascending out of maps/arrays. It processes breaks that
724 * terminate indefinite-length maps and arrays.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800725 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700726 * 3. QCBORDecode_Private_GetNextMapEntry - This handles the combining
727 * of two items, the label and the data, that make up a map entry. It
728 * only does work on maps. It combines the label and data items into
729 * one labeled item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800730 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700731 * 4. QCBORDecode_Private_GetNextTagNumber - This decodes type 6 tag
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800732 * numbers. It turns the tag numbers into bit flags associated with
733 * the data item. No actual decoding of the contents of the tag is
734 * performed here.
735 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700736 * 5. QCBORDecode_Private_GetNextFullString - This assembles the
737 * sub-items that make up an indefinite-length string into one string
738 * item. It uses the string allocator to create contiguous space for
739 * the item. It processes all breaks that are part of
740 * indefinite-length strings.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800741 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700742 * 6. QCBOR_Private_DecodeAtomicDataItem - This decodes the atomic
743 * data items in CBOR. Each atomic data item has a "major type", an
744 * integer "argument" and optionally some content. For text and byte
745 * strings, the content is the bytes that make up the string. These
746 * are the smallest data items that are considered to be well-formed.
747 * The content may also be other data items in the case of aggregate
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800748 * types. They are not handled in this layer.
749 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700750 * This uses about 350 bytes of stack. This number comes from
751 * instrumenting (printf address of stack variables) the code on x86
752 * compiled for size optimization.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700753 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800754
755
756/*
757 * Note about use of int and unsigned variables.
758 *
759 * See http://www.unix.org/whitepapers/64bit.html for reasons int is
760 * used carefully here, and in particular why it isn't used in the
761 * public interface. Also see
762 * https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers
763 *
764 * Int is used for values that need less than 16-bits and would be
765 * subject to integer promotion and result in complaining from static
766 * analyzers.
767 */
768
769
770/**
771 * @brief Decode the CBOR head, the type and argument.
772 *
773 * @param[in] pUInBuf The input buffer to read from.
774 * @param[out] pnMajorType The decoded major type.
775 * @param[out] puArgument The decoded argument.
776 * @param[out] pnAdditionalInfo The decoded Lower 5 bits of initial byte.
777 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -0700778 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved features
779 * @retval QCBOR_ERR_HIT_END Unexpected end of input
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800780 *
781 * This decodes the CBOR "head" that every CBOR data item has. See
782 * longer explaination of the head in documentation for
783 * QCBOREncode_EncodeHead().
784 *
785 * This does the network->host byte order conversion. The conversion
786 * here also results in the conversion for floats in addition to that
787 * for lengths, tags and integer values.
788 *
789 * The int type is preferred to uint8_t for some variables as this
790 * avoids integer promotions, can reduce code size and makes static
791 * analyzers happier.
792 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700793static QCBORError
794QCBOR_Private_DecodeHead(UsefulInputBuf *pUInBuf,
795 int *pnMajorType,
796 uint64_t *puArgument,
797 int *pnAdditionalInfo)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700798{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800799 QCBORError uReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800800
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800801 /* Get the initial byte that every CBOR data item has and break it
802 * down. */
803 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800804 const int nTmpMajorType = nInitialByte >> 5;
805 const int nAdditionalInfo = nInitialByte & 0x1f;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800806
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800807 /* Where the argument accumulates */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800808 uint64_t uArgument;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800809
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800810 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800811 /* Need to get 1,2,4 or 8 additional argument bytes. Map
812 * LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length.
813 */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800814 static const uint8_t aIterate[] = {1,2,4,8};
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800815
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800816 /* Loop getting all the bytes in the argument */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800817 uArgument = 0;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800818 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800819 /* This shift and add gives the endian conversion. */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800820 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
821 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800822 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800823 /* The reserved and thus-far unused additional info values */
824 uReturn = QCBOR_ERR_UNSUPPORTED;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800825 goto Done;
826 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800827 /* Less than 24, additional info is argument or 31, an
828 * indefinite-length. No more bytes to get.
829 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800830 uArgument = (uint64_t)nAdditionalInfo;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700831 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800832
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700833 if(UsefulInputBuf_GetError(pUInBuf)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800834 uReturn = QCBOR_ERR_HIT_END;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700835 goto Done;
836 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800837
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800838 /* All successful if arrived here. */
839 uReturn = QCBOR_SUCCESS;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800840 *pnMajorType = nTmpMajorType;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800841 *puArgument = uArgument;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800842 *pnAdditionalInfo = nAdditionalInfo;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800843
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700844Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800845 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700846}
847
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800848
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800849/**
850 * @brief Decode integer types, major types 0 and 1.
851 *
852 * @param[in] nMajorType The CBOR major type (0 or 1).
853 * @param[in] uArgument The argument from the head.
854 * @param[out] pDecodedItem The filled in decoded item.
855 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -0700856 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800857 *
858 * Must only be called when major type is 0 or 1.
859 *
860 * CBOR doesn't explicitly specify two's compliment for integers but
861 * all CPUs use it these days and the test vectors in the RFC are
862 * so. All integers in the CBOR structure are positive and the major
863 * type indicates positive or negative. CBOR can express positive
864 * integers up to 2^x - 1 where x is the number of bits and negative
865 * integers down to 2^x. Note that negative numbers can be one more
866 * away from zero than positive. Stdint, as far as I can tell, uses
867 * two's compliment to represent negative integers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700868 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700869static QCBORError
870QCBOR_Private_DecodeInteger(const int nMajorType,
871 const uint64_t uArgument,
Laurence Lundblade62cae932024-06-03 13:16:17 -0700872 const int nAdditionalInfo,
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700873 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700874{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800875 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800876
Laurence Lundblade62cae932024-06-03 13:16:17 -0700877 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
878 uReturn = QCBOR_ERR_BAD_INT;
879 goto Done;
880 }
881
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700882 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800883 if (uArgument <= INT64_MAX) {
884 pDecodedItem->val.int64 = (int64_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700885 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800886
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700887 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800888 pDecodedItem->val.uint64 = uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700889 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700890 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800891
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700892 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800893 if(uArgument <= INT64_MAX) {
894 /* CBOR's representation of negative numbers lines up with
895 * the two-compliment representation. A negative integer has
896 * one more in range than a positive integer. INT64_MIN is
897 * equal to (-INT64_MAX) - 1.
898 */
899 pDecodedItem->val.int64 = (-(int64_t)uArgument) - 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700900 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800901
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700902 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800903 /* C can't represent a negative integer in this range so it
904 * is an error.
905 */
906 uReturn = QCBOR_ERR_INT_OVERFLOW;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700907 }
908 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800909
Laurence Lundblade62cae932024-06-03 13:16:17 -0700910Done:
911 return uReturn;
912}
913
914
915static QCBORError
916QCBOR_Private_DecodeTag(const int nAdditionalInfo,
917 const uint64_t uArgument,
918 QCBORItem *pDecodedItem)
919{
920 QCBORError uReturn;
921
922#ifndef QCBOR_DISABLE_TAGS
923 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
924 uReturn = QCBOR_ERR_BAD_INT;
925 } else {
926 pDecodedItem->val.uTagV = uArgument;
927 pDecodedItem->uDataType = QCBOR_TYPE_TAG;
928 uReturn = QCBOR_SUCCESS;
929 }
930#else /* QCBOR_DISABLE_TAGS */
Laurence Lundbladecfd8a2c2024-06-06 21:01:42 -0700931 (void)nAdditionalInfo;
932 (void)uArgument;
933 (void)pDecodedItem;
934 uReturn = QCBOR_ERR_TAGS_DISABLED;
Laurence Lundblade62cae932024-06-03 13:16:17 -0700935#endif /* QCBOR_DISABLE_TAGS */
936
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800937 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700938}
939
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800940
941/* Make sure #define value line up as DecodeSimple counts on this. */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700942#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
943#error QCBOR_TYPE_FALSE macro value wrong
944#endif
945
946#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
947#error QCBOR_TYPE_TRUE macro value wrong
948#endif
949
950#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
951#error QCBOR_TYPE_NULL macro value wrong
952#endif
953
954#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
955#error QCBOR_TYPE_UNDEF macro value wrong
956#endif
957
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700958#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
959#error QCBOR_TYPE_BREAK macro value wrong
960#endif
961
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700962#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
963#error QCBOR_TYPE_DOUBLE macro value wrong
964#endif
965
966#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
967#error QCBOR_TYPE_FLOAT macro value wrong
968#endif
969
Laurence Lundblade9b334962020-08-27 10:55:53 -0700970
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800971/**
972 * @brief Decode major type 7 -- true, false, floating-point, break...
973 *
974 * @param[in] nAdditionalInfo The lower five bits from the initial byte.
975 * @param[in] uArgument The argument from the head.
976 * @param[out] pDecodedItem The filled in decoded item.
977 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -0700978 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
979 * of half-precision disabled
980 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all float
981 * decode is disabled.
982 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of simple
983 * type in input.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700984 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700985static QCBORError
986QCBOR_Private_DecodeType7(const int nAdditionalInfo,
987 const uint64_t uArgument,
988 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800989{
990 QCBORError uReturn = QCBOR_SUCCESS;
991
992 /* uAdditionalInfo is 5 bits from the initial byte. Compile time
993 * checks above make sure uAdditionalInfo values line up with
994 * uDataType values. DecodeHead() never returns an AdditionalInfo
995 * > 0x1f so cast is safe.
996 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800997 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800998
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800999 switch(nAdditionalInfo) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001000 /* No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they
1001 * are caught before this is called.
1002 */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001003
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001004 case HALF_PREC_FLOAT: /* 25 */
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -07001005#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001006 /* Half-precision is returned as a double. The cast to
1007 * uint16_t is safe because the encoded value was 16 bits. It
1008 * was widened to 64 bits to be passed in here.
1009 */
1010 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uArgument);
Laurence Lundblade67bd5512018-11-02 21:44:06 +07001011 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001012#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001013 uReturn = FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001014 break;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001015 case SINGLE_PREC_FLOAT: /* 26 */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001016#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001017 /* Single precision is normally returned as a double since
1018 * double is widely supported, there is no loss of precision,
1019 * it makes it easy for the caller in most cases and it can
1020 * be converted back to single with no loss of precision
1021 *
1022 * The cast to uint32_t is safe because the encoded value was
1023 * 32 bits. It was widened to 64 bits to be passed in here.
1024 */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001025 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001026 const float f = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uArgument);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001027#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001028 /* In the normal case, use HW to convert float to
1029 * double. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001030 pDecodedItem->val.dfnum = (double)f;
1031 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001032#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001033 /* Use of float HW is disabled, return as a float. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001034 pDecodedItem->val.fnum = f;
1035 pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
1036
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001037 /* IEEE754_FloatToDouble() could be used here to return as
1038 * a double, but it adds object code and most likely
1039 * anyone disabling FLOAT HW use doesn't care about floats
1040 * and wants to save object code.
1041 */
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001042#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001043 }
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001044#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1045 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001046 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001047
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001048 case DOUBLE_PREC_FLOAT: /* 27 */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001049#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001050 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uArgument);
Laurence Lundblade67bd5512018-11-02 21:44:06 +07001051 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001052#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1053 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001054 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001055
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001056 case CBOR_SIMPLEV_FALSE: /* 20 */
1057 case CBOR_SIMPLEV_TRUE: /* 21 */
1058 case CBOR_SIMPLEV_NULL: /* 22 */
1059 case CBOR_SIMPLEV_UNDEF: /* 23 */
1060 case CBOR_SIMPLE_BREAK: /* 31 */
1061 break; /* nothing to do */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001062
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001063 case CBOR_SIMPLEV_ONEBYTE: /* 24 */
1064 if(uArgument <= CBOR_SIMPLE_BREAK) {
1065 /* This takes out f8 00 ... f8 1f which should be encoded
1066 * as e0 … f7
1067 */
1068 uReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001069 goto Done;
1070 }
Laurence Lundblade5e390822019-01-06 12:35:01 -08001071 /* FALLTHROUGH */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001072
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001073 default: /* 0-19 */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001074 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001075 /* DecodeHead() will make uArgument equal to
1076 * nAdditionalInfo when nAdditionalInfo is < 24. This cast is
1077 * safe because the 2, 4 and 8 byte lengths of uNumber are in
1078 * the double/float cases above
Laurence Lundbladeee851742020-01-08 08:37:05 -08001079 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001080 pDecodedItem->val.uSimple = (uint8_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001081 break;
1082 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001083
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001084Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001085 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001086}
1087
1088
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001089/**
1090 * @brief Decode text and byte strings
1091 *
1092 * @param[in] pAllocator The string allocator or NULL.
1093 * @param[in] uStrLen The length of the string.
1094 * @param[in] pUInBuf The surce from which to read the string's bytes.
1095 * @param[out] pDecodedItem The filled in decoded item.
1096 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001097 * @retval QCBOR_ERR_HIT_END Unexpected end of input.
1098 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1099 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001100 *
1101 * The reads @c uStrlen bytes from @c pUInBuf and fills in @c
1102 * pDecodedItem. If @c pAllocator is not NULL then memory for the
1103 * string is allocated.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001104 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001105static QCBORError
1106QCBOR_Private_DecodeBytes(const QCBORInternalAllocator *pAllocator,
Laurence Lundblade62cae932024-06-03 13:16:17 -07001107 int nMajorType,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001108 const uint64_t uStrLen,
Laurence Lundblade62cae932024-06-03 13:16:17 -07001109 int nAdditionalInfo,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001110 UsefulInputBuf *pUInBuf,
1111 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001112{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001113 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001114
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001115 #if CBOR_MAJOR_TYPE_BYTE_STRING + 4 != QCBOR_TYPE_BYTE_STRING
1116 #error QCBOR_TYPE_BYTE_STRING no lined up with major type
1117 #endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001118
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001119 #if CBOR_MAJOR_TYPE_TEXT_STRING + 4 != QCBOR_TYPE_TEXT_STRING
1120 #error QCBOR_TYPE_TEXT_STRING no lined up with major type
1121 #endif
Laurence Lundblade62cae932024-06-03 13:16:17 -07001122 pDecodedItem->uDataType = (uint8_t)(nMajorType + 4);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001123
Laurence Lundblade62cae932024-06-03 13:16:17 -07001124
1125 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1126 pDecodedItem->val.string = (UsefulBufC){NULL, QCBOR_STRING_LENGTH_INDEFINITE};
1127
1128 } else {
1129 /* CBOR lengths can be 64 bits, but size_t is not 64 bits on all
1130 * CPUs. This check makes the casts to size_t below safe.
1131 *
1132 * The max is 4 bytes less than the largest sizeof() so this can be
1133 * tested by putting a SIZE_MAX length in the CBOR test input (no
1134 * one will care the limit on strings is 4 bytes shorter).
1135 */
1136 if(uStrLen > SIZE_MAX-4) {
1137 uReturn = QCBOR_ERR_STRING_TOO_LONG;
1138 goto Done;
1139 }
1140
1141 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, (size_t)uStrLen);
1142 if(UsefulBuf_IsNULLC(Bytes)) {
1143 /* Failed to get the bytes for this string item */
1144 uReturn = QCBOR_ERR_HIT_END;
1145 goto Done;
1146 }
1147
1148#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
1149 /* Note that this is not where allocation to coalesce
1150 * indefinite-length strings is done. This is for when the caller
1151 * has requested all strings be allocated. Disabling indefinite
1152 * length strings also disables this allocate-all option.
1153 */
1154 if(pAllocator) {
1155 /* request to use the string allocator to make a copy */
1156 UsefulBuf NewMem = StringAllocator_Allocate(pAllocator, (size_t)uStrLen);
1157 if(UsefulBuf_IsNULL(NewMem)) {
1158 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1159 goto Done;
1160 }
1161 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
1162 pDecodedItem->uDataAlloc = 1;
1163 goto Done;
1164 }
1165#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1166 (void)pAllocator;
1167#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1168
1169 /* Normal case with no string allocator */
1170 pDecodedItem->val.string = Bytes;
1171 }
1172
1173Done:
1174 return uReturn;
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001175}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001176
1177
Laurence Lundblade62cae932024-06-03 13:16:17 -07001178
1179
1180
1181static QCBORError
1182QCBOR_Private_DecodeArrayOrMap(const uint8_t uMode,
1183 const int nMajorType,
1184 const uint64_t uItemCount,
1185 const int nAdditionalInfo,
1186 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001187{
Laurence Lundblade62cae932024-06-03 13:16:17 -07001188 QCBORError uReturn;
1189
1190 /* ------ Sort out the data type ------ */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001191 #if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
1192 #error QCBOR_TYPE_ARRAY value not lined up with major type
1193 #endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001194
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001195 #if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
1196 #error QCBOR_TYPE_MAP value not lined up with major type
1197 #endif
Laurence Lundblade62cae932024-06-03 13:16:17 -07001198 pDecodedItem->uDataType = (uint8_t)nMajorType;
1199#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1200 if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
1201 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
1202 }
Laurence Lundbladecfd8a2c2024-06-06 21:01:42 -07001203#else
1204 (void)uMode;
Laurence Lundblade62cae932024-06-03 13:16:17 -07001205#endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001206
Laurence Lundblade62cae932024-06-03 13:16:17 -07001207 uReturn = QCBOR_SUCCESS;
1208
1209 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1210 /* ------ Indefinite-length arra/map ----- */
1211#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
1212 pDecodedItem->val.uCount = QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH;
1213#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1214 uReturn = QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED;
1215#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1216 } else {
1217
1218#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1219 if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
1220 /* ------ Definite-length map as array ------ */
1221
1222 if(uItemCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
1223 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
1224 } else {
1225 /* cast OK because of check above */
1226 pDecodedItem->val.uCount = (uint16_t)uItemCount*2;
1227 }
1228
1229 } else
1230#endif
1231 {
1232 /* ------ Definite-length array/map ------ */
1233 if(uItemCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
1234 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
1235 } else {
1236 /* cast OK because of check above */
1237 pDecodedItem->val.uCount = (uint16_t)uItemCount;
1238 }
1239 }
1240 }
1241
1242 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001243}
1244
1245
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001246/**
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001247 * @brief Decode a single primitive data item (decode layer 6).
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001248 *
Laurence Lundblade62cae932024-06-03 13:16:17 -07001249 * param[in] pUInBuf Input buffer to read data item from.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001250 * @param[out] pDecodedItem The filled-in decoded item.
1251 * @param[in] pAllocator The allocator to use for strings or NULL.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001252 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001253 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1254 * features
1255 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1256 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1257 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1258 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1259 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1260 * of half-precision disabled
1261 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1262 * float decode is disabled.
1263 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1264 * simple type in input.
1265 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1266 * in input, but indefinite
1267 * lengths disabled.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001268 *
1269 * This decodes the most primitive / atomic data item. It does
1270 * no combing of data items.
1271 */
1272static QCBORError
Laurence Lundblade62cae932024-06-03 13:16:17 -07001273QCBOR_Private_DecodeAtomicDataItem(QCBORDecodeContext *pMe,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001274 QCBORItem *pDecodedItem,
1275 const QCBORInternalAllocator *pAllocator)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001276{
1277 QCBORError uReturn;
1278
1279 /* Get the major type and the argument. The argument could be
1280 * length of more bytes or the value depending on the major
1281 * type. nAdditionalInfo is an encoding of the length of the
1282 * uNumber and is needed to decode floats and doubles.
1283 */
1284 int nMajorType = 0;
1285 uint64_t uArgument = 0;
1286 int nAdditionalInfo = 0;
1287
1288 memset(pDecodedItem, 0, sizeof(QCBORItem));
1289
Laurence Lundblade62cae932024-06-03 13:16:17 -07001290 uReturn = QCBOR_Private_DecodeHead(&(pMe->InBuf), &nMajorType, &uArgument, &nAdditionalInfo);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001291 if(uReturn) {
1292 goto Done;
1293 }
1294
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001295 switch (nMajorType) {
1296 case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
1297 case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001298 uReturn = QCBOR_Private_DecodeInteger(nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001299 break;
1300
1301 case CBOR_MAJOR_TYPE_BYTE_STRING: /* Major type 2 */
1302 case CBOR_MAJOR_TYPE_TEXT_STRING: /* Major type 3 */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001303 uReturn = QCBOR_Private_DecodeBytes(pAllocator, nMajorType, uArgument, nAdditionalInfo, &(pMe->InBuf), pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001304 break;
1305
1306 case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */
1307 case CBOR_MAJOR_TYPE_MAP: /* Major type 5 */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001308 uReturn = QCBOR_Private_DecodeArrayOrMap(pMe->uDecodeMode, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001309 break;
1310
1311 case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001312 uReturn = QCBOR_Private_DecodeTag(nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001313 break;
1314
1315 case CBOR_MAJOR_TYPE_SIMPLE:
1316 /* Major type 7: float, double, true, false, null... */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001317 uReturn = QCBOR_Private_DecodeType7(nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001318 break;
1319
1320 default:
1321 /* Never happens because DecodeHead() should never return > 7 */
1322 uReturn = QCBOR_ERR_UNSUPPORTED;
1323 break;
1324 }
1325
1326Done:
1327 return uReturn;
1328}
1329
1330
1331/**
1332 * @brief Process indefinite-length strings (decode layer 5).
1333 *
1334 * @param[in] pMe Decoder context
1335 * @param[out] pDecodedItem The decoded item that work is done on.
1336 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001337 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1338 * features
1339 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1340 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1341 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1342 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1343 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1344 * of half-precision disabled
1345 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1346 * float decode is disabled.
1347 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1348 * simple type in input.
1349 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1350 * in input, but indefinite
1351 * lengths disabled.
1352 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1353 * but no string allocator.
1354 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1355 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1356 * input, but indefinite-length
1357 * strings are disabled.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001358 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001359 * If @c pDecodedItem is not an indefinite-length string, this does nothing.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001360 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001361 * If it is, this loops getting the subsequent chunk data items that
1362 * make up the string. The string allocator is used to make a
1363 * contiguous buffer for the chunks. When this completes @c
1364 * pDecodedItem contains the put-together string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001365 *
1366 * Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001367 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001368static QCBORError
1369QCBORDecode_Private_GetNextFullString(QCBORDecodeContext *pMe,
1370 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001371{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001372 /* Aproximate stack usage
1373 * 64-bit 32-bit
1374 * local vars 32 16
1375 * 2 UsefulBufs 32 16
1376 * QCBORItem 56 52
1377 * TOTAL 120 74
1378 */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001379
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001380 /* The string allocator is used here for two purposes: 1)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001381 * coalescing the chunks of an indefinite-length string, 2)
1382 * allocating storage for every string returned when requested.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001383 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001384 * The first use is below in this function. Indefinite-length
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001385 * strings cannot be processed at all without a string allocator.
1386 *
1387 * The second used is in DecodeBytes() which is called by
1388 * GetNext_Item() below. This second use unneccessary for most use
1389 * and only happens when requested in the call to
1390 * QCBORDecode_SetMemPool(). If the second use not requested then
1391 * NULL is passed for the string allocator to GetNext_Item().
1392 *
1393 * QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS disables the string
1394 * allocator altogether and thus both of these uses. It reduced the
1395 * decoder object code by about 400 bytes.
1396 */
Laurence Lundblade3a691a02020-12-28 04:15:16 -08001397 const QCBORInternalAllocator *pAllocatorForGetNext = NULL;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001398
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001399#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3a691a02020-12-28 04:15:16 -08001400 const QCBORInternalAllocator *pAllocator = NULL;
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001401
1402 if(pMe->StringAllocator.pfAllocator) {
1403 pAllocator = &(pMe->StringAllocator);
1404 if(pMe->bStringAllocateAll) {
1405 pAllocatorForGetNext = pAllocator;
1406 }
1407 }
1408#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1409
1410 QCBORError uReturn;
Laurence Lundblade62cae932024-06-03 13:16:17 -07001411 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, pDecodedItem, pAllocatorForGetNext);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001412 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001413 goto Done;
1414 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001415
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001416 /* Only do indefinite-length processing on strings */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001417 const uint8_t uStringType = pDecodedItem->uDataType;
1418 if(uStringType!= QCBOR_TYPE_BYTE_STRING && uStringType != QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001419 goto Done;
1420 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001421
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001422 /* Is this a string with an indefinite length? */
1423 if(pDecodedItem->val.string.len != QCBOR_STRING_LENGTH_INDEFINITE) {
1424 goto Done;
1425 }
1426
1427#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001428 /* Can't decode indefinite-length strings without a string allocator */
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001429 if(pAllocator == NULL) {
1430 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1431 goto Done;
1432 }
1433
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001434 /* Loop getting chunks of the indefinite-length string */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001435 UsefulBufC FullString = NULLUsefulBufC;
1436
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001437 for(;;) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001438 /* Get QCBORItem for next chunk */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001439 QCBORItem StringChunkItem;
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001440 /* Pass a NULL string allocator to GetNext_Item() because the
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001441 * individual string chunks in an indefinite-length should not
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001442 * be allocated. They are always copied in the the contiguous
1443 * buffer allocated here.
1444 */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001445 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, &StringChunkItem, NULL);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001446 if(uReturn) {
1447 break;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001448 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001449
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001450 /* Is item is the marker for end of the indefinite-length string? */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001451 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001452 /* String is complete */
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001453 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301454 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001455 break;
1456 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001457
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001458 /* All chunks must be of the same type, the type of the item
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001459 * that introduces the indefinite-length string. This also
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001460 * catches errors where the chunk is not a string at all and an
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001461 * indefinite-length string inside an indefinite-length string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001462 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001463 if(StringChunkItem.uDataType != uStringType ||
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001464 StringChunkItem.val.string.len == QCBOR_STRING_LENGTH_INDEFINITE) {
1465 uReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001466 break;
1467 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001468
David Navarro9123e5b2022-03-28 16:04:03 +02001469 if (StringChunkItem.val.string.len > 0) {
1470 /* The first time throurgh FullString.ptr is NULL and this is
1471 * equivalent to StringAllocator_Allocate(). Subsequently it is
1472 * not NULL and a reallocation happens.
1473 */
1474 UsefulBuf NewMem = StringAllocator_Reallocate(pAllocator,
1475 FullString.ptr,
1476 FullString.len + StringChunkItem.val.string.len);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001477
David Navarro9123e5b2022-03-28 16:04:03 +02001478 if(UsefulBuf_IsNULL(NewMem)) {
1479 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1480 break;
1481 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001482
David Navarro9123e5b2022-03-28 16:04:03 +02001483 /* Copy new string chunk to the end of accumulated string */
1484 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001485 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001486 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001487
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001488 if(uReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
1489 /* Getting the item failed, clean up the allocated memory */
Laurence Lundbladeb9702452021-03-08 21:02:57 -08001490 StringAllocator_Free(pAllocator, FullString.ptr);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001491 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001492#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1493 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1494#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001495
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001496Done:
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001497 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001498}
1499
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001500
Laurence Lundblade37286c02022-09-03 10:05:02 -07001501#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001502/**
1503 * @brief This converts a tag number to a shorter mapped value for storage.
1504 *
1505 * @param[in] pMe The decode context.
1506 * @param[in] uUnMappedTag The tag number to map
1507 * @param[out] puMappedTagNumer The stored tag number.
1508 *
1509 * @return error code.
1510 *
1511 * The main point of mapping tag numbers is make QCBORItem
1512 * smaller. With this mapping storage of 4 tags takes up 8
1513 * bytes. Without, it would take up 32 bytes.
1514 *
1515 * This maps tag numbers greater than QCBOR_LAST_UNMAPPED_TAG.
1516 * QCBOR_LAST_UNMAPPED_TAG is a little smaller than MAX_UINT16.
1517 *
1518 * See also UnMapTagNumber() and @ref QCBORItem.
1519 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001520static QCBORError
1521QCBORDecode_Private_MapTagNumber(QCBORDecodeContext *pMe,
1522 const uint64_t uUnMappedTag,
1523 uint16_t *puMappedTagNumer)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001524{
1525 if(uUnMappedTag > QCBOR_LAST_UNMAPPED_TAG) {
1526 unsigned uTagMapIndex;
1527 /* Is there room in the tag map, or is it in it already? */
1528 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
1529 if(pMe->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID64) {
1530 break;
1531 }
1532 if(pMe->auMappedTags[uTagMapIndex] == uUnMappedTag) {
1533 break;
1534 }
1535 }
1536 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
1537 return QCBOR_ERR_TOO_MANY_TAGS;
1538 }
1539
1540 /* Covers the cases where tag is new and were it is already in the map */
1541 pMe->auMappedTags[uTagMapIndex] = uUnMappedTag;
1542 *puMappedTagNumer = (uint16_t)(uTagMapIndex + QCBOR_LAST_UNMAPPED_TAG + 1);
1543
1544 } else {
1545 *puMappedTagNumer = (uint16_t)uUnMappedTag;
1546 }
1547
1548 return QCBOR_SUCCESS;
1549}
1550
1551
1552/**
1553 * @brief This converts a mapped tag number to the actual tag number.
1554 *
1555 * @param[in] pMe The decode context.
1556 * @param[in] uMappedTagNumber The stored tag number.
1557 *
1558 * @return The actual tag number is returned or
1559 * @ref CBOR_TAG_INVALID64 on error.
1560 *
1561 * This is the reverse of MapTagNumber()
1562 */
1563static uint64_t
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001564QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe,
1565 const uint16_t uMappedTagNumber)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001566{
1567 if(uMappedTagNumber <= QCBOR_LAST_UNMAPPED_TAG) {
1568 return uMappedTagNumber;
1569 } else if(uMappedTagNumber == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07001570 return CBOR_TAG_INVALID64;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001571 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001572 /* This won't be negative because of code below in
1573 * MapTagNumber()
1574 */
1575 const unsigned uIndex = uMappedTagNumber - (QCBOR_LAST_UNMAPPED_TAG + 1);
1576 return pMe->auMappedTags[uIndex];
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001577 }
1578}
Laurence Lundblade37286c02022-09-03 10:05:02 -07001579#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001580
Laurence Lundblade9b334962020-08-27 10:55:53 -07001581
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001582/**
1583 * @brief Aggregate all tags wrapping a data item (decode layer 4).
1584 *
1585 * @param[in] pMe Decoder context
1586 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001587 *
1588 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1589 * features
1590 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1591 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1592 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1593 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1594 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1595 * of half-precision disabled
1596 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1597 * float decode is disabled.
1598 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1599 * simple type in input.
1600 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1601 * in input, but indefinite
1602 * lengths disabled.
1603 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1604 * but no string allocator.
1605 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1606 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1607 * input, but indefinite-length
1608 * strings are disabled.
1609 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001610 *
1611 * This loops getting atomic data items until one is not a tag
1612 * number. Usually this is largely pass-through because most
1613 * item are not tag numbers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001614 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001615static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001616QCBORDecode_Private_GetNextTagNumber(QCBORDecodeContext *pMe,
1617 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001618{
Laurence Lundblade37286c02022-09-03 10:05:02 -07001619#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001620 /* Accummulate the tags from multiple items here and then copy them
1621 * into the last item, the non-tag item.
1622 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001623 uint16_t auItemsTags[QCBOR_MAX_TAGS_PER_ITEM];
1624
1625 /* Initialize to CBOR_TAG_INVALID16 */
1626 #if CBOR_TAG_INVALID16 != 0xffff
1627 /* Be sure the memset does the right thing. */
1628 #err CBOR_TAG_INVALID16 tag not defined as expected
1629 #endif
1630 memset(auItemsTags, 0xff, sizeof(auItemsTags));
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001631
Laurence Lundblade9b334962020-08-27 10:55:53 -07001632 QCBORError uReturn = QCBOR_SUCCESS;
1633
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001634 /* Loop fetching data items until the item fetched is not a tag */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001635 for(;;) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001636 QCBORError uErr = QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07001637 if(uErr != QCBOR_SUCCESS) {
1638 uReturn = uErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001639 goto Done;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001640 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001641
Laurence Lundblade9b334962020-08-27 10:55:53 -07001642 if(pDecodedItem->uDataType != QCBOR_TYPE_TAG) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001643 /* Successful exit from loop; maybe got some tags, maybe not */
1644 memcpy(pDecodedItem->uTags, auItemsTags, sizeof(auItemsTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001645 break;
1646 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001647
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001648 if(auItemsTags[QCBOR_MAX_TAGS_PER_ITEM - 1] != CBOR_TAG_INVALID16) {
1649 /* No room in the tag list */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001650 uReturn = QCBOR_ERR_TOO_MANY_TAGS;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001651 /* Continue on to get all tags wrapping this item even though
1652 * it is erroring out in the end. This allows decoding to
1653 * continue. This is a resource limit error, not a problem
1654 * with being well-formed CBOR.
1655 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001656 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001657 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001658 /* Slide tags over one in the array to make room at index 0.
1659 * Must use memmove because the move source and destination
1660 * overlap.
1661 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001662 memmove(&auItemsTags[1],
1663 auItemsTags,
1664 sizeof(auItemsTags) - sizeof(auItemsTags[0]));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001665
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001666 /* Map the tag */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001667 uint16_t uMappedTagNumber = 0;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001668 uReturn = QCBORDecode_Private_MapTagNumber(pMe, pDecodedItem->val.uTagV, &uMappedTagNumber);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001669 /* Continue even on error so as to consume all tags wrapping
1670 * this data item so decoding can go on. If MapTagNumber()
1671 * errors once it will continue to error.
1672 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001673 auItemsTags[0] = uMappedTagNumber;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001674 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001675
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001676Done:
Laurence Lundblade9b334962020-08-27 10:55:53 -07001677 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001678
Laurence Lundblade37286c02022-09-03 10:05:02 -07001679#else /* QCBOR_DISABLE_TAGS */
1680
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07001681 return QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07001682
1683#endif /* QCBOR_DISABLE_TAGS */
1684}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001685
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001686
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001687/**
1688 * @brief Combine a map entry label and value into one item (decode layer 3).
1689 *
1690 * @param[in] pMe Decoder context
1691 * @param[out] pDecodedItem The decoded item that work is done on.
1692 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001693 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1694 * features
1695 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1696 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1697 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1698 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1699 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1700 * of half-precision disabled
1701 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1702 * float decode is disabled.
1703 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1704 * simple type in input.
1705 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1706 * in input, but indefinite
1707 * lengths disabled.
1708 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1709 * but no string allocator.
1710 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1711 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1712 * input, but indefinite-length
1713 * strings are disabled.
1714 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1715 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1716 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001717 *
Laurence Lundblade62cae932024-06-03 13:16:17 -07001718 * If the current nesting level is a map, then this
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001719 * combines pairs of items into one data item with a label
1720 * and value.
1721 *
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07001722 * This is passthrough if the current nesting level is
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001723 * not a map.
1724 *
1725 * This also implements maps-as-array mode where a map
1726 * is treated like an array to allow caller to do their
1727 * own label processing.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001728 */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001729
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001730static QCBORError
1731QCBORDecode_Private_GetNextMapEntry(QCBORDecodeContext *pMe,
1732 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001733{
Laurence Lundblade62cae932024-06-03 13:16:17 -07001734 QCBORItem LabelItem;
1735 QCBORError uErr;
1736
1737 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1738 if(QCBORDecode_IsUnrecoverableError(uErr)) {
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001739 goto Done;
1740 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001741
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001742 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
1743 /* Break can't be a map entry */
1744 goto Done;
1745 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001746
Laurence Lundblade62cae932024-06-03 13:16:17 -07001747 if(!DecodeNesting_IsCurrentTypeMap(&(pMe->nesting))) {
1748 /* Not decoding a map; nothing to do */
1749 /* This is where maps-as-arrays is effected too */
1750 goto Done;
1751 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001752
Laurence Lundblade62cae932024-06-03 13:16:17 -07001753 /* Decoding a map entry, so the item so far is the label; must get value */
1754 LabelItem = *pDecodedItem;
1755 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1756 if(QCBORDecode_IsUnrecoverableError(uErr)) {
1757 goto Done;
1758 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001759
Laurence Lundblade62cae932024-06-03 13:16:17 -07001760 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
1761 pDecodedItem->uLabelType = LabelItem.uDataType;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001762
Laurence Lundblade62cae932024-06-03 13:16:17 -07001763#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1764 /* QCBOR_DECODE_MODE_MAP_STRINGS_ONLY was a bad idea. Maybe
1765 * get rid of it in QCBOR 2.0
1766 */
1767 if(pMe->uDecodeMode == QCBOR_DECODE_MODE_MAP_STRINGS_ONLY &&
1768 LabelItem.uDataType != QCBOR_TYPE_TEXT_STRING) {
1769 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
1770 goto Done;
1771 }
1772#endif /* !QCBOR_DISABLE_NON_INTEGER_LABELS */
1773
1774 switch(LabelItem.uDataType) {
1775 case QCBOR_TYPE_INT64:
1776 pDecodedItem->label.int64 = LabelItem.val.int64;
1777 break;
1778
1779#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1780 case QCBOR_TYPE_UINT64:
1781 pDecodedItem->label.uint64 = LabelItem.val.uint64;
1782 break;
1783
1784 case QCBOR_TYPE_TEXT_STRING:
1785 case QCBOR_TYPE_BYTE_STRING:
1786 pDecodedItem->label.string = LabelItem.val.string;
1787 break;
1788#endif /* !QCBOR_DISABLE_NON_INTEGER_LABELS */
1789
1790 /* case QCBOR_TYPE_BREAK:
1791 uErr = 99;
1792 goto Done; */
1793
1794 default:
1795 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
1796 goto Done;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001797 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001798
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001799Done:
Laurence Lundblade62cae932024-06-03 13:16:17 -07001800 return uErr;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001801}
1802
1803
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001804#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001805/**
1806 * @brief Peek and see if next data item is a break;
1807 *
Laurence Lundblade62cae932024-06-03 13:16:17 -07001808 * param[in] pUIB UsefulInputBuf to read from.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001809 * @param[out] pbNextIsBreak Indicate if next was a break or not.
1810 *
1811 * @return Any decoding error.
1812 *
1813 * See if next item is a CBOR break. If it is, it is consumed,
1814 * if not it is not consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07001815*/
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001816static QCBORError
Laurence Lundblade62cae932024-06-03 13:16:17 -07001817QCBOR_Private_NextIsBreak(QCBORDecodeContext *pMe, bool *pbNextIsBreak)
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001818{
1819 *pbNextIsBreak = false;
Laurence Lundblade62cae932024-06-03 13:16:17 -07001820 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) != 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001821 QCBORItem Peek;
Laurence Lundblade62cae932024-06-03 13:16:17 -07001822 size_t uPeek = UsefulInputBuf_Tell(&(pMe->InBuf));
1823 QCBORError uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, &Peek, NULL);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001824 if(uReturn != QCBOR_SUCCESS) {
1825 return uReturn;
1826 }
1827 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001828 /* It is not a break, rewind so it can be processed normally. */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001829 UsefulInputBuf_Seek(&(pMe->InBuf), uPeek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001830 } else {
1831 *pbNextIsBreak = true;
1832 }
1833 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001834
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001835 return QCBOR_SUCCESS;
1836}
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001837#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001838
1839
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001840/**
1841 * @brief Ascend up nesting levels if all items in them have been consumed.
1842 *
1843 * @param[in] pMe The decode context.
1844 * @param[in] bMarkEnd If true mark end of maps/arrays with count of zero.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001845 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001846 *
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001847 * An item was just consumed, now figure out if it was the
1848 * end of an array/map map that can be closed out. That
1849 * may in turn close out the above array/map...
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001850 *
1851 * When ascending indefinite-length arrays and maps, this will correctly
1852 * consume the break for the level above. This is a problem for the
1853 * implementation of QCBORDecode_GetArray() that must not return
1854 * that break. @c pbBreak is set to true to indicate that one
1855 * byte should be removed.
1856 *
1857 * Improvement: this could reduced further if indef is disabled
1858 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001859static QCBORError
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001860QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd, bool *pbBreak)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001861{
1862 QCBORError uReturn;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001863
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001864 /* Loop ascending nesting levels as long as there is ascending to do */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001865 while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001866 if(pbBreak) {
1867 *pbBreak = false;
1868 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001869
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001870 if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) {
1871 /* Nesting level is bstr-wrapped CBOR */
1872
1873 /* Ascent for bstr-wrapped CBOR is always by explicit call
1874 * so no further ascending can happen.
1875 */
1876 break;
1877
1878 } else if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
1879 /* Level is a definite-length array/map */
1880
1881 /* Decrement the item count the definite-length array/map */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001882 DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(&(pMe->nesting));
1883 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001884 /* Didn't close out array/map, so all work here is done */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001885 break;
1886 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001887 /* All items in a definite-length array were consumed so it
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001888 * is time to ascend one level. This happens below.
1889 */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001890
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001891#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001892 } else {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001893 /* Level is an indefinite-length array/map. */
1894
1895 /* Check for a break which is what ends indefinite-length arrays/maps */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001896 bool bIsBreak = false;
Laurence Lundblade62cae932024-06-03 13:16:17 -07001897 uReturn = QCBOR_Private_NextIsBreak(pMe, &bIsBreak);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001898 if(uReturn != QCBOR_SUCCESS) {
1899 goto Done;
1900 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001901
1902 if(!bIsBreak) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001903 /* Not a break so array/map does not close out. All work is done */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001904 break;
1905 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001906
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001907 /* It was a break in an indefinitelength map / array so
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001908 * it is time to ascend one level.
1909 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001910 if(pbBreak) {
1911 *pbBreak = true;
1912 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001913
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001914#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001915 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001916
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001917
1918 /* All items in the array/map have been consumed. */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001919
Laurence Lundblade93d89472020-10-03 22:30:50 -07001920 /* But ascent in bounded mode is only by explicit call to
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001921 * QCBORDecode_ExitBoundedMode().
1922 */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07001923 if(DecodeNesting_IsCurrentBounded(&(pMe->nesting))) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001924 /* Set the count to zero for definite-length arrays to indicate
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001925 * cursor is at end of bounded array/map */
Laurence Lundbladed0304932020-06-27 10:59:38 -07001926 if(bMarkEnd) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001927 /* Used for definite and indefinite to signal end */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07001928 DecodeNesting_ZeroMapOrArrayCount(&(pMe->nesting));
Laurence Lundbladed0304932020-06-27 10:59:38 -07001929
Laurence Lundblade2c1faf92020-06-26 22:43:56 -07001930 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001931 break;
1932 }
1933
1934 /* Finally, actually ascend one level. */
1935 DecodeNesting_Ascend(&(pMe->nesting));
1936 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001937
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001938 uReturn = QCBOR_SUCCESS;
1939
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001940#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001941Done:
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001942#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1943
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001944 return uReturn;
1945}
1946
1947
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001948/**
1949 * @brief Ascending & Descending out of nesting levels (decode layer 2).
1950 *
1951 * @param[in] pMe Decoder context
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001952 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001953 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001954
1955 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1956 * features
1957 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1958 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1959 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1960 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1961 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1962 * of half-precision disabled
1963 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1964 * float decode is disabled.
1965 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1966 * simple type in input.
1967 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1968 * in input, but indefinite
1969 * lengths disabled.
1970 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1971 * but no string allocator.
1972 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1973 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1974 * input, but indefinite-length
1975 * strings are disabled.
1976 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1977 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1978 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
1979 * @retval QCBOR_ERR_NO_MORE_ITEMS Need more items for map or array.
1980 * @retval QCBOR_ERR_BAD_BREAK Indefinite-length break in wrong
1981 * place.
1982 * @retval QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP Nesting deeper than QCBOR
1983 * can handle.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001984 *
1985 * This handles the traversal descending into and asecnding out of
1986 * maps, arrays and bstr-wrapped CBOR. It figures out the ends of
1987 * definite- and indefinte-length maps and arrays by looking at the
1988 * item count or finding CBOR breaks. It detects the ends of the
1989 * top-level sequence and of bstr-wrapped CBOR by byte count.
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001990 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001991static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001992QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001993 bool *pbBreak,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001994 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001995{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001996 QCBORError uReturn;
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07001997 /* ==== First: figure out if at the end of a traversal ==== */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001998
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001999 /* If out of bytes to consume, it is either the end of the
2000 * top-level sequence of some bstr-wrapped CBOR that was entered.
2001 *
2002 * In the case of bstr-wrapped CBOR, the length of the
2003 * UsefulInputBuf was set to that of the bstr-wrapped CBOR. When
2004 * the bstr-wrapped CBOR is exited, the length is set back to the
2005 * top-level's length or to the next highest bstr-wrapped CBOR.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002006 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002007 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) == 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002008 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002009 goto Done;
2010 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07002011
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002012 /* Check to see if at the end of a bounded definite-length map or
2013 * array. The check for a break ending indefinite-length array is
2014 * later in QCBORDecode_NestLevelAscender().
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002015 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002016 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002017 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002018 goto Done;
2019 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002020
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002021 /* ==== Next: not at the end, so get another item ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002022 uReturn = QCBORDecode_Private_GetNextMapEntry(pMe, pDecodedItem);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002023 if(QCBORDecode_IsUnrecoverableError(uReturn)) {
2024 /* Error is so bad that traversal is not possible. */
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002025 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002026 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05302027
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002028 /* Breaks ending arrays/maps are processed later in the call to
2029 * QCBORDecode_NestLevelAscender(). They should never show up here.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002030 */
Laurence Lundblade6de37062018-10-15 12:22:42 +05302031 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002032 uReturn = QCBOR_ERR_BAD_BREAK;
Laurence Lundblade6de37062018-10-15 12:22:42 +05302033 goto Done;
Laurence Lundblade5b8c5852018-10-14 21:11:42 +05302034 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002035
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002036 /* Record the nesting level for this data item before processing
2037 * any of decrementing and descending.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002038 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002039 pDecodedItem->uNestingLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002040
Laurence Lundblade642282a2020-06-23 12:00:33 -07002041
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002042 /* ==== Next: Process the item for descent, ascent, decrement... ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002043 if(QCBORItem_IsMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002044 /* If the new item is a map or array, descend.
2045 *
2046 * Empty indefinite-length maps and arrays are descended into,
2047 * but then ascended out of in the next chunk of code.
2048 *
2049 * Maps and arrays do count as items in the map/array that
2050 * encloses them so a decrement needs to be done for them too,
2051 * but that is done only when all the items in them have been
2052 * processed, not when they are opened with the exception of an
2053 * empty map or array.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002054 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002055 QCBORError uDescendErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002056 uDescendErr = DecodeNesting_DescendMapOrArray(&(pMe->nesting),
Laurence Lundblade642282a2020-06-23 12:00:33 -07002057 pDecodedItem->uDataType,
2058 pDecodedItem->val.uCount);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002059 if(uDescendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002060 /* This error is probably a traversal error and it overrides
2061 * the non-traversal error.
2062 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002063 uReturn = uDescendErr;
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002064 goto Done;
2065 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002066 }
2067
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002068 if(!QCBORItem_IsMapOrArray(*pDecodedItem) ||
2069 QCBORItem_IsEmptyDefiniteLengthMapOrArray(*pDecodedItem) ||
2070 QCBORItem_IsIndefiniteLengthMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002071 /* The following cases are handled here:
2072 * - A non-aggregate item like an integer or string
2073 * - An empty definite-length map or array
2074 * - An indefinite-length map or array that might be empty or might not.
2075 *
2076 * QCBORDecode_NestLevelAscender() does the work of decrementing the count
2077 * for an definite-length map/array and break detection for an
2078 * indefinite-0length map/array. If the end of the map/array was
2079 * reached, then it ascends nesting levels, possibly all the way
2080 * to the top level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002081 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002082 QCBORError uAscendErr;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002083 uAscendErr = QCBORDecode_Private_NestLevelAscender(pMe, true, pbBreak);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002084 if(uAscendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002085 /* This error is probably a traversal error and it overrides
2086 * the non-traversal error.
2087 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002088 uReturn = uAscendErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002089 goto Done;
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002090 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05302091 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002092
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002093 /* ==== Last: tell the caller the nest level of the next item ==== */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002094 /* Tell the caller what level is next. This tells them what
2095 * maps/arrays were closed out and makes it possible for them to
2096 * reconstruct the tree with just the information returned in a
2097 * QCBORItem.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002098 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002099 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07002100 /* At end of a bounded map/array; uNextNestLevel 0 to indicate this */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002101 pDecodedItem->uNextNestLevel = 0;
2102 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002103 pDecodedItem->uNextNestLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002104 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002105
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002106Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002107 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002108}
2109
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002110
Laurence Lundblade37286c02022-09-03 10:05:02 -07002111#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002112/**
2113 * @brief Shift 0th tag out of the tag list.
2114 *
2115 * pDecodedItem[in,out] The data item to convert.
2116 *
2117 * The 0th tag is discarded. \ref CBOR_TAG_INVALID16 is
2118 * shifted into empty slot at the end of the tag list.
2119 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002120static void
2121QCBOR_Private_ShiftTags(QCBORItem *pDecodedItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002122{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002123 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM-1; i++) {
2124 pDecodedItem->uTags[i] = pDecodedItem->uTags[i+1];
2125 }
2126 pDecodedItem->uTags[QCBOR_MAX_TAGS_PER_ITEM-1] = CBOR_TAG_INVALID16;
Laurence Lundblade9b334962020-08-27 10:55:53 -07002127}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002128#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002129
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002130
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002131/**
2132 * @brief Convert different epoch date formats in to the QCBOR epoch date format
2133 *
2134 * pDecodedItem[in,out] The data item to convert.
2135 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002136 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2137 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2138 * floating-point date disabled.
2139 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2140 * all floating-point disabled.
2141 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2142 * error decoding date.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002143 *
2144 * The epoch date tag defined in QCBOR allows for floating-point
2145 * dates. It even allows a protocol to flop between date formats when
2146 * ever it wants. Floating-point dates aren't that useful as they are
2147 * only needed for dates beyond the age of the earth.
2148 *
2149 * This converts all the date formats into one format of an unsigned
2150 * integer plus a floating-point fraction.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002151 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002152static QCBORError
2153QCBOR_Private_DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002154{
Laurence Lundbladec7114722020-08-13 05:11:40 -07002155 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002156
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002157#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade59289e52019-12-30 13:44:37 -08002158 pDecodedItem->val.epochDate.fSecondsFraction = 0;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002159#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002160
2161 switch (pDecodedItem->uDataType) {
2162
2163 case QCBOR_TYPE_INT64:
2164 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
2165 break;
2166
2167 case QCBOR_TYPE_UINT64:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002168 /* This only happens for CBOR type 0 > INT64_MAX so it is
2169 * always an overflow.
2170 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07002171 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2172 goto Done;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002173 break;
2174
2175 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade9682a532020-06-06 18:33:04 -07002176 case QCBOR_TYPE_FLOAT:
2177#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade59289e52019-12-30 13:44:37 -08002178 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002179 /* Convert working value to double if input was a float */
Laurence Lundblade3ed0bca2020-07-14 22:50:10 -07002180 const double d = pDecodedItem->uDataType == QCBOR_TYPE_DOUBLE ?
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002181 pDecodedItem->val.dfnum :
2182 (double)pDecodedItem->val.fnum;
2183
2184 /* The conversion from float to integer requires overflow
2185 * detection since floats can be much larger than integers.
2186 * This implementation errors out on these large float values
2187 * since they are beyond the age of the earth.
2188 *
2189 * These constants for the overflow check are computed by the
2190 * compiler. They are not computed at run time.
2191 *
2192 * The factor of 0x7ff is added/subtracted to avoid a
2193 * rounding error in the wrong direction when the compiler
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002194 * computes these constants. There is rounding because a
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002195 * 64-bit integer has 63 bits of precision where a double
2196 * only has 53 bits. Without the 0x7ff factor, the compiler
2197 * may round up and produce a double for the bounds check
2198 * that is larger than can be stored in a 64-bit integer. The
2199 * amount of 0x7ff is picked because it has 11 bits set.
2200 *
2201 * Without the 0x7ff there is a ~30 minute range of time
2202 * values 10 billion years in the past and in the future
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002203 * where this code could go wrong. Some compilers
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002204 * generate a warning or error without the 0x7ff.
2205 */
2206 const double dDateMax = (double)(INT64_MAX - 0x7ff);
2207 const double dDateMin = (double)(INT64_MIN + 0x7ff);
2208
2209 if(isnan(d) || d > dDateMax || d < dDateMin) {
Laurence Lundbladec7114722020-08-13 05:11:40 -07002210 uReturn = QCBOR_ERR_DATE_OVERFLOW;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002211 goto Done;
2212 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002213
2214 /* The actual conversion */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002215 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
Laurence Lundblade2feb1e12020-07-15 03:50:45 -07002216 pDecodedItem->val.epochDate.fSecondsFraction =
2217 d - (double)pDecodedItem->val.epochDate.nSeconds;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002218 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002219#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade4b270642020-08-14 12:53:07 -07002220
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002221 uReturn = QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundblade4b270642020-08-14 12:53:07 -07002222 goto Done;
2223
Laurence Lundblade9682a532020-06-06 18:33:04 -07002224#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002225 break;
2226
2227 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002228 /* It's the arrays and maps that are unrecoverable because
2229 * they are not consumed here. Since this is just an error
2230 * condition, no extra code is added here to make the error
2231 * recoverable for non-arrays and maps like strings. */
2232 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002233 goto Done;
2234 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002235
Laurence Lundblade59289e52019-12-30 13:44:37 -08002236 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
2237
2238Done:
Laurence Lundbladec7114722020-08-13 05:11:40 -07002239 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002240}
2241
2242
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002243/**
2244 * @brief Convert the days epoch date.
2245 *
2246 * pDecodedItem[in,out] The data item to convert.
2247 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002248 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2249 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2250 * floating-point date disabled.
2251 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2252 * all floating-point disabled.
2253 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2254 * error decoding date.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002255 *
2256 * This is much simpler than the other epoch date format because
2257 * floating-porint is not allowed. This is mostly a simple type check.
2258 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002259static QCBORError
2260QCBOR_Private_DecodeDaysEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002261{
2262 QCBORError uReturn = QCBOR_SUCCESS;
2263
2264 switch (pDecodedItem->uDataType) {
2265
2266 case QCBOR_TYPE_INT64:
2267 pDecodedItem->val.epochDays = pDecodedItem->val.int64;
2268 break;
2269
2270 case QCBOR_TYPE_UINT64:
2271 /* This only happens for CBOR type 0 > INT64_MAX so it is
2272 * always an overflow.
2273 */
2274 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2275 goto Done;
2276 break;
2277
2278 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002279 /* It's the arrays and maps that are unrecoverable because
2280 * they are not consumed here. Since this is just an error
2281 * condition, no extra code is added here to make the error
2282 * recoverable for non-arrays and maps like strings. */
2283 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002284 goto Done;
2285 break;
2286 }
2287
2288 pDecodedItem->uDataType = QCBOR_TYPE_DAYS_EPOCH;
2289
2290Done:
2291 return uReturn;
2292}
2293
2294
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002295#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade37286c02022-09-03 10:05:02 -07002296
2297/* Forward declaration is necessary for
2298 * QCBORDecode_MantissaAndExponent(). to be able to decode bignum
2299 * tags in the mantissa. If the mantissa is a decimal fraction or big
2300 * float in error, this will result in a recurive call to
2301 * QCBORDecode_MantissaAndExponent(), but the recursion will unwined
2302 * correctly and the correct error is returned.
2303 */
2304static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002305QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2306 QCBORItem *pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002307
2308
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002309/**
2310 * @brief Decode decimal fractions and big floats.
2311 *
2312 * @param[in] pMe The decode context.
2313 * @param[in,out] pDecodedItem On input the array data item that
2314 * holds the mantissa and exponent. On
2315 * output the decoded mantissa and
2316 * exponent.
2317 *
2318 * @returns Decoding errors from getting primitive data items or
2319 * \ref QCBOR_ERR_BAD_EXP_AND_MANTISSA.
2320 *
Laurence Lundblade37286c02022-09-03 10:05:02 -07002321 * When called pDecodedItem must be the array with two members, the
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002322 * exponent and mantissa.
2323 *
2324 * This will fetch and decode the exponent and mantissa and put the
2325 * result back into pDecodedItem.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002326 *
2327 * This does no checking or processing of tag numbers. That is to be
2328 * done by the code that calls this.
2329 *
2330 * This stuffs the type of the mantissa into pDecodedItem with the expectation
2331 * the caller will process it.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002332 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002333static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002334QCBORDecode_Private_ExpMantissa(QCBORDecodeContext *pMe,
2335 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002336{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002337 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002338
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002339 /* --- Make sure it is an array; track nesting level of members --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002340 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002341 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002342 goto Done;
2343 }
2344
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002345 /* A check for pDecodedItem->val.uCount == 2 would work for
Laurence Lundblade37286c02022-09-03 10:05:02 -07002346 * definite-length arrays, but not for indefinite. Instead remember
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002347 * the nesting level the two integers must be at, which is one
2348 * deeper than that of the array.
2349 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002350 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
2351
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002352 /* --- Get the exponent --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002353 QCBORItem exponentItem;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002354 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, &exponentItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002355 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002356 goto Done;
2357 }
2358 if(exponentItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002359 /* Array is empty or a map/array encountered when expecting an int */
2360 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002361 goto Done;
2362 }
2363 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002364 /* Data arriving as an unsigned int < INT64_MAX has been
2365 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2366 * also means that the only data arriving here of type
2367 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2368 * and thus an error that will get handled in the next else.
2369 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002370 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
2371 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002372 /* Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX */
2373 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002374 goto Done;
2375 }
2376
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002377 /* --- Get the mantissa --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002378 QCBORItem mantissaItem;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002379 uReturn = QCBORDecode_Private_GetNextTagContent(pMe, &mantissaItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002380 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002381 goto Done;
2382 }
2383 if(mantissaItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002384 /* Mantissa missing or map/array encountered when expecting number */
2385 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002386 goto Done;
2387 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002388 /* Stuff the mantissa data type into the item to send it up to the
2389 * the next level. */
2390 pDecodedItem->uDataType = mantissaItem.uDataType;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002391 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002392 /* Data arriving as an unsigned int < INT64_MAX has been
2393 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2394 * also means that the only data arriving here of type
2395 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2396 * and thus an error that will get handled in an else below.
2397 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002398 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002399#ifndef QCBOR_DISABLE_TAGS
2400 /* With tags fully disabled a big number mantissa will error out
2401 * in the call to QCBORDecode_GetNextWithTags() because it has
2402 * a tag number.
2403 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07002404 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM ||
2405 mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002406 /* Got a good big num mantissa */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002407 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002408#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002409 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002410 /* Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX */
2411 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002412 goto Done;
2413 }
2414
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002415 /* --- Check that array only has the two numbers --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002416 if(mantissaItem.uNextNestLevel == nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002417 /* Extra items in the decimal fraction / big float */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002418 /* Improvement: this should probably be an unrecoverable error. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002419 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002420 goto Done;
2421 }
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002422 pDecodedItem->uNextNestLevel = mantissaItem.uNextNestLevel;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002423
2424Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002425 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002426}
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002427#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002428
2429
Laurence Lundblade37286c02022-09-03 10:05:02 -07002430#ifndef QCBOR_DISABLE_TAGS
2431
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002432#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002433/**
2434 * @brief Decode the MIME type tag
2435 *
2436 * @param[in,out] pDecodedItem The item to decode.
2437 *
2438 * Handle the text and binary MIME type tags. Slightly too complicated
2439 * f or ProcessTaggedString() because the RFC 7049 MIME type was
2440 * incorreclty text-only.
2441 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002442static QCBORError
2443QCBOR_Private_DecodeMIME(QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002444{
2445 if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) {
2446 pDecodedItem->uDataType = QCBOR_TYPE_MIME;
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07002447 } else if(pDecodedItem->uDataType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002448 pDecodedItem->uDataType = QCBOR_TYPE_BINARY_MIME;
2449 } else {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002450 /* It's the arrays and maps that are unrecoverable because
2451 * they are not consumed here. Since this is just an error
2452 * condition, no extra code is added here to make the error
2453 * recoverable for non-arrays and maps like strings. */
2454 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002455 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002456
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002457 return QCBOR_SUCCESS;
2458}
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002459#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002460
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002461/**
Laurence Lundblade99615302020-11-29 11:19:47 -08002462 * Table of CBOR tags whose content is either a text string or a byte
2463 * string. The table maps the CBOR tag to the QCBOR type. The high-bit
2464 * of uQCBORtype indicates the content should be a byte string rather
2465 * than a text string
2466 */
2467struct StringTagMapEntry {
2468 uint16_t uTagNumber;
2469 uint8_t uQCBORtype;
2470};
2471
2472#define IS_BYTE_STRING_BIT 0x80
2473#define QCBOR_TYPE_MASK ~IS_BYTE_STRING_BIT
2474
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002475static const struct StringTagMapEntry QCBOR_Private_StringTagMap[] = {
Laurence Lundblade99615302020-11-29 11:19:47 -08002476 {CBOR_TAG_DATE_STRING, QCBOR_TYPE_DATE_STRING},
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002477 {CBOR_TAG_DAYS_STRING, QCBOR_TYPE_DAYS_STRING},
Laurence Lundblade99615302020-11-29 11:19:47 -08002478 {CBOR_TAG_POS_BIGNUM, QCBOR_TYPE_POSBIGNUM | IS_BYTE_STRING_BIT},
2479 {CBOR_TAG_NEG_BIGNUM, QCBOR_TYPE_NEGBIGNUM | IS_BYTE_STRING_BIT},
2480 {CBOR_TAG_CBOR, QBCOR_TYPE_WRAPPED_CBOR | IS_BYTE_STRING_BIT},
2481 {CBOR_TAG_URI, QCBOR_TYPE_URI},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002482#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002483 {CBOR_TAG_B64URL, QCBOR_TYPE_BASE64URL},
2484 {CBOR_TAG_B64, QCBOR_TYPE_BASE64},
2485 {CBOR_TAG_REGEX, QCBOR_TYPE_REGEX},
2486 {CBOR_TAG_BIN_UUID, QCBOR_TYPE_UUID | IS_BYTE_STRING_BIT},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002487#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade99615302020-11-29 11:19:47 -08002488 {CBOR_TAG_CBOR_SEQUENCE, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE | IS_BYTE_STRING_BIT},
2489 {CBOR_TAG_INVALID16, QCBOR_TYPE_NONE}
2490};
2491
2492
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002493/**
2494 * @brief Process standard CBOR tags whose content is a string
2495 *
2496 * @param[in] uTag The tag.
2497 * @param[in,out] pDecodedItem The data item.
2498 *
2499 * @returns This returns QCBOR_SUCCESS if the tag was procssed,
2500 * \ref QCBOR_ERR_UNSUPPORTED if the tag was not processed and
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002501 * \ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT if the content type was wrong for the tag.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002502 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002503 * Process the CBOR tags that whose content is a byte string or a text
2504 * string and for which the string is just passed on to the caller.
2505 *
2506 * This maps the CBOR tag to the QCBOR type and checks the content
2507 * type. Nothing more. It may not be the most important
Laurence Lundbladec02e13e2020-12-06 05:45:41 -08002508 * functionality, but it part of implementing as much of RFC 8949 as
Laurence Lundblade99615302020-11-29 11:19:47 -08002509 * possible.
Laurence Lundblade99615302020-11-29 11:19:47 -08002510 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002511static QCBORError
2512QCBOR_Private_ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002513{
Laurence Lundblade99615302020-11-29 11:19:47 -08002514 /* This only works on tags that were not mapped; no need for other yet */
2515 if(uTag > QCBOR_LAST_UNMAPPED_TAG) {
2516 return QCBOR_ERR_UNSUPPORTED;
2517 }
2518
2519 unsigned uIndex;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002520 for(uIndex = 0; QCBOR_Private_StringTagMap[uIndex].uTagNumber != CBOR_TAG_INVALID16; uIndex++) {
2521 if(QCBOR_Private_StringTagMap[uIndex].uTagNumber == uTag) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002522 break;
2523 }
2524 }
2525
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002526 const uint8_t uQCBORType = QCBOR_Private_StringTagMap[uIndex].uQCBORtype;
Laurence Lundblade99615302020-11-29 11:19:47 -08002527 if(uQCBORType == QCBOR_TYPE_NONE) {
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002528 /* repurpose this error to mean not handled here */
Laurence Lundblade99615302020-11-29 11:19:47 -08002529 return QCBOR_ERR_UNSUPPORTED;
2530 }
2531
2532 uint8_t uExpectedType = QCBOR_TYPE_TEXT_STRING;
2533 if(uQCBORType & IS_BYTE_STRING_BIT) {
2534 uExpectedType = QCBOR_TYPE_BYTE_STRING;
2535 }
2536
2537 if(pDecodedItem->uDataType != uExpectedType) {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002538 /* It's the arrays and maps that are unrecoverable because
2539 * they are not consumed here. Since this is just an error
2540 * condition, no extra code is added here to make the error
2541 * recoverable for non-arrays and maps like strings. */
2542 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002543 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002544
Laurence Lundblade99615302020-11-29 11:19:47 -08002545 pDecodedItem->uDataType = (uint8_t)(uQCBORType & QCBOR_TYPE_MASK);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002546 return QCBOR_SUCCESS;
2547}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002548#endif /* QCBOR_DISABLE_TAGS */
2549
2550
2551#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002552/**
2553 * @brief Figures out data type for exponent mantissa tags.
2554 *
2555 * @param[in] uTagToProcess Either @ref CBOR_TAG_DECIMAL_FRACTION or
2556 * @ref CBOR_TAG_BIG_FLOAT.
2557 * @param[in] pDecodedItem Item being decoded.
2558 *
2559 * @returns One of the 6 values between \ref QCBOR_TYPE_DECIMAL_FRACTION
2560 * and @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM.
2561 *
2562 * Does mapping between a CBOR tag number and a QCBOR type. with a
2563 * little bit of logic and arithmatic.
2564 *
2565 * Used in serveral contexts. Does the work where sometimes the data
2566 * item is explicitly tagged and sometimes not.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002567 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002568static uint8_t
2569QCBOR_Private_ExpMantissaDataType(const uint16_t uTagToProcess,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002570 const QCBORItem *pDecodedItem)
Laurence Lundblade37286c02022-09-03 10:05:02 -07002571{
2572 uint8_t uBase = uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ?
2573 QCBOR_TYPE_DECIMAL_FRACTION :
2574 QCBOR_TYPE_BIGFLOAT;
2575 if(pDecodedItem->uDataType != QCBOR_TYPE_INT64) {
2576 uBase = (uint8_t)(uBase + pDecodedItem->uDataType - QCBOR_TYPE_POSBIGNUM + 1);
2577 }
2578 return uBase;
2579}
2580#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002581
2582
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002583/**
2584 * @brief Decode tag content for select tags (decoding layer 1).
2585 *
2586 * @param[in] pMe The decode context.
2587 * @param[out] pDecodedItem The decoded item.
2588 *
2589 * @return Decoding error code.
2590 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002591 * CBOR tag numbers for the item were decoded in GetNext_TaggedItem(),
2592 * but the whole tag was not decoded. Here, the whole tags (tag number
2593 * and tag content) that are supported by QCBOR are decoded. This is a
2594 * quick pass through for items that are not tags.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002595 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002596static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002597QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2598 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002599{
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002600 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002601
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002602 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pDecodedItem);
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002603 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002604 goto Done;
2605 }
2606
Laurence Lundblade37286c02022-09-03 10:05:02 -07002607#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002608 /* When there are no tag numbers for the item, this exits first
2609 * thing and effectively does nothing.
2610 *
2611 * This loops over all the tag numbers accumulated for this item
2612 * trying to decode and interpret them. This stops at the end of
2613 * the list or at the first tag number that can't be interpreted by
2614 * this code. This is effectively a recursive processing of the
2615 * tags number list that handles nested tags.
2616 */
2617 while(1) {
2618 /* Don't bother to unmap tags via QCBORITem.uTags since this
2619 * code only works on tags less than QCBOR_LAST_UNMAPPED_TAG.
2620 */
2621 const uint16_t uTagToProcess = pDecodedItem->uTags[0];
Laurence Lundblade59289e52019-12-30 13:44:37 -08002622
Laurence Lundblade99615302020-11-29 11:19:47 -08002623 if(uTagToProcess == CBOR_TAG_INVALID16) {
2624 /* Hit the end of the tag list. A successful exit. */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002625 break;
2626
Laurence Lundblade99615302020-11-29 11:19:47 -08002627 } else if(uTagToProcess == CBOR_TAG_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002628 uReturn = QCBOR_Private_DecodeDateEpoch(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002629
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002630 } else if(uTagToProcess == CBOR_TAG_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002631 uReturn = QCBOR_Private_DecodeDaysEpoch(pDecodedItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002632
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002633#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade99615302020-11-29 11:19:47 -08002634 } else if(uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ||
2635 uTagToProcess == CBOR_TAG_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002636 uReturn = QCBORDecode_Private_ExpMantissa(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002637 /* --- Which is it, decimal fraction or a bigfloat? --- */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002638 pDecodedItem->uDataType = QCBOR_Private_ExpMantissaDataType(uTagToProcess, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002639
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002640#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002641#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002642 } else if(uTagToProcess == CBOR_TAG_MIME ||
2643 uTagToProcess == CBOR_TAG_BINARY_MIME) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002644 uReturn = QCBOR_Private_DecodeMIME(pDecodedItem);
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002645#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002646
Laurence Lundblade99615302020-11-29 11:19:47 -08002647 } else {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002648 /* See if it is a passthrough byte/text string tag; process if so */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002649 uReturn = QCBOR_Private_ProcessTaggedString(pDecodedItem->uTags[0], pDecodedItem);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002650
Laurence Lundblade99615302020-11-29 11:19:47 -08002651 if(uReturn == QCBOR_ERR_UNSUPPORTED) {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002652 /* It wasn't a passthrough byte/text string tag so it is
Laurence Lundblade99615302020-11-29 11:19:47 -08002653 * an unknown tag. This is the exit from the loop on the
2654 * first unknown tag. It is a successful exit.
2655 */
2656 uReturn = QCBOR_SUCCESS;
2657 break;
2658 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002659 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002660
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002661 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002662 /* Error exit from the loop */
2663 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002664 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002665
2666 /* A tag was successfully processed, shift it out of the list of
2667 * tags returned. This is the loop increment.
2668 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002669 QCBOR_Private_ShiftTags(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002670 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002671#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002672
2673Done:
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002674 return uReturn;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002675}
2676
2677
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002678/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002679 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002680 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002681QCBORError
2682QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2683{
2684 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002685 uErr = QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002686 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002687 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2688 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
2689 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002690 return uErr;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002691}
2692
2693
2694/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002695 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08002696 */
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002697QCBORError
2698QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2699{
2700 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2701 const UsefulInputBuf Save = pMe->InBuf;
2702
2703 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
2704
2705 pMe->nesting = SaveNesting;
2706 pMe->InBuf = Save;
2707
2708 return uErr;
2709}
2710
2711
2712/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002713 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002714 */
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002715void
2716QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2717{
2718 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002719 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2720 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002721 return;
2722 }
2723
2724 pMe->uLastError = (uint8_t)QCBORDecode_PeekNext(pMe, pDecodedItem);
2725}
2726
2727
2728/*
2729 * Public function, see header qcbor/qcbor_decode.h file
2730 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002731void
2732QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002733{
2734 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002735 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2736 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002737 return;
2738 }
2739
2740 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem);
2741}
2742
2743
2744/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002745 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002746 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002747QCBORError
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002748QCBORDecode_GetNextWithTags(QCBORDecodeContext *pMe,
2749 QCBORItem *pDecodedItem,
2750 QCBORTagListOut *pTags)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002751{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002752#ifndef QCBOR_DISABLE_TAGS
2753
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002754 QCBORError uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002755
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002756 uReturn = QCBORDecode_GetNext(pMe, pDecodedItem);
2757 if(uReturn != QCBOR_SUCCESS) {
2758 return uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002759 }
2760
2761 if(pTags != NULL) {
2762 pTags->uNumUsed = 0;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002763 /* Reverse the order because pTags is reverse of QCBORItem.uTags. */
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002764 for(int nTagIndex = QCBOR_MAX_TAGS_PER_ITEM-1; nTagIndex >=0; nTagIndex--) {
2765 if(pDecodedItem->uTags[nTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07002766 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002767 }
2768 if(pTags->uNumUsed >= pTags->uNumAllocated) {
2769 return QCBOR_ERR_TOO_MANY_TAGS;
2770 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002771 pTags->puTags[pTags->uNumUsed] = QCBORDecode_Private_UnMapTagNumber(pMe,pDecodedItem->uTags[nTagIndex]);
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002772 pTags->uNumUsed++;
2773 }
2774 }
2775
2776 return QCBOR_SUCCESS;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002777
2778#else /* QCBOR_DISABLE_TAGS */
2779 (void)pMe;
2780 (void)pDecodedItem;
2781 (void)pTags;
2782 return QCBOR_ERR_TAGS_DISABLED;
2783#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002784}
2785
2786
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002787/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002788 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05302789 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002790bool
2791QCBORDecode_IsTagged(QCBORDecodeContext *pMe,
2792 const QCBORItem *pItem,
2793 uint64_t uTag)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002794{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002795#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002796 for(unsigned uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) {
2797 if(pItem->uTags[uTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002798 break;
2799 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002800 if(QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uTagIndex]) == uTag) {
Laurence Lundbladef71e1622020-08-06 18:52:13 -07002801 return true;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002802 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002803 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002804#else /* QCBOR_TAGS_DISABLED */
2805 (void)pMe;
2806 (void)pItem;
2807 (void)uTag;
2808#endif /* QCBOR_TAGS_DISABLED */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002809
Laurence Lundbladef71e1622020-08-06 18:52:13 -07002810 return false;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002811}
2812
2813
2814/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002815 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002816 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002817QCBORError
2818QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002819{
Laurence Lundblade87495732021-02-26 10:05:55 -07002820 if(puConsumed != NULL) {
2821 *puConsumed = pMe->InBuf.cursor;
2822 }
2823
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002824 QCBORError uReturn = pMe->uLastError;
Laurence Lundblade085d7952020-07-24 10:26:30 -07002825
2826 if(uReturn != QCBOR_SUCCESS) {
2827 goto Done;
2828 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002829
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002830 /* Error out if all the maps/arrays are not closed out */
2831 if(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002832 uReturn = QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002833 goto Done;
2834 }
2835
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002836 /* Error out if not all the bytes are consumed */
2837 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf))) {
Laurence Lundblade085d7952020-07-24 10:26:30 -07002838 uReturn = QCBOR_ERR_EXTRA_BYTES;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002839 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002840
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002841Done:
Laurence Lundblade87495732021-02-26 10:05:55 -07002842 return uReturn;
2843}
2844
2845
2846/*
2847 * Public function, see header qcbor/qcbor_decode.h file
2848 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002849QCBORError
2850QCBORDecode_Finish(QCBORDecodeContext *pMe)
Laurence Lundblade87495732021-02-26 10:05:55 -07002851{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002852#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002853 /* Call the destructor for the string allocator if there is one.
2854 * Always called, even if there are errors; always have to clean up.
2855 */
2856 StringAllocator_Destruct(&(pMe->StringAllocator));
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002857#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002858
Laurence Lundblade87495732021-02-26 10:05:55 -07002859 return QCBORDecode_PartialFinish(pMe, NULL);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002860}
2861
2862
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002863/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002864 * Public function, see header qcbor/qcbor_decode.h file
2865 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002866uint64_t
2867QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
2868 const QCBORItem *pItem,
2869 uint32_t uIndex)
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002870{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002871#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002872 if(pItem->uDataType == QCBOR_TYPE_NONE) {
2873 return CBOR_TAG_INVALID64;
2874 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002875 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2876 return CBOR_TAG_INVALID64;
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002877 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002878 return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uIndex]);
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002879 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002880#else /* QCBOR_DISABLE_TAGS */
2881 (void)pMe;
2882 (void)pItem;
2883 (void)uIndex;
2884
2885 return CBOR_TAG_INVALID64;
2886#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002887}
2888
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002889
Laurence Lundblade9b334962020-08-27 10:55:53 -07002890/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002891 * Public function, see header qcbor/qcbor_decode.h file
2892 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002893uint64_t
2894QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe,
2895 uint32_t uIndex)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002896{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002897#ifndef QCBOR_DISABLE_TAGS
2898
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002899 if(pMe->uLastError != QCBOR_SUCCESS) {
2900 return CBOR_TAG_INVALID64;
2901 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002902 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2903 return CBOR_TAG_INVALID64;
2904 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002905 return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->uLastTags[uIndex]);
Laurence Lundblade9b334962020-08-27 10:55:53 -07002906 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002907#else /* QCBOR_DISABLE_TAGS */
2908 (void)pMe;
2909 (void)uIndex;
2910
2911 return CBOR_TAG_INVALID64;
2912#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07002913}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002914
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002915
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002916
2917
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002918#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladef6531662018-12-04 10:42:22 +09002919
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002920/* ===========================================================================
2921 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002922
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002923 This implements a simple sting allocator for indefinite-length
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002924 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
2925 implements the function type QCBORStringAllocate and allows easy
2926 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09002927
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002928 This particular allocator is built-in for convenience. The caller
2929 can implement their own. All of this following code will get
2930 dead-stripped if QCBORDecode_SetMemPool() is not called.
2931
2932 This is a very primitive memory allocator. It does not track
2933 individual allocations, only a high-water mark. A free or
2934 reallocation must be of the last chunk allocated.
2935
2936 The size of the pool and offset to free memory are packed into the
2937 first 8 bytes of the memory pool so we don't have to keep them in
2938 the decode context. Since the address of the pool may not be
2939 aligned, they have to be packed and unpacked as if they were
2940 serialized data of the wire or such.
2941
2942 The sizes packed in are uint32_t to be the same on all CPU types
2943 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08002944 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002945
2946
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002947static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08002948MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002949{
2950 // Use of UsefulInputBuf is overkill, but it is convenient.
2951 UsefulInputBuf UIB;
2952
Laurence Lundbladeee851742020-01-08 08:37:05 -08002953 // Just assume the size here. It was checked during SetUp so
2954 // the assumption is safe.
Laurence Lundblade93d89472020-10-03 22:30:50 -07002955 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem,QCBOR_DECODE_MIN_MEM_POOL_SIZE});
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002956 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
2957 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
2958 return UsefulInputBuf_GetError(&UIB);
2959}
2960
2961
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002962static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08002963MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002964{
2965 // Use of UsefulOutBuf is overkill, but convenient. The
2966 // length check performed here is useful.
2967 UsefulOutBuf UOB;
2968
2969 UsefulOutBuf_Init(&UOB, Pool);
2970 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
2971 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
2972 return UsefulOutBuf_GetError(&UOB);
2973}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002974
2975
2976/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002977 Internal function for an allocation, reallocation free and destuct.
2978
2979 Having only one function rather than one each per mode saves space in
2980 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002981
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002982 Code Reviewers: THIS FUNCTION DOES POINTER MATH
2983 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08002984static UsefulBuf
2985MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002986{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002987 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002988
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002989 uint32_t uPoolSize;
2990 uint32_t uFreeOffset;
2991
2992 if(uNewSize > UINT32_MAX) {
2993 // This allocator is only good up to 4GB. This check should
2994 // optimize out if sizeof(size_t) == sizeof(uint32_t)
2995 goto Done;
2996 }
2997 const uint32_t uNewSize32 = (uint32_t)uNewSize;
2998
2999 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
3000 goto Done;
3001 }
3002
3003 if(uNewSize) {
3004 if(pMem) {
3005 // REALLOCATION MODE
3006 // Calculate pointer to the end of the memory pool. It is
3007 // assumed that pPool + uPoolSize won't wrap around by
3008 // assuming the caller won't pass a pool buffer in that is
3009 // not in legitimate memory space.
3010 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
3011
3012 // Check that the pointer for reallocation is in the range of the
3013 // pool. This also makes sure that pointer math further down
3014 // doesn't wrap under or over.
3015 if(pMem >= pPool && pMem < pPoolEnd) {
3016 // Offset to start of chunk for reallocation. This won't
3017 // wrap under because of check that pMem >= pPool. Cast
3018 // is safe because the pool is always less than UINT32_MAX
3019 // because of check in QCBORDecode_SetMemPool().
3020 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3021
3022 // Check to see if the allocation will fit. uPoolSize -
3023 // uMemOffset will not wrap under because of check that
3024 // pMem is in the range of the uPoolSize by check above.
3025 if(uNewSize <= uPoolSize - uMemOffset) {
3026 ReturnValue.ptr = pMem;
3027 ReturnValue.len = uNewSize;
3028
3029 // Addition won't wrap around over because uNewSize was
3030 // checked to be sure it is less than the pool size.
3031 uFreeOffset = uMemOffset + uNewSize32;
3032 }
3033 }
3034 } else {
3035 // ALLOCATION MODE
3036 // uPoolSize - uFreeOffset will not underflow because this
3037 // pool implementation makes sure uFreeOffset is always
3038 // smaller than uPoolSize through this check here and
3039 // reallocation case.
3040 if(uNewSize <= uPoolSize - uFreeOffset) {
3041 ReturnValue.len = uNewSize;
3042 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08003043 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003044 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003045 }
3046 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003047 if(pMem) {
3048 // FREE MODE
3049 // Cast is safe because of limit on pool size in
3050 // QCBORDecode_SetMemPool()
3051 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3052 } else {
3053 // DESTRUCT MODE
3054 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003055 }
3056 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003057
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003058 UsefulBuf Pool = {pPool, uPoolSize};
3059 MemPool_Pack(Pool, uFreeOffset);
3060
3061Done:
3062 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003063}
3064
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003065
Laurence Lundbladef6531662018-12-04 10:42:22 +09003066/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003067 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09003068 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003069QCBORError
3070QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
3071 UsefulBuf Pool,
3072 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003073{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003074 // The pool size and free mem offset are packed into the beginning
Dave Thaler93c01182022-08-06 15:08:35 -04003075 // of the pool memory. This compile time check makes sure the
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003076 // constant in the header is correct. This check should optimize
3077 // down to nothing.
Dave Thaler93c01182022-08-06 15:08:35 -04003078#ifdef _MSC_VER
3079#pragma warning(push)
3080#pragma warning(disable:4127) // conditional expression is constant
3081#endif
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003082 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003083 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003084 }
Dave Thaler93c01182022-08-06 15:08:35 -04003085#ifdef _MSC_VER
3086#pragma warning(pop)
3087#endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003088
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003089 // The pool size and free offset packed in to the beginning of pool
3090 // memory are only 32-bits. This check will optimize out on 32-bit
3091 // machines.
3092 if(Pool.len > UINT32_MAX) {
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 Lundblade1d7eb632019-02-17 17:23:38 -08003096 // This checks that the pool buffer given is big enough.
3097 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003098 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003099 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003100
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003101 QCBORDecode_SetUpAllocator(pMe, MemPool_Function, Pool.ptr, bAllStrings);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003102
Laurence Lundblade30816f22018-11-10 13:40:22 +07003103 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003104}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003105#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003106
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003107
3108
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003109static void
3110QCBORDecode_Private_CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07003111{
Laurence Lundblade37286c02022-09-03 10:05:02 -07003112#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade9b334962020-08-27 10:55:53 -07003113 memcpy(pMe->uLastTags, pItem->uTags, sizeof(pItem->uTags));
Laurence Lundblade37286c02022-09-03 10:05:02 -07003114#else
3115 (void)pMe;
3116 (void)pItem;
3117#endif
Laurence Lundblade9b334962020-08-27 10:55:53 -07003118}
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003119
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003120
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003121/**
3122 * @brief Consume an entire map or array including its contents.
3123 *
3124 * @param[in] pMe The decoder context.
3125 * @param[in] pItemToConsume The array/map whose contents are to be
3126 * consumed.
3127 * @param[out] puNextNestLevel The next nesting level after the item was
3128 * fully consumed.
3129 *
3130 * This may be called when @c pItemToConsume is not an array or
3131 * map. In that case, this is just a pass through for @c puNextNestLevel
3132 * since there is nothing to do.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003133 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003134static QCBORError
3135QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
3136 const QCBORItem *pItemToConsume,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003137 bool *pbBreak,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003138 uint8_t *puNextNestLevel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003139{
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003140 QCBORError uReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003141 QCBORItem Item;
Laurence Lundblade9b334962020-08-27 10:55:53 -07003142
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003143 /* If it is a map or array, this will tell if it is empty. */
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003144 const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel);
3145
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003146 if(QCBORItem_IsMapOrArray(*pItemToConsume) && !bIsEmpty) {
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003147 /* There is only real work to do for non-empty maps and arrays */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003148
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003149 /* This works for definite- and indefinite-length maps and
3150 * arrays by using the nesting level
Laurence Lundblade1341c592020-04-11 14:19:05 -07003151 */
3152 do {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003153 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pbBreak, &Item);
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003154 if(QCBORDecode_IsUnrecoverableError(uReturn) ||
3155 uReturn == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003156 goto Done;
3157 }
3158 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003159
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003160 *puNextNestLevel = Item.uNextNestLevel;
3161
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003162 uReturn = QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003163
Laurence Lundblade1341c592020-04-11 14:19:05 -07003164 } else {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003165 /* pItemToConsume is not a map or array. Just pass the nesting
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003166 * level through. */
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003167 *puNextNestLevel = pItemToConsume->uNextNestLevel;
3168
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003169 uReturn = QCBOR_SUCCESS;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003170 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003171
3172Done:
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003173 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003174}
3175
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003176
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003177/*
3178 * Public function, see header qcbor/qcbor_decode.h file
3179 */
3180void
3181QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003182{
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003183 QCBORDecode_VGetNext(pMe, pDecodedItem);
3184
3185 if(pMe->uLastError == QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003186 pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL,
Máté Tóth-Pálc6d59682021-05-26 18:55:30 +02003187 &pDecodedItem->uNextNestLevel);
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003188 }
3189}
3190
3191
Laurence Lundblade11654912024-05-09 11:49:24 -07003192/*
3193 * Public function, see header qcbor/qcbor_decode.h file
3194 */
3195uint32_t
3196QCBORDecode_Tell(QCBORDecodeContext *pMe)
3197{
3198 size_t uCursorOffset;
3199
3200 if(pMe->uLastError != QCBOR_SUCCESS) {
3201 return UINT32_MAX;
3202 }
3203
3204 uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
3205
3206 if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
3207 return UINT32_MAX;
3208 } else {
3209 /* Cast is safe because decoder input size is restricted. */
3210 return (uint32_t)uCursorOffset;
3211 }
3212}
3213
3214
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003215/**
3216 * @brief Rewind cursor to start as if map or array were just entered.
3217 *
3218 * @param[in] pMe The decoding context
3219 *
3220 * This affects the nesting tracking and the UsefulInputBuf.
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003221 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003222static void
3223QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003224{
3225 /* Reset nesting tracking to the deepest bounded level */
3226 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3227
3228 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3229
3230 /* Reposition traversal cursor to the start of the map/array */
3231 UsefulInputBuf_Seek(&(pMe->InBuf),
3232 DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
3233}
3234
3235
3236/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003237 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003238 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003239void
3240QCBORDecode_Rewind(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003241{
3242 if(pMe->nesting.pCurrentBounded != NULL) {
3243 /* In a bounded map, array or bstr-wrapped CBOR */
3244
3245 if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
3246 /* In bstr-wrapped CBOR. */
3247
3248 /* Reposition traversal cursor to start of wrapping byte string */
3249 UsefulInputBuf_Seek(&(pMe->InBuf),
3250 pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
3251 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3252
3253 } else {
3254 /* In a map or array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003255 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003256 }
3257
3258 } else {
3259 /* Not in anything bounded */
3260
3261 /* Reposition traversal cursor to the start of input CBOR */
3262 UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
3263
3264 /* Reset nesting tracking to beginning of input. */
3265 DecodeNesting_Init(&(pMe->nesting));
3266 }
3267
3268 pMe->uLastError = QCBOR_SUCCESS;
3269}
3270
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003271
Laurence Lundblade9b334962020-08-27 10:55:53 -07003272
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003273
3274
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003275typedef struct {
3276 void *pCBContext;
3277 QCBORItemCallback pfCallback;
3278} MapSearchCallBack;
3279
3280typedef struct {
3281 size_t uStartOffset;
3282 uint16_t uItemCount;
3283} MapSearchInfo;
3284
3285
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003286/**
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003287 * @brief Search a map for a set of items.
3288 *
3289 * @param[in] pMe The decode context to search.
3290 * @param[in,out] pItemArray The items to search for and the items found.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003291 * @param[out] pInfo Several bits of meta-info returned by search.
3292 * @param[in] pCallBack Callback object or @c NULL.
3293 * TODO: fix params
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003294 *
3295 * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map.
3296 *
3297 * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label)
3298 * were found for one of the labels being
3299 * search for. This duplicate detection is
3300 * only performed for items in pItemArray,
3301 * not every item in the map.
3302 *
3303 * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was
3304 * wrong for the matchd label.
3305 *
3306 * @retval Also errors returned by QCBORDecode_GetNext().
3307 *
3308 * On input, \c pItemArray contains a list of labels and data types of
3309 * items to be found.
3310 *
3311 * On output, the fully retrieved items are filled in with values and
3312 * such. The label was matched, so it never changes.
3313 *
3314 * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE.
3315 *
3316 * This also finds the ends of maps and arrays when they are exited.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003317 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003318static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003319QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
3320 QCBORItem *pItemArray,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003321 MapSearchInfo *pInfo,
3322 MapSearchCallBack *pCallBack)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003323{
Laurence Lundbladee6f15112020-07-23 18:44:16 -07003324 QCBORError uReturn;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003325 uint64_t uFoundItemBitMap = 0;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07003326
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003327 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003328 uReturn = pMe->uLastError;
3329 goto Done2;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003330 }
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003331
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003332 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) &&
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003333 pItemArray->uLabelType != QCBOR_TYPE_NONE) {
3334 /* QCBOR_TYPE_NONE as first item indicates just looking
3335 for the end of an array, so don't give error. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003336 uReturn = QCBOR_ERR_MAP_NOT_ENTERED;
3337 goto Done2;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003338 }
3339
Laurence Lundblade085d7952020-07-24 10:26:30 -07003340 if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) {
3341 // It is an empty bounded array or map
3342 if(pItemArray->uLabelType == QCBOR_TYPE_NONE) {
3343 // Just trying to find the end of the map or array
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003344 pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003345 uReturn = QCBOR_SUCCESS;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003346 } else {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003347 // Nothing is ever found in an empty array or map. All items
3348 // are marked as not found below.
Laurence Lundblade085d7952020-07-24 10:26:30 -07003349 uReturn = QCBOR_SUCCESS;
3350 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003351 goto Done2;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003352 }
3353
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003354 QCBORDecodeNesting SaveNesting;
Laurence Lundblade11654912024-05-09 11:49:24 -07003355 size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003356 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3357
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003358 /* Reposition to search from the start of the map / array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003359 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundblade1341c592020-04-11 14:19:05 -07003360
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003361 /*
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003362 Loop over all the items in the map or array. Each item
3363 could be a map or array, but label matching is only at
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003364 the main level. This handles definite- and indefinite-
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003365 length maps and arrays. The only reason this is ever
3366 called on arrays is to find their end position.
3367
3368 This will always run over all items in order to do
3369 duplicate detection.
3370
3371 This will exit with failure if it encounters an
3372 unrecoverable error, but continue on for recoverable
3373 errors.
3374
3375 If a recoverable error occurs on a matched item, then
3376 that error code is returned.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003377 */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07003378 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003379 if(pInfo) {
3380 pInfo->uItemCount = 0;
3381 }
Máté Tóth-Pál2f2aa5f2021-05-17 21:35:09 +02003382 uint8_t uNextNestLevel;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003383 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003384 /* Remember offset of the item because sometimes it has to be returned */
Laurence Lundblade1341c592020-04-11 14:19:05 -07003385 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003386
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003387 /* Get the item */
3388 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003389 QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003390 if(QCBORDecode_IsUnrecoverableError(uResult)) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003391 /* The map/array can't be decoded when unrecoverable errors occur */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003392 uReturn = uResult;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003393 goto Done;
3394 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003395 if(uResult == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003396 /* Unexpected end of map or array. */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003397 uReturn = uResult;
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003398 goto Done;
3399 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003400
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003401 /* See if item has one of the labels that are of interest */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003402 bool bMatched = false;
3403 for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003404 if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003405 /* A label match has been found */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003406 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
3407 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003408 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003409 }
Laurence Lundblade63926052021-03-29 16:05:51 -07003410 if(uResult != QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003411 /* The label matches, but the data item is in error.
3412 * It is OK to have recoverable errors on items that are not
3413 * matched. */
Laurence Lundblade63926052021-03-29 16:05:51 -07003414 uReturn = uResult;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003415 goto Done;
3416 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003417 if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) {
Laurence Lundblade63926052021-03-29 16:05:51 -07003418 /* The data item is not of the type(s) requested */
3419 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003420 goto Done;
3421 }
3422
Laurence Lundblade1341c592020-04-11 14:19:05 -07003423 /* Successful match. Return the item. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003424 pItemArray[nIndex] = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003425 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003426 if(pInfo) {
3427 pInfo->uStartOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003428 }
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003429 bMatched = true;
3430 }
3431 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003432
3433
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003434 if(!bMatched && pCallBack != NULL) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003435 /*
3436 Call the callback on unmatched labels.
3437 (It is tempting to do duplicate detection here, but that would
3438 require dynamic memory allocation because the number of labels
3439 that might be encountered is unbounded.)
3440 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003441 uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item);
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003442 if(uReturn != QCBOR_SUCCESS) {
3443 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003444 }
3445 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003446
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003447 /*
3448 Consume the item whether matched or not. This
3449 does the work of traversing maps and array and
3450 everything in them. In this loop only the
3451 items at the current nesting level are examined
3452 to match the labels.
3453 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003454 uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel);
Laurence Lundbladec7114722020-08-13 05:11:40 -07003455 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003456 goto Done;
3457 }
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003458
3459 if(pInfo) {
3460 pInfo->uItemCount++;
3461 }
3462
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003463 } while (uNextNestLevel >= uMapNestLevel);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003464
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003465 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003466
3467 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003468
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003469 // Check here makes sure that this won't accidentally be
3470 // QCBOR_MAP_OFFSET_CACHE_INVALID which is larger than
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003471 // QCBOR_MAX_DECODE_INPUT_SIZE.
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -08003472 // Cast to uint32_t to possibly address cases where SIZE_MAX < UINT32_MAX
3473 if((uint32_t)uEndOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003474 uReturn = QCBOR_ERR_INPUT_TOO_LARGE;
3475 goto Done;
3476 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003477 /* Cast OK because encoded CBOR is limited to UINT32_MAX */
3478 pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003479
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003480 Done:
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003481 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade11654912024-05-09 11:49:24 -07003482 UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos);
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003483
3484 Done2:
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003485 /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */
Laurence Lundbladec7114722020-08-13 05:11:40 -07003486 for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003487 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003488 pItemArray[i].uDataType = QCBOR_TYPE_NONE;
3489 pItemArray[i].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003490 }
3491 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003492
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003493 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003494}
3495
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003496
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003497/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003498 * Public function, see header qcbor/qcbor_decode.h file
3499 */
3500void
3501QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
3502 int64_t nLabel,
3503 uint8_t uQcborType,
3504 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003505{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003506 if(pMe->uLastError != QCBOR_SUCCESS) {
3507 return;
3508 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003509
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003510 QCBORItem OneItemSeach[2];
3511 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3512 OneItemSeach[0].label.int64 = nLabel;
3513 OneItemSeach[0].uDataType = uQcborType;
3514 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003515
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003516 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003517
3518 *pItem = OneItemSeach[0];
3519
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003520 if(uReturn != QCBOR_SUCCESS) {
3521 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003522 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003523 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003524 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003525 }
3526
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003527 Done:
3528 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003529}
3530
3531
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003532/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003533 * Public function, see header qcbor/qcbor_decode.h file
3534 */
3535void
3536QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
3537 const char *szLabel,
3538 uint8_t uQcborType,
3539 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003540{
Laurence Lundbladeda095972020-06-06 18:35:33 -07003541 if(pMe->uLastError != QCBOR_SUCCESS) {
3542 return;
3543 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003544
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003545 QCBORItem OneItemSeach[2];
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003546 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3547 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3548 OneItemSeach[0].uDataType = uQcborType;
3549 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003550
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003551 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
3552
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003553 if(uReturn != QCBOR_SUCCESS) {
3554 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003555 }
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003556 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003557 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003558 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003559 }
3560
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003561 *pItem = OneItemSeach[0];
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003562
3563Done:
3564 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 Lundblade62cae932024-06-03 13:16:17 -07003618#endif
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 Lundbladebb87be22020-04-09 19:15:32 -07004034{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004035 QCBORItem OneItemSeach[2];
4036 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4037 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4038 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4039 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004040
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004041 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004042}
4043
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004044/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004045 * Public function, see header qcbor/qcbor_decode.h file
4046 */
4047void
4048QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07004049{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004050 QCBORItem OneItemSeach[2];
4051 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4052 OneItemSeach[0].label.int64 = nLabel;
4053 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4054 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004055
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004056 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07004057}
4058
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004059/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004060 * Public function, see header qcbor/qcbor_decode.h file
4061 */
4062void
4063QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundblade34691b92020-05-18 22:25:25 -07004064{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004065 QCBORItem OneItemSeach[2];
4066 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4067 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4068 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4069 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004070
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004071 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade1341c592020-04-11 14:19:05 -07004072}
4073
4074
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004075/**
4076 * @brief Semi-private to do the the work for EnterMap() and EnterArray().
4077 *
4078 * @param[in] pMe The decode context
4079 * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY.
4080 * @param[out] pItem The data item for the map or array entered.
4081 *
4082 * The next item in the traversal must be a map or array. This
4083 * consumes that item and does the book keeping to enter the map or
4084 * array.
4085 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004086void
4087QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe,
4088 const uint8_t uType,
4089 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004090{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004091 QCBORError uErr;
4092
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004093 /* Must only be called on maps and arrays. */
Laurence Lundblade34691b92020-05-18 22:25:25 -07004094 if(pMe->uLastError != QCBOR_SUCCESS) {
4095 // Already in error state; do nothing.
4096 return;
4097 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07004098
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004099 /* Get the data item that is the map or array being entered. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004100 QCBORItem Item;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004101 uErr = QCBORDecode_GetNext(pMe, &Item);
4102 if(uErr != QCBOR_SUCCESS) {
4103 goto Done;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07004104 }
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004105
4106 uint8_t uItemDataType = Item.uDataType;
Laurence Lundblade62cae932024-06-03 13:16:17 -07004107#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004108 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) {
4109 uItemDataType = QCBOR_TYPE_ARRAY;
4110 }
Laurence Lundblade62cae932024-06-03 13:16:17 -07004111#endif
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004112 if(uItemDataType != uType) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004113 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
4114 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004115 }
4116
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004117 QCBORDecode_Private_CopyTags(pMe, &Item);
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004118
4119
Laurence Lundbladef0499502020-08-01 11:55:57 -07004120 const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
Laurence Lundblade085d7952020-07-24 10:26:30 -07004121 if(bIsEmpty) {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004122 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
4123 // Undo decrement done by QCBORDecode_GetNext() so the the
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004124 // the decrement when exiting the map/array works correctly
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004125 pMe->nesting.pCurrent->u.ma.uCountCursor++;
4126 }
Laurence Lundblade93d89472020-10-03 22:30:50 -07004127 // Special case to increment nesting level for zero-length maps
4128 // and arrays entered in bounded mode.
Laurence Lundbladee6f15112020-07-23 18:44:16 -07004129 DecodeNesting_Descend(&(pMe->nesting), uType);
4130 }
4131
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004132 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004133
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004134 uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty,
4135 UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004136
Laurence Lundblade6545d1b2020-10-14 11:13:13 -07004137 if(pItem != NULL) {
4138 *pItem = Item;
4139 }
4140
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004141Done:
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004142 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004143}
4144
Laurence Lundblade02625d42020-06-25 14:41:41 -07004145
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004146/**
4147 * @brief Exit a bounded map, array or bstr (semi-private).
4148 *
4149 * @param[in] pMe Decode context.
4150 * @param[in] uEndOffset The input buffer offset of the end of item exited.
4151 *
4152 * @returns QCBOR_SUCCESS or an error code.
4153 *
4154 * This is the common work for exiting a level that is a bounded map,
4155 * array or bstr wrapped CBOR.
4156 *
4157 * One chunk of work is to set up the pre-order traversal so it is at
4158 * the item just after the bounded map, array or bstr that is being
4159 * exited. This is somewhat complex.
4160 *
4161 * The other work is to level-up the bounded mode to next higest
4162 * bounded mode or the top level if there isn't one.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004163 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004164static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004165QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
4166 const uint32_t uEndOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004167{
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004168 QCBORError uErr;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004169
Laurence Lundblade02625d42020-06-25 14:41:41 -07004170 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004171 * First the pre-order-traversal byte offset is positioned to the
4172 * item just after the bounded mode item that was just consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004173 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004174 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
4175
Laurence Lundblade02625d42020-06-25 14:41:41 -07004176 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004177 * Next, set the current nesting level to one above the bounded
4178 * level that was just exited.
4179 *
4180 * DecodeNesting_CheckBoundedType() is always called before this
4181 * and makes sure pCurrentBounded is valid.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004182 */
4183 DecodeNesting_LevelUpCurrent(&(pMe->nesting));
4184
4185 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004186 * This does the complex work of leveling up the pre-order
4187 * traversal when the end of a map or array or another bounded
4188 * level is reached. It may do nothing, or ascend all the way to
4189 * the top level.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004190 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004191 uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004192 if(uErr != QCBOR_SUCCESS) {
4193 goto Done;
4194 }
4195
Laurence Lundblade02625d42020-06-25 14:41:41 -07004196 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004197 * This makes the next highest bounded level the current bounded
4198 * level. If there is no next highest level, then no bounded mode
4199 * is in effect.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004200 */
4201 DecodeNesting_LevelUpBounded(&(pMe->nesting));
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004202
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004203 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004204
4205Done:
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004206 return uErr;
4207}
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004208
Laurence Lundblade02625d42020-06-25 14:41:41 -07004209
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004210/**
4211 * @brief Get started exiting a map or array (semi-private)
4212 *
4213 * @param[in] pMe The decode context
4214 * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP
4215 *
4216 * This does some work for map and array exiting (but not
4217 * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel()
4218 * is called to do the rest.
4219 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004220void
4221QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe,
4222 const uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004223{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004224 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07004225 /* Already in error state; do nothing. */
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004226 return;
4227 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004228
Laurence Lundblade02625d42020-06-25 14:41:41 -07004229 QCBORError uErr;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004230
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004231 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004232 uErr = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004233 goto Done;
4234 }
4235
Laurence Lundblade02625d42020-06-25 14:41:41 -07004236 /*
4237 Have to set the offset to the end of the map/array
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004238 that is being exited. If there is no cached value,
Laurence Lundblade02625d42020-06-25 14:41:41 -07004239 from previous map search, then do a dummy search.
4240 */
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004241 if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004242 QCBORItem Dummy;
4243 Dummy.uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004244 uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL);
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004245 if(uErr != QCBOR_SUCCESS) {
4246 goto Done;
4247 }
4248 }
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004249
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004250 uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004251
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004252Done:
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004253 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004254}
4255
4256
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004257/**
4258 * @brief The main work of entering some byte-string wrapped CBOR.
4259 *
4260 * @param[in] pMe The decode context.
4261 * @param[in] pItem The byte string item.
4262 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX
4263 * @param[out] pBstr Pointer and length of byte string entered.
4264 *
4265 * This is called once the byte string item has been decoded to do all
4266 * the book keeping work for descending a nesting level into the
4267 * nested CBOR.
4268 *
4269 * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement.
4270 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004271static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004272QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe,
4273 const QCBORItem *pItem,
4274 const uint8_t uTagRequirement,
4275 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004276{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004277 if(pBstr) {
4278 *pBstr = NULLUsefulBufC;
4279 }
4280
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004281 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004282 /* Already in error state; do nothing. */
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004283 return pMe->uLastError;
4284 }
4285
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004286 QCBORError uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004287
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004288 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004289 {
4290 uTagRequirement,
4291 {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE},
4292 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4293 };
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004294
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004295 uError = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004296 if(uError != QCBOR_SUCCESS) {
4297 goto Done;
4298 }
4299
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004300 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004301 /* Reverse the decrement done by GetNext() for the bstr so the
4302 * increment in QCBORDecode_NestLevelAscender() called by
4303 * ExitBoundedLevel() will work right.
4304 */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004305 DecodeNesting_ReverseDecrement(&(pMe->nesting));
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07004306 }
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004307
4308 if(pBstr) {
4309 *pBstr = pItem->val.string;
4310 }
4311
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004312 /* This saves the current length of the UsefulInputBuf and then
4313 * narrows the UsefulInputBuf to start and length of the wrapped
4314 * CBOR that is being entered.
4315 *
4316 * Most of these calls are simple inline accessors so this doesn't
4317 * amount to much code.
4318 */
4319
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004320 const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004321 /* This check makes the cast of uPreviousLength to uint32_t below safe. */
4322 if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004323 uError = QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladef76a2622020-08-06 19:51:03 -07004324 goto Done;
4325 }
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004326
4327 const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
4328 pItem->val.string.ptr);
4329 /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
4330 if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
4331 /* This should never happen because pItem->val.string.ptr should
4332 * always be valid since it was just returned.
4333 */
4334 uError = QCBOR_ERR_INPUT_TOO_LARGE;
4335 goto Done;
4336 }
4337
4338 const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
4339
4340 UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004341 UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004342
Laurence Lundblade02625d42020-06-25 14:41:41 -07004343 uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004344 (uint32_t)uPreviousLength,
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004345 (uint32_t)uStartOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004346Done:
4347 return uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004348}
4349
4350
Laurence Lundblade02625d42020-06-25 14:41:41 -07004351/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004352 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004353 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004354void
4355QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe,
4356 const uint8_t uTagRequirement,
4357 UsefulBufC *pBstr)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004358{
4359 if(pMe->uLastError != QCBOR_SUCCESS) {
4360 // Already in error state; do nothing.
4361 return;
4362 }
4363
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004364 /* Get the data item that is the byte string being entered */
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004365 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004366 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4367 if(pMe->uLastError != QCBOR_SUCCESS) {
4368 return;
4369 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004370
Laurence Lundblade31fddb72024-05-13 13:03:35 -07004371 if(Item.uDataAlloc) {
4372 pMe->uLastError = QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
4373 return;
4374 }
4375
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004376 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4377 &Item,
4378 uTagRequirement,
4379 pBstr);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004380}
4381
4382
Laurence Lundblade02625d42020-06-25 14:41:41 -07004383/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004384 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004385 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004386void
4387QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe,
4388 const int64_t nLabel,
4389 const uint8_t uTagRequirement,
4390 UsefulBufC *pBstr)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004391{
4392 QCBORItem Item;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004393 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004394
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004395 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4396 &Item,
4397 uTagRequirement,
4398 pBstr);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004399}
4400
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004401
Laurence Lundblade02625d42020-06-25 14:41:41 -07004402/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004403 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004404 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004405void
4406QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe,
4407 const char *szLabel,
4408 const uint8_t uTagRequirement,
4409 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004410{
4411 QCBORItem Item;
4412 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4413
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004414 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4415 &Item,
4416 uTagRequirement,
4417 pBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004418}
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004419
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004420
Laurence Lundblade02625d42020-06-25 14:41:41 -07004421/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004422 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004423 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004424void
4425QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004426{
Laurence Lundblade02625d42020-06-25 14:41:41 -07004427 if(pMe->uLastError != QCBOR_SUCCESS) {
4428 // Already in error state; do nothing.
4429 return;
4430 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004431
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004432 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004433 pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade02625d42020-06-25 14:41:41 -07004434 return;
4435 }
4436
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004437 const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
4438
Laurence Lundblade02625d42020-06-25 14:41:41 -07004439 /*
4440 Reset the length of the UsefulInputBuf to what it was before
4441 the bstr wrapped CBOR was entered.
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004442 */
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004443 UsefulInputBuf_SetBufferLength(&(pMe->InBuf),
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004444 DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004445
4446
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004447 QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004448 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004449}
4450
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004451
Laurence Lundbladee6430642020-03-14 21:15:44 -07004452
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004453/**
4454 * @brief Process simple type true and false, a boolean
4455 *
4456 * @param[in] pMe The decode context.
4457 * @param[in] pItem The item with either true or false.
4458 * @param[out] pBool The boolean value output.
4459 *
4460 * Sets the internal error if the item isn't a true or a false. Also
4461 * records any tag numbers as the tag numbers of the last item.
4462 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004463static void
4464QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe,
4465 const QCBORItem *pItem,
4466 bool *pBool)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004467{
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004468 if(pMe->uLastError != QCBOR_SUCCESS) {
4469 /* Already in error state, do nothing */
4470 return;
4471 }
4472
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004473 switch(pItem->uDataType) {
4474 case QCBOR_TYPE_TRUE:
4475 *pBool = true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004476 break;
4477
4478 case QCBOR_TYPE_FALSE:
4479 *pBool = false;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004480 break;
4481
4482 default:
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004483 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004484 break;
4485 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004486 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004487}
Laurence Lundbladee6430642020-03-14 21:15:44 -07004488
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004489
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004490/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004491 * Public function, see header qcbor/qcbor_decode.h file
4492 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004493void
4494QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004495{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004496 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004497 /* Already in error state, do nothing */
Laurence Lundbladee6430642020-03-14 21:15:44 -07004498 return;
4499 }
4500
Laurence Lundbladec4537442020-04-14 18:53:22 -07004501 QCBORItem Item;
4502
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004503 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4504
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004505 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004506}
4507
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004508
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004509/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004510 * Public function, see header qcbor/qcbor_decode.h file
4511 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004512void
4513QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe,
4514 const int64_t nLabel,
4515 bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004516{
4517 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004518 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004519
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004520 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004521}
4522
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004523
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004524/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004525 * Public function, see header qcbor/qcbor_decode.h file
4526 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004527void
4528QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe,
4529 const char *szLabel,
4530 bool *pValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004531{
4532 QCBORItem Item;
4533 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4534
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004535 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004536}
4537
4538
4539
Laurence Lundbladec7114722020-08-13 05:11:40 -07004540
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004541/**
4542 * @brief Common processing for an epoch date.
4543 *
4544 * @param[in] pMe The decode context.
4545 * @param[in] pItem The item with the date.
4546 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4547 * @param[out] pnTime The returned date.
4548 *
4549 * Common processing for the date tag. Mostly make sure the tag
4550 * content is correct and copy forward any further other tag numbers.
4551 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004552static void
4553QCBORDecode_Private_ProcessEpochDate(QCBORDecodeContext *pMe,
4554 QCBORItem *pItem,
4555 const uint8_t uTagRequirement,
4556 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004557{
4558 if(pMe->uLastError != QCBOR_SUCCESS) {
4559 // Already in error state, do nothing
4560 return;
4561 }
4562
4563 QCBORError uErr;
4564
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004565 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladec7114722020-08-13 05:11:40 -07004566 {
4567 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004568 {QCBOR_TYPE_DATE_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4569 {QCBOR_TYPE_INT64, QCBOR_TYPE_DOUBLE, QCBOR_TYPE_FLOAT, QCBOR_TYPE_UINT64}
Laurence Lundbladec7114722020-08-13 05:11:40 -07004570 };
4571
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004572 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004573 if(uErr != QCBOR_SUCCESS) {
4574 goto Done;
4575 }
4576
4577 if(pItem->uDataType != QCBOR_TYPE_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004578 uErr = QCBOR_Private_DecodeDateEpoch(pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004579 if(uErr != QCBOR_SUCCESS) {
4580 goto Done;
4581 }
4582 }
4583
Laurence Lundblade9b334962020-08-27 10:55:53 -07004584 // Save the tags in the last item's tags in the decode context
4585 // for QCBORDecode_GetNthTagOfLast()
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004586 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07004587
Laurence Lundbladec7114722020-08-13 05:11:40 -07004588 *pnTime = pItem->val.epochDate.nSeconds;
4589
4590Done:
4591 pMe->uLastError = (uint8_t)uErr;
4592}
4593
4594
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004595
4596/*
4597 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4598 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004599void
4600QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
4601 uint8_t uTagRequirement,
4602 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004603{
4604 if(pMe->uLastError != QCBOR_SUCCESS) {
4605 // Already in error state, do nothing
4606 return;
4607 }
4608
4609 QCBORItem Item;
4610 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4611
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004612 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004613}
4614
4615
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004616/*
4617 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4618 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07004619void
4620QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
4621 int64_t nLabel,
4622 uint8_t uTagRequirement,
4623 int64_t *pnTime)
4624{
4625 QCBORItem Item;
4626 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004627 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004628}
4629
4630
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004631/*
4632 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4633 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07004634void
4635QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
4636 const char *szLabel,
4637 uint8_t uTagRequirement,
4638 int64_t *pnTime)
4639{
4640 QCBORItem Item;
4641 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004642 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004643}
4644
4645
4646
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004647/**
4648 * @brief Common processing for an epoch date.
4649 *
4650 * @param[in] pMe The decode context.
4651 * @param[in] pItem The item with the date.
4652 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4653 * @param[out] pnDays The returned day count.
4654 *
4655 * Common processing for the RFC 8943 day-count tag. Mostly make sure
4656 * the tag content is correct and copy forward any further other tag
4657 * numbers.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004658 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004659static void
4660QCBORDecode_Private_ProcessEpochDays(QCBORDecodeContext *pMe,
4661 QCBORItem *pItem,
4662 uint8_t uTagRequirement,
4663 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004664{
4665 if(pMe->uLastError != QCBOR_SUCCESS) {
4666 /* Already in error state, do nothing */
4667 return;
4668 }
4669
4670 QCBORError uErr;
4671
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004672 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004673 {
4674 uTagRequirement,
4675 {QCBOR_TYPE_DAYS_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4676 {QCBOR_TYPE_INT64, QCBOR_TYPE_UINT64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4677 };
4678
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004679 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004680 if(uErr != QCBOR_SUCCESS) {
4681 goto Done;
4682 }
4683
4684 if(pItem->uDataType != QCBOR_TYPE_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004685 uErr = QCBOR_Private_DecodeDaysEpoch(pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004686 if(uErr != QCBOR_SUCCESS) {
4687 goto Done;
4688 }
4689 }
4690
4691 /* Save the tags in the last item's tags in the decode context
4692 * for QCBORDecode_GetNthTagOfLast()
4693 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004694 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004695
4696 *pnDays = pItem->val.epochDays;
4697
4698Done:
4699 pMe->uLastError = (uint8_t)uErr;
4700}
4701
4702
4703/*
4704 * Public function, see header qcbor/qcbor_decode.h
4705 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004706void
4707QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe,
4708 uint8_t uTagRequirement,
4709 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004710{
4711 if(pMe->uLastError != QCBOR_SUCCESS) {
4712 /* Already in error state, do nothing */
4713 return;
4714 }
4715
4716 QCBORItem Item;
4717 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4718
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004719 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004720}
4721
4722
4723/*
4724 * Public function, see header qcbor/qcbor_decode.h
4725 */
4726void
4727QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe,
4728 int64_t nLabel,
4729 uint8_t uTagRequirement,
4730 int64_t *pnDays)
4731{
4732 QCBORItem Item;
4733 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004734 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004735}
4736
4737
4738/*
4739 * Public function, see header qcbor/qcbor_decode.h
4740 */
4741void
4742QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe,
4743 const char *szLabel,
4744 uint8_t uTagRequirement,
4745 int64_t *pnDays)
4746{
4747 QCBORItem Item;
4748 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004749 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004750}
4751
4752
4753
Laurence Lundblade37286c02022-09-03 10:05:02 -07004754/*
4755 * @brief Get a string that matches the type/tag specification.
4756 */
4757void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004758QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
4759 const QCBOR_Private_TagSpec TagSpec,
4760 UsefulBufC *pBstr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004761{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004762 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade37286c02022-09-03 10:05:02 -07004763 /* Already in error state, do nothing */
Laurence Lundbladec4537442020-04-14 18:53:22 -07004764 return;
4765 }
4766
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004767 QCBORError uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004768 QCBORItem Item;
4769
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004770 uError = QCBORDecode_GetNext(pMe, &Item);
4771 if(uError != QCBOR_SUCCESS) {
4772 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004773 return;
4774 }
4775
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004776 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004777
4778 if(pMe->uLastError == QCBOR_SUCCESS) {
4779 *pBstr = Item.val.string;
Laurence Lundbladeab40c6f2020-08-28 11:24:58 -07004780 } else {
4781 *pBstr = NULLUsefulBufC;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004782 }
4783}
4784
Laurence Lundbladec4537442020-04-14 18:53:22 -07004785
4786
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004787
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004788/**
4789 * @brief Common processing for a big number tag.
4790 *
4791 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4792 * @param[in] pItem The item with the date.
4793 * @param[out] pValue The returned big number
4794 * @param[out] pbIsNegative The returned sign of the big number.
4795 *
4796 * Common processing for the big number tag. Mostly make sure
4797 * the tag content is correct and copy forward any further other tag
4798 * numbers.
4799 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004800static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004801QCBOR_Private_ProcessBigNum(const uint8_t uTagRequirement,
4802 const QCBORItem *pItem,
4803 UsefulBufC *pValue,
4804 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004805{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004806 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004807 {
4808 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004809 {QCBOR_TYPE_POSBIGNUM, QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4810 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004811 };
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004812
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004813 QCBORError uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004814 if(uErr != QCBOR_SUCCESS) {
4815 return uErr;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004816 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004817
4818 *pValue = pItem->val.string;
4819
4820 if(pItem->uDataType == QCBOR_TYPE_POSBIGNUM) {
4821 *pbIsNegative = false;
4822 } else if(pItem->uDataType == QCBOR_TYPE_NEGBIGNUM) {
4823 *pbIsNegative = true;
4824 }
4825
4826 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004827}
4828
4829
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004830/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004831 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004832 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004833void
4834QCBORDecode_GetBignum(QCBORDecodeContext *pMe,
4835 const uint8_t uTagRequirement,
4836 UsefulBufC *pValue,
4837 bool *pbIsNegative)
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004838{
4839 if(pMe->uLastError != QCBOR_SUCCESS) {
4840 // Already in error state, do nothing
4841 return;
4842 }
4843
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004844 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004845 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
4846 if(uError != QCBOR_SUCCESS) {
4847 pMe->uLastError = (uint8_t)uError;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004848 return;
4849 }
4850
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004851 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4852 &Item,
4853 pValue,
4854 pbIsNegative);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004855}
4856
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004857
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004858/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004859 * Public function, see header qcbor/qcbor_spiffy_decode.h
4860 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004861void
4862QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe,
4863 const int64_t nLabel,
4864 const uint8_t uTagRequirement,
4865 UsefulBufC *pValue,
4866 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004867{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004868 QCBORItem Item;
4869 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004870 if(pMe->uLastError != QCBOR_SUCCESS) {
4871 return;
4872 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004873
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004874 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4875 &Item,
4876 pValue,
4877 pbIsNegative);
Laurence Lundbladec4537442020-04-14 18:53:22 -07004878}
4879
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004880
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004881/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004882 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004883 */
4884void
4885QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe,
4886 const char *szLabel,
4887 const uint8_t uTagRequirement,
4888 UsefulBufC *pValue,
4889 bool *pbIsNegative)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004890{
4891 QCBORItem Item;
4892 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004893 if(pMe->uLastError != QCBOR_SUCCESS) {
4894 return;
4895 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004896
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004897 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4898 &Item,
4899 pValue,
4900 pbIsNegative);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004901}
4902
4903
4904
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004905/**
4906 * @brief Common processing for MIME tag (semi-private).
4907 *
4908 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4909 * @param[in] pItem The item with the date.
4910 * @param[out] pMessage The returned MIME message.
4911 * @param[out] pbIsTag257 If true, binary MIME, if not, text MIME.
4912 *
4913 * Common processing for the MIME tag. Mostly make sure the tag
4914 * content is correct and copy forward any further other tag
4915 * numbers. See QCBORDecode_GetMIMEMessage().
4916 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004917QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004918QCBORDecode_Private_GetMIME(const uint8_t uTagRequirement,
Laurence Lundblade37286c02022-09-03 10:05:02 -07004919 const QCBORItem *pItem,
4920 UsefulBufC *pMessage,
4921 bool *pbIsTag257)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004922{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004923 const QCBOR_Private_TagSpec TagSpecText =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004924 {
4925 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004926 {QCBOR_TYPE_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4927 {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004928 };
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004929 const QCBOR_Private_TagSpec TagSpecBinary =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004930 {
4931 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004932 {QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4933 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004934 };
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004935
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004936 QCBORError uReturn;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004937
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004938 if(QCBOR_Private_CheckTagRequirement(TagSpecText, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004939 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07004940 if(pbIsTag257 != NULL) {
4941 *pbIsTag257 = false;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004942 }
4943 uReturn = QCBOR_SUCCESS;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004944 } else if(QCBOR_Private_CheckTagRequirement(TagSpecBinary, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004945 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07004946 if(pbIsTag257 != NULL) {
4947 *pbIsTag257 = true;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004948 }
4949 uReturn = QCBOR_SUCCESS;
4950
4951 } else {
4952 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
4953 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07004954
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004955 return uReturn;
4956}
4957
Laurence Lundblade93d89472020-10-03 22:30:50 -07004958// Improvement: add methods for wrapped CBOR, a simple alternate
4959// to EnterBstrWrapped
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004960
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004961
4962
4963
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07004964#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundbladee6430642020-03-14 21:15:44 -07004965
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004966/**
4967 * @brief Prototype for conversion of exponent and mantissa to unsigned integer.
4968 *
4969 * @param[in] uMantissa The mantissa.
4970 * @param[in] nExponent The exponent.
4971 * @param[out] puResult The resulting integer.
4972 *
4973 * Concrete implementations of this are for exponent base 10 and 2 supporting
4974 * decimal fractions and big floats.
4975 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004976typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004977
4978
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004979/**
4980 * @brief Base 10 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
4981 *
4982 * @param[in] uMantissa The unsigned integer mantissa.
4983 * @param[in] nExponent The signed integer exponent.
4984 * @param[out] puResult Place to return the unsigned integer result.
4985 *
4986 * This computes: mantissa * 10 ^^ exponent as for a decimal fraction. The output is a 64-bit
4987 * unsigned integer.
4988 *
4989 * There are many inputs for which the result will not fit in the
4990 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
4991 * be returned.
4992 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07004993static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004994QCBOR_Private_Exponentitate10(const uint64_t uMantissa,
4995 int64_t nExponent,
4996 uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004997{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07004998 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004999
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005000 if(uResult != 0) {
5001 /* This loop will run a maximum of 19 times because
5002 * UINT64_MAX < 10 ^^ 19. More than that will cause
5003 * exit with the overflow error
5004 */
5005 for(; nExponent > 0; nExponent--) {
5006 if(uResult > UINT64_MAX / 10) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005007 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005008 }
5009 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005010 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005011
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005012 for(; nExponent < 0; nExponent++) {
5013 uResult = uResult / 10;
5014 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005015 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005016 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005017 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005018 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005019 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07005020
5021 *puResult = uResult;
5022
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005023 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005024}
5025
5026
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005027/**
5028 * @brief Base 2 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5029 *
5030 * @param[in] uMantissa The unsigned integer mantissa.
5031 * @param[in] nExponent The signed integer exponent.
5032 * @param[out] puResult Place to return the unsigned integer result.
5033 *
5034 * This computes: mantissa * 2 ^^ exponent as for a big float. The
5035 * output is a 64-bit unsigned integer.
5036 *
5037 * There are many inputs for which the result will not fit in the
5038 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5039 * be returned.
5040 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005041static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005042QCBOR_Private_Exponentitate2(const uint64_t uMantissa,
5043 int64_t nExponent,
5044 uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005045{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005046 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005047
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005048 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005049
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005050 /* This loop will run a maximum of 64 times because INT64_MAX <
5051 * 2^31. More than that will cause exit with the overflow error
Laurence Lundbladee6430642020-03-14 21:15:44 -07005052 */
5053 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005054 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005055 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005056 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005057 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005058 nExponent--;
5059 }
5060
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005061 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005062 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005063 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005064 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005065 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005066 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005067 }
5068
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005069 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005070
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005071 return QCBOR_SUCCESS;
5072}
5073
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005074
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005075/**
5076 * @brief Exponentiate a signed mantissa and signed exponent to produce a signed result.
5077 *
5078 * @param[in] nMantissa Signed integer mantissa.
5079 * @param[in] nExponent Signed integer exponent.
5080 * @param[out] pnResult Place to put the signed integer result.
5081 * @param[in] pfExp Exponentiation function.
5082 *
5083 * @returns Error code
5084 *
5085 * \c pfExp performs exponentiation on and unsigned mantissa and
5086 * produces an unsigned result. This converts the mantissa from signed
5087 * and converts the result to signed. The exponentiation function is
5088 * either for base 2 or base 10 (and could be other if needed).
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005089 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005090static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005091QCBOR_Private_ExponentiateNN(const int64_t nMantissa,
5092 const int64_t nExponent,
5093 int64_t *pnResult,
5094 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005095{
5096 uint64_t uResult;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005097 uint64_t uMantissa;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005098
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005099 /* Take the absolute value and put it into an unsigned. */
5100 if(nMantissa >= 0) {
5101 /* Positive case is straightforward */
5102 uMantissa = (uint64_t)nMantissa;
5103 } else if(nMantissa != INT64_MIN) {
5104 /* The common negative case. See next. */
5105 uMantissa = (uint64_t)-nMantissa;
5106 } else {
5107 /* int64_t and uint64_t are always two's complement per the
5108 * C standard (and since QCBOR uses these it only works with
5109 * two's complement, which is pretty much universal these
5110 * days). The range of a negative two's complement integer is
5111 * one more that than a positive, so the simple code above might
5112 * not work all the time because you can't simply negate the
5113 * value INT64_MIN because it can't be represented in an
5114 * int64_t. -INT64_MIN can however be represented in a
5115 * uint64_t. Some compilers seem to recognize this case for the
5116 * above code and put the correct value in uMantissa, however
5117 * they are not required to do this by the C standard. This next
5118 * line does however work for all compilers.
5119 *
5120 * This does assume two's complement where -INT64_MIN ==
5121 * INT64_MAX + 1 (which wouldn't be true for one's complement or
5122 * sign and magnitude (but we know we're using two's complement
5123 * because int64_t requires it)).
5124 *
5125 * See these, particularly the detailed commentary:
5126 * https://stackoverflow.com/questions/54915742/does-c99-mandate-a-int64-t-type-be-available-always
5127 * https://stackoverflow.com/questions/37301078/is-negating-int-min-undefined-behaviour
5128 */
5129 uMantissa = (uint64_t)INT64_MAX+1;
5130 }
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005131
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005132 /* Call the exponentiator passed for either base 2 or base 10.
5133 * Here is where most of the overflow errors are caught. */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005134 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
5135 if(uReturn) {
5136 return uReturn;
5137 }
5138
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005139 /* Convert back to the sign of the original mantissa */
5140 if(nMantissa >= 0) {
5141 if(uResult > INT64_MAX) {
5142 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5143 }
5144 *pnResult = (int64_t)uResult;
5145 } else {
5146 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
5147 * of INT64_MIN. This assumes two's compliment representation
5148 * where INT64_MIN is one increment farther from 0 than
5149 * INT64_MAX. Trying to write -INT64_MIN doesn't work to get
5150 * this because the compiler makes it an int64_t which can't
5151 * represent -INT64_MIN. Also see above.
5152 */
5153 if(uResult > (uint64_t)INT64_MAX+1) {
5154 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5155 }
5156 *pnResult = -(int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005157 }
5158
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005159 return QCBOR_SUCCESS;
5160}
5161
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005162
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005163/**
5164 * @brief Exponentiate an unsigned mantissa and signed exponent to produce an unsigned result.
5165 *
5166 * @param[in] nMantissa Signed integer mantissa.
5167 * @param[in] nExponent Signed integer exponent.
5168 * @param[out] puResult Place to put the signed integer result.
5169 * @param[in] pfExp Exponentiation function.
5170 *
5171 * @returns Error code
5172 *
5173 * \c pfExp performs exponentiation on and unsigned mantissa and
5174 * produces an unsigned result. This errors out if the mantissa
5175 * is negative because the output is unsigned.
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005176 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005177static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005178QCBOR_Private_ExponentitateNU(const int64_t nMantissa,
5179 const int64_t nExponent,
5180 uint64_t *puResult,
5181 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005182{
5183 if(nMantissa < 0) {
5184 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5185 }
5186
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005187 /* Cast to unsigned is OK because of check for negative.
5188 * Cast to unsigned is OK because UINT64_MAX > INT64_MAX.
5189 * Exponentiation is straight forward
5190 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005191 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
5192}
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005193
5194
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005195/**
5196 * @brief Exponentiate an usnigned mantissa and unsigned exponent to produce an unsigned result.
5197 *
5198 * @param[in] uMantissa Unsigned integer mantissa.
5199 * @param[in] nExponent Unsigned integer exponent.
5200 * @param[out] puResult Place to put the unsigned integer result.
5201 * @param[in] pfExp Exponentiation function.
5202 *
5203 * @returns Error code
5204 *
5205 * \c pfExp performs exponentiation on and unsigned mantissa and
5206 * produces an unsigned result so this is just a wrapper that does
5207 * nothing (and is likely inlined).
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005208 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005209static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005210QCBOR_Private_ExponentitateUU(const uint64_t uMantissa,
5211 const int64_t nExponent,
5212 uint64_t *puResult,
5213 fExponentiator pfExp)
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005214{
5215 return (*pfExp)(uMantissa, nExponent, puResult);
5216}
5217
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005218#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005219
5220
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005221
5222
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005223/**
5224 * @brief Convert a CBOR big number to a uint64_t.
5225 *
5226 * @param[in] BigNum Bytes of the big number to convert.
5227 * @param[in] uMax Maximum value allowed for the result.
5228 * @param[out] pResult Place to put the unsigned integer result.
5229 *
5230 * @returns Error code
5231 *
5232 * Many values will overflow because a big num can represent a much
5233 * larger range than uint64_t.
5234 */
5235static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005236QCBOR_Private_ConvertBigNumToUnsigned(const UsefulBufC BigNum,
5237 const uint64_t uMax,
5238 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005239{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005240 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005241
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005242 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005243 const uint8_t *pByte = BigNum.ptr;
5244 size_t uLen = BigNum.len;
5245 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07005246 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005247 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005248 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07005249 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005250 }
5251
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005252 *pResult = uResult;
5253 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005254}
5255
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005256
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005257/**
5258 * @brief Convert a CBOR postive big number to a uint64_t.
5259 *
5260 * @param[in] BigNum Bytes of the big number to convert.
5261 * @param[out] pResult Place to put the unsigned integer result.
5262 *
5263 * @returns Error code
5264 *
5265 * Many values will overflow because a big num can represent a much
5266 * larger range than uint64_t.
5267 */
5268static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005269QCBOR_Private_ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum,
5270 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005271{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005272 return QCBOR_Private_ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005273}
5274
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005275
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005276/**
5277 * @brief Convert a CBOR positive big number to an int64_t.
5278 *
5279 * @param[in] BigNum Bytes of the big number to convert.
5280 * @param[out] pResult Place to put the signed integer result.
5281 *
5282 * @returns Error code
5283 *
5284 * Many values will overflow because a big num can represent a much
5285 * larger range than int64_t.
5286 */
5287static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005288QCBOR_Private_ConvertPositiveBigNumToSigned(const UsefulBufC BigNum,
5289 int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005290{
5291 uint64_t uResult;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005292 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5293 INT64_MAX,
5294 &uResult);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005295 if(uError) {
5296 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005297 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005298 /* Cast is safe because ConvertBigNumToUnsigned limits to INT64_MAX */
Laurence Lundbladee6430642020-03-14 21:15:44 -07005299 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005300 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005301}
5302
5303
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005304/**
5305 * @brief Convert a CBOR negative big number to an int64_t.
5306 *
5307 * @param[in] BigNum Bytes of the big number to convert.
5308 * @param[out] pnResult Place to put the signed integer result.
5309 *
5310 * @returns Error code
5311 *
5312 * Many values will overflow because a big num can represent a much
5313 * larger range than int64_t.
5314 */
5315static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005316QCBOR_Private_ConvertNegativeBigNumToSigned(const UsefulBufC BigNum,
5317 int64_t *pnResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005318{
5319 uint64_t uResult;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005320 /* The negative integer furthest from zero for a C int64_t is
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005321 * INT64_MIN which is expressed as -INT64_MAX - 1. The value of a
5322 * negative number in CBOR is computed as -n - 1 where n is the
5323 * encoded integer, where n is what is in the variable BigNum. When
5324 * converting BigNum to a uint64_t, the maximum value is thus
5325 * INT64_MAX, so that when it -n - 1 is applied to it the result
5326 * will never be further from 0 than INT64_MIN.
5327 *
5328 * -n - 1 <= INT64_MIN.
5329 * -n - 1 <= -INT64_MAX - 1
5330 * n <= INT64_MAX.
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005331 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005332 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5333 INT64_MAX,
5334 &uResult);
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005335 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005336 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005337 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005338
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005339 /* Now apply -n - 1. The cast is safe because
5340 * ConvertBigNumToUnsigned() is limited to INT64_MAX which does fit
5341 * is the largest positive integer that an int64_t can
5342 * represent. */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005343 *pnResult = -(int64_t)uResult - 1;
5344
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005345 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005346}
5347
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005348
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005349
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005350
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005351/**
5352 * @brief Convert integers and floats to an int64_t.
5353 *
5354 * @param[in] pItem The item to convert.
5355 * @param[in] uConvertTypes Bit mask list of conversion options.
5356 * @param[out] pnValue The resulting converted value.
5357 *
5358 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5359 * in uConvertTypes.
5360 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5361 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5362 * or too small.
5363 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005364static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005365QCBOR_Private_ConvertInt64(const QCBORItem *pItem,
5366 const uint32_t uConvertTypes,
5367 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005368{
5369 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005370 case QCBOR_TYPE_FLOAT:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005371 case QCBOR_TYPE_DOUBLE:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005372#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005373 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005374 /* https://pubs.opengroup.org/onlinepubs/009695399/functions/llround.html
5375 http://www.cplusplus.com/reference/cmath/llround/
5376 */
5377 // Not interested in FE_INEXACT
5378 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005379 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5380 *pnValue = llround(pItem->val.dfnum);
5381 } else {
5382 *pnValue = lroundf(pItem->val.fnum);
5383 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005384 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5385 // llround() shouldn't result in divide by zero, but catch
5386 // it here in case it unexpectedly does. Don't try to
5387 // distinguish between the various exceptions because it seems
5388 // they vary by CPU, compiler and OS.
5389 return QCBOR_ERR_FLOAT_EXCEPTION;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005390 }
5391 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005392 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005393 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005394#else
5395 return QCBOR_ERR_HW_FLOAT_DISABLED;
5396#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005397 break;
5398
5399 case QCBOR_TYPE_INT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005400 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005401 *pnValue = pItem->val.int64;
5402 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005403 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005404 }
5405 break;
5406
5407 case QCBOR_TYPE_UINT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005408 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005409 if(pItem->val.uint64 < INT64_MAX) {
5410 *pnValue = pItem->val.int64;
5411 } else {
5412 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5413 }
5414 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005415 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005416 }
5417 break;
5418
5419 default:
5420 return QCBOR_ERR_UNEXPECTED_TYPE;
5421 }
5422 return QCBOR_SUCCESS;
5423}
5424
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005425
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005426/**
5427 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5428 *
5429 * @param[in] pMe The decode context.
5430 * @param[in] uConvertTypes Bit mask list of conversion options.
5431 * @param[out] pnValue Result of the conversion.
5432 * @param[in,out] pItem Temporary space to store Item, returned item.
5433 *
5434 * See QCBORDecode_GetInt64Convert().
5435 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005436void
5437QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pMe,
5438 uint32_t uConvertTypes,
5439 int64_t *pnValue,
5440 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005441{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07005442 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005443 return;
5444 }
5445
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005446 QCBORError uError = QCBORDecode_GetNext(pMe, pItem);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005447 if(uError) {
5448 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005449 return;
5450 }
5451
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005452 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005453 uConvertTypes,
5454 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005455}
5456
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005457/**
5458 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5459 *
5460 * @param[in] pMe The decode context.
5461 * @param[in] nLabel Label to find in map.
5462 * @param[in] uConvertTypes Bit mask list of conversion options.
5463 * @param[out] pnValue Result of the conversion.
5464 * @param[in,out] pItem Temporary space to store Item, returned item.
5465 *
5466 * See QCBORDecode_GetInt64ConvertInMapN().
5467 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005468void
5469QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pMe,
5470 int64_t nLabel,
5471 uint32_t uConvertTypes,
5472 int64_t *pnValue,
5473 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005474{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005475 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005476 if(pMe->uLastError != QCBOR_SUCCESS) {
5477 return;
5478 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005479
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005480 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5481 uConvertTypes,
5482 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005483}
5484
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005485/**
5486 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5487 *
5488 * @param[in] pMe The decode context.
5489 * @param[in] szLabel Label to find in map.
5490 * @param[in] uConvertTypes Bit mask list of conversion options.
5491 * @param[out] pnValue Result of the conversion.
5492 * @param[in,out] pItem Temporary space to store Item, returned item.
5493 *
5494 * See QCBORDecode_GetInt64ConvertInMapSZ().
5495 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005496void
5497QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5498 const char * szLabel,
5499 uint32_t uConvertTypes,
5500 int64_t *pnValue,
5501 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005502{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005503 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005504 if(pMe->uLastError != QCBOR_SUCCESS) {
5505 return;
5506 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005507
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005508 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5509 uConvertTypes,
5510 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005511}
5512
5513
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005514/**
5515 * @brief Convert many number types to an int64_t.
5516 *
5517 * @param[in] pItem The item to convert.
5518 * @param[in] uConvertTypes Bit mask list of conversion options.
5519 * @param[out] pnValue The resulting converted value.
5520 *
5521 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5522 * in uConvertTypes.
5523 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5524 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5525 * or too small.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005526 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005527static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005528QCBOR_Private_Int64ConvertAll(const QCBORItem *pItem,
5529 const uint32_t uConvertTypes,
5530 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005531{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005532 switch(pItem->uDataType) {
5533
5534 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005535 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005536 return QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005537 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005538 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005539 }
5540 break;
5541
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005542 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005543 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005544 return QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005545 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005546 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005547 }
5548 break;
5549
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005550#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005551 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005552 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005553 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005554 pItem->val.expAndMantissa.nExponent,
5555 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005556 &QCBOR_Private_Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005557 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005558 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005559 }
5560 break;
5561
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005562 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005563 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005564 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005565 pItem->val.expAndMantissa.nExponent,
5566 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005567 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005568 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005569 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005570 }
5571 break;
5572
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005573 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005574 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005575 int64_t nMantissa;
5576 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005577 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005578 if(uErr) {
5579 return uErr;
5580 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005581 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005582 pItem->val.expAndMantissa.nExponent,
5583 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005584 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005585 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005586 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005587 }
5588 break;
5589
5590 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005591 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005592 int64_t nMantissa;
5593 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005594 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005595 if(uErr) {
5596 return uErr;
5597 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005598 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005599 pItem->val.expAndMantissa.nExponent,
5600 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005601 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005602 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005603 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005604 }
5605 break;
5606
5607 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005608 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005609 int64_t nMantissa;
5610 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005611 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005612 if(uErr) {
5613 return uErr;
5614 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005615 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005616 pItem->val.expAndMantissa.nExponent,
5617 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005618 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005619 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005620 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005621 }
5622 break;
5623
5624 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005625 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005626 int64_t nMantissa;
5627 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005628 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005629 if(uErr) {
5630 return uErr;
5631 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005632 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005633 pItem->val.expAndMantissa.nExponent,
5634 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005635 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005636 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005637 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005638 }
5639 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005640#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005641
Laurence Lundbladee6430642020-03-14 21:15:44 -07005642
Laurence Lundbladec4537442020-04-14 18:53:22 -07005643 default:
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005644 return QCBOR_ERR_UNEXPECTED_TYPE; }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005645}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005646
5647
Laurence Lundbladec4537442020-04-14 18:53:22 -07005648/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005649 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005650 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005651void
5652QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe,
5653 const uint32_t uConvertTypes,
5654 int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005655{
5656 QCBORItem Item;
5657
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005658 QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005659
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005660 if(pMe->uLastError == QCBOR_SUCCESS) {
5661 // The above conversion succeeded
5662 return;
5663 }
5664
Laurence Lundbladef6c86662020-05-12 02:08:00 -07005665 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005666 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07005667 return;
5668 }
5669
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005670 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5671 uConvertTypes,
5672 pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005673}
5674
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005675
5676/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005677 * Public function, see header qcbor/qcbor_decode.h file
5678 */
5679void
5680QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
5681 const int64_t nLabel,
5682 const uint32_t uConvertTypes,
5683 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005684{
5685 QCBORItem Item;
5686
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005687 QCBORDecode_Private_GetInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07005688 nLabel,
5689 uConvertTypes,
5690 pnValue,
5691 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005692
5693 if(pMe->uLastError == QCBOR_SUCCESS) {
5694 // The above conversion succeeded
5695 return;
5696 }
5697
5698 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5699 // The above conversion failed in a way that code below can't correct
5700 return;
5701 }
5702
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005703 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5704 uConvertTypes,
5705 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005706}
5707
5708
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005709/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005710 * Public function, see header qcbor/qcbor_decode.h file
5711 */
5712void
5713QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
5714 const char *szLabel,
5715 const uint32_t uConvertTypes,
5716 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005717{
5718 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005719 QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07005720 szLabel,
5721 uConvertTypes,
5722 pnValue,
5723 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005724
5725 if(pMe->uLastError == QCBOR_SUCCESS) {
5726 // The above conversion succeeded
5727 return;
5728 }
5729
5730 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5731 // The above conversion failed in a way that code below can't correct
5732 return;
5733 }
5734
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005735 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5736 uConvertTypes,
5737 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005738}
5739
5740
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005741/**
5742 * @brief Convert many number types to an uint64_t.
5743 *
5744 * @param[in] pItem The item to convert.
5745 * @param[in] uConvertTypes Bit mask list of conversion options.
5746 * @param[out] puValue The resulting converted value.
5747 *
5748 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5749 * in uConvertTypes.
5750 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5751 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5752 * or too small.
5753 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005754static QCBORError
5755QCBOR_Private_ConvertUInt64(const QCBORItem *pItem,
5756 const uint32_t uConvertTypes,
5757 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005758{
5759 switch(pItem->uDataType) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005760 case QCBOR_TYPE_DOUBLE:
5761 case QCBOR_TYPE_FLOAT:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005762#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005763 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005764 // Can't use llround here because it will not convert values
5765 // greater than INT64_MAX and less than UINT64_MAX that
5766 // need to be converted so it is more complicated.
5767 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
5768 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5769 if(isnan(pItem->val.dfnum)) {
5770 return QCBOR_ERR_FLOAT_EXCEPTION;
5771 } else if(pItem->val.dfnum < 0) {
5772 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5773 } else {
5774 double dRounded = round(pItem->val.dfnum);
5775 // See discussion in DecodeDateEpoch() for
5776 // explanation of - 0x7ff
5777 if(dRounded > (double)(UINT64_MAX- 0x7ff)) {
5778 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5779 }
5780 *puValue = (uint64_t)dRounded;
5781 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005782 } else {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005783 if(isnan(pItem->val.fnum)) {
5784 return QCBOR_ERR_FLOAT_EXCEPTION;
5785 } else if(pItem->val.fnum < 0) {
5786 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5787 } else {
5788 float fRounded = roundf(pItem->val.fnum);
5789 // See discussion in DecodeDateEpoch() for
5790 // explanation of - 0x7ff
5791 if(fRounded > (float)(UINT64_MAX- 0x7ff)) {
5792 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5793 }
5794 *puValue = (uint64_t)fRounded;
5795 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005796 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005797 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5798 // round() and roundf() shouldn't result in exceptions here, but
5799 // catch them to be robust and thorough. Don't try to
5800 // distinguish between the various exceptions because it seems
5801 // they vary by CPU, compiler and OS.
5802 return QCBOR_ERR_FLOAT_EXCEPTION;
5803 }
5804
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005805 } else {
5806 return QCBOR_ERR_UNEXPECTED_TYPE;
5807 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005808#else
5809 return QCBOR_ERR_HW_FLOAT_DISABLED;
5810#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005811 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005812
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005813 case QCBOR_TYPE_INT64:
5814 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
5815 if(pItem->val.int64 >= 0) {
5816 *puValue = (uint64_t)pItem->val.int64;
5817 } else {
5818 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5819 }
5820 } else {
5821 return QCBOR_ERR_UNEXPECTED_TYPE;
5822 }
5823 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005824
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005825 case QCBOR_TYPE_UINT64:
5826 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
5827 *puValue = pItem->val.uint64;
5828 } else {
5829 return QCBOR_ERR_UNEXPECTED_TYPE;
5830 }
5831 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005832
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005833 default:
5834 return QCBOR_ERR_UNEXPECTED_TYPE;
5835 }
5836
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005837 return QCBOR_SUCCESS;
5838}
Laurence Lundbladec4537442020-04-14 18:53:22 -07005839
5840
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005841/**
5842 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5843 *
5844 * @param[in] pMe The decode context.
5845 * @param[in] uConvertTypes Bit mask list of conversion options.
5846 * @param[out] puValue Result of the conversion.
5847 * @param[in,out] pItem Temporary space to store Item, returned item.
5848 *
5849 * See QCBORDecode_GetUInt64Convert().
5850 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005851void
5852QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pMe,
5853 const uint32_t uConvertTypes,
5854 uint64_t *puValue,
5855 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005856{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005857 if(pMe->uLastError != QCBOR_SUCCESS) {
5858 return;
5859 }
5860
Laurence Lundbladec4537442020-04-14 18:53:22 -07005861 QCBORItem Item;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005862
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005863 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
5864 if(uError) {
5865 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005866 return;
5867 }
5868
Laurence Lundbladea826c502020-05-10 21:07:00 -07005869 if(pItem) {
5870 *pItem = Item;
5871 }
5872
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005873 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(&Item,
5874 uConvertTypes,
5875 puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005876}
5877
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005878
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005879/**
5880 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5881 *
5882 * @param[in] pMe The decode context.
5883 * @param[in] nLabel Label to find in map.
5884 * @param[in] uConvertTypes Bit mask list of conversion options.
5885 * @param[out] puValue Result of the conversion.
5886 * @param[in,out] pItem Temporary space to store Item, returned item.
5887 *
5888 * See QCBORDecode_GetUInt64ConvertInMapN().
5889 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005890void
5891QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe,
5892 const int64_t nLabel,
5893 const uint32_t uConvertTypes,
5894 uint64_t *puValue,
5895 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005896{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005897 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005898 if(pMe->uLastError != QCBOR_SUCCESS) {
5899 return;
5900 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005901
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005902 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
5903 uConvertTypes,
5904 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005905}
5906
5907
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005908/**
5909 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5910 *
5911 * @param[in] pMe The decode context.
5912 * @param[in] szLabel Label to find in map.
5913 * @param[in] uConvertTypes Bit mask list of conversion options.
5914 * @param[out] puValue Result of the conversion.
5915 * @param[in,out] pItem Temporary space to store Item, returned item.
5916 *
5917 * See QCBORDecode_GetUInt64ConvertInMapSZ().
5918 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005919void
5920QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5921 const char *szLabel,
5922 const uint32_t uConvertTypes,
5923 uint64_t *puValue,
5924 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005925{
5926 if(pMe->uLastError != QCBOR_SUCCESS) {
5927 return;
5928 }
5929
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005930 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005931 if(pMe->uLastError != QCBOR_SUCCESS) {
5932 return;
5933 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005934
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005935 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
5936 uConvertTypes,
5937 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005938}
5939
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005940
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005941/**
5942 * @brief Convert many number types to an unt64_t.
5943 *
5944 * @param[in] pItem The item to convert.
5945 * @param[in] uConvertTypes Bit mask list of conversion options.
5946 * @param[out] puValue The resulting converted value.
5947 *
5948 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5949 * in uConvertTypes.
5950 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5951 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5952 * or too small.
5953 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005954static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005955QCBOR_Private_UInt64ConvertAll(const QCBORItem *pItem,
5956 const uint32_t uConvertTypes,
5957 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005958{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08005959 switch(pItem->uDataType) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005960
5961 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005962 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005963 return QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005964 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005965 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005966 }
5967 break;
5968
5969 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005970 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005971 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5972 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005973 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005974 }
5975 break;
5976
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005977#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005978
5979 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005980 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005981 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005982 pItem->val.expAndMantissa.nExponent,
5983 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005984 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005985 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005986 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005987 }
5988 break;
5989
5990 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005991 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005992 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005993 pItem->val.expAndMantissa.nExponent,
5994 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005995 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005996 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005997 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005998 }
5999 break;
6000
6001 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006002 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006003 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006004 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006005 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006006 if(uErr != QCBOR_SUCCESS) {
6007 return uErr;
6008 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006009 return QCBOR_Private_ExponentitateUU(uMantissa,
6010 pItem->val.expAndMantissa.nExponent,
6011 puValue,
6012 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006013 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006014 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006015 }
6016 break;
6017
6018 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006019 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006020 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6021 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006022 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006023 }
6024 break;
6025
6026 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006027 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006028 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006029 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006030 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum,
6031 &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006032 if(uErr != QCBOR_SUCCESS) {
6033 return uErr;
6034 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006035 return QCBOR_Private_ExponentitateUU(uMantissa,
6036 pItem->val.expAndMantissa.nExponent,
6037 puValue,
6038 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006039 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006040 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006041 }
6042 break;
6043
6044 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006045 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006046 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6047 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006048 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006049 }
6050 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006051#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006052 default:
6053 return QCBOR_ERR_UNEXPECTED_TYPE;
6054 }
6055}
6056
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006057
Laurence Lundblade4e2da002020-06-13 23:08:31 -07006058/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006059 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006060 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006061void
6062QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe,
6063 const uint32_t uConvertTypes,
6064 uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006065{
6066 QCBORItem Item;
6067
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006068 QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006069
Laurence Lundbladef6c86662020-05-12 02:08:00 -07006070 if(pMe->uLastError == QCBOR_SUCCESS) {
6071 // The above conversion succeeded
6072 return;
6073 }
6074
6075 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6076 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07006077 return;
6078 }
6079
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006080 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6081 uConvertTypes,
6082 puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006083}
6084
Laurence Lundbladec4537442020-04-14 18:53:22 -07006085
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006086/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006087 * Public function, see header qcbor/qcbor_decode.h file
6088 */
6089void
6090QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
6091 const int64_t nLabel,
6092 const uint32_t uConvertTypes,
6093 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006094{
6095 QCBORItem Item;
6096
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006097 QCBORDecode_Private_GetUInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006098 nLabel,
6099 uConvertTypes,
6100 puValue,
6101 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006102
6103 if(pMe->uLastError == QCBOR_SUCCESS) {
6104 // The above conversion succeeded
6105 return;
6106 }
6107
6108 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6109 // The above conversion failed in a way that code below can't correct
6110 return;
6111 }
6112
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006113 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6114 uConvertTypes,
6115 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006116}
6117
6118
6119/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006120 * Public function, see header qcbor/qcbor_decode.h file
6121 */
6122void
6123QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
6124 const char *szLabel,
6125 const uint32_t uConvertTypes,
6126 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006127{
6128 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006129 QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006130 szLabel,
6131 uConvertTypes,
6132 puValue,
6133 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006134
6135 if(pMe->uLastError == QCBOR_SUCCESS) {
6136 // The above conversion succeeded
6137 return;
6138 }
6139
6140 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6141 // The above conversion failed in a way that code below can't correct
6142 return;
6143 }
6144
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006145 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6146 uConvertTypes,
6147 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006148}
6149
6150
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006151
6152
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006153#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006154/**
6155 * @brief Basic conversions to a double.
6156 *
6157 * @param[in] pItem The item to convert
6158 * @param[in] uConvertTypes Bit flags indicating source types for conversion
6159 * @param[out] pdValue The value converted to a double
6160 *
6161 * This does the conversions that don't need much object code,
6162 * the conversions from int, uint and float to double.
6163 *
6164 * See QCBOR_Private_DoubleConvertAll() for the full set
6165 * of conversions.
6166 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006167static QCBORError
6168QCBOR_Private_ConvertDouble(const QCBORItem *pItem,
6169 const uint32_t uConvertTypes,
6170 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006171{
6172 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006173 case QCBOR_TYPE_FLOAT:
6174#ifndef QCBOR_DISABLE_FLOAT_HW_USE
6175 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6176 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006177 // Simple cast does the job.
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006178 *pdValue = (double)pItem->val.fnum;
6179 } else {
6180 return QCBOR_ERR_UNEXPECTED_TYPE;
6181 }
6182 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006183#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006184 return QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006185#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006186 break;
6187
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006188 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006189 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6190 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006191 *pdValue = pItem->val.dfnum;
6192 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006193 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006194 }
6195 }
6196 break;
6197
6198 case QCBOR_TYPE_INT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006199#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006200 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006201 // A simple cast seems to do the job with no worry of exceptions.
6202 // There will be precision loss for some values.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006203 *pdValue = (double)pItem->val.int64;
6204
6205 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006206 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006207 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006208#else
6209 return QCBOR_ERR_HW_FLOAT_DISABLED;
6210#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006211 break;
6212
6213 case QCBOR_TYPE_UINT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006214#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006215 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006216 // A simple cast seems to do the job with no worry of exceptions.
6217 // There will be precision loss for some values.
6218 *pdValue = (double)pItem->val.uint64;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006219 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006220 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006221 }
6222 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006223#else
6224 return QCBOR_ERR_HW_FLOAT_DISABLED;
6225#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006226
6227 default:
6228 return QCBOR_ERR_UNEXPECTED_TYPE;
6229 }
6230
6231 return QCBOR_SUCCESS;
6232}
6233
6234
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006235/**
6236 * @brief Almost-public method to decode a number and convert to double (semi-private).
6237 *
6238 * @param[in] pMe The decode context.
6239 * @param[in] uConvertTypes Bit mask list of conversion options
6240 * @param[out] pdValue The output of the conversion.
6241 * @param[in,out] pItem Temporary space to store Item, returned item.
6242 *
6243 * See QCBORDecode_GetDoubleConvert().
6244 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006245void
6246QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pMe,
6247 const uint32_t uConvertTypes,
6248 double *pdValue,
6249 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07006250{
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006251 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07006252 return;
6253 }
6254
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006255 QCBORError uError = QCBORDecode_GetNext(pMe, pItem);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006256 if(uError) {
6257 pMe->uLastError = (uint8_t)uError;
6258 return;
6259 }
6260
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006261 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006262 uConvertTypes,
6263 pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006264}
Laurence Lundbladec4537442020-04-14 18:53:22 -07006265
Laurence Lundbladec4537442020-04-14 18:53:22 -07006266
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006267/**
6268 * @brief Almost-public method to decode a number and convert to double (semi-private).
6269 *
6270 * @param[in] pMe The decode context.
6271 * @param[in] nLabel Label to find in map.
6272 * @param[in] uConvertTypes Bit mask list of conversion options
6273 * @param[out] pdValue The output of the conversion.
6274 * @param[in,out] pItem Temporary space to store Item, returned item.
6275 *
6276 * See QCBORDecode_GetDoubleConvertInMapN().
6277 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006278void
6279QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pMe,
6280 const int64_t nLabel,
6281 const uint32_t uConvertTypes,
6282 double *pdValue,
6283 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006284{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006285 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006286 if(pMe->uLastError != QCBOR_SUCCESS) {
6287 return;
6288 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006289
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006290 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6291 uConvertTypes,
6292 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006293}
6294
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006295
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006296/**
6297 * @brief Almost-public method to decode a number and convert to double (semi-private).
6298 *
6299 * @param[in] pMe The decode context.
6300 * @param[in] szLabel Label to find in map.
6301 * @param[in] uConvertTypes Bit mask list of conversion options
6302 * @param[out] pdValue The output of the conversion.
6303 * @param[in,out] pItem Temporary space to store Item, returned item.
6304 *
6305 * See QCBORDecode_GetDoubleConvertInMapSZ().
6306 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006307void
6308QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe,
6309 const char *szLabel,
6310 const uint32_t uConvertTypes,
6311 double *pdValue,
6312 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006313{
6314 if(pMe->uLastError != QCBOR_SUCCESS) {
6315 return;
6316 }
6317
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006318 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006319 if(pMe->uLastError != QCBOR_SUCCESS) {
6320 return;
6321 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006322
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006323 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6324 uConvertTypes,
6325 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006326}
6327
6328
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006329#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006330/**
6331 * @brief Convert a big number to double-precision float.
6332 *
6333 * @param[in] BigNum The big number to convert
6334 *
6335 * @returns The double value.
6336 *
6337 * This will always succeed. It will lose precision for larger
6338 * numbers. If the big number is too large to fit (more than
6339 * 1.7976931348623157E+308) infinity will be returned. NaN is never
6340 * returned.
6341 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006342static double
6343QCBOR_Private_ConvertBigNumToDouble(const UsefulBufC BigNum)
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006344{
6345 double dResult;
6346
6347 dResult = 0.0;
6348 const uint8_t *pByte = BigNum.ptr;
6349 size_t uLen = BigNum.len;
6350 /* This will overflow and become the float value INFINITY if the number
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006351 * is too large to fit. */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006352 while(uLen--) {
6353 dResult = (dResult * 256.0) + (double)*pByte++;
6354 }
6355
6356 return dResult;
6357}
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006358#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6359
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006360
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006361
6362
6363/**
6364 * @brief Convert many number types to a double.
6365 *
6366 * @param[in] pItem The item to convert.
6367 * @param[in] uConvertTypes Bit mask list of conversion options.
6368 * @param[out] pdValue The resulting converted value.
6369 *
6370 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6371 * in uConvertTypes.
6372 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6373 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6374 * or too small.
6375 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006376static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006377QCBOR_Private_DoubleConvertAll(const QCBORItem *pItem,
6378 const uint32_t uConvertTypes,
6379 double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006380{
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006381#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07006382 /*
Laurence Lundblade16a207a2021-09-18 17:22:46 -07006383 * What Every Computer Scientist Should Know About Floating-Point Arithmetic
6384 * https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
6385 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006386 switch(pItem->uDataType) {
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006387
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006388#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006389 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006390 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006391 // Underflow gives 0, overflow gives infinity
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006392 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6393 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
6394 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006395 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006396 }
6397 break;
6398
6399 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006400 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006401 // Underflow gives 0, overflow gives infinity
6402 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6403 exp2((double)pItem->val.expAndMantissa.nExponent);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006404 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006405 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006406 }
6407 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006408#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006409
6410 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006411 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006412 *pdValue = QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006413 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006414 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006415 }
6416 break;
6417
6418 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006419 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006420 *pdValue = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006421 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006422 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006423 }
6424 break;
6425
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006426#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006427 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006428 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006429 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006430 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6431 } 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
6436 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006437 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006438 double dMantissa = -QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006439 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6440 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006441 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006442 }
6443 break;
6444
6445 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006446 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006447 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006448 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6449 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006450 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006451 }
6452 break;
6453
6454 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006455 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006456 double dMantissa = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006457 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6458 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006459 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006460 }
6461 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006462#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006463
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006464 default:
6465 return QCBOR_ERR_UNEXPECTED_TYPE;
6466 }
6467
6468 return QCBOR_SUCCESS;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006469
6470#else
6471 (void)pItem;
6472 (void)uConvertTypes;
6473 (void)pdValue;
6474 return QCBOR_ERR_HW_FLOAT_DISABLED;
6475#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6476
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006477}
6478
6479
6480/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006481 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006482 */
6483void
6484QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe,
6485 const uint32_t uConvertTypes,
6486 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006487{
6488
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006489 QCBORItem Item;
6490
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006491 QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006492
6493 if(pMe->uLastError == QCBOR_SUCCESS) {
6494 // The above conversion succeeded
6495 return;
6496 }
6497
6498 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6499 // The above conversion failed in a way that code below can't correct
6500 return;
6501 }
6502
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006503 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6504 uConvertTypes,
6505 pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006506}
6507
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006508
6509/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006510 * Public function, see header qcbor/qcbor_decode.h file
6511 */
6512void
6513QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe,
6514 const int64_t nLabel,
6515 const uint32_t uConvertTypes,
6516 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006517{
6518 QCBORItem Item;
6519
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006520 QCBORDecode_Private_GetDoubleConvertInMapN(pMe,
6521 nLabel,
6522 uConvertTypes,
6523 pdValue,
6524 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006525
6526 if(pMe->uLastError == QCBOR_SUCCESS) {
6527 // The above conversion succeeded
6528 return;
6529 }
6530
6531 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6532 // The above conversion failed in a way that code below can't correct
6533 return;
6534 }
6535
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006536 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6537 uConvertTypes,
6538 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006539}
6540
6541
6542/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006543 * Public function, see header qcbor/qcbor_decode.h file
6544 */
6545void
6546QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe,
6547 const char *szLabel,
6548 const uint32_t uConvertTypes,
6549 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006550{
6551 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006552 QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe,
6553 szLabel,
6554 uConvertTypes,
6555 pdValue,
6556 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006557
6558 if(pMe->uLastError == QCBOR_SUCCESS) {
6559 // The above conversion succeeded
6560 return;
6561 }
6562
6563 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6564 // The above conversion failed in a way that code below can't correct
6565 return;
6566 }
6567
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006568 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6569 uConvertTypes,
6570 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006571}
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006572#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006573
6574
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006575
6576
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006577#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006578/**
6579 * @brief Convert an integer to a big number
6580 *
6581 * @param[in] uInt The integer to convert.
6582 * @param[in] Buffer The buffer to output the big number to.
6583 *
6584 * @returns The big number or NULLUsefulBufC is the buffer is to small.
6585 *
6586 * This always succeeds unless the buffer is too small.
6587 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006588static UsefulBufC
6589QCBOR_Private_ConvertIntToBigNum(uint64_t uInt, const UsefulBuf Buffer)
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006590{
6591 while((uInt & 0xff00000000000000UL) == 0) {
6592 uInt = uInt << 8;
6593 };
6594
6595 UsefulOutBuf UOB;
6596
6597 UsefulOutBuf_Init(&UOB, Buffer);
6598
6599 while(uInt) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006600 UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff00000000000000UL) >> 56));
6601 uInt = uInt << 8;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006602 }
6603
6604 return UsefulOutBuf_OutUBuf(&UOB);
6605}
6606
6607
Laurence Lundblade37286c02022-09-03 10:05:02 -07006608/**
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006609 * @brief Check and/or complete exponent and mantissa item.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006610 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006611 * @param[in] pMe The decoder context.
6612 * @param[in] TagSpec Expected type(s).
6613 * @param[in,out] pItem See below.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006614 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006615 * This is for decimal fractions and big floats, both of which are an
6616 * exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006617 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006618 * If the item item had a tag number indicating it was a
6619 * decimal fraction or big float, then the input @c pItem will
6620 * have been decoded as exponent and mantissa. If there was
6621 * no tag number, the caller is asking this be decoded as a
6622 * big float or decimal fraction and @c pItem just has the
6623 * first item in an exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006624 *
6625 * On output, the item is always a fully decoded decimal fraction or
6626 * big float.
6627 *
6628 * This errors out if the input type does not meet the TagSpec.
6629 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07006630static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006631QCBOR_Private_ExpMantissaTypeHandler(QCBORDecodeContext *pMe,
6632 const QCBOR_Private_TagSpec TagSpec,
6633 QCBORItem *pItem)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006634{
6635 QCBORError uErr;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006636
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006637 /* pItem could either be a decoded exponent and mantissa or
6638 * the opening array of an undecoded exponent and mantissa. This
Laurence Lundblade37286c02022-09-03 10:05:02 -07006639 * check will succeed on either, but doesn't say which it was.
6640 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006641 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07006642 if(uErr != QCBOR_SUCCESS) {
6643 goto Done;
6644 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006645
Laurence Lundblade37286c02022-09-03 10:05:02 -07006646 if(pItem->uDataType == QCBOR_TYPE_ARRAY) {
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006647 /* The item is an array, which means is is an undecoded exponent
6648 * and mantissa. This call consumes the items in the array and
6649 * results in a decoded exponent and mantissa in pItem. This is
Laurence Lundblade37286c02022-09-03 10:05:02 -07006650 * the case where there was no tag.
6651 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006652 uErr = QCBORDecode_Private_ExpMantissa(pMe, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006653 if(uErr != QCBOR_SUCCESS) {
6654 goto Done;
6655 }
6656
Laurence Lundblade37286c02022-09-03 10:05:02 -07006657 /* The above decode didn't determine whether it is a decimal
6658 * fraction or big num. Which of these two depends on what the
6659 * caller wants it decoded as since there is no tag, so fish the
6660 * type out of the TagSpec. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006661 pItem->uDataType = QCBOR_Private_ExpMantissaDataType(TagSpec.uTaggedTypes[0], pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07006662
6663 /* No need to check the type again. All that we need to know was
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006664 * that it decoded correctly as a exponent and mantissa. The
Laurence Lundblade37286c02022-09-03 10:05:02 -07006665 * QCBOR type is set out by what was requested.
6666 */
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006667 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07006668
6669 /* If the item was not an array and the check passed, then
6670 * it is a fully decoded big float or decimal fraction and
6671 * matches what is requested.
6672 */
6673
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006674Done:
6675 return uErr;
6676}
6677
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006678
Laurence Lundblade37286c02022-09-03 10:05:02 -07006679/* Some notes from the work to disable tags.
6680 *
6681 * The API for big floats and decimal fractions seems good.
6682 * If there's any issue with it it's that the code size to
6683 * implement is a bit large because of the conversion
6684 * to/from int and bignum that is required. There is no API
6685 * that doesn't do the conversion so dead stripping will never
6686 * leave that code out.
6687 *
6688 * The implementation itself seems correct, but not as clean
6689 * and neat as it could be. It could probably be smaller too.
6690 *
6691 * The implementation has three main parts / functions
6692 * - The decoding of the array of two
6693 * - All the tag and type checking for the various API functions
6694 * - Conversion to/from bignum and int
6695 *
6696 * The type checking seems like it wastes the most code for
6697 * what it needs to do.
6698 *
6699 * The inlining for the conversion is probably making the
6700 * overall code base larger.
6701 *
6702 * The tests cases could be organized a lot better and be
6703 * more thorough.
6704 *
6705 * Seems also like there could be more common code in the
6706 * first tier part of the public API. Some functions only
6707 * vary by a TagSpec.
6708 */
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006709
6710/**
6711 * @brief Common processor for exponent and mantissa.
6712 *
6713 * @param[in] pMe The decode context.
6714 * @param[in] TagSpec The expected/allowed tags.
6715 * @param[in] pItem The data item to process.
6716 * @param[out] pnMantissa The returned mantissa as an int64_t.
6717 * @param[out] pnExponent The returned exponent as an int64_t.
6718 *
6719 * This handles exponent and mantissa for base 2 and 10. This
6720 * is limited to a mantissa that is an int64_t. See also
6721 * QCBORDecode_Private_ProcessExpMantissaBig().
6722 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006723static void
6724QCBOR_Private_ProcessExpMantissa(QCBORDecodeContext *pMe,
6725 const QCBOR_Private_TagSpec TagSpec,
6726 QCBORItem *pItem,
6727 int64_t *pnMantissa,
6728 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006729{
6730 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006731
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006732 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006733 if(uErr != QCBOR_SUCCESS) {
6734 goto Done;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006735 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006736
Laurence Lundblade9b334962020-08-27 10:55:53 -07006737 switch (pItem->uDataType) {
6738
6739 case QCBOR_TYPE_DECIMAL_FRACTION:
6740 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade9b334962020-08-27 10:55:53 -07006741 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006742 *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
Laurence Lundblade9b334962020-08-27 10:55:53 -07006743 break;
6744
Laurence Lundblade37286c02022-09-03 10:05:02 -07006745#ifndef QCBOR_DISABLE_TAGS
6746 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006747 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
6748 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
6749 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006750 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006751 break;
6752
6753 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
6754 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
6755 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006756 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006757 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006758#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006759
6760 default:
6761 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
6762 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006763
6764 Done:
6765 pMe->uLastError = (uint8_t)uErr;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006766}
6767
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006768
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006769/**
6770 * @brief Decode exponent and mantissa into a big number.
6771 *
6772 * @param[in] pMe The decode context.
6773 * @param[in] TagSpec The expected/allowed tags.
6774 * @param[in] pItem Item to decode and convert.
6775 * @param[in] BufferForMantissa Buffer to output mantissa into.
6776 * @param[out] pMantissa The output mantissa.
6777 * @param[out] pbIsNegative The sign of the output.
6778 * @param[out] pnExponent The mantissa of the output.
6779 *
6780 * This is the common processing of a decimal fraction or a big float
6781 * into a big number. This will decode and consume all the CBOR items
6782 * that make up the decimal fraction or big float.
6783 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006784static void
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006785QCBORDecode_Private_ProcessExpMantissaBig(QCBORDecodeContext *pMe,
6786 const QCBOR_Private_TagSpec TagSpec,
6787 QCBORItem *pItem,
6788 const UsefulBuf BufferForMantissa,
6789 UsefulBufC *pMantissa,
6790 bool *pbIsNegative,
6791 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006792{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006793 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006794
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006795 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006796 if(uErr != QCBOR_SUCCESS) {
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006797 goto Done;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006798 }
6799
6800 uint64_t uMantissa;
6801
6802 switch (pItem->uDataType) {
6803
6804 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006805 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006806 /* See comments in ExponentiateNN() on handling INT64_MIN */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006807 if(pItem->val.expAndMantissa.Mantissa.nInt >= 0) {
6808 uMantissa = (uint64_t)pItem->val.expAndMantissa.Mantissa.nInt;
6809 *pbIsNegative = false;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006810 } else if(pItem->val.expAndMantissa.Mantissa.nInt != INT64_MIN) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006811 uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt;
6812 *pbIsNegative = true;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006813 } else {
6814 uMantissa = (uint64_t)INT64_MAX+1;
6815 *pbIsNegative = true;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006816 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006817 *pMantissa = QCBOR_Private_ConvertIntToBigNum(uMantissa,
6818 BufferForMantissa);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006819 *pnExponent = pItem->val.expAndMantissa.nExponent;
6820 break;
6821
Laurence Lundblade37286c02022-09-03 10:05:02 -07006822#ifndef QCBOR_DISABLE_TAGS
6823 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006824 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006825 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006826 *pnExponent = pItem->val.expAndMantissa.nExponent;
6827 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6828 *pbIsNegative = false;
6829 break;
6830
6831 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006832 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006833 *pnExponent = pItem->val.expAndMantissa.nExponent;
6834 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6835 *pbIsNegative = true;
6836 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006837#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006838
6839 default:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006840 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006841 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006842
6843Done:
6844 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006845}
6846
6847
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006848/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006849 * Public function, see header qcbor/qcbor_decode.h file
6850 */
6851void
6852QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe,
6853 const uint8_t uTagRequirement,
6854 int64_t *pnMantissa,
6855 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006856{
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006857 if(pMe->uLastError != QCBOR_SUCCESS) {
6858 return;
6859 }
6860
6861 QCBORItem Item;
6862 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
6863 if(uError) {
6864 pMe->uLastError = (uint8_t)uError;
6865 return;
6866 }
6867
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006868 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006869 {
6870 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006871 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6872 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6873 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006874 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006875
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006876 QCBOR_Private_ProcessExpMantissa(pMe,
6877 TagSpec,
6878 &Item,
6879 pnMantissa,
6880 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006881}
6882
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006883
6884/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006885 * Public function, see header qcbor/qcbor_decode.h file
6886 */
6887void
6888QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe,
6889 const int64_t nLabel,
6890 const uint8_t uTagRequirement,
6891 int64_t *pnMantissa,
6892 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006893{
6894 if(pMe->uLastError != QCBOR_SUCCESS) {
6895 return;
6896 }
6897
6898 QCBORItem Item;
6899 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
6900
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006901 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006902 {
6903 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006904 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6905 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6906 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006907 };
6908
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006909 QCBOR_Private_ProcessExpMantissa(pMe,
6910 TagSpec,
6911 &Item,
6912 pnMantissa,
6913 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006914}
6915
6916
6917/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006918 * Public function, see header qcbor/qcbor_decode.h file
6919 */
6920void
6921QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
6922 const char *szLabel,
6923 const uint8_t uTagRequirement,
6924 int64_t *pnMantissa,
6925 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006926{
6927 if(pMe->uLastError != QCBOR_SUCCESS) {
6928 return;
6929 }
6930
6931 QCBORItem Item;
6932 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
6933
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006934 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006935 {
6936 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006937 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6938 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6939 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006940 };
Laurence Lundblade9b334962020-08-27 10:55:53 -07006941
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006942 QCBOR_Private_ProcessExpMantissa(pMe,
6943 TagSpec,
6944 &Item,
6945 pnMantissa,
6946 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006947}
6948
6949
6950/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006951 * Public function, see header qcbor/qcbor_decode.h file
6952 */
6953void
6954QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe,
6955 const uint8_t uTagRequirement,
6956 const UsefulBuf MantissaBuffer,
6957 UsefulBufC *pMantissa,
6958 bool *pbMantissaIsNegative,
6959 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006960{
6961 if(pMe->uLastError != QCBOR_SUCCESS) {
6962 return;
6963 }
6964
6965 QCBORItem Item;
6966 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
6967 if(uError) {
6968 pMe->uLastError = (uint8_t)uError;
6969 return;
6970 }
6971
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006972 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006973 {
6974 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006975 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6976 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6977 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006978 };
6979
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006980 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
6981 TagSpec,
6982 &Item,
6983 MantissaBuffer,
6984 pMantissa,
6985 pbMantissaIsNegative,
6986 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006987}
6988
6989
6990/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006991 * Public function, see header qcbor/qcbor_decode.h file
6992 */
6993void
6994QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe,
6995 const int64_t nLabel,
6996 const uint8_t uTagRequirement,
6997 const UsefulBuf BufferForMantissa,
6998 UsefulBufC *pMantissa,
6999 bool *pbIsNegative,
7000 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007001{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007002 if(pMe->uLastError != QCBOR_SUCCESS) {
7003 return;
7004 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007005
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007006 QCBORItem Item;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007007 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007008 if(pMe->uLastError != QCBOR_SUCCESS) {
7009 return;
7010 }
7011
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007012 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007013 {
7014 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007015 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7016 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7017 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007018 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007019
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007020 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7021 TagSpec,
7022 &Item,
7023 BufferForMantissa,
7024 pMantissa,
7025 pbIsNegative,
7026 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007027}
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007028
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007029
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007030/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007031 * Public function, see header qcbor/qcbor_decode.h file
7032 */
7033void
7034QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe,
7035 const char *szLabel,
7036 const uint8_t uTagRequirement,
7037 const UsefulBuf BufferForMantissa,
7038 UsefulBufC *pMantissa,
7039 bool *pbIsNegative,
7040 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007041{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007042 if(pMe->uLastError != QCBOR_SUCCESS) {
7043 return;
7044 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007045
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007046 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007047 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7048 if(pMe->uLastError != QCBOR_SUCCESS) {
7049 return;
7050 }
7051
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007052 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007053 {
7054 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007055 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7056 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7057 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007058 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007059
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007060 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7061 TagSpec,
7062 &Item,
7063 BufferForMantissa,
7064 pMantissa,
7065 pbIsNegative,
7066 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007067}
7068
7069
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007070/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007071 * Public function, see header qcbor/qcbor_decode.h file
7072 */
7073void
7074QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe,
7075 const uint8_t uTagRequirement,
7076 int64_t *pnMantissa,
7077 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007078{
7079 if(pMe->uLastError != QCBOR_SUCCESS) {
7080 return;
7081 }
7082
7083 QCBORItem Item;
7084 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
7085 if(uError) {
7086 pMe->uLastError = (uint8_t)uError;
7087 return;
7088 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007089 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007090 {
7091 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007092 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7093 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7094 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007095 };
7096
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007097 QCBOR_Private_ProcessExpMantissa(pMe,
7098 TagSpec,
7099 &Item,
7100 pnMantissa,
7101 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007102}
7103
7104
7105/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007106 * Public function, see header qcbor/qcbor_decode.h file
7107 */
7108void
7109QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe,
7110 const int64_t nLabel,
7111 const uint8_t uTagRequirement,
7112 int64_t *pnMantissa,
7113 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007114{
7115 if(pMe->uLastError != QCBOR_SUCCESS) {
7116 return;
7117 }
7118
7119 QCBORItem Item;
7120 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7121 if(pMe->uLastError != QCBOR_SUCCESS) {
7122 return;
7123 }
7124
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007125 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007126 {
7127 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007128 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7129 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7130 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007131 };
7132
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007133 QCBOR_Private_ProcessExpMantissa(pMe,
7134 TagSpec,
7135 &Item,
7136 pnMantissa,
7137 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007138}
7139
7140
7141/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007142 * Public function, see header qcbor/qcbor_decode.h file
7143 */
7144void
7145QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe,
7146 const char *szLabel,
7147 const uint8_t uTagRequirement,
7148 int64_t *pnMantissa,
7149 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007150{
7151 if(pMe->uLastError != QCBOR_SUCCESS) {
7152 return;
7153 }
7154
7155 QCBORItem Item;
7156 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7157 if(pMe->uLastError != QCBOR_SUCCESS) {
7158 return;
7159 }
7160
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007161 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007162 {
7163 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007164 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7165 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7166 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007167 };
7168
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007169 QCBOR_Private_ProcessExpMantissa(pMe,
7170 TagSpec,
7171 &Item,
7172 pnMantissa,
7173 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007174}
7175
7176
7177/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007178 * Public function, see header qcbor/qcbor_decode.h file
7179 */
7180void
7181QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe,
7182 const uint8_t uTagRequirement,
7183 const UsefulBuf MantissaBuffer,
7184 UsefulBufC *pMantissa,
7185 bool *pbMantissaIsNegative,
7186 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007187{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007188 if(pMe->uLastError != QCBOR_SUCCESS) {
7189 return;
7190 }
7191
7192 QCBORItem Item;
7193 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
7194 if(uError) {
7195 pMe->uLastError = (uint8_t)uError;
7196 return;
7197 }
7198
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007199 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007200 {
7201 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007202 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7203 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7204 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007205 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007206
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007207 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7208 TagSpec,
7209 &Item,
7210 MantissaBuffer,
7211 pMantissa,
7212 pbMantissaIsNegative,
7213 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007214}
7215
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007216
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007217/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007218 * Public function, see header qcbor/qcbor_decode.h file
7219 */
7220void
7221QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe,
7222 const int64_t nLabel,
7223 const uint8_t uTagRequirement,
7224 const UsefulBuf BufferForMantissa,
7225 UsefulBufC *pMantissa,
7226 bool *pbIsNegative,
7227 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007228{
7229 if(pMe->uLastError != QCBOR_SUCCESS) {
7230 return;
7231 }
7232
7233 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007234 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7235 if(pMe->uLastError != QCBOR_SUCCESS) {
7236 return;
7237 }
7238
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007239 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007240 {
7241 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007242 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7243 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7244 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007245 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007246
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007247 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7248 TagSpec,
7249 &Item,
7250 BufferForMantissa,
7251 pMantissa,
7252 pbIsNegative,
7253 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007254}
7255
7256
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007257/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007258 * Public function, see header qcbor/qcbor_decode.h file
7259 */
7260void
7261QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe,
7262 const char *szLabel,
7263 const uint8_t uTagRequirement,
7264 const UsefulBuf BufferForMantissa,
7265 UsefulBufC *pMantissa,
7266 bool *pbIsNegative,
7267 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007268{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007269 if(pMe->uLastError != QCBOR_SUCCESS) {
7270 return;
7271 }
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007272
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007273 QCBORItem Item;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007274 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7275 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007276 return;
7277 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007278
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007279 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007280 {
7281 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007282 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7283 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7284 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007285 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007286
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007287 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7288 TagSpec,
7289 &Item,
7290 BufferForMantissa,
7291 pMantissa,
7292 pbIsNegative,
7293 pnExponent);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007294}
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007295
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07007296#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */