blob: c8231d5cda414cc06481355bb20f7329740a405e [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 */
931 uReturn = QCBOR_ERR_TAGS_DISABLED;
932#endif /* QCBOR_DISABLE_TAGS */
933
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800934 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700935}
936
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800937
938/* Make sure #define value line up as DecodeSimple counts on this. */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700939#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
940#error QCBOR_TYPE_FALSE macro value wrong
941#endif
942
943#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
944#error QCBOR_TYPE_TRUE macro value wrong
945#endif
946
947#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
948#error QCBOR_TYPE_NULL macro value wrong
949#endif
950
951#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
952#error QCBOR_TYPE_UNDEF macro value wrong
953#endif
954
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700955#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
956#error QCBOR_TYPE_BREAK macro value wrong
957#endif
958
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700959#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
960#error QCBOR_TYPE_DOUBLE macro value wrong
961#endif
962
963#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
964#error QCBOR_TYPE_FLOAT macro value wrong
965#endif
966
Laurence Lundblade9b334962020-08-27 10:55:53 -0700967
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800968/**
969 * @brief Decode major type 7 -- true, false, floating-point, break...
970 *
971 * @param[in] nAdditionalInfo The lower five bits from the initial byte.
972 * @param[in] uArgument The argument from the head.
973 * @param[out] pDecodedItem The filled in decoded item.
974 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -0700975 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
976 * of half-precision disabled
977 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all float
978 * decode is disabled.
979 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of simple
980 * type in input.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700981 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700982static QCBORError
983QCBOR_Private_DecodeType7(const int nAdditionalInfo,
984 const uint64_t uArgument,
985 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800986{
987 QCBORError uReturn = QCBOR_SUCCESS;
988
989 /* uAdditionalInfo is 5 bits from the initial byte. Compile time
990 * checks above make sure uAdditionalInfo values line up with
991 * uDataType values. DecodeHead() never returns an AdditionalInfo
992 * > 0x1f so cast is safe.
993 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800994 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800995
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800996 switch(nAdditionalInfo) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800997 /* No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they
998 * are caught before this is called.
999 */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001000
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001001 case HALF_PREC_FLOAT: /* 25 */
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -07001002#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001003 /* Half-precision is returned as a double. The cast to
1004 * uint16_t is safe because the encoded value was 16 bits. It
1005 * was widened to 64 bits to be passed in here.
1006 */
1007 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uArgument);
Laurence Lundblade67bd5512018-11-02 21:44:06 +07001008 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001009#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001010 uReturn = FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001011 break;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001012 case SINGLE_PREC_FLOAT: /* 26 */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001013#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001014 /* Single precision is normally returned as a double since
1015 * double is widely supported, there is no loss of precision,
1016 * it makes it easy for the caller in most cases and it can
1017 * be converted back to single with no loss of precision
1018 *
1019 * The cast to uint32_t is safe because the encoded value was
1020 * 32 bits. It was widened to 64 bits to be passed in here.
1021 */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001022 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001023 const float f = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uArgument);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001024#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001025 /* In the normal case, use HW to convert float to
1026 * double. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001027 pDecodedItem->val.dfnum = (double)f;
1028 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001029#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001030 /* Use of float HW is disabled, return as a float. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001031 pDecodedItem->val.fnum = f;
1032 pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
1033
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001034 /* IEEE754_FloatToDouble() could be used here to return as
1035 * a double, but it adds object code and most likely
1036 * anyone disabling FLOAT HW use doesn't care about floats
1037 * and wants to save object code.
1038 */
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001039#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001040 }
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001041#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1042 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001043 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001044
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001045 case DOUBLE_PREC_FLOAT: /* 27 */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001046#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001047 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uArgument);
Laurence Lundblade67bd5512018-11-02 21:44:06 +07001048 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001049#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1050 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001051 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001052
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001053 case CBOR_SIMPLEV_FALSE: /* 20 */
1054 case CBOR_SIMPLEV_TRUE: /* 21 */
1055 case CBOR_SIMPLEV_NULL: /* 22 */
1056 case CBOR_SIMPLEV_UNDEF: /* 23 */
1057 case CBOR_SIMPLE_BREAK: /* 31 */
1058 break; /* nothing to do */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001059
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001060 case CBOR_SIMPLEV_ONEBYTE: /* 24 */
1061 if(uArgument <= CBOR_SIMPLE_BREAK) {
1062 /* This takes out f8 00 ... f8 1f which should be encoded
1063 * as e0 … f7
1064 */
1065 uReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001066 goto Done;
1067 }
Laurence Lundblade5e390822019-01-06 12:35:01 -08001068 /* FALLTHROUGH */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001069
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001070 default: /* 0-19 */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001071 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001072 /* DecodeHead() will make uArgument equal to
1073 * nAdditionalInfo when nAdditionalInfo is < 24. This cast is
1074 * safe because the 2, 4 and 8 byte lengths of uNumber are in
1075 * the double/float cases above
Laurence Lundbladeee851742020-01-08 08:37:05 -08001076 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001077 pDecodedItem->val.uSimple = (uint8_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001078 break;
1079 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001080
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001081Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001082 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001083}
1084
1085
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001086/**
1087 * @brief Decode text and byte strings
1088 *
1089 * @param[in] pAllocator The string allocator or NULL.
1090 * @param[in] uStrLen The length of the string.
1091 * @param[in] pUInBuf The surce from which to read the string's bytes.
1092 * @param[out] pDecodedItem The filled in decoded item.
1093 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001094 * @retval QCBOR_ERR_HIT_END Unexpected end of input.
1095 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1096 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001097 *
1098 * The reads @c uStrlen bytes from @c pUInBuf and fills in @c
1099 * pDecodedItem. If @c pAllocator is not NULL then memory for the
1100 * string is allocated.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001101 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001102static QCBORError
1103QCBOR_Private_DecodeBytes(const QCBORInternalAllocator *pAllocator,
Laurence Lundblade62cae932024-06-03 13:16:17 -07001104 int nMajorType,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001105 const uint64_t uStrLen,
Laurence Lundblade62cae932024-06-03 13:16:17 -07001106 int nAdditionalInfo,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001107 UsefulInputBuf *pUInBuf,
1108 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001109{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001110 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001111
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001112 #if CBOR_MAJOR_TYPE_BYTE_STRING + 4 != QCBOR_TYPE_BYTE_STRING
1113 #error QCBOR_TYPE_BYTE_STRING no lined up with major type
1114 #endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001115
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001116 #if CBOR_MAJOR_TYPE_TEXT_STRING + 4 != QCBOR_TYPE_TEXT_STRING
1117 #error QCBOR_TYPE_TEXT_STRING no lined up with major type
1118 #endif
Laurence Lundblade62cae932024-06-03 13:16:17 -07001119 pDecodedItem->uDataType = (uint8_t)(nMajorType + 4);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001120
Laurence Lundblade62cae932024-06-03 13:16:17 -07001121
1122 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1123 pDecodedItem->val.string = (UsefulBufC){NULL, QCBOR_STRING_LENGTH_INDEFINITE};
1124
1125 } else {
1126 /* CBOR lengths can be 64 bits, but size_t is not 64 bits on all
1127 * CPUs. This check makes the casts to size_t below safe.
1128 *
1129 * The max is 4 bytes less than the largest sizeof() so this can be
1130 * tested by putting a SIZE_MAX length in the CBOR test input (no
1131 * one will care the limit on strings is 4 bytes shorter).
1132 */
1133 if(uStrLen > SIZE_MAX-4) {
1134 uReturn = QCBOR_ERR_STRING_TOO_LONG;
1135 goto Done;
1136 }
1137
1138 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, (size_t)uStrLen);
1139 if(UsefulBuf_IsNULLC(Bytes)) {
1140 /* Failed to get the bytes for this string item */
1141 uReturn = QCBOR_ERR_HIT_END;
1142 goto Done;
1143 }
1144
1145#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
1146 /* Note that this is not where allocation to coalesce
1147 * indefinite-length strings is done. This is for when the caller
1148 * has requested all strings be allocated. Disabling indefinite
1149 * length strings also disables this allocate-all option.
1150 */
1151 if(pAllocator) {
1152 /* request to use the string allocator to make a copy */
1153 UsefulBuf NewMem = StringAllocator_Allocate(pAllocator, (size_t)uStrLen);
1154 if(UsefulBuf_IsNULL(NewMem)) {
1155 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1156 goto Done;
1157 }
1158 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
1159 pDecodedItem->uDataAlloc = 1;
1160 goto Done;
1161 }
1162#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1163 (void)pAllocator;
1164#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1165
1166 /* Normal case with no string allocator */
1167 pDecodedItem->val.string = Bytes;
1168 }
1169
1170Done:
1171 return uReturn;
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001172}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001173
1174
Laurence Lundblade62cae932024-06-03 13:16:17 -07001175
1176
1177
1178static QCBORError
1179QCBOR_Private_DecodeArrayOrMap(const uint8_t uMode,
1180 const int nMajorType,
1181 const uint64_t uItemCount,
1182 const int nAdditionalInfo,
1183 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001184{
Laurence Lundblade62cae932024-06-03 13:16:17 -07001185 QCBORError uReturn;
1186
1187 /* ------ Sort out the data type ------ */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001188 #if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
1189 #error QCBOR_TYPE_ARRAY value not lined up with major type
1190 #endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001191
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001192 #if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
1193 #error QCBOR_TYPE_MAP value not lined up with major type
1194 #endif
Laurence Lundblade62cae932024-06-03 13:16:17 -07001195 pDecodedItem->uDataType = (uint8_t)nMajorType;
1196#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1197 if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
1198 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
1199 }
1200#endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001201
Laurence Lundblade62cae932024-06-03 13:16:17 -07001202 uReturn = QCBOR_SUCCESS;
1203
1204 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1205 /* ------ Indefinite-length arra/map ----- */
1206#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
1207 pDecodedItem->val.uCount = QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH;
1208#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1209 uReturn = QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED;
1210#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1211 } else {
1212
1213#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1214 if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
1215 /* ------ Definite-length map as array ------ */
1216
1217 if(uItemCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
1218 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
1219 } else {
1220 /* cast OK because of check above */
1221 pDecodedItem->val.uCount = (uint16_t)uItemCount*2;
1222 }
1223
1224 } else
1225#endif
1226 {
1227 /* ------ Definite-length array/map ------ */
1228 if(uItemCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
1229 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
1230 } else {
1231 /* cast OK because of check above */
1232 pDecodedItem->val.uCount = (uint16_t)uItemCount;
1233 }
1234 }
1235 }
1236
1237 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001238}
1239
1240
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001241/**
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001242 * @brief Decode a single primitive data item (decode layer 6).
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001243 *
Laurence Lundblade62cae932024-06-03 13:16:17 -07001244 * param[in] pUInBuf Input buffer to read data item from.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001245 * @param[out] pDecodedItem The filled-in decoded item.
1246 * @param[in] pAllocator The allocator to use for strings or NULL.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001247 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001248 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1249 * features
1250 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1251 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1252 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1253 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1254 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1255 * of half-precision disabled
1256 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1257 * float decode is disabled.
1258 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1259 * simple type in input.
1260 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1261 * in input, but indefinite
1262 * lengths disabled.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001263 *
1264 * This decodes the most primitive / atomic data item. It does
1265 * no combing of data items.
1266 */
1267static QCBORError
Laurence Lundblade62cae932024-06-03 13:16:17 -07001268QCBOR_Private_DecodeAtomicDataItem(QCBORDecodeContext *pMe,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001269 QCBORItem *pDecodedItem,
1270 const QCBORInternalAllocator *pAllocator)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001271{
1272 QCBORError uReturn;
1273
1274 /* Get the major type and the argument. The argument could be
1275 * length of more bytes or the value depending on the major
1276 * type. nAdditionalInfo is an encoding of the length of the
1277 * uNumber and is needed to decode floats and doubles.
1278 */
1279 int nMajorType = 0;
1280 uint64_t uArgument = 0;
1281 int nAdditionalInfo = 0;
1282
1283 memset(pDecodedItem, 0, sizeof(QCBORItem));
1284
Laurence Lundblade62cae932024-06-03 13:16:17 -07001285 uReturn = QCBOR_Private_DecodeHead(&(pMe->InBuf), &nMajorType, &uArgument, &nAdditionalInfo);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001286 if(uReturn) {
1287 goto Done;
1288 }
1289
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001290 switch (nMajorType) {
1291 case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
1292 case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001293 uReturn = QCBOR_Private_DecodeInteger(nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001294 break;
1295
1296 case CBOR_MAJOR_TYPE_BYTE_STRING: /* Major type 2 */
1297 case CBOR_MAJOR_TYPE_TEXT_STRING: /* Major type 3 */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001298 uReturn = QCBOR_Private_DecodeBytes(pAllocator, nMajorType, uArgument, nAdditionalInfo, &(pMe->InBuf), pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001299 break;
1300
1301 case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */
1302 case CBOR_MAJOR_TYPE_MAP: /* Major type 5 */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001303 uReturn = QCBOR_Private_DecodeArrayOrMap(pMe->uDecodeMode, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001304 break;
1305
1306 case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001307 uReturn = QCBOR_Private_DecodeTag(nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001308 break;
1309
1310 case CBOR_MAJOR_TYPE_SIMPLE:
1311 /* Major type 7: float, double, true, false, null... */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001312 uReturn = QCBOR_Private_DecodeType7(nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001313 break;
1314
1315 default:
1316 /* Never happens because DecodeHead() should never return > 7 */
1317 uReturn = QCBOR_ERR_UNSUPPORTED;
1318 break;
1319 }
1320
1321Done:
1322 return uReturn;
1323}
1324
1325
1326/**
1327 * @brief Process indefinite-length strings (decode layer 5).
1328 *
1329 * @param[in] pMe Decoder context
1330 * @param[out] pDecodedItem The decoded item that work is done on.
1331 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001332 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1333 * features
1334 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1335 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1336 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1337 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1338 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1339 * of half-precision disabled
1340 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1341 * float decode is disabled.
1342 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1343 * simple type in input.
1344 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1345 * in input, but indefinite
1346 * lengths disabled.
1347 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1348 * but no string allocator.
1349 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1350 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1351 * input, but indefinite-length
1352 * strings are disabled.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001353 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001354 * If @c pDecodedItem is not an indefinite-length string, this does nothing.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001355 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001356 * If it is, this loops getting the subsequent chunk data items that
1357 * make up the string. The string allocator is used to make a
1358 * contiguous buffer for the chunks. When this completes @c
1359 * pDecodedItem contains the put-together string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001360 *
1361 * Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001362 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001363static QCBORError
1364QCBORDecode_Private_GetNextFullString(QCBORDecodeContext *pMe,
1365 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001366{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001367 /* Aproximate stack usage
1368 * 64-bit 32-bit
1369 * local vars 32 16
1370 * 2 UsefulBufs 32 16
1371 * QCBORItem 56 52
1372 * TOTAL 120 74
1373 */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001374
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001375 /* The string allocator is used here for two purposes: 1)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001376 * coalescing the chunks of an indefinite-length string, 2)
1377 * allocating storage for every string returned when requested.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001378 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001379 * The first use is below in this function. Indefinite-length
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001380 * strings cannot be processed at all without a string allocator.
1381 *
1382 * The second used is in DecodeBytes() which is called by
1383 * GetNext_Item() below. This second use unneccessary for most use
1384 * and only happens when requested in the call to
1385 * QCBORDecode_SetMemPool(). If the second use not requested then
1386 * NULL is passed for the string allocator to GetNext_Item().
1387 *
1388 * QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS disables the string
1389 * allocator altogether and thus both of these uses. It reduced the
1390 * decoder object code by about 400 bytes.
1391 */
Laurence Lundblade3a691a02020-12-28 04:15:16 -08001392 const QCBORInternalAllocator *pAllocatorForGetNext = NULL;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001393
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001394#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3a691a02020-12-28 04:15:16 -08001395 const QCBORInternalAllocator *pAllocator = NULL;
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001396
1397 if(pMe->StringAllocator.pfAllocator) {
1398 pAllocator = &(pMe->StringAllocator);
1399 if(pMe->bStringAllocateAll) {
1400 pAllocatorForGetNext = pAllocator;
1401 }
1402 }
1403#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1404
1405 QCBORError uReturn;
Laurence Lundblade62cae932024-06-03 13:16:17 -07001406 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, pDecodedItem, pAllocatorForGetNext);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001407 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001408 goto Done;
1409 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001410
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001411 /* Only do indefinite-length processing on strings */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001412 const uint8_t uStringType = pDecodedItem->uDataType;
1413 if(uStringType!= QCBOR_TYPE_BYTE_STRING && uStringType != QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001414 goto Done;
1415 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001416
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001417 /* Is this a string with an indefinite length? */
1418 if(pDecodedItem->val.string.len != QCBOR_STRING_LENGTH_INDEFINITE) {
1419 goto Done;
1420 }
1421
1422#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001423 /* Can't decode indefinite-length strings without a string allocator */
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001424 if(pAllocator == NULL) {
1425 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1426 goto Done;
1427 }
1428
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001429 /* Loop getting chunks of the indefinite-length string */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001430 UsefulBufC FullString = NULLUsefulBufC;
1431
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001432 for(;;) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001433 /* Get QCBORItem for next chunk */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001434 QCBORItem StringChunkItem;
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001435 /* Pass a NULL string allocator to GetNext_Item() because the
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001436 * individual string chunks in an indefinite-length should not
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001437 * be allocated. They are always copied in the the contiguous
1438 * buffer allocated here.
1439 */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001440 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, &StringChunkItem, NULL);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001441 if(uReturn) {
1442 break;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001443 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001444
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001445 /* Is item is the marker for end of the indefinite-length string? */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001446 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001447 /* String is complete */
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001448 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301449 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001450 break;
1451 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001452
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001453 /* All chunks must be of the same type, the type of the item
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001454 * that introduces the indefinite-length string. This also
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001455 * catches errors where the chunk is not a string at all and an
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001456 * indefinite-length string inside an indefinite-length string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001457 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001458 if(StringChunkItem.uDataType != uStringType ||
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001459 StringChunkItem.val.string.len == QCBOR_STRING_LENGTH_INDEFINITE) {
1460 uReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001461 break;
1462 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001463
David Navarro9123e5b2022-03-28 16:04:03 +02001464 if (StringChunkItem.val.string.len > 0) {
1465 /* The first time throurgh FullString.ptr is NULL and this is
1466 * equivalent to StringAllocator_Allocate(). Subsequently it is
1467 * not NULL and a reallocation happens.
1468 */
1469 UsefulBuf NewMem = StringAllocator_Reallocate(pAllocator,
1470 FullString.ptr,
1471 FullString.len + StringChunkItem.val.string.len);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001472
David Navarro9123e5b2022-03-28 16:04:03 +02001473 if(UsefulBuf_IsNULL(NewMem)) {
1474 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1475 break;
1476 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001477
David Navarro9123e5b2022-03-28 16:04:03 +02001478 /* Copy new string chunk to the end of accumulated string */
1479 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001480 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001481 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001482
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001483 if(uReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
1484 /* Getting the item failed, clean up the allocated memory */
Laurence Lundbladeb9702452021-03-08 21:02:57 -08001485 StringAllocator_Free(pAllocator, FullString.ptr);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001486 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001487#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1488 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1489#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001490
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001491Done:
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001492 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001493}
1494
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001495
Laurence Lundblade37286c02022-09-03 10:05:02 -07001496#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001497/**
1498 * @brief This converts a tag number to a shorter mapped value for storage.
1499 *
1500 * @param[in] pMe The decode context.
1501 * @param[in] uUnMappedTag The tag number to map
1502 * @param[out] puMappedTagNumer The stored tag number.
1503 *
1504 * @return error code.
1505 *
1506 * The main point of mapping tag numbers is make QCBORItem
1507 * smaller. With this mapping storage of 4 tags takes up 8
1508 * bytes. Without, it would take up 32 bytes.
1509 *
1510 * This maps tag numbers greater than QCBOR_LAST_UNMAPPED_TAG.
1511 * QCBOR_LAST_UNMAPPED_TAG is a little smaller than MAX_UINT16.
1512 *
1513 * See also UnMapTagNumber() and @ref QCBORItem.
1514 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001515static QCBORError
1516QCBORDecode_Private_MapTagNumber(QCBORDecodeContext *pMe,
1517 const uint64_t uUnMappedTag,
1518 uint16_t *puMappedTagNumer)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001519{
1520 if(uUnMappedTag > QCBOR_LAST_UNMAPPED_TAG) {
1521 unsigned uTagMapIndex;
1522 /* Is there room in the tag map, or is it in it already? */
1523 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
1524 if(pMe->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID64) {
1525 break;
1526 }
1527 if(pMe->auMappedTags[uTagMapIndex] == uUnMappedTag) {
1528 break;
1529 }
1530 }
1531 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
1532 return QCBOR_ERR_TOO_MANY_TAGS;
1533 }
1534
1535 /* Covers the cases where tag is new and were it is already in the map */
1536 pMe->auMappedTags[uTagMapIndex] = uUnMappedTag;
1537 *puMappedTagNumer = (uint16_t)(uTagMapIndex + QCBOR_LAST_UNMAPPED_TAG + 1);
1538
1539 } else {
1540 *puMappedTagNumer = (uint16_t)uUnMappedTag;
1541 }
1542
1543 return QCBOR_SUCCESS;
1544}
1545
1546
1547/**
1548 * @brief This converts a mapped tag number to the actual tag number.
1549 *
1550 * @param[in] pMe The decode context.
1551 * @param[in] uMappedTagNumber The stored tag number.
1552 *
1553 * @return The actual tag number is returned or
1554 * @ref CBOR_TAG_INVALID64 on error.
1555 *
1556 * This is the reverse of MapTagNumber()
1557 */
1558static uint64_t
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001559QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe,
1560 const uint16_t uMappedTagNumber)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001561{
1562 if(uMappedTagNumber <= QCBOR_LAST_UNMAPPED_TAG) {
1563 return uMappedTagNumber;
1564 } else if(uMappedTagNumber == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07001565 return CBOR_TAG_INVALID64;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001566 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001567 /* This won't be negative because of code below in
1568 * MapTagNumber()
1569 */
1570 const unsigned uIndex = uMappedTagNumber - (QCBOR_LAST_UNMAPPED_TAG + 1);
1571 return pMe->auMappedTags[uIndex];
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001572 }
1573}
Laurence Lundblade37286c02022-09-03 10:05:02 -07001574#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001575
Laurence Lundblade9b334962020-08-27 10:55:53 -07001576
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001577/**
1578 * @brief Aggregate all tags wrapping a data item (decode layer 4).
1579 *
1580 * @param[in] pMe Decoder context
1581 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001582 *
1583 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1584 * features
1585 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1586 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1587 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1588 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1589 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1590 * of half-precision disabled
1591 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1592 * float decode is disabled.
1593 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1594 * simple type in input.
1595 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1596 * in input, but indefinite
1597 * lengths disabled.
1598 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1599 * but no string allocator.
1600 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1601 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1602 * input, but indefinite-length
1603 * strings are disabled.
1604 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001605 *
1606 * This loops getting atomic data items until one is not a tag
1607 * number. Usually this is largely pass-through because most
1608 * item are not tag numbers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001609 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001610static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001611QCBORDecode_Private_GetNextTagNumber(QCBORDecodeContext *pMe,
1612 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001613{
Laurence Lundblade37286c02022-09-03 10:05:02 -07001614#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001615 /* Accummulate the tags from multiple items here and then copy them
1616 * into the last item, the non-tag item.
1617 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001618 uint16_t auItemsTags[QCBOR_MAX_TAGS_PER_ITEM];
1619
1620 /* Initialize to CBOR_TAG_INVALID16 */
1621 #if CBOR_TAG_INVALID16 != 0xffff
1622 /* Be sure the memset does the right thing. */
1623 #err CBOR_TAG_INVALID16 tag not defined as expected
1624 #endif
1625 memset(auItemsTags, 0xff, sizeof(auItemsTags));
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001626
Laurence Lundblade9b334962020-08-27 10:55:53 -07001627 QCBORError uReturn = QCBOR_SUCCESS;
1628
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001629 /* Loop fetching data items until the item fetched is not a tag */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001630 for(;;) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001631 QCBORError uErr = QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07001632 if(uErr != QCBOR_SUCCESS) {
1633 uReturn = uErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001634 goto Done;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001635 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001636
Laurence Lundblade9b334962020-08-27 10:55:53 -07001637 if(pDecodedItem->uDataType != QCBOR_TYPE_TAG) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001638 /* Successful exit from loop; maybe got some tags, maybe not */
1639 memcpy(pDecodedItem->uTags, auItemsTags, sizeof(auItemsTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001640 break;
1641 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001642
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001643 if(auItemsTags[QCBOR_MAX_TAGS_PER_ITEM - 1] != CBOR_TAG_INVALID16) {
1644 /* No room in the tag list */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001645 uReturn = QCBOR_ERR_TOO_MANY_TAGS;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001646 /* Continue on to get all tags wrapping this item even though
1647 * it is erroring out in the end. This allows decoding to
1648 * continue. This is a resource limit error, not a problem
1649 * with being well-formed CBOR.
1650 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001651 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001652 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001653 /* Slide tags over one in the array to make room at index 0.
1654 * Must use memmove because the move source and destination
1655 * overlap.
1656 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001657 memmove(&auItemsTags[1],
1658 auItemsTags,
1659 sizeof(auItemsTags) - sizeof(auItemsTags[0]));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001660
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001661 /* Map the tag */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001662 uint16_t uMappedTagNumber = 0;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001663 uReturn = QCBORDecode_Private_MapTagNumber(pMe, pDecodedItem->val.uTagV, &uMappedTagNumber);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001664 /* Continue even on error so as to consume all tags wrapping
1665 * this data item so decoding can go on. If MapTagNumber()
1666 * errors once it will continue to error.
1667 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001668 auItemsTags[0] = uMappedTagNumber;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001669 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001670
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001671Done:
Laurence Lundblade9b334962020-08-27 10:55:53 -07001672 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001673
Laurence Lundblade37286c02022-09-03 10:05:02 -07001674#else /* QCBOR_DISABLE_TAGS */
1675
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07001676 return QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07001677
1678#endif /* QCBOR_DISABLE_TAGS */
1679}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001680
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001681
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001682/**
1683 * @brief Combine a map entry label and value into one item (decode layer 3).
1684 *
1685 * @param[in] pMe Decoder context
1686 * @param[out] pDecodedItem The decoded item that work is done on.
1687 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001688 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1689 * features
1690 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1691 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1692 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1693 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1694 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1695 * of half-precision disabled
1696 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1697 * float decode is disabled.
1698 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1699 * simple type in input.
1700 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1701 * in input, but indefinite
1702 * lengths disabled.
1703 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1704 * but no string allocator.
1705 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1706 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1707 * input, but indefinite-length
1708 * strings are disabled.
1709 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1710 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1711 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001712 *
Laurence Lundblade62cae932024-06-03 13:16:17 -07001713 * If the current nesting level is a map, then this
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001714 * combines pairs of items into one data item with a label
1715 * and value.
1716 *
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07001717 * This is passthrough if the current nesting level is
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001718 * not a map.
1719 *
1720 * This also implements maps-as-array mode where a map
1721 * is treated like an array to allow caller to do their
1722 * own label processing.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001723 */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001724
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001725static QCBORError
1726QCBORDecode_Private_GetNextMapEntry(QCBORDecodeContext *pMe,
1727 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001728{
Laurence Lundblade62cae932024-06-03 13:16:17 -07001729 QCBORItem LabelItem;
1730 QCBORError uErr;
1731
1732 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1733 if(QCBORDecode_IsUnrecoverableError(uErr)) {
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001734 goto Done;
1735 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001736
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001737 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
1738 /* Break can't be a map entry */
1739 goto Done;
1740 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001741
Laurence Lundblade62cae932024-06-03 13:16:17 -07001742 if(!DecodeNesting_IsCurrentTypeMap(&(pMe->nesting))) {
1743 /* Not decoding a map; nothing to do */
1744 /* This is where maps-as-arrays is effected too */
1745 goto Done;
1746 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001747
Laurence Lundblade62cae932024-06-03 13:16:17 -07001748 /* Decoding a map entry, so the item so far is the label; must get value */
1749 LabelItem = *pDecodedItem;
1750 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1751 if(QCBORDecode_IsUnrecoverableError(uErr)) {
1752 goto Done;
1753 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001754
Laurence Lundblade62cae932024-06-03 13:16:17 -07001755 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
1756 pDecodedItem->uLabelType = LabelItem.uDataType;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001757
Laurence Lundblade62cae932024-06-03 13:16:17 -07001758#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1759 /* QCBOR_DECODE_MODE_MAP_STRINGS_ONLY was a bad idea. Maybe
1760 * get rid of it in QCBOR 2.0
1761 */
1762 if(pMe->uDecodeMode == QCBOR_DECODE_MODE_MAP_STRINGS_ONLY &&
1763 LabelItem.uDataType != QCBOR_TYPE_TEXT_STRING) {
1764 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
1765 goto Done;
1766 }
1767#endif /* !QCBOR_DISABLE_NON_INTEGER_LABELS */
1768
1769 switch(LabelItem.uDataType) {
1770 case QCBOR_TYPE_INT64:
1771 pDecodedItem->label.int64 = LabelItem.val.int64;
1772 break;
1773
1774#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1775 case QCBOR_TYPE_UINT64:
1776 pDecodedItem->label.uint64 = LabelItem.val.uint64;
1777 break;
1778
1779 case QCBOR_TYPE_TEXT_STRING:
1780 case QCBOR_TYPE_BYTE_STRING:
1781 pDecodedItem->label.string = LabelItem.val.string;
1782 break;
1783#endif /* !QCBOR_DISABLE_NON_INTEGER_LABELS */
1784
1785 /* case QCBOR_TYPE_BREAK:
1786 uErr = 99;
1787 goto Done; */
1788
1789 default:
1790 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
1791 goto Done;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001792 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001793
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001794Done:
Laurence Lundblade62cae932024-06-03 13:16:17 -07001795 return uErr;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001796}
1797
1798
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001799#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001800/**
1801 * @brief Peek and see if next data item is a break;
1802 *
Laurence Lundblade62cae932024-06-03 13:16:17 -07001803 * param[in] pUIB UsefulInputBuf to read from.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001804 * @param[out] pbNextIsBreak Indicate if next was a break or not.
1805 *
1806 * @return Any decoding error.
1807 *
1808 * See if next item is a CBOR break. If it is, it is consumed,
1809 * if not it is not consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07001810*/
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001811static QCBORError
Laurence Lundblade62cae932024-06-03 13:16:17 -07001812QCBOR_Private_NextIsBreak(QCBORDecodeContext *pMe, bool *pbNextIsBreak)
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001813{
1814 *pbNextIsBreak = false;
Laurence Lundblade62cae932024-06-03 13:16:17 -07001815 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) != 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001816 QCBORItem Peek;
Laurence Lundblade62cae932024-06-03 13:16:17 -07001817 size_t uPeek = UsefulInputBuf_Tell(&(pMe->InBuf));
1818 QCBORError uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, &Peek, NULL);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001819 if(uReturn != QCBOR_SUCCESS) {
1820 return uReturn;
1821 }
1822 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001823 /* It is not a break, rewind so it can be processed normally. */
Laurence Lundblade62cae932024-06-03 13:16:17 -07001824 UsefulInputBuf_Seek(&(pMe->InBuf), uPeek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001825 } else {
1826 *pbNextIsBreak = true;
1827 }
1828 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001829
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001830 return QCBOR_SUCCESS;
1831}
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001832#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001833
1834
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001835/**
1836 * @brief Ascend up nesting levels if all items in them have been consumed.
1837 *
1838 * @param[in] pMe The decode context.
1839 * @param[in] bMarkEnd If true mark end of maps/arrays with count of zero.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001840 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001841 *
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001842 * An item was just consumed, now figure out if it was the
1843 * end of an array/map map that can be closed out. That
1844 * may in turn close out the above array/map...
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001845 *
1846 * When ascending indefinite-length arrays and maps, this will correctly
1847 * consume the break for the level above. This is a problem for the
1848 * implementation of QCBORDecode_GetArray() that must not return
1849 * that break. @c pbBreak is set to true to indicate that one
1850 * byte should be removed.
1851 *
1852 * Improvement: this could reduced further if indef is disabled
1853 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001854static QCBORError
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001855QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd, bool *pbBreak)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001856{
1857 QCBORError uReturn;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001858
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001859 /* Loop ascending nesting levels as long as there is ascending to do */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001860 while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001861 if(pbBreak) {
1862 *pbBreak = false;
1863 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001864
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001865 if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) {
1866 /* Nesting level is bstr-wrapped CBOR */
1867
1868 /* Ascent for bstr-wrapped CBOR is always by explicit call
1869 * so no further ascending can happen.
1870 */
1871 break;
1872
1873 } else if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
1874 /* Level is a definite-length array/map */
1875
1876 /* Decrement the item count the definite-length array/map */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001877 DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(&(pMe->nesting));
1878 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001879 /* Didn't close out array/map, so all work here is done */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001880 break;
1881 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001882 /* All items in a definite-length array were consumed so it
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001883 * is time to ascend one level. This happens below.
1884 */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001885
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001886#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001887 } else {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001888 /* Level is an indefinite-length array/map. */
1889
1890 /* Check for a break which is what ends indefinite-length arrays/maps */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001891 bool bIsBreak = false;
Laurence Lundblade62cae932024-06-03 13:16:17 -07001892 uReturn = QCBOR_Private_NextIsBreak(pMe, &bIsBreak);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001893 if(uReturn != QCBOR_SUCCESS) {
1894 goto Done;
1895 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001896
1897 if(!bIsBreak) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001898 /* Not a break so array/map does not close out. All work is done */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001899 break;
1900 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001901
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001902 /* It was a break in an indefinitelength map / array so
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001903 * it is time to ascend one level.
1904 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001905 if(pbBreak) {
1906 *pbBreak = true;
1907 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001908
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001909#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001910 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001911
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001912
1913 /* All items in the array/map have been consumed. */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001914
Laurence Lundblade93d89472020-10-03 22:30:50 -07001915 /* But ascent in bounded mode is only by explicit call to
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001916 * QCBORDecode_ExitBoundedMode().
1917 */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07001918 if(DecodeNesting_IsCurrentBounded(&(pMe->nesting))) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001919 /* Set the count to zero for definite-length arrays to indicate
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001920 * cursor is at end of bounded array/map */
Laurence Lundbladed0304932020-06-27 10:59:38 -07001921 if(bMarkEnd) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001922 /* Used for definite and indefinite to signal end */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07001923 DecodeNesting_ZeroMapOrArrayCount(&(pMe->nesting));
Laurence Lundbladed0304932020-06-27 10:59:38 -07001924
Laurence Lundblade2c1faf92020-06-26 22:43:56 -07001925 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001926 break;
1927 }
1928
1929 /* Finally, actually ascend one level. */
1930 DecodeNesting_Ascend(&(pMe->nesting));
1931 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001932
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001933 uReturn = QCBOR_SUCCESS;
1934
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001935#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001936Done:
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001937#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1938
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001939 return uReturn;
1940}
1941
1942
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001943/**
1944 * @brief Ascending & Descending out of nesting levels (decode layer 2).
1945 *
1946 * @param[in] pMe Decoder context
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001947 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001948 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001949
1950 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1951 * features
1952 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1953 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1954 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1955 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1956 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1957 * of half-precision disabled
1958 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1959 * float decode is disabled.
1960 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1961 * simple type in input.
1962 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1963 * in input, but indefinite
1964 * lengths disabled.
1965 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1966 * but no string allocator.
1967 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1968 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1969 * input, but indefinite-length
1970 * strings are disabled.
1971 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1972 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1973 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
1974 * @retval QCBOR_ERR_NO_MORE_ITEMS Need more items for map or array.
1975 * @retval QCBOR_ERR_BAD_BREAK Indefinite-length break in wrong
1976 * place.
1977 * @retval QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP Nesting deeper than QCBOR
1978 * can handle.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001979 *
1980 * This handles the traversal descending into and asecnding out of
1981 * maps, arrays and bstr-wrapped CBOR. It figures out the ends of
1982 * definite- and indefinte-length maps and arrays by looking at the
1983 * item count or finding CBOR breaks. It detects the ends of the
1984 * top-level sequence and of bstr-wrapped CBOR by byte count.
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001985 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001986static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001987QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001988 bool *pbBreak,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001989 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001990{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001991 QCBORError uReturn;
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07001992 /* ==== First: figure out if at the end of a traversal ==== */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001993
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001994 /* If out of bytes to consume, it is either the end of the
1995 * top-level sequence of some bstr-wrapped CBOR that was entered.
1996 *
1997 * In the case of bstr-wrapped CBOR, the length of the
1998 * UsefulInputBuf was set to that of the bstr-wrapped CBOR. When
1999 * the bstr-wrapped CBOR is exited, the length is set back to the
2000 * top-level's length or to the next highest bstr-wrapped CBOR.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002001 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002002 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) == 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002003 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002004 goto Done;
2005 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07002006
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002007 /* Check to see if at the end of a bounded definite-length map or
2008 * array. The check for a break ending indefinite-length array is
2009 * later in QCBORDecode_NestLevelAscender().
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002010 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002011 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002012 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002013 goto Done;
2014 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002015
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002016 /* ==== Next: not at the end, so get another item ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002017 uReturn = QCBORDecode_Private_GetNextMapEntry(pMe, pDecodedItem);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002018 if(QCBORDecode_IsUnrecoverableError(uReturn)) {
2019 /* Error is so bad that traversal is not possible. */
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002020 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002021 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05302022
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002023 /* Breaks ending arrays/maps are processed later in the call to
2024 * QCBORDecode_NestLevelAscender(). They should never show up here.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002025 */
Laurence Lundblade6de37062018-10-15 12:22:42 +05302026 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002027 uReturn = QCBOR_ERR_BAD_BREAK;
Laurence Lundblade6de37062018-10-15 12:22:42 +05302028 goto Done;
Laurence Lundblade5b8c5852018-10-14 21:11:42 +05302029 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002030
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002031 /* Record the nesting level for this data item before processing
2032 * any of decrementing and descending.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002033 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002034 pDecodedItem->uNestingLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002035
Laurence Lundblade642282a2020-06-23 12:00:33 -07002036
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002037 /* ==== Next: Process the item for descent, ascent, decrement... ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002038 if(QCBORItem_IsMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002039 /* If the new item is a map or array, descend.
2040 *
2041 * Empty indefinite-length maps and arrays are descended into,
2042 * but then ascended out of in the next chunk of code.
2043 *
2044 * Maps and arrays do count as items in the map/array that
2045 * encloses them so a decrement needs to be done for them too,
2046 * but that is done only when all the items in them have been
2047 * processed, not when they are opened with the exception of an
2048 * empty map or array.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002049 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002050 QCBORError uDescendErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002051 uDescendErr = DecodeNesting_DescendMapOrArray(&(pMe->nesting),
Laurence Lundblade642282a2020-06-23 12:00:33 -07002052 pDecodedItem->uDataType,
2053 pDecodedItem->val.uCount);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002054 if(uDescendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002055 /* This error is probably a traversal error and it overrides
2056 * the non-traversal error.
2057 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002058 uReturn = uDescendErr;
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002059 goto Done;
2060 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002061 }
2062
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002063 if(!QCBORItem_IsMapOrArray(*pDecodedItem) ||
2064 QCBORItem_IsEmptyDefiniteLengthMapOrArray(*pDecodedItem) ||
2065 QCBORItem_IsIndefiniteLengthMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002066 /* The following cases are handled here:
2067 * - A non-aggregate item like an integer or string
2068 * - An empty definite-length map or array
2069 * - An indefinite-length map or array that might be empty or might not.
2070 *
2071 * QCBORDecode_NestLevelAscender() does the work of decrementing the count
2072 * for an definite-length map/array and break detection for an
2073 * indefinite-0length map/array. If the end of the map/array was
2074 * reached, then it ascends nesting levels, possibly all the way
2075 * to the top level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002076 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002077 QCBORError uAscendErr;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002078 uAscendErr = QCBORDecode_Private_NestLevelAscender(pMe, true, pbBreak);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002079 if(uAscendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002080 /* This error is probably a traversal error and it overrides
2081 * the non-traversal error.
2082 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002083 uReturn = uAscendErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002084 goto Done;
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002085 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05302086 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002087
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002088 /* ==== Last: tell the caller the nest level of the next item ==== */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002089 /* Tell the caller what level is next. This tells them what
2090 * maps/arrays were closed out and makes it possible for them to
2091 * reconstruct the tree with just the information returned in a
2092 * QCBORItem.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002093 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002094 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07002095 /* At end of a bounded map/array; uNextNestLevel 0 to indicate this */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002096 pDecodedItem->uNextNestLevel = 0;
2097 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002098 pDecodedItem->uNextNestLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002099 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002100
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002101Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002102 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002103}
2104
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002105
Laurence Lundblade37286c02022-09-03 10:05:02 -07002106#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002107/**
2108 * @brief Shift 0th tag out of the tag list.
2109 *
2110 * pDecodedItem[in,out] The data item to convert.
2111 *
2112 * The 0th tag is discarded. \ref CBOR_TAG_INVALID16 is
2113 * shifted into empty slot at the end of the tag list.
2114 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002115static void
2116QCBOR_Private_ShiftTags(QCBORItem *pDecodedItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002117{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002118 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM-1; i++) {
2119 pDecodedItem->uTags[i] = pDecodedItem->uTags[i+1];
2120 }
2121 pDecodedItem->uTags[QCBOR_MAX_TAGS_PER_ITEM-1] = CBOR_TAG_INVALID16;
Laurence Lundblade9b334962020-08-27 10:55:53 -07002122}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002123#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002124
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002125
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002126/**
2127 * @brief Convert different epoch date formats in to the QCBOR epoch date format
2128 *
2129 * pDecodedItem[in,out] The data item to convert.
2130 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002131 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2132 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2133 * floating-point date disabled.
2134 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2135 * all floating-point disabled.
2136 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2137 * error decoding date.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002138 *
2139 * The epoch date tag defined in QCBOR allows for floating-point
2140 * dates. It even allows a protocol to flop between date formats when
2141 * ever it wants. Floating-point dates aren't that useful as they are
2142 * only needed for dates beyond the age of the earth.
2143 *
2144 * This converts all the date formats into one format of an unsigned
2145 * integer plus a floating-point fraction.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002146 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002147static QCBORError
2148QCBOR_Private_DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002149{
Laurence Lundbladec7114722020-08-13 05:11:40 -07002150 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002151
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002152#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade59289e52019-12-30 13:44:37 -08002153 pDecodedItem->val.epochDate.fSecondsFraction = 0;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002154#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002155
2156 switch (pDecodedItem->uDataType) {
2157
2158 case QCBOR_TYPE_INT64:
2159 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
2160 break;
2161
2162 case QCBOR_TYPE_UINT64:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002163 /* This only happens for CBOR type 0 > INT64_MAX so it is
2164 * always an overflow.
2165 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07002166 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2167 goto Done;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002168 break;
2169
2170 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade9682a532020-06-06 18:33:04 -07002171 case QCBOR_TYPE_FLOAT:
2172#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade59289e52019-12-30 13:44:37 -08002173 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002174 /* Convert working value to double if input was a float */
Laurence Lundblade3ed0bca2020-07-14 22:50:10 -07002175 const double d = pDecodedItem->uDataType == QCBOR_TYPE_DOUBLE ?
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002176 pDecodedItem->val.dfnum :
2177 (double)pDecodedItem->val.fnum;
2178
2179 /* The conversion from float to integer requires overflow
2180 * detection since floats can be much larger than integers.
2181 * This implementation errors out on these large float values
2182 * since they are beyond the age of the earth.
2183 *
2184 * These constants for the overflow check are computed by the
2185 * compiler. They are not computed at run time.
2186 *
2187 * The factor of 0x7ff is added/subtracted to avoid a
2188 * rounding error in the wrong direction when the compiler
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002189 * computes these constants. There is rounding because a
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002190 * 64-bit integer has 63 bits of precision where a double
2191 * only has 53 bits. Without the 0x7ff factor, the compiler
2192 * may round up and produce a double for the bounds check
2193 * that is larger than can be stored in a 64-bit integer. The
2194 * amount of 0x7ff is picked because it has 11 bits set.
2195 *
2196 * Without the 0x7ff there is a ~30 minute range of time
2197 * values 10 billion years in the past and in the future
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002198 * where this code could go wrong. Some compilers
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002199 * generate a warning or error without the 0x7ff.
2200 */
2201 const double dDateMax = (double)(INT64_MAX - 0x7ff);
2202 const double dDateMin = (double)(INT64_MIN + 0x7ff);
2203
2204 if(isnan(d) || d > dDateMax || d < dDateMin) {
Laurence Lundbladec7114722020-08-13 05:11:40 -07002205 uReturn = QCBOR_ERR_DATE_OVERFLOW;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002206 goto Done;
2207 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002208
2209 /* The actual conversion */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002210 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
Laurence Lundblade2feb1e12020-07-15 03:50:45 -07002211 pDecodedItem->val.epochDate.fSecondsFraction =
2212 d - (double)pDecodedItem->val.epochDate.nSeconds;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002213 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002214#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade4b270642020-08-14 12:53:07 -07002215
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002216 uReturn = QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundblade4b270642020-08-14 12:53:07 -07002217 goto Done;
2218
Laurence Lundblade9682a532020-06-06 18:33:04 -07002219#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002220 break;
2221
2222 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002223 /* It's the arrays and maps that are unrecoverable because
2224 * they are not consumed here. Since this is just an error
2225 * condition, no extra code is added here to make the error
2226 * recoverable for non-arrays and maps like strings. */
2227 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002228 goto Done;
2229 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002230
Laurence Lundblade59289e52019-12-30 13:44:37 -08002231 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
2232
2233Done:
Laurence Lundbladec7114722020-08-13 05:11:40 -07002234 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002235}
2236
2237
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002238/**
2239 * @brief Convert the days epoch date.
2240 *
2241 * pDecodedItem[in,out] The data item to convert.
2242 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002243 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2244 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2245 * floating-point date disabled.
2246 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2247 * all floating-point disabled.
2248 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2249 * error decoding date.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002250 *
2251 * This is much simpler than the other epoch date format because
2252 * floating-porint is not allowed. This is mostly a simple type check.
2253 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002254static QCBORError
2255QCBOR_Private_DecodeDaysEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002256{
2257 QCBORError uReturn = QCBOR_SUCCESS;
2258
2259 switch (pDecodedItem->uDataType) {
2260
2261 case QCBOR_TYPE_INT64:
2262 pDecodedItem->val.epochDays = pDecodedItem->val.int64;
2263 break;
2264
2265 case QCBOR_TYPE_UINT64:
2266 /* This only happens for CBOR type 0 > INT64_MAX so it is
2267 * always an overflow.
2268 */
2269 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2270 goto Done;
2271 break;
2272
2273 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002274 /* It's the arrays and maps that are unrecoverable because
2275 * they are not consumed here. Since this is just an error
2276 * condition, no extra code is added here to make the error
2277 * recoverable for non-arrays and maps like strings. */
2278 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002279 goto Done;
2280 break;
2281 }
2282
2283 pDecodedItem->uDataType = QCBOR_TYPE_DAYS_EPOCH;
2284
2285Done:
2286 return uReturn;
2287}
2288
2289
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002290#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade37286c02022-09-03 10:05:02 -07002291
2292/* Forward declaration is necessary for
2293 * QCBORDecode_MantissaAndExponent(). to be able to decode bignum
2294 * tags in the mantissa. If the mantissa is a decimal fraction or big
2295 * float in error, this will result in a recurive call to
2296 * QCBORDecode_MantissaAndExponent(), but the recursion will unwined
2297 * correctly and the correct error is returned.
2298 */
2299static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002300QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2301 QCBORItem *pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002302
2303
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002304/**
2305 * @brief Decode decimal fractions and big floats.
2306 *
2307 * @param[in] pMe The decode context.
2308 * @param[in,out] pDecodedItem On input the array data item that
2309 * holds the mantissa and exponent. On
2310 * output the decoded mantissa and
2311 * exponent.
2312 *
2313 * @returns Decoding errors from getting primitive data items or
2314 * \ref QCBOR_ERR_BAD_EXP_AND_MANTISSA.
2315 *
Laurence Lundblade37286c02022-09-03 10:05:02 -07002316 * When called pDecodedItem must be the array with two members, the
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002317 * exponent and mantissa.
2318 *
2319 * This will fetch and decode the exponent and mantissa and put the
2320 * result back into pDecodedItem.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002321 *
2322 * This does no checking or processing of tag numbers. That is to be
2323 * done by the code that calls this.
2324 *
2325 * This stuffs the type of the mantissa into pDecodedItem with the expectation
2326 * the caller will process it.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002327 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002328static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002329QCBORDecode_Private_ExpMantissa(QCBORDecodeContext *pMe,
2330 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002331{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002332 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002333
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002334 /* --- Make sure it is an array; track nesting level of members --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002335 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002336 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002337 goto Done;
2338 }
2339
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002340 /* A check for pDecodedItem->val.uCount == 2 would work for
Laurence Lundblade37286c02022-09-03 10:05:02 -07002341 * definite-length arrays, but not for indefinite. Instead remember
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002342 * the nesting level the two integers must be at, which is one
2343 * deeper than that of the array.
2344 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002345 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
2346
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002347 /* --- Get the exponent --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002348 QCBORItem exponentItem;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002349 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, &exponentItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002350 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002351 goto Done;
2352 }
2353 if(exponentItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002354 /* Array is empty or a map/array encountered when expecting an int */
2355 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002356 goto Done;
2357 }
2358 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002359 /* Data arriving as an unsigned int < INT64_MAX has been
2360 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2361 * also means that the only data arriving here of type
2362 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2363 * and thus an error that will get handled in the next else.
2364 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002365 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
2366 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002367 /* Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX */
2368 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002369 goto Done;
2370 }
2371
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002372 /* --- Get the mantissa --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002373 QCBORItem mantissaItem;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002374 uReturn = QCBORDecode_Private_GetNextTagContent(pMe, &mantissaItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002375 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002376 goto Done;
2377 }
2378 if(mantissaItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002379 /* Mantissa missing or map/array encountered when expecting number */
2380 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002381 goto Done;
2382 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002383 /* Stuff the mantissa data type into the item to send it up to the
2384 * the next level. */
2385 pDecodedItem->uDataType = mantissaItem.uDataType;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002386 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002387 /* Data arriving as an unsigned int < INT64_MAX has been
2388 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2389 * also means that the only data arriving here of type
2390 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2391 * and thus an error that will get handled in an else below.
2392 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002393 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002394#ifndef QCBOR_DISABLE_TAGS
2395 /* With tags fully disabled a big number mantissa will error out
2396 * in the call to QCBORDecode_GetNextWithTags() because it has
2397 * a tag number.
2398 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07002399 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM ||
2400 mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002401 /* Got a good big num mantissa */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002402 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002403#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002404 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002405 /* Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX */
2406 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002407 goto Done;
2408 }
2409
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002410 /* --- Check that array only has the two numbers --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002411 if(mantissaItem.uNextNestLevel == nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002412 /* Extra items in the decimal fraction / big float */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002413 /* Improvement: this should probably be an unrecoverable error. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002414 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002415 goto Done;
2416 }
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002417 pDecodedItem->uNextNestLevel = mantissaItem.uNextNestLevel;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002418
2419Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002420 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002421}
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002422#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002423
2424
Laurence Lundblade37286c02022-09-03 10:05:02 -07002425#ifndef QCBOR_DISABLE_TAGS
2426
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002427#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002428/**
2429 * @brief Decode the MIME type tag
2430 *
2431 * @param[in,out] pDecodedItem The item to decode.
2432 *
2433 * Handle the text and binary MIME type tags. Slightly too complicated
2434 * f or ProcessTaggedString() because the RFC 7049 MIME type was
2435 * incorreclty text-only.
2436 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002437static QCBORError
2438QCBOR_Private_DecodeMIME(QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002439{
2440 if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) {
2441 pDecodedItem->uDataType = QCBOR_TYPE_MIME;
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07002442 } else if(pDecodedItem->uDataType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002443 pDecodedItem->uDataType = QCBOR_TYPE_BINARY_MIME;
2444 } else {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002445 /* It's the arrays and maps that are unrecoverable because
2446 * they are not consumed here. Since this is just an error
2447 * condition, no extra code is added here to make the error
2448 * recoverable for non-arrays and maps like strings. */
2449 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002450 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002451
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002452 return QCBOR_SUCCESS;
2453}
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002454#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002455
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002456/**
Laurence Lundblade99615302020-11-29 11:19:47 -08002457 * Table of CBOR tags whose content is either a text string or a byte
2458 * string. The table maps the CBOR tag to the QCBOR type. The high-bit
2459 * of uQCBORtype indicates the content should be a byte string rather
2460 * than a text string
2461 */
2462struct StringTagMapEntry {
2463 uint16_t uTagNumber;
2464 uint8_t uQCBORtype;
2465};
2466
2467#define IS_BYTE_STRING_BIT 0x80
2468#define QCBOR_TYPE_MASK ~IS_BYTE_STRING_BIT
2469
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002470static const struct StringTagMapEntry QCBOR_Private_StringTagMap[] = {
Laurence Lundblade99615302020-11-29 11:19:47 -08002471 {CBOR_TAG_DATE_STRING, QCBOR_TYPE_DATE_STRING},
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002472 {CBOR_TAG_DAYS_STRING, QCBOR_TYPE_DAYS_STRING},
Laurence Lundblade99615302020-11-29 11:19:47 -08002473 {CBOR_TAG_POS_BIGNUM, QCBOR_TYPE_POSBIGNUM | IS_BYTE_STRING_BIT},
2474 {CBOR_TAG_NEG_BIGNUM, QCBOR_TYPE_NEGBIGNUM | IS_BYTE_STRING_BIT},
2475 {CBOR_TAG_CBOR, QBCOR_TYPE_WRAPPED_CBOR | IS_BYTE_STRING_BIT},
2476 {CBOR_TAG_URI, QCBOR_TYPE_URI},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002477#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002478 {CBOR_TAG_B64URL, QCBOR_TYPE_BASE64URL},
2479 {CBOR_TAG_B64, QCBOR_TYPE_BASE64},
2480 {CBOR_TAG_REGEX, QCBOR_TYPE_REGEX},
2481 {CBOR_TAG_BIN_UUID, QCBOR_TYPE_UUID | IS_BYTE_STRING_BIT},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002482#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade99615302020-11-29 11:19:47 -08002483 {CBOR_TAG_CBOR_SEQUENCE, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE | IS_BYTE_STRING_BIT},
2484 {CBOR_TAG_INVALID16, QCBOR_TYPE_NONE}
2485};
2486
2487
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002488/**
2489 * @brief Process standard CBOR tags whose content is a string
2490 *
2491 * @param[in] uTag The tag.
2492 * @param[in,out] pDecodedItem The data item.
2493 *
2494 * @returns This returns QCBOR_SUCCESS if the tag was procssed,
2495 * \ref QCBOR_ERR_UNSUPPORTED if the tag was not processed and
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002496 * \ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT if the content type was wrong for the tag.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002497 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002498 * Process the CBOR tags that whose content is a byte string or a text
2499 * string and for which the string is just passed on to the caller.
2500 *
2501 * This maps the CBOR tag to the QCBOR type and checks the content
2502 * type. Nothing more. It may not be the most important
Laurence Lundbladec02e13e2020-12-06 05:45:41 -08002503 * functionality, but it part of implementing as much of RFC 8949 as
Laurence Lundblade99615302020-11-29 11:19:47 -08002504 * possible.
Laurence Lundblade99615302020-11-29 11:19:47 -08002505 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002506static QCBORError
2507QCBOR_Private_ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002508{
Laurence Lundblade99615302020-11-29 11:19:47 -08002509 /* This only works on tags that were not mapped; no need for other yet */
2510 if(uTag > QCBOR_LAST_UNMAPPED_TAG) {
2511 return QCBOR_ERR_UNSUPPORTED;
2512 }
2513
2514 unsigned uIndex;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002515 for(uIndex = 0; QCBOR_Private_StringTagMap[uIndex].uTagNumber != CBOR_TAG_INVALID16; uIndex++) {
2516 if(QCBOR_Private_StringTagMap[uIndex].uTagNumber == uTag) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002517 break;
2518 }
2519 }
2520
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002521 const uint8_t uQCBORType = QCBOR_Private_StringTagMap[uIndex].uQCBORtype;
Laurence Lundblade99615302020-11-29 11:19:47 -08002522 if(uQCBORType == QCBOR_TYPE_NONE) {
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002523 /* repurpose this error to mean not handled here */
Laurence Lundblade99615302020-11-29 11:19:47 -08002524 return QCBOR_ERR_UNSUPPORTED;
2525 }
2526
2527 uint8_t uExpectedType = QCBOR_TYPE_TEXT_STRING;
2528 if(uQCBORType & IS_BYTE_STRING_BIT) {
2529 uExpectedType = QCBOR_TYPE_BYTE_STRING;
2530 }
2531
2532 if(pDecodedItem->uDataType != uExpectedType) {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002533 /* It's the arrays and maps that are unrecoverable because
2534 * they are not consumed here. Since this is just an error
2535 * condition, no extra code is added here to make the error
2536 * recoverable for non-arrays and maps like strings. */
2537 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002538 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002539
Laurence Lundblade99615302020-11-29 11:19:47 -08002540 pDecodedItem->uDataType = (uint8_t)(uQCBORType & QCBOR_TYPE_MASK);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002541 return QCBOR_SUCCESS;
2542}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002543#endif /* QCBOR_DISABLE_TAGS */
2544
2545
2546#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002547/**
2548 * @brief Figures out data type for exponent mantissa tags.
2549 *
2550 * @param[in] uTagToProcess Either @ref CBOR_TAG_DECIMAL_FRACTION or
2551 * @ref CBOR_TAG_BIG_FLOAT.
2552 * @param[in] pDecodedItem Item being decoded.
2553 *
2554 * @returns One of the 6 values between \ref QCBOR_TYPE_DECIMAL_FRACTION
2555 * and @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM.
2556 *
2557 * Does mapping between a CBOR tag number and a QCBOR type. with a
2558 * little bit of logic and arithmatic.
2559 *
2560 * Used in serveral contexts. Does the work where sometimes the data
2561 * item is explicitly tagged and sometimes not.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002562 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002563static uint8_t
2564QCBOR_Private_ExpMantissaDataType(const uint16_t uTagToProcess,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002565 const QCBORItem *pDecodedItem)
Laurence Lundblade37286c02022-09-03 10:05:02 -07002566{
2567 uint8_t uBase = uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ?
2568 QCBOR_TYPE_DECIMAL_FRACTION :
2569 QCBOR_TYPE_BIGFLOAT;
2570 if(pDecodedItem->uDataType != QCBOR_TYPE_INT64) {
2571 uBase = (uint8_t)(uBase + pDecodedItem->uDataType - QCBOR_TYPE_POSBIGNUM + 1);
2572 }
2573 return uBase;
2574}
2575#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002576
2577
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002578/**
2579 * @brief Decode tag content for select tags (decoding layer 1).
2580 *
2581 * @param[in] pMe The decode context.
2582 * @param[out] pDecodedItem The decoded item.
2583 *
2584 * @return Decoding error code.
2585 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002586 * CBOR tag numbers for the item were decoded in GetNext_TaggedItem(),
2587 * but the whole tag was not decoded. Here, the whole tags (tag number
2588 * and tag content) that are supported by QCBOR are decoded. This is a
2589 * quick pass through for items that are not tags.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002590 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002591static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002592QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2593 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002594{
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002595 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002596
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002597 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pDecodedItem);
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002598 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002599 goto Done;
2600 }
2601
Laurence Lundblade37286c02022-09-03 10:05:02 -07002602#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002603 /* When there are no tag numbers for the item, this exits first
2604 * thing and effectively does nothing.
2605 *
2606 * This loops over all the tag numbers accumulated for this item
2607 * trying to decode and interpret them. This stops at the end of
2608 * the list or at the first tag number that can't be interpreted by
2609 * this code. This is effectively a recursive processing of the
2610 * tags number list that handles nested tags.
2611 */
2612 while(1) {
2613 /* Don't bother to unmap tags via QCBORITem.uTags since this
2614 * code only works on tags less than QCBOR_LAST_UNMAPPED_TAG.
2615 */
2616 const uint16_t uTagToProcess = pDecodedItem->uTags[0];
Laurence Lundblade59289e52019-12-30 13:44:37 -08002617
Laurence Lundblade99615302020-11-29 11:19:47 -08002618 if(uTagToProcess == CBOR_TAG_INVALID16) {
2619 /* Hit the end of the tag list. A successful exit. */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002620 break;
2621
Laurence Lundblade99615302020-11-29 11:19:47 -08002622 } else if(uTagToProcess == CBOR_TAG_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002623 uReturn = QCBOR_Private_DecodeDateEpoch(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002624
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002625 } else if(uTagToProcess == CBOR_TAG_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002626 uReturn = QCBOR_Private_DecodeDaysEpoch(pDecodedItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002627
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002628#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade99615302020-11-29 11:19:47 -08002629 } else if(uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ||
2630 uTagToProcess == CBOR_TAG_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002631 uReturn = QCBORDecode_Private_ExpMantissa(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002632 /* --- Which is it, decimal fraction or a bigfloat? --- */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002633 pDecodedItem->uDataType = QCBOR_Private_ExpMantissaDataType(uTagToProcess, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002634
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002635#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002636#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002637 } else if(uTagToProcess == CBOR_TAG_MIME ||
2638 uTagToProcess == CBOR_TAG_BINARY_MIME) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002639 uReturn = QCBOR_Private_DecodeMIME(pDecodedItem);
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002640#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002641
Laurence Lundblade99615302020-11-29 11:19:47 -08002642 } else {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002643 /* See if it is a passthrough byte/text string tag; process if so */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002644 uReturn = QCBOR_Private_ProcessTaggedString(pDecodedItem->uTags[0], pDecodedItem);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002645
Laurence Lundblade99615302020-11-29 11:19:47 -08002646 if(uReturn == QCBOR_ERR_UNSUPPORTED) {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002647 /* It wasn't a passthrough byte/text string tag so it is
Laurence Lundblade99615302020-11-29 11:19:47 -08002648 * an unknown tag. This is the exit from the loop on the
2649 * first unknown tag. It is a successful exit.
2650 */
2651 uReturn = QCBOR_SUCCESS;
2652 break;
2653 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002654 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002655
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002656 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002657 /* Error exit from the loop */
2658 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002659 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002660
2661 /* A tag was successfully processed, shift it out of the list of
2662 * tags returned. This is the loop increment.
2663 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002664 QCBOR_Private_ShiftTags(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002665 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002666#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002667
2668Done:
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002669 return uReturn;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002670}
2671
2672
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002673/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002674 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002675 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002676QCBORError
2677QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2678{
2679 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002680 uErr = QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002681 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002682 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2683 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
2684 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002685 return uErr;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002686}
2687
2688
2689/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002690 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08002691 */
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002692QCBORError
2693QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2694{
2695 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2696 const UsefulInputBuf Save = pMe->InBuf;
2697
2698 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
2699
2700 pMe->nesting = SaveNesting;
2701 pMe->InBuf = Save;
2702
2703 return uErr;
2704}
2705
2706
2707/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002708 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002709 */
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002710void
2711QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2712{
2713 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002714 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2715 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002716 return;
2717 }
2718
2719 pMe->uLastError = (uint8_t)QCBORDecode_PeekNext(pMe, pDecodedItem);
2720}
2721
2722
2723/*
2724 * Public function, see header qcbor/qcbor_decode.h file
2725 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002726void
2727QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002728{
2729 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002730 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2731 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002732 return;
2733 }
2734
2735 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem);
2736}
2737
2738
2739/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002740 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002741 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002742QCBORError
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002743QCBORDecode_GetNextWithTags(QCBORDecodeContext *pMe,
2744 QCBORItem *pDecodedItem,
2745 QCBORTagListOut *pTags)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002746{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002747#ifndef QCBOR_DISABLE_TAGS
2748
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002749 QCBORError uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002750
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002751 uReturn = QCBORDecode_GetNext(pMe, pDecodedItem);
2752 if(uReturn != QCBOR_SUCCESS) {
2753 return uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002754 }
2755
2756 if(pTags != NULL) {
2757 pTags->uNumUsed = 0;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002758 /* Reverse the order because pTags is reverse of QCBORItem.uTags. */
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002759 for(int nTagIndex = QCBOR_MAX_TAGS_PER_ITEM-1; nTagIndex >=0; nTagIndex--) {
2760 if(pDecodedItem->uTags[nTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07002761 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002762 }
2763 if(pTags->uNumUsed >= pTags->uNumAllocated) {
2764 return QCBOR_ERR_TOO_MANY_TAGS;
2765 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002766 pTags->puTags[pTags->uNumUsed] = QCBORDecode_Private_UnMapTagNumber(pMe,pDecodedItem->uTags[nTagIndex]);
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002767 pTags->uNumUsed++;
2768 }
2769 }
2770
2771 return QCBOR_SUCCESS;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002772
2773#else /* QCBOR_DISABLE_TAGS */
2774 (void)pMe;
2775 (void)pDecodedItem;
2776 (void)pTags;
2777 return QCBOR_ERR_TAGS_DISABLED;
2778#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002779}
2780
2781
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002782/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002783 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05302784 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002785bool
2786QCBORDecode_IsTagged(QCBORDecodeContext *pMe,
2787 const QCBORItem *pItem,
2788 uint64_t uTag)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002789{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002790#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002791 for(unsigned uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) {
2792 if(pItem->uTags[uTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002793 break;
2794 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002795 if(QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uTagIndex]) == uTag) {
Laurence Lundbladef71e1622020-08-06 18:52:13 -07002796 return true;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002797 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002798 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002799#else /* QCBOR_TAGS_DISABLED */
2800 (void)pMe;
2801 (void)pItem;
2802 (void)uTag;
2803#endif /* QCBOR_TAGS_DISABLED */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002804
Laurence Lundbladef71e1622020-08-06 18:52:13 -07002805 return false;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002806}
2807
2808
2809/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002810 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002811 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002812QCBORError
2813QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002814{
Laurence Lundblade87495732021-02-26 10:05:55 -07002815 if(puConsumed != NULL) {
2816 *puConsumed = pMe->InBuf.cursor;
2817 }
2818
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002819 QCBORError uReturn = pMe->uLastError;
Laurence Lundblade085d7952020-07-24 10:26:30 -07002820
2821 if(uReturn != QCBOR_SUCCESS) {
2822 goto Done;
2823 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002824
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002825 /* Error out if all the maps/arrays are not closed out */
2826 if(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002827 uReturn = QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002828 goto Done;
2829 }
2830
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002831 /* Error out if not all the bytes are consumed */
2832 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf))) {
Laurence Lundblade085d7952020-07-24 10:26:30 -07002833 uReturn = QCBOR_ERR_EXTRA_BYTES;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002834 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002835
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002836Done:
Laurence Lundblade87495732021-02-26 10:05:55 -07002837 return uReturn;
2838}
2839
2840
2841/*
2842 * Public function, see header qcbor/qcbor_decode.h file
2843 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002844QCBORError
2845QCBORDecode_Finish(QCBORDecodeContext *pMe)
Laurence Lundblade87495732021-02-26 10:05:55 -07002846{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002847#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002848 /* Call the destructor for the string allocator if there is one.
2849 * Always called, even if there are errors; always have to clean up.
2850 */
2851 StringAllocator_Destruct(&(pMe->StringAllocator));
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002852#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002853
Laurence Lundblade87495732021-02-26 10:05:55 -07002854 return QCBORDecode_PartialFinish(pMe, NULL);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002855}
2856
2857
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002858/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002859 * Public function, see header qcbor/qcbor_decode.h file
2860 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002861uint64_t
2862QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
2863 const QCBORItem *pItem,
2864 uint32_t uIndex)
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002865{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002866#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002867 if(pItem->uDataType == QCBOR_TYPE_NONE) {
2868 return CBOR_TAG_INVALID64;
2869 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002870 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2871 return CBOR_TAG_INVALID64;
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002872 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002873 return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uIndex]);
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002874 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002875#else /* QCBOR_DISABLE_TAGS */
2876 (void)pMe;
2877 (void)pItem;
2878 (void)uIndex;
2879
2880 return CBOR_TAG_INVALID64;
2881#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002882}
2883
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002884
Laurence Lundblade9b334962020-08-27 10:55:53 -07002885/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002886 * Public function, see header qcbor/qcbor_decode.h file
2887 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002888uint64_t
2889QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe,
2890 uint32_t uIndex)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002891{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002892#ifndef QCBOR_DISABLE_TAGS
2893
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002894 if(pMe->uLastError != QCBOR_SUCCESS) {
2895 return CBOR_TAG_INVALID64;
2896 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002897 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2898 return CBOR_TAG_INVALID64;
2899 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002900 return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->uLastTags[uIndex]);
Laurence Lundblade9b334962020-08-27 10:55:53 -07002901 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002902#else /* QCBOR_DISABLE_TAGS */
2903 (void)pMe;
2904 (void)uIndex;
2905
2906 return CBOR_TAG_INVALID64;
2907#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07002908}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002909
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002910
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002911
2912
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002913#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladef6531662018-12-04 10:42:22 +09002914
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002915/* ===========================================================================
2916 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002917
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002918 This implements a simple sting allocator for indefinite-length
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002919 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
2920 implements the function type QCBORStringAllocate and allows easy
2921 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09002922
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002923 This particular allocator is built-in for convenience. The caller
2924 can implement their own. All of this following code will get
2925 dead-stripped if QCBORDecode_SetMemPool() is not called.
2926
2927 This is a very primitive memory allocator. It does not track
2928 individual allocations, only a high-water mark. A free or
2929 reallocation must be of the last chunk allocated.
2930
2931 The size of the pool and offset to free memory are packed into the
2932 first 8 bytes of the memory pool so we don't have to keep them in
2933 the decode context. Since the address of the pool may not be
2934 aligned, they have to be packed and unpacked as if they were
2935 serialized data of the wire or such.
2936
2937 The sizes packed in are uint32_t to be the same on all CPU types
2938 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08002939 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002940
2941
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002942static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08002943MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002944{
2945 // Use of UsefulInputBuf is overkill, but it is convenient.
2946 UsefulInputBuf UIB;
2947
Laurence Lundbladeee851742020-01-08 08:37:05 -08002948 // Just assume the size here. It was checked during SetUp so
2949 // the assumption is safe.
Laurence Lundblade93d89472020-10-03 22:30:50 -07002950 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem,QCBOR_DECODE_MIN_MEM_POOL_SIZE});
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002951 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
2952 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
2953 return UsefulInputBuf_GetError(&UIB);
2954}
2955
2956
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002957static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08002958MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002959{
2960 // Use of UsefulOutBuf is overkill, but convenient. The
2961 // length check performed here is useful.
2962 UsefulOutBuf UOB;
2963
2964 UsefulOutBuf_Init(&UOB, Pool);
2965 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
2966 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
2967 return UsefulOutBuf_GetError(&UOB);
2968}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002969
2970
2971/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002972 Internal function for an allocation, reallocation free and destuct.
2973
2974 Having only one function rather than one each per mode saves space in
2975 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002976
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002977 Code Reviewers: THIS FUNCTION DOES POINTER MATH
2978 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08002979static UsefulBuf
2980MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002981{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002982 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002983
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002984 uint32_t uPoolSize;
2985 uint32_t uFreeOffset;
2986
2987 if(uNewSize > UINT32_MAX) {
2988 // This allocator is only good up to 4GB. This check should
2989 // optimize out if sizeof(size_t) == sizeof(uint32_t)
2990 goto Done;
2991 }
2992 const uint32_t uNewSize32 = (uint32_t)uNewSize;
2993
2994 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
2995 goto Done;
2996 }
2997
2998 if(uNewSize) {
2999 if(pMem) {
3000 // REALLOCATION MODE
3001 // Calculate pointer to the end of the memory pool. It is
3002 // assumed that pPool + uPoolSize won't wrap around by
3003 // assuming the caller won't pass a pool buffer in that is
3004 // not in legitimate memory space.
3005 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
3006
3007 // Check that the pointer for reallocation is in the range of the
3008 // pool. This also makes sure that pointer math further down
3009 // doesn't wrap under or over.
3010 if(pMem >= pPool && pMem < pPoolEnd) {
3011 // Offset to start of chunk for reallocation. This won't
3012 // wrap under because of check that pMem >= pPool. Cast
3013 // is safe because the pool is always less than UINT32_MAX
3014 // because of check in QCBORDecode_SetMemPool().
3015 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3016
3017 // Check to see if the allocation will fit. uPoolSize -
3018 // uMemOffset will not wrap under because of check that
3019 // pMem is in the range of the uPoolSize by check above.
3020 if(uNewSize <= uPoolSize - uMemOffset) {
3021 ReturnValue.ptr = pMem;
3022 ReturnValue.len = uNewSize;
3023
3024 // Addition won't wrap around over because uNewSize was
3025 // checked to be sure it is less than the pool size.
3026 uFreeOffset = uMemOffset + uNewSize32;
3027 }
3028 }
3029 } else {
3030 // ALLOCATION MODE
3031 // uPoolSize - uFreeOffset will not underflow because this
3032 // pool implementation makes sure uFreeOffset is always
3033 // smaller than uPoolSize through this check here and
3034 // reallocation case.
3035 if(uNewSize <= uPoolSize - uFreeOffset) {
3036 ReturnValue.len = uNewSize;
3037 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08003038 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003039 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003040 }
3041 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003042 if(pMem) {
3043 // FREE MODE
3044 // Cast is safe because of limit on pool size in
3045 // QCBORDecode_SetMemPool()
3046 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3047 } else {
3048 // DESTRUCT MODE
3049 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003050 }
3051 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003052
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003053 UsefulBuf Pool = {pPool, uPoolSize};
3054 MemPool_Pack(Pool, uFreeOffset);
3055
3056Done:
3057 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003058}
3059
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003060
Laurence Lundbladef6531662018-12-04 10:42:22 +09003061/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003062 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09003063 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003064QCBORError
3065QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
3066 UsefulBuf Pool,
3067 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003068{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003069 // The pool size and free mem offset are packed into the beginning
Dave Thaler93c01182022-08-06 15:08:35 -04003070 // of the pool memory. This compile time check makes sure the
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003071 // constant in the header is correct. This check should optimize
3072 // down to nothing.
Dave Thaler93c01182022-08-06 15:08:35 -04003073#ifdef _MSC_VER
3074#pragma warning(push)
3075#pragma warning(disable:4127) // conditional expression is constant
3076#endif
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003077 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003078 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003079 }
Dave Thaler93c01182022-08-06 15:08:35 -04003080#ifdef _MSC_VER
3081#pragma warning(pop)
3082#endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003083
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003084 // The pool size and free offset packed in to the beginning of pool
3085 // memory are only 32-bits. This check will optimize out on 32-bit
3086 // machines.
3087 if(Pool.len > UINT32_MAX) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003088 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003089 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003090
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003091 // This checks that the pool buffer given is big enough.
3092 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003093 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003094 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003095
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003096 QCBORDecode_SetUpAllocator(pMe, MemPool_Function, Pool.ptr, bAllStrings);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003097
Laurence Lundblade30816f22018-11-10 13:40:22 +07003098 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003099}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003100#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003101
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003102
3103
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003104static void
3105QCBORDecode_Private_CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07003106{
Laurence Lundblade37286c02022-09-03 10:05:02 -07003107#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade9b334962020-08-27 10:55:53 -07003108 memcpy(pMe->uLastTags, pItem->uTags, sizeof(pItem->uTags));
Laurence Lundblade37286c02022-09-03 10:05:02 -07003109#else
3110 (void)pMe;
3111 (void)pItem;
3112#endif
Laurence Lundblade9b334962020-08-27 10:55:53 -07003113}
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003114
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003115
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003116/**
3117 * @brief Consume an entire map or array including its contents.
3118 *
3119 * @param[in] pMe The decoder context.
3120 * @param[in] pItemToConsume The array/map whose contents are to be
3121 * consumed.
3122 * @param[out] puNextNestLevel The next nesting level after the item was
3123 * fully consumed.
3124 *
3125 * This may be called when @c pItemToConsume is not an array or
3126 * map. In that case, this is just a pass through for @c puNextNestLevel
3127 * since there is nothing to do.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003128 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003129static QCBORError
3130QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
3131 const QCBORItem *pItemToConsume,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003132 bool *pbBreak,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003133 uint8_t *puNextNestLevel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003134{
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003135 QCBORError uReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003136 QCBORItem Item;
Laurence Lundblade9b334962020-08-27 10:55:53 -07003137
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003138 /* If it is a map or array, this will tell if it is empty. */
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003139 const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel);
3140
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003141 if(QCBORItem_IsMapOrArray(*pItemToConsume) && !bIsEmpty) {
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003142 /* There is only real work to do for non-empty maps and arrays */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003143
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003144 /* This works for definite- and indefinite-length maps and
3145 * arrays by using the nesting level
Laurence Lundblade1341c592020-04-11 14:19:05 -07003146 */
3147 do {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003148 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pbBreak, &Item);
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003149 if(QCBORDecode_IsUnrecoverableError(uReturn) ||
3150 uReturn == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003151 goto Done;
3152 }
3153 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003154
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003155 *puNextNestLevel = Item.uNextNestLevel;
3156
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003157 uReturn = QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003158
Laurence Lundblade1341c592020-04-11 14:19:05 -07003159 } else {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003160 /* pItemToConsume is not a map or array. Just pass the nesting
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003161 * level through. */
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003162 *puNextNestLevel = pItemToConsume->uNextNestLevel;
3163
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003164 uReturn = QCBOR_SUCCESS;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003165 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003166
3167Done:
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003168 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003169}
3170
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003171
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003172/*
3173 * Public function, see header qcbor/qcbor_decode.h file
3174 */
3175void
3176QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003177{
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003178 QCBORDecode_VGetNext(pMe, pDecodedItem);
3179
3180 if(pMe->uLastError == QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003181 pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL,
Máté Tóth-Pálc6d59682021-05-26 18:55:30 +02003182 &pDecodedItem->uNextNestLevel);
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003183 }
3184}
3185
3186
Laurence Lundblade11654912024-05-09 11:49:24 -07003187/*
3188 * Public function, see header qcbor/qcbor_decode.h file
3189 */
3190uint32_t
3191QCBORDecode_Tell(QCBORDecodeContext *pMe)
3192{
3193 size_t uCursorOffset;
3194
3195 if(pMe->uLastError != QCBOR_SUCCESS) {
3196 return UINT32_MAX;
3197 }
3198
3199 uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
3200
3201 if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
3202 return UINT32_MAX;
3203 } else {
3204 /* Cast is safe because decoder input size is restricted. */
3205 return (uint32_t)uCursorOffset;
3206 }
3207}
3208
3209
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003210/**
3211 * @brief Rewind cursor to start as if map or array were just entered.
3212 *
3213 * @param[in] pMe The decoding context
3214 *
3215 * This affects the nesting tracking and the UsefulInputBuf.
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003216 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003217static void
3218QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003219{
3220 /* Reset nesting tracking to the deepest bounded level */
3221 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3222
3223 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3224
3225 /* Reposition traversal cursor to the start of the map/array */
3226 UsefulInputBuf_Seek(&(pMe->InBuf),
3227 DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
3228}
3229
3230
3231/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003232 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003233 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003234void
3235QCBORDecode_Rewind(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003236{
3237 if(pMe->nesting.pCurrentBounded != NULL) {
3238 /* In a bounded map, array or bstr-wrapped CBOR */
3239
3240 if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
3241 /* In bstr-wrapped CBOR. */
3242
3243 /* Reposition traversal cursor to start of wrapping byte string */
3244 UsefulInputBuf_Seek(&(pMe->InBuf),
3245 pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
3246 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3247
3248 } else {
3249 /* In a map or array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003250 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003251 }
3252
3253 } else {
3254 /* Not in anything bounded */
3255
3256 /* Reposition traversal cursor to the start of input CBOR */
3257 UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
3258
3259 /* Reset nesting tracking to beginning of input. */
3260 DecodeNesting_Init(&(pMe->nesting));
3261 }
3262
3263 pMe->uLastError = QCBOR_SUCCESS;
3264}
3265
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003266
Laurence Lundblade9b334962020-08-27 10:55:53 -07003267
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003268
3269
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003270typedef struct {
3271 void *pCBContext;
3272 QCBORItemCallback pfCallback;
3273} MapSearchCallBack;
3274
3275typedef struct {
3276 size_t uStartOffset;
3277 uint16_t uItemCount;
3278} MapSearchInfo;
3279
3280
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003281/**
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003282 * @brief Search a map for a set of items.
3283 *
3284 * @param[in] pMe The decode context to search.
3285 * @param[in,out] pItemArray The items to search for and the items found.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003286 * @param[out] pInfo Several bits of meta-info returned by search.
3287 * @param[in] pCallBack Callback object or @c NULL.
3288 * TODO: fix params
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003289 *
3290 * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map.
3291 *
3292 * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label)
3293 * were found for one of the labels being
3294 * search for. This duplicate detection is
3295 * only performed for items in pItemArray,
3296 * not every item in the map.
3297 *
3298 * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was
3299 * wrong for the matchd label.
3300 *
3301 * @retval Also errors returned by QCBORDecode_GetNext().
3302 *
3303 * On input, \c pItemArray contains a list of labels and data types of
3304 * items to be found.
3305 *
3306 * On output, the fully retrieved items are filled in with values and
3307 * such. The label was matched, so it never changes.
3308 *
3309 * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE.
3310 *
3311 * This also finds the ends of maps and arrays when they are exited.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003312 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003313static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003314QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
3315 QCBORItem *pItemArray,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003316 MapSearchInfo *pInfo,
3317 MapSearchCallBack *pCallBack)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003318{
Laurence Lundbladee6f15112020-07-23 18:44:16 -07003319 QCBORError uReturn;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003320 uint64_t uFoundItemBitMap = 0;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07003321
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003322 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003323 uReturn = pMe->uLastError;
3324 goto Done2;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003325 }
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003326
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003327 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) &&
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003328 pItemArray->uLabelType != QCBOR_TYPE_NONE) {
3329 /* QCBOR_TYPE_NONE as first item indicates just looking
3330 for the end of an array, so don't give error. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003331 uReturn = QCBOR_ERR_MAP_NOT_ENTERED;
3332 goto Done2;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003333 }
3334
Laurence Lundblade085d7952020-07-24 10:26:30 -07003335 if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) {
3336 // It is an empty bounded array or map
3337 if(pItemArray->uLabelType == QCBOR_TYPE_NONE) {
3338 // Just trying to find the end of the map or array
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003339 pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003340 uReturn = QCBOR_SUCCESS;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003341 } else {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003342 // Nothing is ever found in an empty array or map. All items
3343 // are marked as not found below.
Laurence Lundblade085d7952020-07-24 10:26:30 -07003344 uReturn = QCBOR_SUCCESS;
3345 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003346 goto Done2;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003347 }
3348
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003349 QCBORDecodeNesting SaveNesting;
Laurence Lundblade11654912024-05-09 11:49:24 -07003350 size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003351 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3352
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003353 /* Reposition to search from the start of the map / array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003354 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundblade1341c592020-04-11 14:19:05 -07003355
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003356 /*
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003357 Loop over all the items in the map or array. Each item
3358 could be a map or array, but label matching is only at
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003359 the main level. This handles definite- and indefinite-
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003360 length maps and arrays. The only reason this is ever
3361 called on arrays is to find their end position.
3362
3363 This will always run over all items in order to do
3364 duplicate detection.
3365
3366 This will exit with failure if it encounters an
3367 unrecoverable error, but continue on for recoverable
3368 errors.
3369
3370 If a recoverable error occurs on a matched item, then
3371 that error code is returned.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003372 */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07003373 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003374 if(pInfo) {
3375 pInfo->uItemCount = 0;
3376 }
Máté Tóth-Pál2f2aa5f2021-05-17 21:35:09 +02003377 uint8_t uNextNestLevel;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003378 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003379 /* Remember offset of the item because sometimes it has to be returned */
Laurence Lundblade1341c592020-04-11 14:19:05 -07003380 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003381
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003382 /* Get the item */
3383 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003384 QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003385 if(QCBORDecode_IsUnrecoverableError(uResult)) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003386 /* The map/array can't be decoded when unrecoverable errors occur */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003387 uReturn = uResult;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003388 goto Done;
3389 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003390 if(uResult == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003391 /* Unexpected end of map or array. */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003392 uReturn = uResult;
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003393 goto Done;
3394 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003395
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003396 /* See if item has one of the labels that are of interest */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003397 bool bMatched = false;
3398 for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003399 if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003400 /* A label match has been found */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003401 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
3402 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003403 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003404 }
Laurence Lundblade63926052021-03-29 16:05:51 -07003405 if(uResult != QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003406 /* The label matches, but the data item is in error.
3407 * It is OK to have recoverable errors on items that are not
3408 * matched. */
Laurence Lundblade63926052021-03-29 16:05:51 -07003409 uReturn = uResult;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003410 goto Done;
3411 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003412 if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) {
Laurence Lundblade63926052021-03-29 16:05:51 -07003413 /* The data item is not of the type(s) requested */
3414 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003415 goto Done;
3416 }
3417
Laurence Lundblade1341c592020-04-11 14:19:05 -07003418 /* Successful match. Return the item. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003419 pItemArray[nIndex] = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003420 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003421 if(pInfo) {
3422 pInfo->uStartOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003423 }
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003424 bMatched = true;
3425 }
3426 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003427
3428
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003429 if(!bMatched && pCallBack != NULL) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003430 /*
3431 Call the callback on unmatched labels.
3432 (It is tempting to do duplicate detection here, but that would
3433 require dynamic memory allocation because the number of labels
3434 that might be encountered is unbounded.)
3435 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003436 uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item);
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003437 if(uReturn != QCBOR_SUCCESS) {
3438 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003439 }
3440 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003441
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003442 /*
3443 Consume the item whether matched or not. This
3444 does the work of traversing maps and array and
3445 everything in them. In this loop only the
3446 items at the current nesting level are examined
3447 to match the labels.
3448 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003449 uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel);
Laurence Lundbladec7114722020-08-13 05:11:40 -07003450 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003451 goto Done;
3452 }
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003453
3454 if(pInfo) {
3455 pInfo->uItemCount++;
3456 }
3457
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003458 } while (uNextNestLevel >= uMapNestLevel);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003459
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003460 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003461
3462 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003463
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003464 // Check here makes sure that this won't accidentally be
3465 // QCBOR_MAP_OFFSET_CACHE_INVALID which is larger than
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003466 // QCBOR_MAX_DECODE_INPUT_SIZE.
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -08003467 // Cast to uint32_t to possibly address cases where SIZE_MAX < UINT32_MAX
3468 if((uint32_t)uEndOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003469 uReturn = QCBOR_ERR_INPUT_TOO_LARGE;
3470 goto Done;
3471 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003472 /* Cast OK because encoded CBOR is limited to UINT32_MAX */
3473 pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003474
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003475 Done:
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003476 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade11654912024-05-09 11:49:24 -07003477 UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos);
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003478
3479 Done2:
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003480 /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */
Laurence Lundbladec7114722020-08-13 05:11:40 -07003481 for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003482 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003483 pItemArray[i].uDataType = QCBOR_TYPE_NONE;
3484 pItemArray[i].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003485 }
3486 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003487
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003488 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003489}
3490
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003491
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003492/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003493 * Public function, see header qcbor/qcbor_decode.h file
3494 */
3495void
3496QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
3497 int64_t nLabel,
3498 uint8_t uQcborType,
3499 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003500{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003501 if(pMe->uLastError != QCBOR_SUCCESS) {
3502 return;
3503 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003504
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003505 QCBORItem OneItemSeach[2];
3506 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3507 OneItemSeach[0].label.int64 = nLabel;
3508 OneItemSeach[0].uDataType = uQcborType;
3509 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003510
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003511 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003512
3513 *pItem = OneItemSeach[0];
3514
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003515 if(uReturn != QCBOR_SUCCESS) {
3516 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003517 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003518 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003519 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003520 }
3521
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003522 Done:
3523 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003524}
3525
3526
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003527/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003528 * Public function, see header qcbor/qcbor_decode.h file
3529 */
3530void
3531QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
3532 const char *szLabel,
3533 uint8_t uQcborType,
3534 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003535{
Laurence Lundbladeda095972020-06-06 18:35:33 -07003536 if(pMe->uLastError != QCBOR_SUCCESS) {
3537 return;
3538 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003539
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003540 QCBORItem OneItemSeach[2];
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003541 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3542 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3543 OneItemSeach[0].uDataType = uQcborType;
3544 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003545
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003546 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
3547
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003548 if(uReturn != QCBOR_SUCCESS) {
3549 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003550 }
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003551 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003552 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003553 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003554 }
3555
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003556 *pItem = OneItemSeach[0];
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003557
3558Done:
3559 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003560}
3561
3562
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003563
3564/**
3565 * @brief Semi-private. Get pointer, length and item for an array or map.
3566 *
3567 * @param[in] pMe The decode context.
3568 * @param[in] uType CBOR major type, either array/map.
3569 * @param[out] pItem The item for the array/map.
3570 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3571 *
3572 * The next item to be decoded must be a map or array as specified by \c uType.
3573 *
3574 * \c pItem will be filled in with the label and tags of the array or map
3575 * in addition to \c pEncodedCBOR giving the pointer and length of the
3576 * encoded CBOR.
3577 *
3578 * When this is complete, the traversal cursor is at the end of the array or
3579 * map that was retrieved.
3580 */
3581void
3582QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe,
3583 const uint8_t uType,
3584 QCBORItem *pItem,
3585 UsefulBufC *pEncodedCBOR)
3586{
3587 QCBORError uErr;
3588 uint8_t uNestLevel;
3589 size_t uStartingCursor;
3590 size_t uStartOfReturned;
3591 size_t uEndOfReturned;
3592 size_t uTempSaveCursor;
3593 bool bInMap;
3594 QCBORItem LabelItem;
3595 bool EndedByBreak;
3596
3597 uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3598 bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting));
3599
3600 /* Could call GetNext here, but don't need to because this
3601 * is only interested in arrays and maps. */
3602 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem);
3603 if(uErr != QCBOR_SUCCESS) {
3604 pMe->uLastError = (uint8_t)uErr;
3605 return;
3606 }
3607
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003608 uint8_t uItemDataType = pItem->uDataType;
Laurence Lundblade62cae932024-06-03 13:16:17 -07003609#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003610 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
3611 uItemDataType = QCBOR_TYPE_ARRAY;
3612 }
Laurence Lundblade62cae932024-06-03 13:16:17 -07003613#endif
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003614
3615 if(uItemDataType != uType) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003616 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
3617 return;
3618 }
3619
3620 if(bInMap) {
3621 /* If the item is in a map, the start of the array/map
3622 * itself, not the label, must be found. Do this by
3623 * rewinding to the starting position and fetching
3624 * just the label data item. QCBORDecode_Private_GetNextTagNumber()
3625 * doesn't do any of the array/map item counting or nesting
3626 * level tracking. Used here it will just fetech the label
3627 * data item.
3628 *
3629 * Have to save the cursor and put it back to the position
3630 * after the full item once the label as been fetched by
3631 * itself.
3632 */
3633 uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3634 UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor);
3635
3636 /* Item has been fetched once so safe to ignore error */
3637 (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem);
3638
3639 uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3640 UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor);
3641 } else {
3642 uStartOfReturned = uStartingCursor;
3643 }
3644
3645 /* Consume the entire array/map to find the end */
3646 uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel);
3647 if(uErr != QCBOR_SUCCESS) {
3648 pMe->uLastError = (uint8_t)uErr;
3649 goto Done;
3650 }
3651
3652 /* Fill in returned values */
3653 uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3654 if(EndedByBreak) {
3655 /* When ascending nesting levels, a break for the level above
3656 * was consumed. That break is not a part of what is consumed here. */
3657 uEndOfReturned--;
3658 }
3659 pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned);
3660 pEncodedCBOR->len = uEndOfReturned - uStartOfReturned;
3661
3662Done:
3663 return;
3664}
3665
3666
3667/**
3668 * @brief Semi-private. Get pointer, length and item count of an array or map.
3669 *
3670 * @param[in] pMe The decode context.
3671 * @param[in] pTarget The label and type of the array or map to retrieve.
3672 * @param[out] pItem The item for the array/map.
3673 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3674 *
3675 * The next item to be decoded must be a map or array as specified by \c uType.
3676 *
3677 * When this is complete, the traversal cursor is unchanged.
3678 */void
3679QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe,
3680 QCBORItem *pTarget,
3681 QCBORItem *pItem,
3682 UsefulBufC *pEncodedCBOR)
3683{
3684 MapSearchInfo Info;
3685 QCBORDecodeNesting SaveNesting;
3686 size_t uSaveCursor;
3687
3688 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL);
3689 if(pMe->uLastError != QCBOR_SUCCESS) {
3690 return;
3691 }
3692
3693 /* Save the whole position of things so they can be restored.
3694 * so the cursor position is unchanged by this operation, like
3695 * all the other GetXxxxInMap() operations. */
3696 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3697 uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3698
3699 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3700 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
3701 QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR);
3702
3703 UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor);
3704 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
3705}
3706
3707
3708
3709
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003710/**
3711 * @brief Is a QCBOR_TYPE in the type list?
3712 *
3713 * @param[in] uDataType Type to check for.
3714 * @param[in] puTypeList List to check.
3715 *
3716 * @retval QCBOR_SUCCESS If in the list.
3717 * @retval QCBOR_ERR_UNEXPECTED_TYPE Not in the list.
3718 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07003719static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003720QCBOR_Private_CheckTypeList(const int uDataType,
3721 const uint8_t puTypeList[QCBOR_TAGSPEC_NUM_TYPES])
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003722{
3723 for(size_t i = 0; i < QCBOR_TAGSPEC_NUM_TYPES; i++) {
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003724 if(uDataType == puTypeList[i]) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003725 return QCBOR_SUCCESS;
3726 }
3727 }
3728 return QCBOR_ERR_UNEXPECTED_TYPE;
3729}
3730
Laurence Lundblade67257dc2020-07-27 03:33:37 -07003731
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003732/**
Laurence Lundblade37286c02022-09-03 10:05:02 -07003733 * Match a tag/type specification against the type of the item.
3734 *
3735 * @param[in] TagSpec Specification for matching tags.
3736 * @param[in] pItem The item to check.
3737 *
3738 * @retval QCBOR_SUCCESS \c uDataType is allowed by @c TagSpec
3739 * @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec
3740 *
3741 * This checks the item data type of untagged items as well as of
3742 * tagged items against a specification to see if decoding should
3743 * proceed.
3744 *
3745 * This relies on the automatic tag decoding done by QCBOR that turns
3746 * tag numbers into particular QCBOR_TYPEs so there is no actual
3747 * comparsion of tag numbers, just of QCBOR_TYPEs.
3748 *
3749 * This checks the data item type as possibly representing the tag
3750 * number or as the tag content type.
3751 *
3752 * If QCBOR_DISABLE_TAGS is #defined, this primarily checks the item
3753 * data type against the allowed tag content types. It will also error out
3754 * if the caller tries to require a tag because there is no way that can
3755 * ever be fulfilled.
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003756 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07003757static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003758QCBOR_Private_CheckTagRequirement(const QCBOR_Private_TagSpec TagSpec,
3759 const QCBORItem *pItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07003760{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003761 const int nItemType = pItem->uDataType; /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade37286c02022-09-03 10:05:02 -07003762 const int nTagReq = TagSpec.uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
3763
3764#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003765 /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003766 if(!(TagSpec.uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS) &&
3767 pItem->uTags[0] != CBOR_TAG_INVALID16) {
3768 /* There are tags that QCBOR couldn't process on this item and
Laurence Lundblade37286c02022-09-03 10:05:02 -07003769 * the caller has told us there should not be.
3770 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003771 return QCBOR_ERR_UNEXPECTED_TYPE;
3772 }
3773
Laurence Lundblade9b334962020-08-27 10:55:53 -07003774 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
Laurence Lundblade37286c02022-09-03 10:05:02 -07003775 /* Must match the tag number and only the tag */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003776 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003777 }
3778
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003779 QCBORError uReturn = QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003780 if(uReturn == QCBOR_SUCCESS) {
3781 return QCBOR_SUCCESS;
3782 }
3783
3784 if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
3785 /* Must match the content type and only the content type.
Laurence Lundblade37286c02022-09-03 10:05:02 -07003786 * There was no match just above so it is a fail. */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003787 return QCBOR_ERR_UNEXPECTED_TYPE;
3788 }
3789
Laurence Lundblade37286c02022-09-03 10:05:02 -07003790 /* QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG: If here it can match either the tag or the content
3791 * and it hasn't matched the content, so the end
3792 * result is whether it matches the tag. This is
3793 * the tag optional case that the CBOR standard discourages.
3794 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003795
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003796 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003797
Laurence Lundblade37286c02022-09-03 10:05:02 -07003798#else /* QCBOR_DISABLE_TAGS */
3799 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
3800 return QCBOR_ERR_UNEXPECTED_TYPE;
3801 }
3802
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07003803 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade37286c02022-09-03 10:05:02 -07003804
3805#endif /* QCBOR_DISABLE_TAGS */
3806}
Laurence Lundblade9b334962020-08-27 10:55:53 -07003807
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003808
3809/**
3810 * @brief Get an item by label to match a tag specification.
3811 *
3812 * @param[in] pMe The decode context.
3813 * @param[in] nLabel The label to search map for.
3814 * @param[in] TagSpec The tag number specification to match.
3815 * @param[out] pItem The item found.
3816 *
3817 * This finds the item with the given label in currently open
3818 * map. Then checks that its tag number and types matches the tag
3819 * specification. If not, an error is set in the decode context.
3820 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003821static void
3822QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
3823 const int64_t nLabel,
3824 const QCBOR_Private_TagSpec TagSpec,
3825 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003826{
3827 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
3828 if(pMe->uLastError != QCBOR_SUCCESS) {
3829 return;
3830 }
3831
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003832 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003833}
3834
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07003835
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003836/**
3837 * @brief Get an item by label to match a tag specification.
3838 *
3839 * @param[in] pMe The decode context.
3840 * @param[in] szLabel The label to search map for.
3841 * @param[in] TagSpec The tag number specification to match.
3842 * @param[out] pItem The item found.
3843 *
3844 * This finds the item with the given label in currently open
3845 * map. Then checks that its tag number and types matches the tag
3846 * specification. If not, an error is set in the decode context.
3847 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003848static void
3849QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
3850 const char *szLabel,
3851 const QCBOR_Private_TagSpec TagSpec,
3852 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003853{
3854 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
3855 if(pMe->uLastError != QCBOR_SUCCESS) {
3856 return;
3857 }
3858
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003859 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003860}
3861
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003862
3863/**
3864 * @brief Semi-private to get an string by label to match a tag specification.
3865 *
3866 * @param[in] pMe The decode context.
3867 * @param[in] nLabel The label to search map for.
3868 * @param[in] TagSpec The tag number specification to match.
3869 * @param[out] pString The string found.
3870 *
3871 * This finds the string with the given label in currently open
3872 * map. Then checks that its tag number and types matches the tag
3873 * specification. If not, an error is set in the decode context.
3874 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003875void
3876QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
3877 const int64_t nLabel,
3878 const QCBOR_Private_TagSpec TagSpec,
3879 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003880{
3881 QCBORItem Item;
3882 QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
3883 if(pMe->uLastError == QCBOR_SUCCESS) {
3884 *pString = Item.val.string;
3885 }
3886}
3887
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003888
3889/**
3890 * @brief Semi-private to get an string by label to match a tag specification.
3891 *
3892 * @param[in] pMe The decode context.
3893 * @param[in] szLabel The label to search map for.
3894 * @param[in] TagSpec The tag number specification to match.
3895 * @param[out] pString The string found.
3896 *
3897 * This finds the string with the given label in currently open
3898 * map. Then checks that its tag number and types matches the tag
3899 * specification. If not, an error is set in the decode context.
3900 */void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003901QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
3902 const char * szLabel,
3903 const QCBOR_Private_TagSpec TagSpec,
3904 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003905{
3906 QCBORItem Item;
3907 QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
3908 if(pMe->uLastError == QCBOR_SUCCESS) {
3909 *pString = Item.val.string;
3910 }
3911}
Laurence Lundblade1341c592020-04-11 14:19:05 -07003912
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003913
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003914/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003915 * Public function, see header qcbor/qcbor_decode.h file
3916 */
3917void
3918QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003919{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003920 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL);
Laurence Lundblade5f53f832020-09-03 12:00:14 -07003921 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003922}
3923
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003924/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003925 * Public function, see header qcbor/qcbor_decode.h file
3926 */
3927void
3928QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe,
3929 QCBORItem *pItemList,
3930 void *pCallbackCtx,
3931 QCBORItemCallback pfCB)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003932{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003933 MapSearchCallBack CallBack;
3934 CallBack.pCBContext = pCallbackCtx;
3935 CallBack.pfCallback = pfCB;
3936
3937 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack);
3938
Laurence Lundblade5f53f832020-09-03 12:00:14 -07003939 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003940}
3941
3942
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08003943/**
3944 * @brief Search for a map/array by label and enter it
3945 *
3946 * @param[in] pMe The decode context.
3947 * @param[in] pSearch The map/array to search for.
3948 *
3949 * @c pSearch is expected to contain one item of type map or array
3950 * with the label specified. The current bounded map will be searched for
3951 * this and if found will be entered.
3952 *
3953 * If the label is not found, or the item found is not a map or array,
3954 * the error state is set.
3955 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003956static void
3957QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07003958{
Laurence Lundblade323f8a92020-09-06 19:43:09 -07003959 // The first item in pSearch is the one that is to be
3960 // entered. It should be the only one filled in. Any other
3961 // will be ignored unless it causes an error.
Laurence Lundblade34691b92020-05-18 22:25:25 -07003962 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07003963 return;
3964 }
3965
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003966 MapSearchInfo Info;
3967 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pSearch, &Info, NULL);
Laurence Lundblade34691b92020-05-18 22:25:25 -07003968 if(pMe->uLastError != QCBOR_SUCCESS) {
3969 return;
3970 }
3971
Laurence Lundblade9b334962020-08-27 10:55:53 -07003972 if(pSearch->uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003973 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade9b334962020-08-27 10:55:53 -07003974 return;
3975 }
3976
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003977
3978 /* The map or array was found. Now enter it.
3979 *
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08003980 * QCBORDecode_EnterBoundedMapOrArray() used here, requires the
3981 * next item for the pre-order traversal cursor to be the map/array
3982 * found by MapSearch(). The next few lines of code force the
3983 * cursor to that.
3984 *
3985 * There is no need to retain the old cursor because
3986 * QCBORDecode_EnterBoundedMapOrArray() will set it to the
3987 * beginning of the map/array being entered.
3988 *
3989 * The cursor is forced by: 1) setting the input buffer position to
3990 * the item offset found by MapSearch(), 2) setting the map/array
3991 * counter to the total in the map/array, 3) setting the nesting
3992 * level. Setting the map/array counter to the total is not
3993 * strictly correct, but this is OK because this cursor only needs
3994 * to be used to get one item and MapSearch() has already found it
3995 * confirming it exists.
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003996 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003997 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07003998
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08003999 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
4000
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004001 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07004002
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004003 QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004004}
4005
4006
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004007/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004008 * Public function, see header qcbor/qcbor_decode.h file
4009 */
4010void
4011QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004012{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004013 QCBORItem OneItemSeach[2];
4014 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4015 OneItemSeach[0].label.int64 = nLabel;
4016 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4017 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004018
Laurence Lundblade9b334962020-08-27 10:55:53 -07004019 /* The map to enter was found, now finish off entering it. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004020 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004021}
4022
4023
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004024/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004025 * Public function, see header qcbor/qcbor_decode.h file
4026 */
4027void
4028QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004029{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004030 QCBORItem OneItemSeach[2];
4031 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4032 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4033 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4034 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004035
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004036 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004037}
4038
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004039/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004040 * Public function, see header qcbor/qcbor_decode.h file
4041 */
4042void
4043QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07004044{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004045 QCBORItem OneItemSeach[2];
4046 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4047 OneItemSeach[0].label.int64 = nLabel;
4048 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4049 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004050
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004051 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07004052}
4053
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004054/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004055 * Public function, see header qcbor/qcbor_decode.h file
4056 */
4057void
4058QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundblade34691b92020-05-18 22:25:25 -07004059{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004060 QCBORItem OneItemSeach[2];
4061 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4062 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4063 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4064 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004065
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004066 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade1341c592020-04-11 14:19:05 -07004067}
4068
4069
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004070/**
4071 * @brief Semi-private to do the the work for EnterMap() and EnterArray().
4072 *
4073 * @param[in] pMe The decode context
4074 * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY.
4075 * @param[out] pItem The data item for the map or array entered.
4076 *
4077 * The next item in the traversal must be a map or array. This
4078 * consumes that item and does the book keeping to enter the map or
4079 * array.
4080 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004081void
4082QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe,
4083 const uint8_t uType,
4084 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004085{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004086 QCBORError uErr;
4087
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004088 /* Must only be called on maps and arrays. */
Laurence Lundblade34691b92020-05-18 22:25:25 -07004089 if(pMe->uLastError != QCBOR_SUCCESS) {
4090 // Already in error state; do nothing.
4091 return;
4092 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07004093
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004094 /* Get the data item that is the map or array being entered. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004095 QCBORItem Item;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004096 uErr = QCBORDecode_GetNext(pMe, &Item);
4097 if(uErr != QCBOR_SUCCESS) {
4098 goto Done;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07004099 }
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004100
4101 uint8_t uItemDataType = Item.uDataType;
Laurence Lundblade62cae932024-06-03 13:16:17 -07004102#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004103 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) {
4104 uItemDataType = QCBOR_TYPE_ARRAY;
4105 }
Laurence Lundblade62cae932024-06-03 13:16:17 -07004106#endif
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004107 if(uItemDataType != uType) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004108 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
4109 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004110 }
4111
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004112 QCBORDecode_Private_CopyTags(pMe, &Item);
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004113
4114
Laurence Lundbladef0499502020-08-01 11:55:57 -07004115 const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
Laurence Lundblade085d7952020-07-24 10:26:30 -07004116 if(bIsEmpty) {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004117 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
4118 // Undo decrement done by QCBORDecode_GetNext() so the the
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004119 // the decrement when exiting the map/array works correctly
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004120 pMe->nesting.pCurrent->u.ma.uCountCursor++;
4121 }
Laurence Lundblade93d89472020-10-03 22:30:50 -07004122 // Special case to increment nesting level for zero-length maps
4123 // and arrays entered in bounded mode.
Laurence Lundbladee6f15112020-07-23 18:44:16 -07004124 DecodeNesting_Descend(&(pMe->nesting), uType);
4125 }
4126
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004127 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004128
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004129 uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty,
4130 UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004131
Laurence Lundblade6545d1b2020-10-14 11:13:13 -07004132 if(pItem != NULL) {
4133 *pItem = Item;
4134 }
4135
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004136Done:
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004137 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004138}
4139
Laurence Lundblade02625d42020-06-25 14:41:41 -07004140
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004141/**
4142 * @brief Exit a bounded map, array or bstr (semi-private).
4143 *
4144 * @param[in] pMe Decode context.
4145 * @param[in] uEndOffset The input buffer offset of the end of item exited.
4146 *
4147 * @returns QCBOR_SUCCESS or an error code.
4148 *
4149 * This is the common work for exiting a level that is a bounded map,
4150 * array or bstr wrapped CBOR.
4151 *
4152 * One chunk of work is to set up the pre-order traversal so it is at
4153 * the item just after the bounded map, array or bstr that is being
4154 * exited. This is somewhat complex.
4155 *
4156 * The other work is to level-up the bounded mode to next higest
4157 * bounded mode or the top level if there isn't one.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004158 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004159static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004160QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
4161 const uint32_t uEndOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004162{
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004163 QCBORError uErr;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004164
Laurence Lundblade02625d42020-06-25 14:41:41 -07004165 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004166 * First the pre-order-traversal byte offset is positioned to the
4167 * item just after the bounded mode item that was just consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004168 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004169 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
4170
Laurence Lundblade02625d42020-06-25 14:41:41 -07004171 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004172 * Next, set the current nesting level to one above the bounded
4173 * level that was just exited.
4174 *
4175 * DecodeNesting_CheckBoundedType() is always called before this
4176 * and makes sure pCurrentBounded is valid.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004177 */
4178 DecodeNesting_LevelUpCurrent(&(pMe->nesting));
4179
4180 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004181 * This does the complex work of leveling up the pre-order
4182 * traversal when the end of a map or array or another bounded
4183 * level is reached. It may do nothing, or ascend all the way to
4184 * the top level.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004185 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004186 uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004187 if(uErr != QCBOR_SUCCESS) {
4188 goto Done;
4189 }
4190
Laurence Lundblade02625d42020-06-25 14:41:41 -07004191 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004192 * This makes the next highest bounded level the current bounded
4193 * level. If there is no next highest level, then no bounded mode
4194 * is in effect.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004195 */
4196 DecodeNesting_LevelUpBounded(&(pMe->nesting));
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004197
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004198 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004199
4200Done:
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004201 return uErr;
4202}
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004203
Laurence Lundblade02625d42020-06-25 14:41:41 -07004204
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004205/**
4206 * @brief Get started exiting a map or array (semi-private)
4207 *
4208 * @param[in] pMe The decode context
4209 * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP
4210 *
4211 * This does some work for map and array exiting (but not
4212 * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel()
4213 * is called to do the rest.
4214 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004215void
4216QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe,
4217 const uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004218{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004219 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07004220 /* Already in error state; do nothing. */
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004221 return;
4222 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004223
Laurence Lundblade02625d42020-06-25 14:41:41 -07004224 QCBORError uErr;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004225
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004226 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004227 uErr = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004228 goto Done;
4229 }
4230
Laurence Lundblade02625d42020-06-25 14:41:41 -07004231 /*
4232 Have to set the offset to the end of the map/array
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004233 that is being exited. If there is no cached value,
Laurence Lundblade02625d42020-06-25 14:41:41 -07004234 from previous map search, then do a dummy search.
4235 */
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004236 if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004237 QCBORItem Dummy;
4238 Dummy.uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004239 uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL);
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004240 if(uErr != QCBOR_SUCCESS) {
4241 goto Done;
4242 }
4243 }
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004244
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004245 uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004246
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004247Done:
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004248 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004249}
4250
4251
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004252/**
4253 * @brief The main work of entering some byte-string wrapped CBOR.
4254 *
4255 * @param[in] pMe The decode context.
4256 * @param[in] pItem The byte string item.
4257 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX
4258 * @param[out] pBstr Pointer and length of byte string entered.
4259 *
4260 * This is called once the byte string item has been decoded to do all
4261 * the book keeping work for descending a nesting level into the
4262 * nested CBOR.
4263 *
4264 * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement.
4265 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004266static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004267QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe,
4268 const QCBORItem *pItem,
4269 const uint8_t uTagRequirement,
4270 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004271{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004272 if(pBstr) {
4273 *pBstr = NULLUsefulBufC;
4274 }
4275
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004276 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004277 /* Already in error state; do nothing. */
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004278 return pMe->uLastError;
4279 }
4280
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004281 QCBORError uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004282
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004283 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004284 {
4285 uTagRequirement,
4286 {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE},
4287 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4288 };
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004289
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004290 uError = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004291 if(uError != QCBOR_SUCCESS) {
4292 goto Done;
4293 }
4294
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004295 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004296 /* Reverse the decrement done by GetNext() for the bstr so the
4297 * increment in QCBORDecode_NestLevelAscender() called by
4298 * ExitBoundedLevel() will work right.
4299 */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004300 DecodeNesting_ReverseDecrement(&(pMe->nesting));
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07004301 }
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004302
4303 if(pBstr) {
4304 *pBstr = pItem->val.string;
4305 }
4306
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004307 /* This saves the current length of the UsefulInputBuf and then
4308 * narrows the UsefulInputBuf to start and length of the wrapped
4309 * CBOR that is being entered.
4310 *
4311 * Most of these calls are simple inline accessors so this doesn't
4312 * amount to much code.
4313 */
4314
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004315 const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004316 /* This check makes the cast of uPreviousLength to uint32_t below safe. */
4317 if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004318 uError = QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladef76a2622020-08-06 19:51:03 -07004319 goto Done;
4320 }
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004321
4322 const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
4323 pItem->val.string.ptr);
4324 /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
4325 if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
4326 /* This should never happen because pItem->val.string.ptr should
4327 * always be valid since it was just returned.
4328 */
4329 uError = QCBOR_ERR_INPUT_TOO_LARGE;
4330 goto Done;
4331 }
4332
4333 const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
4334
4335 UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004336 UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004337
Laurence Lundblade02625d42020-06-25 14:41:41 -07004338 uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004339 (uint32_t)uPreviousLength,
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004340 (uint32_t)uStartOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004341Done:
4342 return uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004343}
4344
4345
Laurence Lundblade02625d42020-06-25 14:41:41 -07004346/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004347 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004348 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004349void
4350QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe,
4351 const uint8_t uTagRequirement,
4352 UsefulBufC *pBstr)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004353{
4354 if(pMe->uLastError != QCBOR_SUCCESS) {
4355 // Already in error state; do nothing.
4356 return;
4357 }
4358
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004359 /* Get the data item that is the byte string being entered */
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004360 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004361 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4362 if(pMe->uLastError != QCBOR_SUCCESS) {
4363 return;
4364 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004365
Laurence Lundblade31fddb72024-05-13 13:03:35 -07004366 if(Item.uDataAlloc) {
4367 pMe->uLastError = QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
4368 return;
4369 }
4370
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004371 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4372 &Item,
4373 uTagRequirement,
4374 pBstr);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004375}
4376
4377
Laurence Lundblade02625d42020-06-25 14:41:41 -07004378/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004379 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004380 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004381void
4382QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe,
4383 const int64_t nLabel,
4384 const uint8_t uTagRequirement,
4385 UsefulBufC *pBstr)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004386{
4387 QCBORItem Item;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004388 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004389
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004390 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4391 &Item,
4392 uTagRequirement,
4393 pBstr);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004394}
4395
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004396
Laurence Lundblade02625d42020-06-25 14:41:41 -07004397/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004398 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004399 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004400void
4401QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe,
4402 const char *szLabel,
4403 const uint8_t uTagRequirement,
4404 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004405{
4406 QCBORItem Item;
4407 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4408
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004409 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4410 &Item,
4411 uTagRequirement,
4412 pBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004413}
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004414
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004415
Laurence Lundblade02625d42020-06-25 14:41:41 -07004416/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004417 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004418 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004419void
4420QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004421{
Laurence Lundblade02625d42020-06-25 14:41:41 -07004422 if(pMe->uLastError != QCBOR_SUCCESS) {
4423 // Already in error state; do nothing.
4424 return;
4425 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004426
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004427 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004428 pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade02625d42020-06-25 14:41:41 -07004429 return;
4430 }
4431
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004432 const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
4433
Laurence Lundblade02625d42020-06-25 14:41:41 -07004434 /*
4435 Reset the length of the UsefulInputBuf to what it was before
4436 the bstr wrapped CBOR was entered.
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004437 */
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004438 UsefulInputBuf_SetBufferLength(&(pMe->InBuf),
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004439 DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004440
4441
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004442 QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004443 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004444}
4445
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004446
Laurence Lundbladee6430642020-03-14 21:15:44 -07004447
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004448/**
4449 * @brief Process simple type true and false, a boolean
4450 *
4451 * @param[in] pMe The decode context.
4452 * @param[in] pItem The item with either true or false.
4453 * @param[out] pBool The boolean value output.
4454 *
4455 * Sets the internal error if the item isn't a true or a false. Also
4456 * records any tag numbers as the tag numbers of the last item.
4457 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004458static void
4459QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe,
4460 const QCBORItem *pItem,
4461 bool *pBool)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004462{
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004463 if(pMe->uLastError != QCBOR_SUCCESS) {
4464 /* Already in error state, do nothing */
4465 return;
4466 }
4467
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004468 switch(pItem->uDataType) {
4469 case QCBOR_TYPE_TRUE:
4470 *pBool = true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004471 break;
4472
4473 case QCBOR_TYPE_FALSE:
4474 *pBool = false;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004475 break;
4476
4477 default:
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004478 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004479 break;
4480 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004481 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004482}
Laurence Lundbladee6430642020-03-14 21:15:44 -07004483
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004484
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004485/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004486 * Public function, see header qcbor/qcbor_decode.h file
4487 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004488void
4489QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004490{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004491 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004492 /* Already in error state, do nothing */
Laurence Lundbladee6430642020-03-14 21:15:44 -07004493 return;
4494 }
4495
Laurence Lundbladec4537442020-04-14 18:53:22 -07004496 QCBORItem Item;
4497
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004498 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4499
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004500 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004501}
4502
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004503
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004504/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004505 * Public function, see header qcbor/qcbor_decode.h file
4506 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004507void
4508QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe,
4509 const int64_t nLabel,
4510 bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004511{
4512 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004513 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004514
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004515 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004516}
4517
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004518
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004519/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004520 * Public function, see header qcbor/qcbor_decode.h file
4521 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004522void
4523QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe,
4524 const char *szLabel,
4525 bool *pValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004526{
4527 QCBORItem Item;
4528 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4529
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004530 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004531}
4532
4533
4534
Laurence Lundbladec7114722020-08-13 05:11:40 -07004535
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004536/**
4537 * @brief Common processing for an epoch date.
4538 *
4539 * @param[in] pMe The decode context.
4540 * @param[in] pItem The item with the date.
4541 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4542 * @param[out] pnTime The returned date.
4543 *
4544 * Common processing for the date tag. Mostly make sure the tag
4545 * content is correct and copy forward any further other tag numbers.
4546 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004547static void
4548QCBORDecode_Private_ProcessEpochDate(QCBORDecodeContext *pMe,
4549 QCBORItem *pItem,
4550 const uint8_t uTagRequirement,
4551 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004552{
4553 if(pMe->uLastError != QCBOR_SUCCESS) {
4554 // Already in error state, do nothing
4555 return;
4556 }
4557
4558 QCBORError uErr;
4559
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004560 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladec7114722020-08-13 05:11:40 -07004561 {
4562 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004563 {QCBOR_TYPE_DATE_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4564 {QCBOR_TYPE_INT64, QCBOR_TYPE_DOUBLE, QCBOR_TYPE_FLOAT, QCBOR_TYPE_UINT64}
Laurence Lundbladec7114722020-08-13 05:11:40 -07004565 };
4566
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004567 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004568 if(uErr != QCBOR_SUCCESS) {
4569 goto Done;
4570 }
4571
4572 if(pItem->uDataType != QCBOR_TYPE_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004573 uErr = QCBOR_Private_DecodeDateEpoch(pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004574 if(uErr != QCBOR_SUCCESS) {
4575 goto Done;
4576 }
4577 }
4578
Laurence Lundblade9b334962020-08-27 10:55:53 -07004579 // Save the tags in the last item's tags in the decode context
4580 // for QCBORDecode_GetNthTagOfLast()
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004581 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07004582
Laurence Lundbladec7114722020-08-13 05:11:40 -07004583 *pnTime = pItem->val.epochDate.nSeconds;
4584
4585Done:
4586 pMe->uLastError = (uint8_t)uErr;
4587}
4588
4589
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004590
4591/*
4592 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4593 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004594void
4595QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
4596 uint8_t uTagRequirement,
4597 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004598{
4599 if(pMe->uLastError != QCBOR_SUCCESS) {
4600 // Already in error state, do nothing
4601 return;
4602 }
4603
4604 QCBORItem Item;
4605 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4606
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004607 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004608}
4609
4610
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004611/*
4612 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4613 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07004614void
4615QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
4616 int64_t nLabel,
4617 uint8_t uTagRequirement,
4618 int64_t *pnTime)
4619{
4620 QCBORItem Item;
4621 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004622 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004623}
4624
4625
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004626/*
4627 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4628 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07004629void
4630QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
4631 const char *szLabel,
4632 uint8_t uTagRequirement,
4633 int64_t *pnTime)
4634{
4635 QCBORItem Item;
4636 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004637 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004638}
4639
4640
4641
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004642/**
4643 * @brief Common processing for an epoch date.
4644 *
4645 * @param[in] pMe The decode context.
4646 * @param[in] pItem The item with the date.
4647 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4648 * @param[out] pnDays The returned day count.
4649 *
4650 * Common processing for the RFC 8943 day-count tag. Mostly make sure
4651 * the tag content is correct and copy forward any further other tag
4652 * numbers.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004653 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004654static void
4655QCBORDecode_Private_ProcessEpochDays(QCBORDecodeContext *pMe,
4656 QCBORItem *pItem,
4657 uint8_t uTagRequirement,
4658 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004659{
4660 if(pMe->uLastError != QCBOR_SUCCESS) {
4661 /* Already in error state, do nothing */
4662 return;
4663 }
4664
4665 QCBORError uErr;
4666
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004667 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004668 {
4669 uTagRequirement,
4670 {QCBOR_TYPE_DAYS_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4671 {QCBOR_TYPE_INT64, QCBOR_TYPE_UINT64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4672 };
4673
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004674 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004675 if(uErr != QCBOR_SUCCESS) {
4676 goto Done;
4677 }
4678
4679 if(pItem->uDataType != QCBOR_TYPE_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004680 uErr = QCBOR_Private_DecodeDaysEpoch(pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004681 if(uErr != QCBOR_SUCCESS) {
4682 goto Done;
4683 }
4684 }
4685
4686 /* Save the tags in the last item's tags in the decode context
4687 * for QCBORDecode_GetNthTagOfLast()
4688 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004689 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004690
4691 *pnDays = pItem->val.epochDays;
4692
4693Done:
4694 pMe->uLastError = (uint8_t)uErr;
4695}
4696
4697
4698/*
4699 * Public function, see header qcbor/qcbor_decode.h
4700 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004701void
4702QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe,
4703 uint8_t uTagRequirement,
4704 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004705{
4706 if(pMe->uLastError != QCBOR_SUCCESS) {
4707 /* Already in error state, do nothing */
4708 return;
4709 }
4710
4711 QCBORItem Item;
4712 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4713
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004714 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004715}
4716
4717
4718/*
4719 * Public function, see header qcbor/qcbor_decode.h
4720 */
4721void
4722QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe,
4723 int64_t nLabel,
4724 uint8_t uTagRequirement,
4725 int64_t *pnDays)
4726{
4727 QCBORItem Item;
4728 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004729 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004730}
4731
4732
4733/*
4734 * Public function, see header qcbor/qcbor_decode.h
4735 */
4736void
4737QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe,
4738 const char *szLabel,
4739 uint8_t uTagRequirement,
4740 int64_t *pnDays)
4741{
4742 QCBORItem Item;
4743 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004744 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004745}
4746
4747
4748
Laurence Lundblade37286c02022-09-03 10:05:02 -07004749/*
4750 * @brief Get a string that matches the type/tag specification.
4751 */
4752void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004753QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
4754 const QCBOR_Private_TagSpec TagSpec,
4755 UsefulBufC *pBstr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004756{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004757 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade37286c02022-09-03 10:05:02 -07004758 /* Already in error state, do nothing */
Laurence Lundbladec4537442020-04-14 18:53:22 -07004759 return;
4760 }
4761
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004762 QCBORError uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004763 QCBORItem Item;
4764
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004765 uError = QCBORDecode_GetNext(pMe, &Item);
4766 if(uError != QCBOR_SUCCESS) {
4767 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004768 return;
4769 }
4770
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004771 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004772
4773 if(pMe->uLastError == QCBOR_SUCCESS) {
4774 *pBstr = Item.val.string;
Laurence Lundbladeab40c6f2020-08-28 11:24:58 -07004775 } else {
4776 *pBstr = NULLUsefulBufC;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004777 }
4778}
4779
Laurence Lundbladec4537442020-04-14 18:53:22 -07004780
4781
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004782
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004783/**
4784 * @brief Common processing for a big number tag.
4785 *
4786 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4787 * @param[in] pItem The item with the date.
4788 * @param[out] pValue The returned big number
4789 * @param[out] pbIsNegative The returned sign of the big number.
4790 *
4791 * Common processing for the big number tag. Mostly make sure
4792 * the tag content is correct and copy forward any further other tag
4793 * numbers.
4794 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004795static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004796QCBOR_Private_ProcessBigNum(const uint8_t uTagRequirement,
4797 const QCBORItem *pItem,
4798 UsefulBufC *pValue,
4799 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004800{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004801 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004802 {
4803 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004804 {QCBOR_TYPE_POSBIGNUM, QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4805 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004806 };
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004807
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004808 QCBORError uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004809 if(uErr != QCBOR_SUCCESS) {
4810 return uErr;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004811 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004812
4813 *pValue = pItem->val.string;
4814
4815 if(pItem->uDataType == QCBOR_TYPE_POSBIGNUM) {
4816 *pbIsNegative = false;
4817 } else if(pItem->uDataType == QCBOR_TYPE_NEGBIGNUM) {
4818 *pbIsNegative = true;
4819 }
4820
4821 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004822}
4823
4824
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004825/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004826 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004827 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004828void
4829QCBORDecode_GetBignum(QCBORDecodeContext *pMe,
4830 const uint8_t uTagRequirement,
4831 UsefulBufC *pValue,
4832 bool *pbIsNegative)
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004833{
4834 if(pMe->uLastError != QCBOR_SUCCESS) {
4835 // Already in error state, do nothing
4836 return;
4837 }
4838
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004839 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004840 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
4841 if(uError != QCBOR_SUCCESS) {
4842 pMe->uLastError = (uint8_t)uError;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004843 return;
4844 }
4845
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004846 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4847 &Item,
4848 pValue,
4849 pbIsNegative);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004850}
4851
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004852
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004853/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004854 * Public function, see header qcbor/qcbor_spiffy_decode.h
4855 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004856void
4857QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe,
4858 const int64_t nLabel,
4859 const uint8_t uTagRequirement,
4860 UsefulBufC *pValue,
4861 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004862{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004863 QCBORItem Item;
4864 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004865 if(pMe->uLastError != QCBOR_SUCCESS) {
4866 return;
4867 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004868
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004869 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4870 &Item,
4871 pValue,
4872 pbIsNegative);
Laurence Lundbladec4537442020-04-14 18:53:22 -07004873}
4874
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004875
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004876/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004877 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004878 */
4879void
4880QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe,
4881 const char *szLabel,
4882 const uint8_t uTagRequirement,
4883 UsefulBufC *pValue,
4884 bool *pbIsNegative)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004885{
4886 QCBORItem Item;
4887 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004888 if(pMe->uLastError != QCBOR_SUCCESS) {
4889 return;
4890 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004891
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004892 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4893 &Item,
4894 pValue,
4895 pbIsNegative);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004896}
4897
4898
4899
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004900/**
4901 * @brief Common processing for MIME tag (semi-private).
4902 *
4903 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4904 * @param[in] pItem The item with the date.
4905 * @param[out] pMessage The returned MIME message.
4906 * @param[out] pbIsTag257 If true, binary MIME, if not, text MIME.
4907 *
4908 * Common processing for the MIME tag. Mostly make sure the tag
4909 * content is correct and copy forward any further other tag
4910 * numbers. See QCBORDecode_GetMIMEMessage().
4911 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004912QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004913QCBORDecode_Private_GetMIME(const uint8_t uTagRequirement,
Laurence Lundblade37286c02022-09-03 10:05:02 -07004914 const QCBORItem *pItem,
4915 UsefulBufC *pMessage,
4916 bool *pbIsTag257)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004917{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004918 const QCBOR_Private_TagSpec TagSpecText =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004919 {
4920 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004921 {QCBOR_TYPE_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4922 {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004923 };
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004924 const QCBOR_Private_TagSpec TagSpecBinary =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004925 {
4926 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004927 {QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4928 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004929 };
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004930
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004931 QCBORError uReturn;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004932
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004933 if(QCBOR_Private_CheckTagRequirement(TagSpecText, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004934 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07004935 if(pbIsTag257 != NULL) {
4936 *pbIsTag257 = false;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004937 }
4938 uReturn = QCBOR_SUCCESS;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004939 } else if(QCBOR_Private_CheckTagRequirement(TagSpecBinary, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004940 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07004941 if(pbIsTag257 != NULL) {
4942 *pbIsTag257 = true;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004943 }
4944 uReturn = QCBOR_SUCCESS;
4945
4946 } else {
4947 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
4948 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07004949
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004950 return uReturn;
4951}
4952
Laurence Lundblade93d89472020-10-03 22:30:50 -07004953// Improvement: add methods for wrapped CBOR, a simple alternate
4954// to EnterBstrWrapped
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004955
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004956
4957
4958
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07004959#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundbladee6430642020-03-14 21:15:44 -07004960
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004961/**
4962 * @brief Prototype for conversion of exponent and mantissa to unsigned integer.
4963 *
4964 * @param[in] uMantissa The mantissa.
4965 * @param[in] nExponent The exponent.
4966 * @param[out] puResult The resulting integer.
4967 *
4968 * Concrete implementations of this are for exponent base 10 and 2 supporting
4969 * decimal fractions and big floats.
4970 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004971typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004972
4973
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004974/**
4975 * @brief Base 10 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
4976 *
4977 * @param[in] uMantissa The unsigned integer mantissa.
4978 * @param[in] nExponent The signed integer exponent.
4979 * @param[out] puResult Place to return the unsigned integer result.
4980 *
4981 * This computes: mantissa * 10 ^^ exponent as for a decimal fraction. The output is a 64-bit
4982 * unsigned integer.
4983 *
4984 * There are many inputs for which the result will not fit in the
4985 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
4986 * be returned.
4987 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07004988static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004989QCBOR_Private_Exponentitate10(const uint64_t uMantissa,
4990 int64_t nExponent,
4991 uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004992{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07004993 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004994
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07004995 if(uResult != 0) {
4996 /* This loop will run a maximum of 19 times because
4997 * UINT64_MAX < 10 ^^ 19. More than that will cause
4998 * exit with the overflow error
4999 */
5000 for(; nExponent > 0; nExponent--) {
5001 if(uResult > UINT64_MAX / 10) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005002 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005003 }
5004 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005005 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005006
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005007 for(; nExponent < 0; nExponent++) {
5008 uResult = uResult / 10;
5009 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005010 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005011 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005012 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005013 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005014 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07005015
5016 *puResult = uResult;
5017
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005018 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005019}
5020
5021
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005022/**
5023 * @brief Base 2 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5024 *
5025 * @param[in] uMantissa The unsigned integer mantissa.
5026 * @param[in] nExponent The signed integer exponent.
5027 * @param[out] puResult Place to return the unsigned integer result.
5028 *
5029 * This computes: mantissa * 2 ^^ exponent as for a big float. The
5030 * output is a 64-bit unsigned integer.
5031 *
5032 * There are many inputs for which the result will not fit in the
5033 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5034 * be returned.
5035 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005036static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005037QCBOR_Private_Exponentitate2(const uint64_t uMantissa,
5038 int64_t nExponent,
5039 uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005040{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005041 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005042
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005043 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005044
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005045 /* This loop will run a maximum of 64 times because INT64_MAX <
5046 * 2^31. More than that will cause exit with the overflow error
Laurence Lundbladee6430642020-03-14 21:15:44 -07005047 */
5048 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005049 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005050 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005051 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005052 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005053 nExponent--;
5054 }
5055
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005056 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005057 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005058 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005059 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005060 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005061 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005062 }
5063
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005064 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005065
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005066 return QCBOR_SUCCESS;
5067}
5068
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005069
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005070/**
5071 * @brief Exponentiate a signed mantissa and signed exponent to produce a signed result.
5072 *
5073 * @param[in] nMantissa Signed integer mantissa.
5074 * @param[in] nExponent Signed integer exponent.
5075 * @param[out] pnResult Place to put the signed integer result.
5076 * @param[in] pfExp Exponentiation function.
5077 *
5078 * @returns Error code
5079 *
5080 * \c pfExp performs exponentiation on and unsigned mantissa and
5081 * produces an unsigned result. This converts the mantissa from signed
5082 * and converts the result to signed. The exponentiation function is
5083 * either for base 2 or base 10 (and could be other if needed).
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005084 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005085static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005086QCBOR_Private_ExponentiateNN(const int64_t nMantissa,
5087 const int64_t nExponent,
5088 int64_t *pnResult,
5089 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005090{
5091 uint64_t uResult;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005092 uint64_t uMantissa;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005093
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005094 /* Take the absolute value and put it into an unsigned. */
5095 if(nMantissa >= 0) {
5096 /* Positive case is straightforward */
5097 uMantissa = (uint64_t)nMantissa;
5098 } else if(nMantissa != INT64_MIN) {
5099 /* The common negative case. See next. */
5100 uMantissa = (uint64_t)-nMantissa;
5101 } else {
5102 /* int64_t and uint64_t are always two's complement per the
5103 * C standard (and since QCBOR uses these it only works with
5104 * two's complement, which is pretty much universal these
5105 * days). The range of a negative two's complement integer is
5106 * one more that than a positive, so the simple code above might
5107 * not work all the time because you can't simply negate the
5108 * value INT64_MIN because it can't be represented in an
5109 * int64_t. -INT64_MIN can however be represented in a
5110 * uint64_t. Some compilers seem to recognize this case for the
5111 * above code and put the correct value in uMantissa, however
5112 * they are not required to do this by the C standard. This next
5113 * line does however work for all compilers.
5114 *
5115 * This does assume two's complement where -INT64_MIN ==
5116 * INT64_MAX + 1 (which wouldn't be true for one's complement or
5117 * sign and magnitude (but we know we're using two's complement
5118 * because int64_t requires it)).
5119 *
5120 * See these, particularly the detailed commentary:
5121 * https://stackoverflow.com/questions/54915742/does-c99-mandate-a-int64-t-type-be-available-always
5122 * https://stackoverflow.com/questions/37301078/is-negating-int-min-undefined-behaviour
5123 */
5124 uMantissa = (uint64_t)INT64_MAX+1;
5125 }
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005126
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005127 /* Call the exponentiator passed for either base 2 or base 10.
5128 * Here is where most of the overflow errors are caught. */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005129 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
5130 if(uReturn) {
5131 return uReturn;
5132 }
5133
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005134 /* Convert back to the sign of the original mantissa */
5135 if(nMantissa >= 0) {
5136 if(uResult > INT64_MAX) {
5137 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5138 }
5139 *pnResult = (int64_t)uResult;
5140 } else {
5141 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
5142 * of INT64_MIN. This assumes two's compliment representation
5143 * where INT64_MIN is one increment farther from 0 than
5144 * INT64_MAX. Trying to write -INT64_MIN doesn't work to get
5145 * this because the compiler makes it an int64_t which can't
5146 * represent -INT64_MIN. Also see above.
5147 */
5148 if(uResult > (uint64_t)INT64_MAX+1) {
5149 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5150 }
5151 *pnResult = -(int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005152 }
5153
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005154 return QCBOR_SUCCESS;
5155}
5156
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005157
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005158/**
5159 * @brief Exponentiate an unsigned mantissa and signed exponent to produce an unsigned result.
5160 *
5161 * @param[in] nMantissa Signed integer mantissa.
5162 * @param[in] nExponent Signed integer exponent.
5163 * @param[out] puResult Place to put the signed integer result.
5164 * @param[in] pfExp Exponentiation function.
5165 *
5166 * @returns Error code
5167 *
5168 * \c pfExp performs exponentiation on and unsigned mantissa and
5169 * produces an unsigned result. This errors out if the mantissa
5170 * is negative because the output is unsigned.
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005171 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005172static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005173QCBOR_Private_ExponentitateNU(const int64_t nMantissa,
5174 const int64_t nExponent,
5175 uint64_t *puResult,
5176 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005177{
5178 if(nMantissa < 0) {
5179 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5180 }
5181
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005182 /* Cast to unsigned is OK because of check for negative.
5183 * Cast to unsigned is OK because UINT64_MAX > INT64_MAX.
5184 * Exponentiation is straight forward
5185 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005186 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
5187}
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005188
5189
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005190/**
5191 * @brief Exponentiate an usnigned mantissa and unsigned exponent to produce an unsigned result.
5192 *
5193 * @param[in] uMantissa Unsigned integer mantissa.
5194 * @param[in] nExponent Unsigned integer exponent.
5195 * @param[out] puResult Place to put the unsigned integer result.
5196 * @param[in] pfExp Exponentiation function.
5197 *
5198 * @returns Error code
5199 *
5200 * \c pfExp performs exponentiation on and unsigned mantissa and
5201 * produces an unsigned result so this is just a wrapper that does
5202 * nothing (and is likely inlined).
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005203 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005204static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005205QCBOR_Private_ExponentitateUU(const uint64_t uMantissa,
5206 const int64_t nExponent,
5207 uint64_t *puResult,
5208 fExponentiator pfExp)
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005209{
5210 return (*pfExp)(uMantissa, nExponent, puResult);
5211}
5212
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005213#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005214
5215
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005216
5217
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005218/**
5219 * @brief Convert a CBOR big number to a uint64_t.
5220 *
5221 * @param[in] BigNum Bytes of the big number to convert.
5222 * @param[in] uMax Maximum value allowed for the result.
5223 * @param[out] pResult Place to put the unsigned integer result.
5224 *
5225 * @returns Error code
5226 *
5227 * Many values will overflow because a big num can represent a much
5228 * larger range than uint64_t.
5229 */
5230static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005231QCBOR_Private_ConvertBigNumToUnsigned(const UsefulBufC BigNum,
5232 const uint64_t uMax,
5233 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005234{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005235 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005236
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005237 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005238 const uint8_t *pByte = BigNum.ptr;
5239 size_t uLen = BigNum.len;
5240 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07005241 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005242 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005243 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07005244 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005245 }
5246
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005247 *pResult = uResult;
5248 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005249}
5250
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005251
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005252/**
5253 * @brief Convert a CBOR postive big number to a uint64_t.
5254 *
5255 * @param[in] BigNum Bytes of the big number to convert.
5256 * @param[out] pResult Place to put the unsigned integer result.
5257 *
5258 * @returns Error code
5259 *
5260 * Many values will overflow because a big num can represent a much
5261 * larger range than uint64_t.
5262 */
5263static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005264QCBOR_Private_ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum,
5265 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005266{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005267 return QCBOR_Private_ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005268}
5269
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005270
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005271/**
5272 * @brief Convert a CBOR positive big number to an int64_t.
5273 *
5274 * @param[in] BigNum Bytes of the big number to convert.
5275 * @param[out] pResult Place to put the signed integer result.
5276 *
5277 * @returns Error code
5278 *
5279 * Many values will overflow because a big num can represent a much
5280 * larger range than int64_t.
5281 */
5282static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005283QCBOR_Private_ConvertPositiveBigNumToSigned(const UsefulBufC BigNum,
5284 int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005285{
5286 uint64_t uResult;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005287 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5288 INT64_MAX,
5289 &uResult);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005290 if(uError) {
5291 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005292 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005293 /* Cast is safe because ConvertBigNumToUnsigned limits to INT64_MAX */
Laurence Lundbladee6430642020-03-14 21:15:44 -07005294 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005295 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005296}
5297
5298
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005299/**
5300 * @brief Convert a CBOR negative big number to an int64_t.
5301 *
5302 * @param[in] BigNum Bytes of the big number to convert.
5303 * @param[out] pnResult Place to put the signed integer result.
5304 *
5305 * @returns Error code
5306 *
5307 * Many values will overflow because a big num can represent a much
5308 * larger range than int64_t.
5309 */
5310static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005311QCBOR_Private_ConvertNegativeBigNumToSigned(const UsefulBufC BigNum,
5312 int64_t *pnResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005313{
5314 uint64_t uResult;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005315 /* The negative integer furthest from zero for a C int64_t is
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005316 * INT64_MIN which is expressed as -INT64_MAX - 1. The value of a
5317 * negative number in CBOR is computed as -n - 1 where n is the
5318 * encoded integer, where n is what is in the variable BigNum. When
5319 * converting BigNum to a uint64_t, the maximum value is thus
5320 * INT64_MAX, so that when it -n - 1 is applied to it the result
5321 * will never be further from 0 than INT64_MIN.
5322 *
5323 * -n - 1 <= INT64_MIN.
5324 * -n - 1 <= -INT64_MAX - 1
5325 * n <= INT64_MAX.
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005326 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005327 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5328 INT64_MAX,
5329 &uResult);
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005330 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005331 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005332 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005333
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005334 /* Now apply -n - 1. The cast is safe because
5335 * ConvertBigNumToUnsigned() is limited to INT64_MAX which does fit
5336 * is the largest positive integer that an int64_t can
5337 * represent. */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005338 *pnResult = -(int64_t)uResult - 1;
5339
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005340 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005341}
5342
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005343
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005344
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005345
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005346/**
5347 * @brief Convert integers and floats to an int64_t.
5348 *
5349 * @param[in] pItem The item to convert.
5350 * @param[in] uConvertTypes Bit mask list of conversion options.
5351 * @param[out] pnValue The resulting converted value.
5352 *
5353 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5354 * in uConvertTypes.
5355 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5356 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5357 * or too small.
5358 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005359static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005360QCBOR_Private_ConvertInt64(const QCBORItem *pItem,
5361 const uint32_t uConvertTypes,
5362 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005363{
5364 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005365 case QCBOR_TYPE_FLOAT:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005366 case QCBOR_TYPE_DOUBLE:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005367#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005368 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005369 /* https://pubs.opengroup.org/onlinepubs/009695399/functions/llround.html
5370 http://www.cplusplus.com/reference/cmath/llround/
5371 */
5372 // Not interested in FE_INEXACT
5373 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005374 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5375 *pnValue = llround(pItem->val.dfnum);
5376 } else {
5377 *pnValue = lroundf(pItem->val.fnum);
5378 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005379 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5380 // llround() shouldn't result in divide by zero, but catch
5381 // it here in case it unexpectedly does. Don't try to
5382 // distinguish between the various exceptions because it seems
5383 // they vary by CPU, compiler and OS.
5384 return QCBOR_ERR_FLOAT_EXCEPTION;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005385 }
5386 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005387 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005388 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005389#else
5390 return QCBOR_ERR_HW_FLOAT_DISABLED;
5391#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005392 break;
5393
5394 case QCBOR_TYPE_INT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005395 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005396 *pnValue = pItem->val.int64;
5397 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005398 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005399 }
5400 break;
5401
5402 case QCBOR_TYPE_UINT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005403 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005404 if(pItem->val.uint64 < INT64_MAX) {
5405 *pnValue = pItem->val.int64;
5406 } else {
5407 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5408 }
5409 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005410 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005411 }
5412 break;
5413
5414 default:
5415 return QCBOR_ERR_UNEXPECTED_TYPE;
5416 }
5417 return QCBOR_SUCCESS;
5418}
5419
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005420
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005421/**
5422 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5423 *
5424 * @param[in] pMe The decode context.
5425 * @param[in] uConvertTypes Bit mask list of conversion options.
5426 * @param[out] pnValue Result of the conversion.
5427 * @param[in,out] pItem Temporary space to store Item, returned item.
5428 *
5429 * See QCBORDecode_GetInt64Convert().
5430 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005431void
5432QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pMe,
5433 uint32_t uConvertTypes,
5434 int64_t *pnValue,
5435 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005436{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07005437 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005438 return;
5439 }
5440
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005441 QCBORError uError = QCBORDecode_GetNext(pMe, pItem);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005442 if(uError) {
5443 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005444 return;
5445 }
5446
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005447 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005448 uConvertTypes,
5449 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005450}
5451
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005452/**
5453 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5454 *
5455 * @param[in] pMe The decode context.
5456 * @param[in] nLabel Label to find in map.
5457 * @param[in] uConvertTypes Bit mask list of conversion options.
5458 * @param[out] pnValue Result of the conversion.
5459 * @param[in,out] pItem Temporary space to store Item, returned item.
5460 *
5461 * See QCBORDecode_GetInt64ConvertInMapN().
5462 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005463void
5464QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pMe,
5465 int64_t nLabel,
5466 uint32_t uConvertTypes,
5467 int64_t *pnValue,
5468 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005469{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005470 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005471 if(pMe->uLastError != QCBOR_SUCCESS) {
5472 return;
5473 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005474
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005475 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5476 uConvertTypes,
5477 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005478}
5479
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005480/**
5481 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5482 *
5483 * @param[in] pMe The decode context.
5484 * @param[in] szLabel Label to find in map.
5485 * @param[in] uConvertTypes Bit mask list of conversion options.
5486 * @param[out] pnValue Result of the conversion.
5487 * @param[in,out] pItem Temporary space to store Item, returned item.
5488 *
5489 * See QCBORDecode_GetInt64ConvertInMapSZ().
5490 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005491void
5492QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5493 const char * szLabel,
5494 uint32_t uConvertTypes,
5495 int64_t *pnValue,
5496 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005497{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005498 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005499 if(pMe->uLastError != QCBOR_SUCCESS) {
5500 return;
5501 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005502
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005503 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5504 uConvertTypes,
5505 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005506}
5507
5508
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005509/**
5510 * @brief Convert many number types to an int64_t.
5511 *
5512 * @param[in] pItem The item to convert.
5513 * @param[in] uConvertTypes Bit mask list of conversion options.
5514 * @param[out] pnValue The resulting converted value.
5515 *
5516 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5517 * in uConvertTypes.
5518 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5519 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5520 * or too small.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005521 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005522static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005523QCBOR_Private_Int64ConvertAll(const QCBORItem *pItem,
5524 const uint32_t uConvertTypes,
5525 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005526{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005527 switch(pItem->uDataType) {
5528
5529 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005530 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005531 return QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005532 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005533 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005534 }
5535 break;
5536
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005537 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005538 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005539 return QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005540 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005541 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005542 }
5543 break;
5544
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005545#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005546 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005547 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005548 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005549 pItem->val.expAndMantissa.nExponent,
5550 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005551 &QCBOR_Private_Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005552 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005553 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005554 }
5555 break;
5556
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005557 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005558 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005559 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005560 pItem->val.expAndMantissa.nExponent,
5561 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005562 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005563 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005564 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005565 }
5566 break;
5567
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005568 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005569 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005570 int64_t nMantissa;
5571 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005572 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005573 if(uErr) {
5574 return uErr;
5575 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005576 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005577 pItem->val.expAndMantissa.nExponent,
5578 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005579 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005580 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005581 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005582 }
5583 break;
5584
5585 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005586 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005587 int64_t nMantissa;
5588 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005589 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005590 if(uErr) {
5591 return uErr;
5592 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005593 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005594 pItem->val.expAndMantissa.nExponent,
5595 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005596 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005597 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005598 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005599 }
5600 break;
5601
5602 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005603 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005604 int64_t nMantissa;
5605 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005606 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005607 if(uErr) {
5608 return uErr;
5609 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005610 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005611 pItem->val.expAndMantissa.nExponent,
5612 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005613 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005614 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005615 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005616 }
5617 break;
5618
5619 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005620 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005621 int64_t nMantissa;
5622 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005623 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005624 if(uErr) {
5625 return uErr;
5626 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005627 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005628 pItem->val.expAndMantissa.nExponent,
5629 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005630 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005631 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005632 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005633 }
5634 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005635#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005636
Laurence Lundbladee6430642020-03-14 21:15:44 -07005637
Laurence Lundbladec4537442020-04-14 18:53:22 -07005638 default:
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005639 return QCBOR_ERR_UNEXPECTED_TYPE; }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005640}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005641
5642
Laurence Lundbladec4537442020-04-14 18:53:22 -07005643/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005644 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005645 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005646void
5647QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe,
5648 const uint32_t uConvertTypes,
5649 int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005650{
5651 QCBORItem Item;
5652
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005653 QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005654
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005655 if(pMe->uLastError == QCBOR_SUCCESS) {
5656 // The above conversion succeeded
5657 return;
5658 }
5659
Laurence Lundbladef6c86662020-05-12 02:08:00 -07005660 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005661 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07005662 return;
5663 }
5664
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005665 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5666 uConvertTypes,
5667 pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005668}
5669
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005670
5671/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005672 * Public function, see header qcbor/qcbor_decode.h file
5673 */
5674void
5675QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
5676 const int64_t nLabel,
5677 const uint32_t uConvertTypes,
5678 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005679{
5680 QCBORItem Item;
5681
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005682 QCBORDecode_Private_GetInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07005683 nLabel,
5684 uConvertTypes,
5685 pnValue,
5686 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005687
5688 if(pMe->uLastError == QCBOR_SUCCESS) {
5689 // The above conversion succeeded
5690 return;
5691 }
5692
5693 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5694 // The above conversion failed in a way that code below can't correct
5695 return;
5696 }
5697
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005698 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5699 uConvertTypes,
5700 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005701}
5702
5703
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005704/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005705 * Public function, see header qcbor/qcbor_decode.h file
5706 */
5707void
5708QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
5709 const char *szLabel,
5710 const uint32_t uConvertTypes,
5711 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005712{
5713 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005714 QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07005715 szLabel,
5716 uConvertTypes,
5717 pnValue,
5718 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005719
5720 if(pMe->uLastError == QCBOR_SUCCESS) {
5721 // The above conversion succeeded
5722 return;
5723 }
5724
5725 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5726 // The above conversion failed in a way that code below can't correct
5727 return;
5728 }
5729
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005730 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5731 uConvertTypes,
5732 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005733}
5734
5735
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005736/**
5737 * @brief Convert many number types to an uint64_t.
5738 *
5739 * @param[in] pItem The item to convert.
5740 * @param[in] uConvertTypes Bit mask list of conversion options.
5741 * @param[out] puValue The resulting converted value.
5742 *
5743 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5744 * in uConvertTypes.
5745 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5746 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5747 * or too small.
5748 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005749static QCBORError
5750QCBOR_Private_ConvertUInt64(const QCBORItem *pItem,
5751 const uint32_t uConvertTypes,
5752 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005753{
5754 switch(pItem->uDataType) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005755 case QCBOR_TYPE_DOUBLE:
5756 case QCBOR_TYPE_FLOAT:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005757#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005758 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005759 // Can't use llround here because it will not convert values
5760 // greater than INT64_MAX and less than UINT64_MAX that
5761 // need to be converted so it is more complicated.
5762 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
5763 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5764 if(isnan(pItem->val.dfnum)) {
5765 return QCBOR_ERR_FLOAT_EXCEPTION;
5766 } else if(pItem->val.dfnum < 0) {
5767 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5768 } else {
5769 double dRounded = round(pItem->val.dfnum);
5770 // See discussion in DecodeDateEpoch() for
5771 // explanation of - 0x7ff
5772 if(dRounded > (double)(UINT64_MAX- 0x7ff)) {
5773 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5774 }
5775 *puValue = (uint64_t)dRounded;
5776 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005777 } else {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005778 if(isnan(pItem->val.fnum)) {
5779 return QCBOR_ERR_FLOAT_EXCEPTION;
5780 } else if(pItem->val.fnum < 0) {
5781 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5782 } else {
5783 float fRounded = roundf(pItem->val.fnum);
5784 // See discussion in DecodeDateEpoch() for
5785 // explanation of - 0x7ff
5786 if(fRounded > (float)(UINT64_MAX- 0x7ff)) {
5787 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5788 }
5789 *puValue = (uint64_t)fRounded;
5790 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005791 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005792 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5793 // round() and roundf() shouldn't result in exceptions here, but
5794 // catch them to be robust and thorough. Don't try to
5795 // distinguish between the various exceptions because it seems
5796 // they vary by CPU, compiler and OS.
5797 return QCBOR_ERR_FLOAT_EXCEPTION;
5798 }
5799
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005800 } else {
5801 return QCBOR_ERR_UNEXPECTED_TYPE;
5802 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005803#else
5804 return QCBOR_ERR_HW_FLOAT_DISABLED;
5805#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005806 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005807
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005808 case QCBOR_TYPE_INT64:
5809 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
5810 if(pItem->val.int64 >= 0) {
5811 *puValue = (uint64_t)pItem->val.int64;
5812 } else {
5813 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5814 }
5815 } else {
5816 return QCBOR_ERR_UNEXPECTED_TYPE;
5817 }
5818 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005819
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005820 case QCBOR_TYPE_UINT64:
5821 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
5822 *puValue = pItem->val.uint64;
5823 } else {
5824 return QCBOR_ERR_UNEXPECTED_TYPE;
5825 }
5826 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005827
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005828 default:
5829 return QCBOR_ERR_UNEXPECTED_TYPE;
5830 }
5831
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005832 return QCBOR_SUCCESS;
5833}
Laurence Lundbladec4537442020-04-14 18:53:22 -07005834
5835
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005836/**
5837 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5838 *
5839 * @param[in] pMe The decode context.
5840 * @param[in] uConvertTypes Bit mask list of conversion options.
5841 * @param[out] puValue Result of the conversion.
5842 * @param[in,out] pItem Temporary space to store Item, returned item.
5843 *
5844 * See QCBORDecode_GetUInt64Convert().
5845 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005846void
5847QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pMe,
5848 const uint32_t uConvertTypes,
5849 uint64_t *puValue,
5850 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005851{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005852 if(pMe->uLastError != QCBOR_SUCCESS) {
5853 return;
5854 }
5855
Laurence Lundbladec4537442020-04-14 18:53:22 -07005856 QCBORItem Item;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005857
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005858 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
5859 if(uError) {
5860 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005861 return;
5862 }
5863
Laurence Lundbladea826c502020-05-10 21:07:00 -07005864 if(pItem) {
5865 *pItem = Item;
5866 }
5867
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005868 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(&Item,
5869 uConvertTypes,
5870 puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005871}
5872
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005873
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005874/**
5875 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5876 *
5877 * @param[in] pMe The decode context.
5878 * @param[in] nLabel Label to find in map.
5879 * @param[in] uConvertTypes Bit mask list of conversion options.
5880 * @param[out] puValue Result of the conversion.
5881 * @param[in,out] pItem Temporary space to store Item, returned item.
5882 *
5883 * See QCBORDecode_GetUInt64ConvertInMapN().
5884 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005885void
5886QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe,
5887 const int64_t nLabel,
5888 const uint32_t uConvertTypes,
5889 uint64_t *puValue,
5890 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005891{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005892 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005893 if(pMe->uLastError != QCBOR_SUCCESS) {
5894 return;
5895 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005896
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005897 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
5898 uConvertTypes,
5899 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005900}
5901
5902
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005903/**
5904 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5905 *
5906 * @param[in] pMe The decode context.
5907 * @param[in] szLabel Label to find in map.
5908 * @param[in] uConvertTypes Bit mask list of conversion options.
5909 * @param[out] puValue Result of the conversion.
5910 * @param[in,out] pItem Temporary space to store Item, returned item.
5911 *
5912 * See QCBORDecode_GetUInt64ConvertInMapSZ().
5913 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005914void
5915QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5916 const char *szLabel,
5917 const uint32_t uConvertTypes,
5918 uint64_t *puValue,
5919 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005920{
5921 if(pMe->uLastError != QCBOR_SUCCESS) {
5922 return;
5923 }
5924
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005925 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005926 if(pMe->uLastError != QCBOR_SUCCESS) {
5927 return;
5928 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005929
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005930 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
5931 uConvertTypes,
5932 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005933}
5934
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005935
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005936/**
5937 * @brief Convert many number types to an unt64_t.
5938 *
5939 * @param[in] pItem The item to convert.
5940 * @param[in] uConvertTypes Bit mask list of conversion options.
5941 * @param[out] puValue The resulting converted value.
5942 *
5943 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5944 * in uConvertTypes.
5945 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5946 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5947 * or too small.
5948 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005949static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005950QCBOR_Private_UInt64ConvertAll(const QCBORItem *pItem,
5951 const uint32_t uConvertTypes,
5952 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005953{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08005954 switch(pItem->uDataType) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005955
5956 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005957 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005958 return QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005959 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005960 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005961 }
5962 break;
5963
5964 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005965 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005966 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5967 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005968 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005969 }
5970 break;
5971
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005972#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005973
5974 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005975 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005976 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005977 pItem->val.expAndMantissa.nExponent,
5978 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005979 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005980 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005981 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005982 }
5983 break;
5984
5985 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005986 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005987 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005988 pItem->val.expAndMantissa.nExponent,
5989 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005990 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005991 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005992 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005993 }
5994 break;
5995
5996 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005997 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005998 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005999 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006000 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006001 if(uErr != QCBOR_SUCCESS) {
6002 return uErr;
6003 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006004 return QCBOR_Private_ExponentitateUU(uMantissa,
6005 pItem->val.expAndMantissa.nExponent,
6006 puValue,
6007 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006008 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006009 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006010 }
6011 break;
6012
6013 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006014 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006015 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6016 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006017 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006018 }
6019 break;
6020
6021 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006022 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006023 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006024 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006025 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum,
6026 &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006027 if(uErr != QCBOR_SUCCESS) {
6028 return uErr;
6029 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006030 return QCBOR_Private_ExponentitateUU(uMantissa,
6031 pItem->val.expAndMantissa.nExponent,
6032 puValue,
6033 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006034 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006035 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006036 }
6037 break;
6038
6039 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006040 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006041 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6042 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006043 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006044 }
6045 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006046#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006047 default:
6048 return QCBOR_ERR_UNEXPECTED_TYPE;
6049 }
6050}
6051
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006052
Laurence Lundblade4e2da002020-06-13 23:08:31 -07006053/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006054 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006055 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006056void
6057QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe,
6058 const uint32_t uConvertTypes,
6059 uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006060{
6061 QCBORItem Item;
6062
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006063 QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006064
Laurence Lundbladef6c86662020-05-12 02:08:00 -07006065 if(pMe->uLastError == QCBOR_SUCCESS) {
6066 // The above conversion succeeded
6067 return;
6068 }
6069
6070 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6071 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07006072 return;
6073 }
6074
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006075 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6076 uConvertTypes,
6077 puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006078}
6079
Laurence Lundbladec4537442020-04-14 18:53:22 -07006080
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006081/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006082 * Public function, see header qcbor/qcbor_decode.h file
6083 */
6084void
6085QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
6086 const int64_t nLabel,
6087 const uint32_t uConvertTypes,
6088 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006089{
6090 QCBORItem Item;
6091
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006092 QCBORDecode_Private_GetUInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006093 nLabel,
6094 uConvertTypes,
6095 puValue,
6096 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006097
6098 if(pMe->uLastError == QCBOR_SUCCESS) {
6099 // The above conversion succeeded
6100 return;
6101 }
6102
6103 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6104 // The above conversion failed in a way that code below can't correct
6105 return;
6106 }
6107
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006108 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6109 uConvertTypes,
6110 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006111}
6112
6113
6114/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006115 * Public function, see header qcbor/qcbor_decode.h file
6116 */
6117void
6118QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
6119 const char *szLabel,
6120 const uint32_t uConvertTypes,
6121 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006122{
6123 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006124 QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006125 szLabel,
6126 uConvertTypes,
6127 puValue,
6128 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006129
6130 if(pMe->uLastError == QCBOR_SUCCESS) {
6131 // The above conversion succeeded
6132 return;
6133 }
6134
6135 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6136 // The above conversion failed in a way that code below can't correct
6137 return;
6138 }
6139
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006140 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6141 uConvertTypes,
6142 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006143}
6144
6145
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006146
6147
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006148#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006149/**
6150 * @brief Basic conversions to a double.
6151 *
6152 * @param[in] pItem The item to convert
6153 * @param[in] uConvertTypes Bit flags indicating source types for conversion
6154 * @param[out] pdValue The value converted to a double
6155 *
6156 * This does the conversions that don't need much object code,
6157 * the conversions from int, uint and float to double.
6158 *
6159 * See QCBOR_Private_DoubleConvertAll() for the full set
6160 * of conversions.
6161 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006162static QCBORError
6163QCBOR_Private_ConvertDouble(const QCBORItem *pItem,
6164 const uint32_t uConvertTypes,
6165 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006166{
6167 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006168 case QCBOR_TYPE_FLOAT:
6169#ifndef QCBOR_DISABLE_FLOAT_HW_USE
6170 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6171 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006172 // Simple cast does the job.
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006173 *pdValue = (double)pItem->val.fnum;
6174 } else {
6175 return QCBOR_ERR_UNEXPECTED_TYPE;
6176 }
6177 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006178#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006179 return QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006180#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006181 break;
6182
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006183 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006184 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6185 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006186 *pdValue = pItem->val.dfnum;
6187 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006188 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006189 }
6190 }
6191 break;
6192
6193 case QCBOR_TYPE_INT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006194#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006195 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006196 // A simple cast seems to do the job with no worry of exceptions.
6197 // There will be precision loss for some values.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006198 *pdValue = (double)pItem->val.int64;
6199
6200 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006201 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006202 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006203#else
6204 return QCBOR_ERR_HW_FLOAT_DISABLED;
6205#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006206 break;
6207
6208 case QCBOR_TYPE_UINT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006209#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006210 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006211 // A simple cast seems to do the job with no worry of exceptions.
6212 // There will be precision loss for some values.
6213 *pdValue = (double)pItem->val.uint64;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006214 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006215 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006216 }
6217 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006218#else
6219 return QCBOR_ERR_HW_FLOAT_DISABLED;
6220#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006221
6222 default:
6223 return QCBOR_ERR_UNEXPECTED_TYPE;
6224 }
6225
6226 return QCBOR_SUCCESS;
6227}
6228
6229
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006230/**
6231 * @brief Almost-public method to decode a number and convert to double (semi-private).
6232 *
6233 * @param[in] pMe The decode context.
6234 * @param[in] uConvertTypes Bit mask list of conversion options
6235 * @param[out] pdValue The output of the conversion.
6236 * @param[in,out] pItem Temporary space to store Item, returned item.
6237 *
6238 * See QCBORDecode_GetDoubleConvert().
6239 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006240void
6241QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pMe,
6242 const uint32_t uConvertTypes,
6243 double *pdValue,
6244 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07006245{
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006246 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07006247 return;
6248 }
6249
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006250 QCBORError uError = QCBORDecode_GetNext(pMe, pItem);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006251 if(uError) {
6252 pMe->uLastError = (uint8_t)uError;
6253 return;
6254 }
6255
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006256 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006257 uConvertTypes,
6258 pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006259}
Laurence Lundbladec4537442020-04-14 18:53:22 -07006260
Laurence Lundbladec4537442020-04-14 18:53:22 -07006261
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006262/**
6263 * @brief Almost-public method to decode a number and convert to double (semi-private).
6264 *
6265 * @param[in] pMe The decode context.
6266 * @param[in] nLabel Label to find in map.
6267 * @param[in] uConvertTypes Bit mask list of conversion options
6268 * @param[out] pdValue The output of the conversion.
6269 * @param[in,out] pItem Temporary space to store Item, returned item.
6270 *
6271 * See QCBORDecode_GetDoubleConvertInMapN().
6272 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006273void
6274QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pMe,
6275 const int64_t nLabel,
6276 const uint32_t uConvertTypes,
6277 double *pdValue,
6278 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006279{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006280 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006281 if(pMe->uLastError != QCBOR_SUCCESS) {
6282 return;
6283 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006284
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006285 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6286 uConvertTypes,
6287 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006288}
6289
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006290
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006291/**
6292 * @brief Almost-public method to decode a number and convert to double (semi-private).
6293 *
6294 * @param[in] pMe The decode context.
6295 * @param[in] szLabel Label to find in map.
6296 * @param[in] uConvertTypes Bit mask list of conversion options
6297 * @param[out] pdValue The output of the conversion.
6298 * @param[in,out] pItem Temporary space to store Item, returned item.
6299 *
6300 * See QCBORDecode_GetDoubleConvertInMapSZ().
6301 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006302void
6303QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe,
6304 const char *szLabel,
6305 const uint32_t uConvertTypes,
6306 double *pdValue,
6307 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006308{
6309 if(pMe->uLastError != QCBOR_SUCCESS) {
6310 return;
6311 }
6312
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006313 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006314 if(pMe->uLastError != QCBOR_SUCCESS) {
6315 return;
6316 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006317
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006318 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6319 uConvertTypes,
6320 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006321}
6322
6323
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006324#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006325/**
6326 * @brief Convert a big number to double-precision float.
6327 *
6328 * @param[in] BigNum The big number to convert
6329 *
6330 * @returns The double value.
6331 *
6332 * This will always succeed. It will lose precision for larger
6333 * numbers. If the big number is too large to fit (more than
6334 * 1.7976931348623157E+308) infinity will be returned. NaN is never
6335 * returned.
6336 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006337static double
6338QCBOR_Private_ConvertBigNumToDouble(const UsefulBufC BigNum)
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006339{
6340 double dResult;
6341
6342 dResult = 0.0;
6343 const uint8_t *pByte = BigNum.ptr;
6344 size_t uLen = BigNum.len;
6345 /* This will overflow and become the float value INFINITY if the number
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006346 * is too large to fit. */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006347 while(uLen--) {
6348 dResult = (dResult * 256.0) + (double)*pByte++;
6349 }
6350
6351 return dResult;
6352}
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006353#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6354
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006355
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006356
6357
6358/**
6359 * @brief Convert many number types to a double.
6360 *
6361 * @param[in] pItem The item to convert.
6362 * @param[in] uConvertTypes Bit mask list of conversion options.
6363 * @param[out] pdValue The resulting converted value.
6364 *
6365 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6366 * in uConvertTypes.
6367 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6368 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6369 * or too small.
6370 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006371static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006372QCBOR_Private_DoubleConvertAll(const QCBORItem *pItem,
6373 const uint32_t uConvertTypes,
6374 double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006375{
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006376#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07006377 /*
Laurence Lundblade16a207a2021-09-18 17:22:46 -07006378 * What Every Computer Scientist Should Know About Floating-Point Arithmetic
6379 * https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
6380 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006381 switch(pItem->uDataType) {
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006382
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006383#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006384 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006385 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006386 // Underflow gives 0, overflow gives infinity
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006387 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6388 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
6389 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006390 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006391 }
6392 break;
6393
6394 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006395 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006396 // Underflow gives 0, overflow gives infinity
6397 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6398 exp2((double)pItem->val.expAndMantissa.nExponent);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006399 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006400 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006401 }
6402 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006403#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006404
6405 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006406 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006407 *pdValue = QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006408 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006409 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006410 }
6411 break;
6412
6413 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006414 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006415 *pdValue = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006416 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006417 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006418 }
6419 break;
6420
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006421#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006422 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006423 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006424 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006425 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6426 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006427 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006428 }
6429 break;
6430
6431 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006432 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006433 double dMantissa = -QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006434 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6435 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006436 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006437 }
6438 break;
6439
6440 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006441 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006442 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006443 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6444 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006445 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006446 }
6447 break;
6448
6449 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006450 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006451 double dMantissa = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006452 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6453 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006454 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006455 }
6456 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006457#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006458
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006459 default:
6460 return QCBOR_ERR_UNEXPECTED_TYPE;
6461 }
6462
6463 return QCBOR_SUCCESS;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006464
6465#else
6466 (void)pItem;
6467 (void)uConvertTypes;
6468 (void)pdValue;
6469 return QCBOR_ERR_HW_FLOAT_DISABLED;
6470#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6471
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006472}
6473
6474
6475/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006476 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006477 */
6478void
6479QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe,
6480 const uint32_t uConvertTypes,
6481 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006482{
6483
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006484 QCBORItem Item;
6485
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006486 QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006487
6488 if(pMe->uLastError == QCBOR_SUCCESS) {
6489 // The above conversion succeeded
6490 return;
6491 }
6492
6493 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6494 // The above conversion failed in a way that code below can't correct
6495 return;
6496 }
6497
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006498 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6499 uConvertTypes,
6500 pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006501}
6502
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006503
6504/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006505 * Public function, see header qcbor/qcbor_decode.h file
6506 */
6507void
6508QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe,
6509 const int64_t nLabel,
6510 const uint32_t uConvertTypes,
6511 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006512{
6513 QCBORItem Item;
6514
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006515 QCBORDecode_Private_GetDoubleConvertInMapN(pMe,
6516 nLabel,
6517 uConvertTypes,
6518 pdValue,
6519 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006520
6521 if(pMe->uLastError == QCBOR_SUCCESS) {
6522 // The above conversion succeeded
6523 return;
6524 }
6525
6526 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6527 // The above conversion failed in a way that code below can't correct
6528 return;
6529 }
6530
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006531 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6532 uConvertTypes,
6533 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006534}
6535
6536
6537/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006538 * Public function, see header qcbor/qcbor_decode.h file
6539 */
6540void
6541QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe,
6542 const char *szLabel,
6543 const uint32_t uConvertTypes,
6544 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006545{
6546 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006547 QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe,
6548 szLabel,
6549 uConvertTypes,
6550 pdValue,
6551 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006552
6553 if(pMe->uLastError == QCBOR_SUCCESS) {
6554 // The above conversion succeeded
6555 return;
6556 }
6557
6558 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6559 // The above conversion failed in a way that code below can't correct
6560 return;
6561 }
6562
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006563 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6564 uConvertTypes,
6565 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006566}
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006567#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006568
6569
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006570
6571
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006572#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006573/**
6574 * @brief Convert an integer to a big number
6575 *
6576 * @param[in] uInt The integer to convert.
6577 * @param[in] Buffer The buffer to output the big number to.
6578 *
6579 * @returns The big number or NULLUsefulBufC is the buffer is to small.
6580 *
6581 * This always succeeds unless the buffer is too small.
6582 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006583static UsefulBufC
6584QCBOR_Private_ConvertIntToBigNum(uint64_t uInt, const UsefulBuf Buffer)
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006585{
6586 while((uInt & 0xff00000000000000UL) == 0) {
6587 uInt = uInt << 8;
6588 };
6589
6590 UsefulOutBuf UOB;
6591
6592 UsefulOutBuf_Init(&UOB, Buffer);
6593
6594 while(uInt) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006595 UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff00000000000000UL) >> 56));
6596 uInt = uInt << 8;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006597 }
6598
6599 return UsefulOutBuf_OutUBuf(&UOB);
6600}
6601
6602
Laurence Lundblade37286c02022-09-03 10:05:02 -07006603/**
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006604 * @brief Check and/or complete exponent and mantissa item.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006605 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006606 * @param[in] pMe The decoder context.
6607 * @param[in] TagSpec Expected type(s).
6608 * @param[in,out] pItem See below.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006609 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006610 * This is for decimal fractions and big floats, both of which are an
6611 * exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006612 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006613 * If the item item had a tag number indicating it was a
6614 * decimal fraction or big float, then the input @c pItem will
6615 * have been decoded as exponent and mantissa. If there was
6616 * no tag number, the caller is asking this be decoded as a
6617 * big float or decimal fraction and @c pItem just has the
6618 * first item in an exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006619 *
6620 * On output, the item is always a fully decoded decimal fraction or
6621 * big float.
6622 *
6623 * This errors out if the input type does not meet the TagSpec.
6624 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07006625static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006626QCBOR_Private_ExpMantissaTypeHandler(QCBORDecodeContext *pMe,
6627 const QCBOR_Private_TagSpec TagSpec,
6628 QCBORItem *pItem)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006629{
6630 QCBORError uErr;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006631
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006632 /* pItem could either be a decoded exponent and mantissa or
6633 * the opening array of an undecoded exponent and mantissa. This
Laurence Lundblade37286c02022-09-03 10:05:02 -07006634 * check will succeed on either, but doesn't say which it was.
6635 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006636 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07006637 if(uErr != QCBOR_SUCCESS) {
6638 goto Done;
6639 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006640
Laurence Lundblade37286c02022-09-03 10:05:02 -07006641 if(pItem->uDataType == QCBOR_TYPE_ARRAY) {
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006642 /* The item is an array, which means is is an undecoded exponent
6643 * and mantissa. This call consumes the items in the array and
6644 * results in a decoded exponent and mantissa in pItem. This is
Laurence Lundblade37286c02022-09-03 10:05:02 -07006645 * the case where there was no tag.
6646 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006647 uErr = QCBORDecode_Private_ExpMantissa(pMe, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006648 if(uErr != QCBOR_SUCCESS) {
6649 goto Done;
6650 }
6651
Laurence Lundblade37286c02022-09-03 10:05:02 -07006652 /* The above decode didn't determine whether it is a decimal
6653 * fraction or big num. Which of these two depends on what the
6654 * caller wants it decoded as since there is no tag, so fish the
6655 * type out of the TagSpec. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006656 pItem->uDataType = QCBOR_Private_ExpMantissaDataType(TagSpec.uTaggedTypes[0], pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07006657
6658 /* No need to check the type again. All that we need to know was
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006659 * that it decoded correctly as a exponent and mantissa. The
Laurence Lundblade37286c02022-09-03 10:05:02 -07006660 * QCBOR type is set out by what was requested.
6661 */
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006662 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07006663
6664 /* If the item was not an array and the check passed, then
6665 * it is a fully decoded big float or decimal fraction and
6666 * matches what is requested.
6667 */
6668
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006669Done:
6670 return uErr;
6671}
6672
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006673
Laurence Lundblade37286c02022-09-03 10:05:02 -07006674/* Some notes from the work to disable tags.
6675 *
6676 * The API for big floats and decimal fractions seems good.
6677 * If there's any issue with it it's that the code size to
6678 * implement is a bit large because of the conversion
6679 * to/from int and bignum that is required. There is no API
6680 * that doesn't do the conversion so dead stripping will never
6681 * leave that code out.
6682 *
6683 * The implementation itself seems correct, but not as clean
6684 * and neat as it could be. It could probably be smaller too.
6685 *
6686 * The implementation has three main parts / functions
6687 * - The decoding of the array of two
6688 * - All the tag and type checking for the various API functions
6689 * - Conversion to/from bignum and int
6690 *
6691 * The type checking seems like it wastes the most code for
6692 * what it needs to do.
6693 *
6694 * The inlining for the conversion is probably making the
6695 * overall code base larger.
6696 *
6697 * The tests cases could be organized a lot better and be
6698 * more thorough.
6699 *
6700 * Seems also like there could be more common code in the
6701 * first tier part of the public API. Some functions only
6702 * vary by a TagSpec.
6703 */
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006704
6705/**
6706 * @brief Common processor for exponent and mantissa.
6707 *
6708 * @param[in] pMe The decode context.
6709 * @param[in] TagSpec The expected/allowed tags.
6710 * @param[in] pItem The data item to process.
6711 * @param[out] pnMantissa The returned mantissa as an int64_t.
6712 * @param[out] pnExponent The returned exponent as an int64_t.
6713 *
6714 * This handles exponent and mantissa for base 2 and 10. This
6715 * is limited to a mantissa that is an int64_t. See also
6716 * QCBORDecode_Private_ProcessExpMantissaBig().
6717 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006718static void
6719QCBOR_Private_ProcessExpMantissa(QCBORDecodeContext *pMe,
6720 const QCBOR_Private_TagSpec TagSpec,
6721 QCBORItem *pItem,
6722 int64_t *pnMantissa,
6723 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006724{
6725 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006726
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006727 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006728 if(uErr != QCBOR_SUCCESS) {
6729 goto Done;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006730 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006731
Laurence Lundblade9b334962020-08-27 10:55:53 -07006732 switch (pItem->uDataType) {
6733
6734 case QCBOR_TYPE_DECIMAL_FRACTION:
6735 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade9b334962020-08-27 10:55:53 -07006736 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006737 *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
Laurence Lundblade9b334962020-08-27 10:55:53 -07006738 break;
6739
Laurence Lundblade37286c02022-09-03 10:05:02 -07006740#ifndef QCBOR_DISABLE_TAGS
6741 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006742 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
6743 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
6744 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006745 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006746 break;
6747
6748 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
6749 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
6750 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006751 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006752 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006753#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006754
6755 default:
6756 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
6757 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006758
6759 Done:
6760 pMe->uLastError = (uint8_t)uErr;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006761}
6762
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006763
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006764/**
6765 * @brief Decode exponent and mantissa into a big number.
6766 *
6767 * @param[in] pMe The decode context.
6768 * @param[in] TagSpec The expected/allowed tags.
6769 * @param[in] pItem Item to decode and convert.
6770 * @param[in] BufferForMantissa Buffer to output mantissa into.
6771 * @param[out] pMantissa The output mantissa.
6772 * @param[out] pbIsNegative The sign of the output.
6773 * @param[out] pnExponent The mantissa of the output.
6774 *
6775 * This is the common processing of a decimal fraction or a big float
6776 * into a big number. This will decode and consume all the CBOR items
6777 * that make up the decimal fraction or big float.
6778 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006779static void
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006780QCBORDecode_Private_ProcessExpMantissaBig(QCBORDecodeContext *pMe,
6781 const QCBOR_Private_TagSpec TagSpec,
6782 QCBORItem *pItem,
6783 const UsefulBuf BufferForMantissa,
6784 UsefulBufC *pMantissa,
6785 bool *pbIsNegative,
6786 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006787{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006788 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006789
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006790 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006791 if(uErr != QCBOR_SUCCESS) {
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006792 goto Done;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006793 }
6794
6795 uint64_t uMantissa;
6796
6797 switch (pItem->uDataType) {
6798
6799 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006800 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006801 /* See comments in ExponentiateNN() on handling INT64_MIN */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006802 if(pItem->val.expAndMantissa.Mantissa.nInt >= 0) {
6803 uMantissa = (uint64_t)pItem->val.expAndMantissa.Mantissa.nInt;
6804 *pbIsNegative = false;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006805 } else if(pItem->val.expAndMantissa.Mantissa.nInt != INT64_MIN) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006806 uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt;
6807 *pbIsNegative = true;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006808 } else {
6809 uMantissa = (uint64_t)INT64_MAX+1;
6810 *pbIsNegative = true;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006811 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006812 *pMantissa = QCBOR_Private_ConvertIntToBigNum(uMantissa,
6813 BufferForMantissa);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006814 *pnExponent = pItem->val.expAndMantissa.nExponent;
6815 break;
6816
Laurence Lundblade37286c02022-09-03 10:05:02 -07006817#ifndef QCBOR_DISABLE_TAGS
6818 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006819 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006820 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006821 *pnExponent = pItem->val.expAndMantissa.nExponent;
6822 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6823 *pbIsNegative = false;
6824 break;
6825
6826 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006827 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006828 *pnExponent = pItem->val.expAndMantissa.nExponent;
6829 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6830 *pbIsNegative = true;
6831 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006832#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006833
6834 default:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006835 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006836 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006837
6838Done:
6839 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006840}
6841
6842
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006843/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006844 * Public function, see header qcbor/qcbor_decode.h file
6845 */
6846void
6847QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe,
6848 const uint8_t uTagRequirement,
6849 int64_t *pnMantissa,
6850 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006851{
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006852 if(pMe->uLastError != QCBOR_SUCCESS) {
6853 return;
6854 }
6855
6856 QCBORItem Item;
6857 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
6858 if(uError) {
6859 pMe->uLastError = (uint8_t)uError;
6860 return;
6861 }
6862
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006863 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006864 {
6865 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006866 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6867 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6868 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006869 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006870
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006871 QCBOR_Private_ProcessExpMantissa(pMe,
6872 TagSpec,
6873 &Item,
6874 pnMantissa,
6875 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006876}
6877
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006878
6879/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006880 * Public function, see header qcbor/qcbor_decode.h file
6881 */
6882void
6883QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe,
6884 const int64_t nLabel,
6885 const uint8_t uTagRequirement,
6886 int64_t *pnMantissa,
6887 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006888{
6889 if(pMe->uLastError != QCBOR_SUCCESS) {
6890 return;
6891 }
6892
6893 QCBORItem Item;
6894 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
6895
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006896 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006897 {
6898 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006899 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6900 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6901 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006902 };
6903
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006904 QCBOR_Private_ProcessExpMantissa(pMe,
6905 TagSpec,
6906 &Item,
6907 pnMantissa,
6908 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006909}
6910
6911
6912/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006913 * Public function, see header qcbor/qcbor_decode.h file
6914 */
6915void
6916QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
6917 const char *szLabel,
6918 const uint8_t uTagRequirement,
6919 int64_t *pnMantissa,
6920 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006921{
6922 if(pMe->uLastError != QCBOR_SUCCESS) {
6923 return;
6924 }
6925
6926 QCBORItem Item;
6927 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
6928
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006929 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006930 {
6931 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006932 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6933 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6934 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006935 };
Laurence Lundblade9b334962020-08-27 10:55:53 -07006936
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006937 QCBOR_Private_ProcessExpMantissa(pMe,
6938 TagSpec,
6939 &Item,
6940 pnMantissa,
6941 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006942}
6943
6944
6945/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006946 * Public function, see header qcbor/qcbor_decode.h file
6947 */
6948void
6949QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe,
6950 const uint8_t uTagRequirement,
6951 const UsefulBuf MantissaBuffer,
6952 UsefulBufC *pMantissa,
6953 bool *pbMantissaIsNegative,
6954 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006955{
6956 if(pMe->uLastError != QCBOR_SUCCESS) {
6957 return;
6958 }
6959
6960 QCBORItem Item;
6961 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
6962 if(uError) {
6963 pMe->uLastError = (uint8_t)uError;
6964 return;
6965 }
6966
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006967 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006968 {
6969 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006970 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6971 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6972 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006973 };
6974
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006975 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
6976 TagSpec,
6977 &Item,
6978 MantissaBuffer,
6979 pMantissa,
6980 pbMantissaIsNegative,
6981 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006982}
6983
6984
6985/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006986 * Public function, see header qcbor/qcbor_decode.h file
6987 */
6988void
6989QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe,
6990 const int64_t nLabel,
6991 const uint8_t uTagRequirement,
6992 const UsefulBuf BufferForMantissa,
6993 UsefulBufC *pMantissa,
6994 bool *pbIsNegative,
6995 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006996{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006997 if(pMe->uLastError != QCBOR_SUCCESS) {
6998 return;
6999 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007000
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007001 QCBORItem Item;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007002 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007003 if(pMe->uLastError != QCBOR_SUCCESS) {
7004 return;
7005 }
7006
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007007 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007008 {
7009 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007010 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7011 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7012 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007013 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007014
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007015 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7016 TagSpec,
7017 &Item,
7018 BufferForMantissa,
7019 pMantissa,
7020 pbIsNegative,
7021 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007022}
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007023
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007024
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007025/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007026 * Public function, see header qcbor/qcbor_decode.h file
7027 */
7028void
7029QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe,
7030 const char *szLabel,
7031 const uint8_t uTagRequirement,
7032 const UsefulBuf BufferForMantissa,
7033 UsefulBufC *pMantissa,
7034 bool *pbIsNegative,
7035 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007036{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007037 if(pMe->uLastError != QCBOR_SUCCESS) {
7038 return;
7039 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007040
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007041 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007042 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7043 if(pMe->uLastError != QCBOR_SUCCESS) {
7044 return;
7045 }
7046
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007047 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007048 {
7049 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007050 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7051 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7052 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007053 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007054
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007055 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7056 TagSpec,
7057 &Item,
7058 BufferForMantissa,
7059 pMantissa,
7060 pbIsNegative,
7061 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007062}
7063
7064
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007065/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007066 * Public function, see header qcbor/qcbor_decode.h file
7067 */
7068void
7069QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe,
7070 const uint8_t uTagRequirement,
7071 int64_t *pnMantissa,
7072 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007073{
7074 if(pMe->uLastError != QCBOR_SUCCESS) {
7075 return;
7076 }
7077
7078 QCBORItem Item;
7079 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
7080 if(uError) {
7081 pMe->uLastError = (uint8_t)uError;
7082 return;
7083 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007084 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007085 {
7086 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007087 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7088 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7089 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007090 };
7091
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007092 QCBOR_Private_ProcessExpMantissa(pMe,
7093 TagSpec,
7094 &Item,
7095 pnMantissa,
7096 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007097}
7098
7099
7100/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007101 * Public function, see header qcbor/qcbor_decode.h file
7102 */
7103void
7104QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe,
7105 const int64_t nLabel,
7106 const uint8_t uTagRequirement,
7107 int64_t *pnMantissa,
7108 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007109{
7110 if(pMe->uLastError != QCBOR_SUCCESS) {
7111 return;
7112 }
7113
7114 QCBORItem Item;
7115 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7116 if(pMe->uLastError != QCBOR_SUCCESS) {
7117 return;
7118 }
7119
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007120 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007121 {
7122 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007123 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7124 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7125 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007126 };
7127
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007128 QCBOR_Private_ProcessExpMantissa(pMe,
7129 TagSpec,
7130 &Item,
7131 pnMantissa,
7132 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007133}
7134
7135
7136/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007137 * Public function, see header qcbor/qcbor_decode.h file
7138 */
7139void
7140QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe,
7141 const char *szLabel,
7142 const uint8_t uTagRequirement,
7143 int64_t *pnMantissa,
7144 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007145{
7146 if(pMe->uLastError != QCBOR_SUCCESS) {
7147 return;
7148 }
7149
7150 QCBORItem Item;
7151 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7152 if(pMe->uLastError != QCBOR_SUCCESS) {
7153 return;
7154 }
7155
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007156 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007157 {
7158 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007159 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7160 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7161 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007162 };
7163
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007164 QCBOR_Private_ProcessExpMantissa(pMe,
7165 TagSpec,
7166 &Item,
7167 pnMantissa,
7168 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007169}
7170
7171
7172/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007173 * Public function, see header qcbor/qcbor_decode.h file
7174 */
7175void
7176QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe,
7177 const uint8_t uTagRequirement,
7178 const UsefulBuf MantissaBuffer,
7179 UsefulBufC *pMantissa,
7180 bool *pbMantissaIsNegative,
7181 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007182{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007183 if(pMe->uLastError != QCBOR_SUCCESS) {
7184 return;
7185 }
7186
7187 QCBORItem Item;
7188 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
7189 if(uError) {
7190 pMe->uLastError = (uint8_t)uError;
7191 return;
7192 }
7193
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007194 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007195 {
7196 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007197 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7198 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7199 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007200 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007201
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007202 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7203 TagSpec,
7204 &Item,
7205 MantissaBuffer,
7206 pMantissa,
7207 pbMantissaIsNegative,
7208 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007209}
7210
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007211
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007212/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007213 * Public function, see header qcbor/qcbor_decode.h file
7214 */
7215void
7216QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe,
7217 const int64_t nLabel,
7218 const uint8_t uTagRequirement,
7219 const UsefulBuf BufferForMantissa,
7220 UsefulBufC *pMantissa,
7221 bool *pbIsNegative,
7222 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007223{
7224 if(pMe->uLastError != QCBOR_SUCCESS) {
7225 return;
7226 }
7227
7228 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007229 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7230 if(pMe->uLastError != QCBOR_SUCCESS) {
7231 return;
7232 }
7233
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007234 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007235 {
7236 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007237 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7238 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7239 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007240 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007241
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007242 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7243 TagSpec,
7244 &Item,
7245 BufferForMantissa,
7246 pMantissa,
7247 pbIsNegative,
7248 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007249}
7250
7251
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007252/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007253 * Public function, see header qcbor/qcbor_decode.h file
7254 */
7255void
7256QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe,
7257 const char *szLabel,
7258 const uint8_t uTagRequirement,
7259 const UsefulBuf BufferForMantissa,
7260 UsefulBufC *pMantissa,
7261 bool *pbIsNegative,
7262 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007263{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007264 if(pMe->uLastError != QCBOR_SUCCESS) {
7265 return;
7266 }
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007267
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007268 QCBORItem Item;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007269 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7270 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007271 return;
7272 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007273
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007274 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007275 {
7276 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007277 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7278 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7279 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007280 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007281
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007282 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7283 TagSpec,
7284 &Item,
7285 BufferForMantissa,
7286 pMantissa,
7287 pbIsNegative,
7288 pnExponent);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007289}
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007290
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07007291#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */