blob: 64818dfd5e0fcf165c9d3822934aa7720798c4bd [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 ||
108 uDataType == QCBOR_TYPE_ARRAY ||
109 uDataType == QCBOR_TYPE_MAP_AS_ARRAY;
110}
111
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700112static bool
113QCBORItem_IsEmptyDefiniteLengthMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700114{
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700115 if(!QCBORItem_IsMapOrArray(Item)){
Laurence Lundblade02625d42020-06-25 14:41:41 -0700116 return false;
117 }
118
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700119 if(Item.val.uCount != 0) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700120 return false;
121 }
122 return true;
123}
124
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700125static bool
126QCBORItem_IsIndefiniteLengthMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700127{
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800128#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700129 if(!QCBORItem_IsMapOrArray(Item)){
Laurence Lundblade02625d42020-06-25 14:41:41 -0700130 return false;
131 }
132
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700133 if(Item.val.uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700134 return false;
135 }
136 return true;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800137#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700138 (void)Item;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800139 return false;
140#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700141}
142
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700143/* Return true if the labels in Item1 and Item2 are the same.
144 Works only for integer and string labels. Returns false
145 for any other type. */
146static bool
147QCBORItem_MatchLabel(const QCBORItem Item1, const QCBORItem Item2)
148{
149 if(Item1.uLabelType == QCBOR_TYPE_INT64) {
150 if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
151 return true;
152 }
153 } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
154 if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
155 return true;
156 }
157 } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
158 if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
159 return true;
160 }
161 } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
162 if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
163 return true;
164 }
165 }
166
167 /* Other label types are never matched */
168 return false;
169}
170
171
172/*
173 Returns true if Item1 and Item2 are the same type
174 or if either are of QCBOR_TYPE_ANY.
175 */
176static bool
177QCBORItem_MatchType(const QCBORItem Item1, const QCBORItem Item2)
178{
179 if(Item1.uDataType == Item2.uDataType) {
180 return true;
181 } else if(Item1.uDataType == QCBOR_TYPE_ANY) {
182 return true;
183 } else if(Item2.uDataType == QCBOR_TYPE_ANY) {
184 return true;
185 }
186 return false;
187}
188
Laurence Lundblade02625d42020-06-25 14:41:41 -0700189
Laurence Lundbladeee851742020-01-08 08:37:05 -0800190/*===========================================================================
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700191 DecodeNesting -- Tracking array/map/sequence/bstr-wrapped nesting
Laurence Lundbladeee851742020-01-08 08:37:05 -0800192 ===========================================================================*/
193
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700194/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800195 * See comments about and typedef of QCBORDecodeNesting in qcbor_private.h,
196 * the data structure all these functions work on.
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700197 */
198
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700199
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700200static uint8_t
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700201DecodeNesting_GetCurrentLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700202{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700203 const ptrdiff_t nLevel = pNesting->pCurrent - &(pNesting->pLevels[0]);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800204 /* Limit in DecodeNesting_Descend against more than
205 * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
Laurence Lundblade02625d42020-06-25 14:41:41 -0700206 */
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700207 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700208}
209
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700210
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700211static uint8_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700212DecodeNesting_GetBoundedModeLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700213{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700214 const ptrdiff_t nLevel = pNesting->pCurrentBounded - &(pNesting->pLevels[0]);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800215 /* Limit in DecodeNesting_Descend against more than
216 * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
Laurence Lundblade02625d42020-06-25 14:41:41 -0700217 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700218 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700219}
220
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700221
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700222static uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700223DecodeNesting_GetMapOrArrayStart(const QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700224{
225 return pNesting->pCurrentBounded->u.ma.uStartOffset;
226}
227
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700228
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700229static bool
Laurence Lundblade085d7952020-07-24 10:26:30 -0700230DecodeNesting_IsBoundedEmpty(const QCBORDecodeNesting *pNesting)
231{
232 if(pNesting->pCurrentBounded->u.ma.uCountCursor == QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
233 return true;
234 } else {
235 return false;
236 }
237}
238
239
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700240static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700241DecodeNesting_IsCurrentAtTop(const QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700242{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700243 if(pNesting->pCurrent == &(pNesting->pLevels[0])) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700244 return true;
245 } else {
246 return false;
247 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700248}
249
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700250
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700251static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700252DecodeNesting_IsCurrentDefiniteLength(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700253{
254 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800255 /* Not a map or array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700256 return false;
257 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800258
259#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700260 if(pNesting->pCurrent->u.ma.uCountTotal == QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800261 /* Is indefinite */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700262 return false;
263 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800264
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800265#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
266
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800267 /* All checks passed; is a definte length map or array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700268 return true;
269}
270
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700271static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700272DecodeNesting_IsCurrentBstrWrapped(const QCBORDecodeNesting *pNesting)
Laurence Lundblade642282a2020-06-23 12:00:33 -0700273{
274 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800275 /* is a byte string */
Laurence Lundblade642282a2020-06-23 12:00:33 -0700276 return true;
277 }
278 return false;
279}
280
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700281
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700282static bool
283DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700284{
285 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
286 return true;
287 }
Laurence Lundblade02625d42020-06-25 14:41:41 -0700288 if(pNesting->pCurrent->u.ma.uStartOffset != QCBOR_NON_BOUNDED_OFFSET) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700289 return true;
290 }
291 return false;
292}
293
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700294
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700295static void
296DecodeNesting_SetMapOrArrayBoundedMode(QCBORDecodeNesting *pNesting, bool bIsEmpty, size_t uStart)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700297{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800298 /* Should be only called on maps and arrays */
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700299 /*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800300 * DecodeNesting_EnterBoundedMode() checks to be sure uStart is not
301 * larger than DecodeNesting_EnterBoundedMode which keeps it less than
302 * uin32_t so the cast is safe.
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700303 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700304 pNesting->pCurrent->u.ma.uStartOffset = (uint32_t)uStart;
Laurence Lundblade085d7952020-07-24 10:26:30 -0700305
306 if(bIsEmpty) {
307 pNesting->pCurrent->u.ma.uCountCursor = QCBOR_COUNT_INDICATES_ZERO_LENGTH;
308 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700309}
310
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700311
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700312static void
313DecodeNesting_ClearBoundedMode(QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700314{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700315 pNesting->pCurrent->u.ma.uStartOffset = QCBOR_NON_BOUNDED_OFFSET;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700316}
317
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700318
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700319static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700320DecodeNesting_IsAtEndOfBoundedLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700321{
322 if(pNesting->pCurrentBounded == NULL) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800323 /* No bounded map or array set up */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700324 return false;
325 }
326 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800327 /* Not a map or array; end of those is by byte count */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700328 return false;
329 }
Laurence Lundblade6ab01fb2020-10-01 13:04:49 -0700330 if(!DecodeNesting_IsCurrentBounded(pNesting)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800331 /* In a traveral at a level deeper than the bounded level */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700332 return false;
333 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800334 /* Works for both definite- and indefinitelength maps/arrays */
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800335 if(pNesting->pCurrentBounded->u.ma.uCountCursor != 0 &&
336 pNesting->pCurrentBounded->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800337 /* Count is not zero, still unconsumed item */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700338 return false;
339 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800340 /* All checks passed, got to the end of an array or map*/
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700341 return true;
342}
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700343
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700344
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700345static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700346DecodeNesting_IsEndOfDefiniteLengthMapOrArray(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700347{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800348 /* Must only be called on map / array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700349 if(pNesting->pCurrent->u.ma.uCountCursor == 0) {
350 return true;
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700351 } else {
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700352 return false;
353 }
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700354}
355
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700356
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700357static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700358DecodeNesting_IsCurrentTypeMap(const QCBORDecodeNesting *pNesting)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700359{
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700360 if(pNesting->pCurrent->uLevelType == CBOR_MAJOR_TYPE_MAP) {
361 return true;
362 } else {
363 return false;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700364 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700365}
366
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700367
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700368static bool
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700369DecodeNesting_IsBoundedType(const QCBORDecodeNesting *pNesting, uint8_t uType)
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700370{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700371 if(pNesting->pCurrentBounded == NULL) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700372 return false;
373 }
Laurence Lundblade02625d42020-06-25 14:41:41 -0700374
375 if(pNesting->pCurrentBounded->uLevelType != uType) {
376 return false;
377 }
378
379 return true;
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700380}
381
Laurence Lundblade02625d42020-06-25 14:41:41 -0700382
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700383static void
Laurence Lundblade6c8a4442020-06-22 22:16:11 -0700384DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700385{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800386 /* Only call on a definite-length array / map */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700387 pNesting->pCurrent->u.ma.uCountCursor--;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700388}
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700389
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700390
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700391static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700392DecodeNesting_ReverseDecrement(QCBORDecodeNesting *pNesting)
393{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800394 /* Only call on a definite-length array / map */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700395 pNesting->pCurrent->u.ma.uCountCursor++;
396}
397
398
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700399static void
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700400DecodeNesting_Ascend(QCBORDecodeNesting *pNesting)
401{
402 pNesting->pCurrent--;
403}
404
Laurence Lundblade02625d42020-06-25 14:41:41 -0700405
406static QCBORError
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700407DecodeNesting_Descend(QCBORDecodeNesting *pNesting, uint8_t uType)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700408{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800409 /* Error out if nesting is too deep */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700410 if(pNesting->pCurrent >= &(pNesting->pLevels[QCBOR_MAX_ARRAY_NESTING])) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700411 return QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP;
Laurence Lundblade02625d42020-06-25 14:41:41 -0700412 }
413
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800414 /* The actual descend */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700415 pNesting->pCurrent++;
416
417 pNesting->pCurrent->uLevelType = uType;
418
419 return QCBOR_SUCCESS;
420}
421
422
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700423static QCBORError
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800424DecodeNesting_EnterBoundedMapOrArray(QCBORDecodeNesting *pNesting,
425 bool bIsEmpty,
426 size_t uOffset)
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700427{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700428 /*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800429 * Should only be called on map/array.
430 *
431 * Have descended into this before this is called. The job here is
432 * just to mark it in bounded mode.
433 *
434 * Check against QCBOR_MAX_DECODE_INPUT_SIZE make sure that
435 * uOffset doesn't collide with QCBOR_NON_BOUNDED_OFFSET.
436 *
437 * Cast of uOffset to uint32_t for cases where SIZE_MAX < UINT32_MAX.
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700438 */
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -0800439 if((uint32_t)uOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700440 return QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700441 }
442
Laurence Lundblade0750fc42020-06-20 21:02:34 -0700443 pNesting->pCurrentBounded = pNesting->pCurrent;
Laurence Lundblade085d7952020-07-24 10:26:30 -0700444
445 DecodeNesting_SetMapOrArrayBoundedMode(pNesting, bIsEmpty, uOffset);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700446
447 return QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700448}
449
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700450
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700451static QCBORError
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700452DecodeNesting_DescendMapOrArray(QCBORDecodeNesting *pNesting,
Laurence Lundblade02625d42020-06-25 14:41:41 -0700453 uint8_t uQCBORType,
454 uint64_t uCount)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700455{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700456 QCBORError uError = QCBOR_SUCCESS;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700457
458 if(uCount == 0) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800459 /* Nothing to do for empty definite-length arrays. They are just are
460 * effectively the same as an item that is not a map or array.
461 */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700462 goto Done;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800463 /* Empty indefinite-length maps and arrays are handled elsewhere */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700464 }
465
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800466 /* Error out if arrays is too long to handle */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700467 if(uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH &&
468 uCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700469 uError = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700470 goto Done;
471 }
472
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700473 uError = DecodeNesting_Descend(pNesting, uQCBORType);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700474 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700475 goto Done;
476 }
477
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800478 /* Fill in the new map/array level. Check above makes casts OK. */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -0700479 pNesting->pCurrent->u.ma.uCountCursor = (uint16_t)uCount;
480 pNesting->pCurrent->u.ma.uCountTotal = (uint16_t)uCount;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700481
482 DecodeNesting_ClearBoundedMode(pNesting);
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700483
484Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700485 return uError;;
486}
487
488
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700489static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700490DecodeNesting_LevelUpCurrent(QCBORDecodeNesting *pNesting)
491{
492 pNesting->pCurrent = pNesting->pCurrentBounded - 1;
493}
494
495
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700496static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700497DecodeNesting_LevelUpBounded(QCBORDecodeNesting *pNesting)
498{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700499 while(pNesting->pCurrentBounded != &(pNesting->pLevels[0])) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700500 pNesting->pCurrentBounded--;
501 if(DecodeNesting_IsCurrentBounded(pNesting)) {
502 break;
503 }
504 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700505}
506
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800507
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700508static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700509DecodeNesting_SetCurrentToBoundedLevel(QCBORDecodeNesting *pNesting)
510{
511 pNesting->pCurrent = pNesting->pCurrentBounded;
512}
513
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700514
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700515static QCBORError
Laurence Lundblade02625d42020-06-25 14:41:41 -0700516DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting,
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700517 uint32_t uEndOffset,
518 uint32_t uStartOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700519{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700520 QCBORError uError;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700521
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700522 uError = DecodeNesting_Descend(pNesting, QCBOR_TYPE_BYTE_STRING);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700523 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700524 goto Done;
525 }
526
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800527 /* Fill in the new byte string level */
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700528 pNesting->pCurrent->u.bs.uSavedEndOffset = uEndOffset;
529 pNesting->pCurrent->u.bs.uBstrStartOffset = uStartOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700530
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800531 /* Bstr wrapped levels are always bounded */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700532 pNesting->pCurrentBounded = pNesting->pCurrent;
533
534Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700535 return uError;;
536}
537
Laurence Lundbladed0304932020-06-27 10:59:38 -0700538
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700539static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700540DecodeNesting_ZeroMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700541{
542 pNesting->pCurrent->u.ma.uCountCursor = 0;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700543}
544
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700545
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700546static void
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800547DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting)
548{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700549 if(pNesting->pCurrent->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
550 pNesting->pCurrentBounded->u.ma.uCountCursor = pNesting->pCurrentBounded->u.ma.uCountTotal;
551 }
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800552}
553
554
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700555static void
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700556DecodeNesting_Init(QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700557{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700558 /* Assumes that *pNesting has been zero'd before this call. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700559 pNesting->pLevels[0].uLevelType = QCBOR_TYPE_BYTE_STRING;
560 pNesting->pCurrent = &(pNesting->pLevels[0]);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700561}
562
563
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700564static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800565DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting,
566 QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700567{
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700568 *pSave = *pNesting;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700569}
570
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700571
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700572static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800573DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting,
574 const QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700575{
576 *pNesting = *pSave;
577}
578
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700579
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700580static uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700581DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700582{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700583 return pMe->pCurrentBounded->u.bs.uSavedEndOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700584}
585
586
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800587
588
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800589#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladeee851742020-01-08 08:37:05 -0800590/*===========================================================================
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800591 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
592
593 The following four functions are pretty wrappers for invocation of
594 the string allocator supplied by the caller.
595
Laurence Lundbladeee851742020-01-08 08:37:05 -0800596 ===========================================================================*/
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800597
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700598static void
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800599StringAllocator_Free(const QCBORInternalAllocator *pMe, const void *pMem)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800600{
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300601 /* This cast to uintptr_t suppresses the "-Wcast-qual" warnings.
602 * This is the one place where the const needs to be cast away so const can
603 * be use in the rest of the code.
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800604 */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300605 (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, 0);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800606}
607
Laurence Lundbladeee851742020-01-08 08:37:05 -0800608// StringAllocator_Reallocate called with pMem NULL is
609// equal to StringAllocator_Allocate()
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700610static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800611StringAllocator_Reallocate(const QCBORInternalAllocator *pMe,
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800612 const void *pMem,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800613 size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800614{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800615 /* See comment in StringAllocator_Free() */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300616 return (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, uSize);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800617}
618
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700619static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800620StringAllocator_Allocate(const QCBORInternalAllocator *pMe, size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800621{
622 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
623}
624
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700625static void
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800626StringAllocator_Destruct(const QCBORInternalAllocator *pMe)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800627{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800628 /* See comment in StringAllocator_Free() */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800629 if(pMe->pfAllocator) {
630 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
631 }
632}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800633#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800634
635
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800636
637
Laurence Lundbladeee851742020-01-08 08:37:05 -0800638/*===========================================================================
639 QCBORDecode -- The main implementation of CBOR decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700640
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800641 See qcbor/qcbor_decode.h for definition of the object
642 used here: QCBORDecodeContext
Laurence Lundbladeee851742020-01-08 08:37:05 -0800643 ===========================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700644/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800645 * Public function, see header file
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700646 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700647void
648QCBORDecode_Init(QCBORDecodeContext *pMe,
649 UsefulBufC EncodedCBOR,
650 QCBORDecodeMode nDecodeMode)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700651{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800652 memset(pMe, 0, sizeof(QCBORDecodeContext));
653 UsefulInputBuf_Init(&(pMe->InBuf), EncodedCBOR);
654 /* Don't bother with error check on decode mode. If a bad value is
655 * passed it will just act as if the default normal mode of 0 was set.
656 */
657 pMe->uDecodeMode = (uint8_t)nDecodeMode;
658 DecodeNesting_Init(&(pMe->nesting));
659
660 /* Inialize me->auMappedTags to CBOR_TAG_INVALID16. See
661 * GetNext_TaggedItem() and MapTagNumber(). */
662 memset(pMe->auMappedTags, 0xff, sizeof(pMe->auMappedTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700663}
664
665
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800666#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
667
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700668/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800669 * Public function, see header file
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700670 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700671void
672QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
673 QCBORStringAllocate pfAllocateFunction,
674 void *pAllocateContext,
675 bool bAllStrings)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700676{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800677 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
678 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
679 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700680}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800681#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700682
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800683
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800684
685
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800686/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800687 * Deprecated public function, see header file
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800688 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700689void
690QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pMe,
691 const QCBORTagListIn *pTagList)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700692{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800693 /* This does nothing now. It is retained for backwards compatibility */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700694 (void)pMe;
695 (void)pTagList;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700696}
697
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700698
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800699
700
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700701/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800702 * Decoding items is done in six layers, one calling the next one
703 * down. If a layer has no work to do for a particular item, it
704 * returns quickly.
705 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700706 * 1. QCBORDecode_Private_GetNextTagContent - The top layer processes
707 * tagged data items, turning them into the local C representation.
708 * For the most simple it is just associating a QCBOR_TYPE with the
709 * data. For the complex ones that an aggregate of data items, there
710 * is some further decoding and some limited recursion.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800711 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700712 * 2. QCBORDecode_Private_GetNextMapOrArray - This manages the
713 * beginnings and ends of maps and arrays. It tracks descending into
714 * and ascending out of maps/arrays. It processes breaks that
715 * terminate indefinite-length maps and arrays.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800716 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700717 * 3. QCBORDecode_Private_GetNextMapEntry - This handles the combining
718 * of two items, the label and the data, that make up a map entry. It
719 * only does work on maps. It combines the label and data items into
720 * one labeled item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800721 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700722 * 4. QCBORDecode_Private_GetNextTagNumber - This decodes type 6 tag
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800723 * numbers. It turns the tag numbers into bit flags associated with
724 * the data item. No actual decoding of the contents of the tag is
725 * performed here.
726 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700727 * 5. QCBORDecode_Private_GetNextFullString - This assembles the
728 * sub-items that make up an indefinite-length string into one string
729 * item. It uses the string allocator to create contiguous space for
730 * the item. It processes all breaks that are part of
731 * indefinite-length strings.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800732 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700733 * 6. QCBOR_Private_DecodeAtomicDataItem - This decodes the atomic
734 * data items in CBOR. Each atomic data item has a "major type", an
735 * integer "argument" and optionally some content. For text and byte
736 * strings, the content is the bytes that make up the string. These
737 * are the smallest data items that are considered to be well-formed.
738 * The content may also be other data items in the case of aggregate
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800739 * types. They are not handled in this layer.
740 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700741 * This uses about 350 bytes of stack. This number comes from
742 * instrumenting (printf address of stack variables) the code on x86
743 * compiled for size optimization.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700744 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800745
746
747/*
748 * Note about use of int and unsigned variables.
749 *
750 * See http://www.unix.org/whitepapers/64bit.html for reasons int is
751 * used carefully here, and in particular why it isn't used in the
752 * public interface. Also see
753 * https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers
754 *
755 * Int is used for values that need less than 16-bits and would be
756 * subject to integer promotion and result in complaining from static
757 * analyzers.
758 */
759
760
761/**
762 * @brief Decode the CBOR head, the type and argument.
763 *
764 * @param[in] pUInBuf The input buffer to read from.
765 * @param[out] pnMajorType The decoded major type.
766 * @param[out] puArgument The decoded argument.
767 * @param[out] pnAdditionalInfo The decoded Lower 5 bits of initial byte.
768 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -0700769 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved features
770 * @retval QCBOR_ERR_HIT_END Unexpected end of input
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800771 *
772 * This decodes the CBOR "head" that every CBOR data item has. See
773 * longer explaination of the head in documentation for
774 * QCBOREncode_EncodeHead().
775 *
776 * This does the network->host byte order conversion. The conversion
777 * here also results in the conversion for floats in addition to that
778 * for lengths, tags and integer values.
779 *
780 * The int type is preferred to uint8_t for some variables as this
781 * avoids integer promotions, can reduce code size and makes static
782 * analyzers happier.
783 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700784static QCBORError
785QCBOR_Private_DecodeHead(UsefulInputBuf *pUInBuf,
786 int *pnMajorType,
787 uint64_t *puArgument,
788 int *pnAdditionalInfo)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700789{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800790 QCBORError uReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800791
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800792 /* Get the initial byte that every CBOR data item has and break it
793 * down. */
794 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800795 const int nTmpMajorType = nInitialByte >> 5;
796 const int nAdditionalInfo = nInitialByte & 0x1f;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800797
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800798 /* Where the argument accumulates */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800799 uint64_t uArgument;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800800
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800801 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800802 /* Need to get 1,2,4 or 8 additional argument bytes. Map
803 * LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length.
804 */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800805 static const uint8_t aIterate[] = {1,2,4,8};
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800806
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800807 /* Loop getting all the bytes in the argument */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800808 uArgument = 0;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800809 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800810 /* This shift and add gives the endian conversion. */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800811 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
812 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800813 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800814 /* The reserved and thus-far unused additional info values */
815 uReturn = QCBOR_ERR_UNSUPPORTED;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800816 goto Done;
817 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800818 /* Less than 24, additional info is argument or 31, an
819 * indefinite-length. No more bytes to get.
820 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800821 uArgument = (uint64_t)nAdditionalInfo;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700822 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800823
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700824 if(UsefulInputBuf_GetError(pUInBuf)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800825 uReturn = QCBOR_ERR_HIT_END;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700826 goto Done;
827 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800828
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800829 /* All successful if arrived here. */
830 uReturn = QCBOR_SUCCESS;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800831 *pnMajorType = nTmpMajorType;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800832 *puArgument = uArgument;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800833 *pnAdditionalInfo = nAdditionalInfo;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800834
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700835Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800836 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700837}
838
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800839
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800840/**
841 * @brief Decode integer types, major types 0 and 1.
842 *
843 * @param[in] nMajorType The CBOR major type (0 or 1).
844 * @param[in] uArgument The argument from the head.
845 * @param[out] pDecodedItem The filled in decoded item.
846 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -0700847 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800848 *
849 * Must only be called when major type is 0 or 1.
850 *
851 * CBOR doesn't explicitly specify two's compliment for integers but
852 * all CPUs use it these days and the test vectors in the RFC are
853 * so. All integers in the CBOR structure are positive and the major
854 * type indicates positive or negative. CBOR can express positive
855 * integers up to 2^x - 1 where x is the number of bits and negative
856 * integers down to 2^x. Note that negative numbers can be one more
857 * away from zero than positive. Stdint, as far as I can tell, uses
858 * two's compliment to represent negative integers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700859 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700860static QCBORError
861QCBOR_Private_DecodeInteger(const int nMajorType,
862 const uint64_t uArgument,
863 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700864{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800865 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800866
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700867 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800868 if (uArgument <= INT64_MAX) {
869 pDecodedItem->val.int64 = (int64_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700870 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800871
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700872 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800873 pDecodedItem->val.uint64 = uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700874 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700875 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800876
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700877 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800878 if(uArgument <= INT64_MAX) {
879 /* CBOR's representation of negative numbers lines up with
880 * the two-compliment representation. A negative integer has
881 * one more in range than a positive integer. INT64_MIN is
882 * equal to (-INT64_MAX) - 1.
883 */
884 pDecodedItem->val.int64 = (-(int64_t)uArgument) - 1;
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 Lundblade2d493002024-02-01 11:09:17 -0700888 pDecodedItem->val.uint64 = uArgument;
889 pDecodedItem->uDataType = QCBOR_TYPE_65BIT_NEG_INT;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700890 }
891 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800892
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800893 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700894}
895
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800896
897/* Make sure #define value line up as DecodeSimple counts on this. */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700898#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
899#error QCBOR_TYPE_FALSE macro value wrong
900#endif
901
902#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
903#error QCBOR_TYPE_TRUE macro value wrong
904#endif
905
906#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
907#error QCBOR_TYPE_NULL macro value wrong
908#endif
909
910#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
911#error QCBOR_TYPE_UNDEF macro value wrong
912#endif
913
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700914#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
915#error QCBOR_TYPE_BREAK macro value wrong
916#endif
917
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700918#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
919#error QCBOR_TYPE_DOUBLE macro value wrong
920#endif
921
922#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
923#error QCBOR_TYPE_FLOAT macro value wrong
924#endif
925
Laurence Lundblade9b334962020-08-27 10:55:53 -0700926
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800927/**
928 * @brief Decode major type 7 -- true, false, floating-point, break...
929 *
930 * @param[in] nAdditionalInfo The lower five bits from the initial byte.
931 * @param[in] uArgument The argument from the head.
932 * @param[out] pDecodedItem The filled in decoded item.
933 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -0700934 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
935 * of half-precision disabled
936 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all float
937 * decode is disabled.
938 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of simple
939 * type in input.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700940 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700941static QCBORError
942QCBOR_Private_DecodeType7(const int nAdditionalInfo,
943 const uint64_t uArgument,
944 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800945{
946 QCBORError uReturn = QCBOR_SUCCESS;
947
948 /* uAdditionalInfo is 5 bits from the initial byte. Compile time
949 * checks above make sure uAdditionalInfo values line up with
950 * uDataType values. DecodeHead() never returns an AdditionalInfo
951 * > 0x1f so cast is safe.
952 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800953 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800954
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800955 switch(nAdditionalInfo) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800956 /* No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they
957 * are caught before this is called.
958 */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800959
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800960 case HALF_PREC_FLOAT: /* 25 */
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700961#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800962 /* Half-precision is returned as a double. The cast to
963 * uint16_t is safe because the encoded value was 16 bits. It
964 * was widened to 64 bits to be passed in here.
965 */
966 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uArgument);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700967 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800968#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200969 uReturn = FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700970 break;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800971 case SINGLE_PREC_FLOAT: /* 26 */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200972#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800973 /* Single precision is normally returned as a double since
974 * double is widely supported, there is no loss of precision,
975 * it makes it easy for the caller in most cases and it can
976 * be converted back to single with no loss of precision
977 *
978 * The cast to uint32_t is safe because the encoded value was
979 * 32 bits. It was widened to 64 bits to be passed in here.
980 */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700981 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800982 const float f = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uArgument);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700983#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800984 /* In the normal case, use HW to convert float to
985 * double. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700986 pDecodedItem->val.dfnum = (double)f;
987 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800988#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800989 /* Use of float HW is disabled, return as a float. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700990 pDecodedItem->val.fnum = f;
991 pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
992
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800993 /* IEEE754_FloatToDouble() could be used here to return as
994 * a double, but it adds object code and most likely
995 * anyone disabling FLOAT HW use doesn't care about floats
996 * and wants to save object code.
997 */
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800998#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700999 }
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001000#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1001 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001002 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001003
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001004 case DOUBLE_PREC_FLOAT: /* 27 */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001005#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001006 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uArgument);
Laurence Lundblade67bd5512018-11-02 21:44:06 +07001007 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001008#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1009 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001010 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001011
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001012 case CBOR_SIMPLEV_FALSE: /* 20 */
1013 case CBOR_SIMPLEV_TRUE: /* 21 */
1014 case CBOR_SIMPLEV_NULL: /* 22 */
1015 case CBOR_SIMPLEV_UNDEF: /* 23 */
1016 case CBOR_SIMPLE_BREAK: /* 31 */
1017 break; /* nothing to do */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001018
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001019 case CBOR_SIMPLEV_ONEBYTE: /* 24 */
1020 if(uArgument <= CBOR_SIMPLE_BREAK) {
1021 /* This takes out f8 00 ... f8 1f which should be encoded
1022 * as e0 … f7
1023 */
1024 uReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001025 goto Done;
1026 }
Laurence Lundblade5e390822019-01-06 12:35:01 -08001027 /* FALLTHROUGH */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001028
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001029 default: /* 0-19 */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001030 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001031 /* DecodeHead() will make uArgument equal to
1032 * nAdditionalInfo when nAdditionalInfo is < 24. This cast is
1033 * safe because the 2, 4 and 8 byte lengths of uNumber are in
1034 * the double/float cases above
Laurence Lundbladeee851742020-01-08 08:37:05 -08001035 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001036 pDecodedItem->val.uSimple = (uint8_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001037 break;
1038 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001039
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001040Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001041 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001042}
1043
1044
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001045/**
1046 * @brief Decode text and byte strings
1047 *
1048 * @param[in] pAllocator The string allocator or NULL.
1049 * @param[in] uStrLen The length of the string.
1050 * @param[in] pUInBuf The surce from which to read the string's bytes.
1051 * @param[out] pDecodedItem The filled in decoded item.
1052 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001053 * @retval QCBOR_ERR_HIT_END Unexpected end of input.
1054 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1055 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001056 *
1057 * The reads @c uStrlen bytes from @c pUInBuf and fills in @c
1058 * pDecodedItem. If @c pAllocator is not NULL then memory for the
1059 * string is allocated.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001060 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001061static QCBORError
1062QCBOR_Private_DecodeBytes(const QCBORInternalAllocator *pAllocator,
1063 const uint64_t uStrLen,
1064 UsefulInputBuf *pUInBuf,
1065 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001066{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001067 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001068
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001069 /* CBOR lengths can be 64 bits, but size_t is not 64 bits on all
1070 * CPUs. This check makes the casts to size_t below safe.
1071 *
1072 * The max is 4 bytes less than the largest sizeof() so this can be
1073 * tested by putting a SIZE_MAX length in the CBOR test input (no
1074 * one will care the limit on strings is 4 bytes shorter).
1075 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001076 if(uStrLen > SIZE_MAX-4) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001077 uReturn = QCBOR_ERR_STRING_TOO_LONG;
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001078 goto Done;
1079 }
1080
1081 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, (size_t)uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +05301082 if(UsefulBuf_IsNULLC(Bytes)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001083 /* Failed to get the bytes for this string item */
1084 uReturn = QCBOR_ERR_HIT_END;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +05301085 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001086 }
Laurence Lundblade471a3fd2018-10-18 21:27:45 +05301087
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001088#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001089 /* Note that this is not where allocation to coalesce
1090 * indefinite-length strings is done. This is for when the caller
1091 * has requested all strings be allocated. Disabling indefinite
1092 * length strings also disables this allocate-all option.
1093 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001094 if(pAllocator) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001095 /* request to use the string allocator to make a copy */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001096 UsefulBuf NewMem = StringAllocator_Allocate(pAllocator, (size_t)uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +05301097 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001098 uReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +05301099 goto Done;
1100 }
1101 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001102 pDecodedItem->uDataAlloc = 1;
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001103 goto Done;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +05301104 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001105#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1106 (void)pAllocator;
1107#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1108
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001109 /* Normal case with no string allocator */
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001110 pDecodedItem->val.string = Bytes;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001111
Laurence Lundblade471a3fd2018-10-18 21:27:45 +05301112Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001113 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001114}
1115
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001116
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001117/**
1118 * @brief Map the CBOR major types for strings to the QCBOR types.
1119 *
1120 * @param[in] nCBORMajorType The CBOR major type to convert.
1121 * @retturns QCBOR type number.
1122 *
1123 * This only works for the two string types.
1124 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001125static uint8_t
1126QCBOR_Private_ConvertStringMajorTypes(int nCBORMajorType)
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001127{
1128 #if CBOR_MAJOR_TYPE_BYTE_STRING + 4 != QCBOR_TYPE_BYTE_STRING
1129 #error QCBOR_TYPE_BYTE_STRING no lined up with major type
1130 #endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001131
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001132 #if CBOR_MAJOR_TYPE_TEXT_STRING + 4 != QCBOR_TYPE_TEXT_STRING
1133 #error QCBOR_TYPE_TEXT_STRING no lined up with major type
1134 #endif
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001135
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001136 return (uint8_t)(nCBORMajorType + 4);
1137}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001138
1139
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001140/**
1141 * @brief Map the CBOR major types for arrays/maps to the QCBOR types.
1142 *
1143 * @param[in] nCBORMajorType The CBOR major type to convert.
1144 * @retturns QCBOR type number.
1145 *
1146 * This only works for the two aggregate types.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001147 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001148static uint8_t
1149QCBORDecode_Private_ConvertArrayOrMapType(int nCBORMajorType)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001150{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001151 #if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
1152 #error QCBOR_TYPE_ARRAY value not lined up with major type
1153 #endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001154
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001155 #if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
1156 #error QCBOR_TYPE_MAP value not lined up with major type
1157 #endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001158
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001159 return (uint8_t)(nCBORMajorType);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001160}
1161
1162
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001163/**
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001164 * @brief Decode a single primitive data item (decode layer 6).
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001165 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001166 * @param[in] pUInBuf Input buffer to read data item from.
1167 * @param[out] pDecodedItem The filled-in decoded item.
1168 * @param[in] pAllocator The allocator to use for strings or NULL.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001169 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001170 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1171 * features
1172 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1173 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1174 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1175 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1176 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1177 * of half-precision disabled
1178 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1179 * float decode is disabled.
1180 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1181 * simple type in input.
1182 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1183 * in input, but indefinite
1184 * lengths disabled.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001185 *
1186 * This decodes the most primitive / atomic data item. It does
1187 * no combing of data items.
1188 */
1189static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001190QCBOR_Private_DecodeAtomicDataItem(UsefulInputBuf *pUInBuf,
1191 QCBORItem *pDecodedItem,
1192 const QCBORInternalAllocator *pAllocator)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001193{
1194 QCBORError uReturn;
1195
1196 /* Get the major type and the argument. The argument could be
1197 * length of more bytes or the value depending on the major
1198 * type. nAdditionalInfo is an encoding of the length of the
1199 * uNumber and is needed to decode floats and doubles.
1200 */
1201 int nMajorType = 0;
1202 uint64_t uArgument = 0;
1203 int nAdditionalInfo = 0;
1204
1205 memset(pDecodedItem, 0, sizeof(QCBORItem));
1206
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001207 uReturn = QCBOR_Private_DecodeHead(pUInBuf, &nMajorType, &uArgument, &nAdditionalInfo);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001208 if(uReturn) {
1209 goto Done;
1210 }
1211
1212 /* At this point the major type and the argument are valid. We've
1213 * got the type and the argument that starts every CBOR data item.
1214 */
1215 switch (nMajorType) {
1216 case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
1217 case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
1218 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1219 uReturn = QCBOR_ERR_BAD_INT;
1220 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001221 uReturn = QCBOR_Private_DecodeInteger(nMajorType, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001222 }
1223 break;
1224
1225 case CBOR_MAJOR_TYPE_BYTE_STRING: /* Major type 2 */
1226 case CBOR_MAJOR_TYPE_TEXT_STRING: /* Major type 3 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001227 pDecodedItem->uDataType = QCBOR_Private_ConvertStringMajorTypes(nMajorType);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001228 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1229 pDecodedItem->val.string = (UsefulBufC){NULL, QCBOR_STRING_LENGTH_INDEFINITE};
1230 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001231 uReturn = QCBOR_Private_DecodeBytes(pAllocator, uArgument, pUInBuf, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001232 }
1233 break;
1234
1235 case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */
1236 case CBOR_MAJOR_TYPE_MAP: /* Major type 5 */
1237 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1238 /* Indefinite-length string. */
1239#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
1240 pDecodedItem->val.uCount = QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH;
1241#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1242 uReturn = QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED;
1243 break;
1244#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1245 } else {
1246 /* Definite-length string. */
1247 if(uArgument > QCBOR_MAX_ITEMS_IN_ARRAY) {
1248 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
1249 goto Done;
1250 }
1251 /* cast OK because of check above */
1252 pDecodedItem->val.uCount = (uint16_t)uArgument;
1253 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001254 pDecodedItem->uDataType = QCBORDecode_Private_ConvertArrayOrMapType(nMajorType);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001255 break;
1256
1257 case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */
Laurence Lundblade37286c02022-09-03 10:05:02 -07001258#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001259 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1260 uReturn = QCBOR_ERR_BAD_INT;
1261 } else {
1262 pDecodedItem->val.uTagV = uArgument;
1263 pDecodedItem->uDataType = QCBOR_TYPE_TAG;
1264 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07001265#else /* QCBOR_DISABLE_TAGS */
1266 uReturn = QCBOR_ERR_TAGS_DISABLED;
1267#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001268 break;
1269
1270 case CBOR_MAJOR_TYPE_SIMPLE:
1271 /* Major type 7: float, double, true, false, null... */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001272 uReturn = QCBOR_Private_DecodeType7(nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001273 break;
1274
1275 default:
1276 /* Never happens because DecodeHead() should never return > 7 */
1277 uReturn = QCBOR_ERR_UNSUPPORTED;
1278 break;
1279 }
1280
1281Done:
1282 return uReturn;
1283}
1284
1285
1286/**
1287 * @brief Process indefinite-length strings (decode layer 5).
1288 *
1289 * @param[in] pMe Decoder context
1290 * @param[out] pDecodedItem The decoded item that work is done on.
1291 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001292 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1293 * features
1294 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1295 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1296 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1297 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1298 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1299 * of half-precision disabled
1300 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1301 * float decode is disabled.
1302 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1303 * simple type in input.
1304 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1305 * in input, but indefinite
1306 * lengths disabled.
1307 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1308 * but no string allocator.
1309 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1310 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1311 * input, but indefinite-length
1312 * strings are disabled.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001313 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001314 * If @c pDecodedItem is not an indefinite-length string, this does nothing.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001315 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001316 * If it is, this loops getting the subsequent chunk data items that
1317 * make up the string. The string allocator is used to make a
1318 * contiguous buffer for the chunks. When this completes @c
1319 * pDecodedItem contains the put-together string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001320 *
1321 * Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001322 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001323static QCBORError
1324QCBORDecode_Private_GetNextFullString(QCBORDecodeContext *pMe,
1325 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001326{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001327 /* Aproximate stack usage
1328 * 64-bit 32-bit
1329 * local vars 32 16
1330 * 2 UsefulBufs 32 16
1331 * QCBORItem 56 52
1332 * TOTAL 120 74
1333 */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001334
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001335 /* The string allocator is used here for two purposes: 1)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001336 * coalescing the chunks of an indefinite-length string, 2)
1337 * allocating storage for every string returned when requested.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001338 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001339 * The first use is below in this function. Indefinite-length
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001340 * strings cannot be processed at all without a string allocator.
1341 *
1342 * The second used is in DecodeBytes() which is called by
1343 * GetNext_Item() below. This second use unneccessary for most use
1344 * and only happens when requested in the call to
1345 * QCBORDecode_SetMemPool(). If the second use not requested then
1346 * NULL is passed for the string allocator to GetNext_Item().
1347 *
1348 * QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS disables the string
1349 * allocator altogether and thus both of these uses. It reduced the
1350 * decoder object code by about 400 bytes.
1351 */
Laurence Lundblade3a691a02020-12-28 04:15:16 -08001352 const QCBORInternalAllocator *pAllocatorForGetNext = NULL;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001353
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001354#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3a691a02020-12-28 04:15:16 -08001355 const QCBORInternalAllocator *pAllocator = NULL;
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001356
1357 if(pMe->StringAllocator.pfAllocator) {
1358 pAllocator = &(pMe->StringAllocator);
1359 if(pMe->bStringAllocateAll) {
1360 pAllocatorForGetNext = pAllocator;
1361 }
1362 }
1363#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1364
1365 QCBORError uReturn;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001366 uReturn = QCBOR_Private_DecodeAtomicDataItem(&(pMe->InBuf), pDecodedItem, pAllocatorForGetNext);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001367 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001368 goto Done;
1369 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001370
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001371 /* Only do indefinite-length processing on strings */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001372 const uint8_t uStringType = pDecodedItem->uDataType;
1373 if(uStringType!= QCBOR_TYPE_BYTE_STRING && uStringType != QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001374 goto Done;
1375 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001376
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001377 /* Is this a string with an indefinite length? */
1378 if(pDecodedItem->val.string.len != QCBOR_STRING_LENGTH_INDEFINITE) {
1379 goto Done;
1380 }
1381
1382#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001383 /* Can't decode indefinite-length strings without a string allocator */
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001384 if(pAllocator == NULL) {
1385 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1386 goto Done;
1387 }
1388
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001389 /* Loop getting chunks of the indefinite-length string */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001390 UsefulBufC FullString = NULLUsefulBufC;
1391
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001392 for(;;) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001393 /* Get QCBORItem for next chunk */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001394 QCBORItem StringChunkItem;
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001395 /* Pass a NULL string allocator to GetNext_Item() because the
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001396 * individual string chunks in an indefinite-length should not
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001397 * be allocated. They are always copied in the the contiguous
1398 * buffer allocated here.
1399 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001400 uReturn = QCBOR_Private_DecodeAtomicDataItem(&(pMe->InBuf), &StringChunkItem, NULL);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001401 if(uReturn) {
1402 break;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001403 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001404
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001405 /* Is item is the marker for end of the indefinite-length string? */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001406 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001407 /* String is complete */
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001408 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301409 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001410 break;
1411 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001412
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001413 /* All chunks must be of the same type, the type of the item
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001414 * that introduces the indefinite-length string. This also
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001415 * catches errors where the chunk is not a string at all and an
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001416 * indefinite-length string inside an indefinite-length string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001417 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001418 if(StringChunkItem.uDataType != uStringType ||
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001419 StringChunkItem.val.string.len == QCBOR_STRING_LENGTH_INDEFINITE) {
1420 uReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001421 break;
1422 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001423
David Navarro9123e5b2022-03-28 16:04:03 +02001424 if (StringChunkItem.val.string.len > 0) {
1425 /* The first time throurgh FullString.ptr is NULL and this is
1426 * equivalent to StringAllocator_Allocate(). Subsequently it is
1427 * not NULL and a reallocation happens.
1428 */
1429 UsefulBuf NewMem = StringAllocator_Reallocate(pAllocator,
1430 FullString.ptr,
1431 FullString.len + StringChunkItem.val.string.len);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001432
David Navarro9123e5b2022-03-28 16:04:03 +02001433 if(UsefulBuf_IsNULL(NewMem)) {
1434 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1435 break;
1436 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001437
David Navarro9123e5b2022-03-28 16:04:03 +02001438 /* Copy new string chunk to the end of accumulated string */
1439 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001440 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001441 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001442
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001443 if(uReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
1444 /* Getting the item failed, clean up the allocated memory */
Laurence Lundbladeb9702452021-03-08 21:02:57 -08001445 StringAllocator_Free(pAllocator, FullString.ptr);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001446 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001447#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1448 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1449#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001450
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001451Done:
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001452 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001453}
1454
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001455
Laurence Lundblade37286c02022-09-03 10:05:02 -07001456#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001457/**
1458 * @brief This converts a tag number to a shorter mapped value for storage.
1459 *
1460 * @param[in] pMe The decode context.
1461 * @param[in] uUnMappedTag The tag number to map
1462 * @param[out] puMappedTagNumer The stored tag number.
1463 *
1464 * @return error code.
1465 *
1466 * The main point of mapping tag numbers is make QCBORItem
1467 * smaller. With this mapping storage of 4 tags takes up 8
1468 * bytes. Without, it would take up 32 bytes.
1469 *
1470 * This maps tag numbers greater than QCBOR_LAST_UNMAPPED_TAG.
1471 * QCBOR_LAST_UNMAPPED_TAG is a little smaller than MAX_UINT16.
1472 *
1473 * See also UnMapTagNumber() and @ref QCBORItem.
1474 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001475static QCBORError
1476QCBORDecode_Private_MapTagNumber(QCBORDecodeContext *pMe,
1477 const uint64_t uUnMappedTag,
1478 uint16_t *puMappedTagNumer)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001479{
1480 if(uUnMappedTag > QCBOR_LAST_UNMAPPED_TAG) {
1481 unsigned uTagMapIndex;
1482 /* Is there room in the tag map, or is it in it already? */
1483 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
1484 if(pMe->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID64) {
1485 break;
1486 }
1487 if(pMe->auMappedTags[uTagMapIndex] == uUnMappedTag) {
1488 break;
1489 }
1490 }
1491 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
1492 return QCBOR_ERR_TOO_MANY_TAGS;
1493 }
1494
1495 /* Covers the cases where tag is new and were it is already in the map */
1496 pMe->auMappedTags[uTagMapIndex] = uUnMappedTag;
1497 *puMappedTagNumer = (uint16_t)(uTagMapIndex + QCBOR_LAST_UNMAPPED_TAG + 1);
1498
1499 } else {
1500 *puMappedTagNumer = (uint16_t)uUnMappedTag;
1501 }
1502
1503 return QCBOR_SUCCESS;
1504}
1505
1506
1507/**
1508 * @brief This converts a mapped tag number to the actual tag number.
1509 *
1510 * @param[in] pMe The decode context.
1511 * @param[in] uMappedTagNumber The stored tag number.
1512 *
1513 * @return The actual tag number is returned or
1514 * @ref CBOR_TAG_INVALID64 on error.
1515 *
1516 * This is the reverse of MapTagNumber()
1517 */
1518static uint64_t
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001519QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe,
1520 const uint16_t uMappedTagNumber)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001521{
1522 if(uMappedTagNumber <= QCBOR_LAST_UNMAPPED_TAG) {
1523 return uMappedTagNumber;
1524 } else if(uMappedTagNumber == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07001525 return CBOR_TAG_INVALID64;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001526 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001527 /* This won't be negative because of code below in
1528 * MapTagNumber()
1529 */
1530 const unsigned uIndex = uMappedTagNumber - (QCBOR_LAST_UNMAPPED_TAG + 1);
1531 return pMe->auMappedTags[uIndex];
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001532 }
1533}
Laurence Lundblade37286c02022-09-03 10:05:02 -07001534#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001535
Laurence Lundblade9b334962020-08-27 10:55:53 -07001536
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001537/**
1538 * @brief Aggregate all tags wrapping a data item (decode layer 4).
1539 *
1540 * @param[in] pMe Decoder context
1541 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001542 *
1543 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1544 * features
1545 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1546 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1547 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1548 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1549 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1550 * of half-precision disabled
1551 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1552 * float decode is disabled.
1553 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1554 * simple type in input.
1555 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1556 * in input, but indefinite
1557 * lengths disabled.
1558 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1559 * but no string allocator.
1560 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1561 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1562 * input, but indefinite-length
1563 * strings are disabled.
1564 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001565 *
1566 * This loops getting atomic data items until one is not a tag
1567 * number. Usually this is largely pass-through because most
1568 * item are not tag numbers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001569 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001570static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001571QCBORDecode_Private_GetNextTagNumber(QCBORDecodeContext *pMe,
1572 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001573{
Laurence Lundblade37286c02022-09-03 10:05:02 -07001574#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001575 /* Accummulate the tags from multiple items here and then copy them
1576 * into the last item, the non-tag item.
1577 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001578 uint16_t auItemsTags[QCBOR_MAX_TAGS_PER_ITEM];
1579
1580 /* Initialize to CBOR_TAG_INVALID16 */
1581 #if CBOR_TAG_INVALID16 != 0xffff
1582 /* Be sure the memset does the right thing. */
1583 #err CBOR_TAG_INVALID16 tag not defined as expected
1584 #endif
1585 memset(auItemsTags, 0xff, sizeof(auItemsTags));
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001586
Laurence Lundblade9b334962020-08-27 10:55:53 -07001587 QCBORError uReturn = QCBOR_SUCCESS;
1588
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001589 /* Loop fetching data items until the item fetched is not a tag */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001590 for(;;) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001591 QCBORError uErr = QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07001592 if(uErr != QCBOR_SUCCESS) {
1593 uReturn = uErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001594 goto Done;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001595 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001596
Laurence Lundblade9b334962020-08-27 10:55:53 -07001597 if(pDecodedItem->uDataType != QCBOR_TYPE_TAG) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001598 /* Successful exit from loop; maybe got some tags, maybe not */
1599 memcpy(pDecodedItem->uTags, auItemsTags, sizeof(auItemsTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001600 break;
1601 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001602
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001603 if(auItemsTags[QCBOR_MAX_TAGS_PER_ITEM - 1] != CBOR_TAG_INVALID16) {
1604 /* No room in the tag list */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001605 uReturn = QCBOR_ERR_TOO_MANY_TAGS;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001606 /* Continue on to get all tags wrapping this item even though
1607 * it is erroring out in the end. This allows decoding to
1608 * continue. This is a resource limit error, not a problem
1609 * with being well-formed CBOR.
1610 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001611 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001612 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001613 /* Slide tags over one in the array to make room at index 0.
1614 * Must use memmove because the move source and destination
1615 * overlap.
1616 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001617 memmove(&auItemsTags[1],
1618 auItemsTags,
1619 sizeof(auItemsTags) - sizeof(auItemsTags[0]));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001620
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001621 /* Map the tag */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001622 uint16_t uMappedTagNumber = 0;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001623 uReturn = QCBORDecode_Private_MapTagNumber(pMe, pDecodedItem->val.uTagV, &uMappedTagNumber);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001624 /* Continue even on error so as to consume all tags wrapping
1625 * this data item so decoding can go on. If MapTagNumber()
1626 * errors once it will continue to error.
1627 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001628 auItemsTags[0] = uMappedTagNumber;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001629 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001630
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001631Done:
Laurence Lundblade9b334962020-08-27 10:55:53 -07001632 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001633
Laurence Lundblade37286c02022-09-03 10:05:02 -07001634#else /* QCBOR_DISABLE_TAGS */
1635
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07001636 return QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07001637
1638#endif /* QCBOR_DISABLE_TAGS */
1639}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001640
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001641
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001642/**
1643 * @brief Combine a map entry label and value into one item (decode layer 3).
1644 *
1645 * @param[in] pMe Decoder context
1646 * @param[out] pDecodedItem The decoded item that work is done on.
1647 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001648 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1649 * features
1650 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1651 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1652 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1653 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1654 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1655 * of half-precision disabled
1656 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1657 * float decode is disabled.
1658 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1659 * simple type in input.
1660 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1661 * in input, but indefinite
1662 * lengths disabled.
1663 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1664 * but no string allocator.
1665 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1666 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1667 * input, but indefinite-length
1668 * strings are disabled.
1669 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1670 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1671 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001672 *
1673 * If a the current nesting level is a map, then this
1674 * combines pairs of items into one data item with a label
1675 * and value.
1676 *
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07001677 * This is passthrough if the current nesting level is
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001678 * not a map.
1679 *
1680 * This also implements maps-as-array mode where a map
1681 * is treated like an array to allow caller to do their
1682 * own label processing.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001683 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001684static QCBORError
1685QCBORDecode_Private_GetNextMapEntry(QCBORDecodeContext *pMe,
1686 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001687{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001688 QCBORError uReturn = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001689 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001690 goto Done;
1691 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001692
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001693 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
1694 /* Break can't be a map entry */
1695 goto Done;
1696 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001697
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001698 if(pMe->uDecodeMode != QCBOR_DECODE_MODE_MAP_AS_ARRAY) {
1699 /* Normal decoding of maps -- combine label and value into one item. */
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001700
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001701 if(DecodeNesting_IsCurrentTypeMap(&(pMe->nesting))) {
1702 /* Save label in pDecodedItem and get the next which will
1703 * be the real data item.
1704 */
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001705 QCBORItem LabelItem = *pDecodedItem;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001706 uReturn = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001707 if(QCBORDecode_IsUnrecoverableError(uReturn)) {
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001708 goto Done;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07001709 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001710
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301711 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001712
1713 if(LabelItem.uDataType == QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001714 /* strings are always good labels */
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001715 pDecodedItem->label.string = LabelItem.val.string;
1716 pDecodedItem->uLabelType = QCBOR_TYPE_TEXT_STRING;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001717 } else if (QCBOR_DECODE_MODE_MAP_STRINGS_ONLY == pMe->uDecodeMode) {
1718 /* It's not a string and we only want strings */
1719 uReturn = QCBOR_ERR_MAP_LABEL_TYPE;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001720 goto Done;
1721 } else if(LabelItem.uDataType == QCBOR_TYPE_INT64) {
1722 pDecodedItem->label.int64 = LabelItem.val.int64;
1723 pDecodedItem->uLabelType = QCBOR_TYPE_INT64;
1724 } else if(LabelItem.uDataType == QCBOR_TYPE_UINT64) {
1725 pDecodedItem->label.uint64 = LabelItem.val.uint64;
1726 pDecodedItem->uLabelType = QCBOR_TYPE_UINT64;
1727 } else if(LabelItem.uDataType == QCBOR_TYPE_BYTE_STRING) {
1728 pDecodedItem->label.string = LabelItem.val.string;
1729 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
1730 pDecodedItem->uLabelType = QCBOR_TYPE_BYTE_STRING;
1731 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001732 /* label is not an int or a string. It is an arrray
1733 * or a float or such and this implementation doesn't handle that.
1734 * Also, tags on labels are ignored.
1735 */
1736 uReturn = QCBOR_ERR_MAP_LABEL_TYPE;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001737 goto Done;
1738 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001739 }
1740 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001741 /* Decoding of maps as arrays to let the caller decide what to do
1742 * about labels, particularly lables that are not integers or
1743 * strings.
1744 */
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001745 if(pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001746 if(pDecodedItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001747 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001748 goto Done;
1749 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001750 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001751 /* Cast is safe because of check against QCBOR_MAX_ITEMS_IN_ARRAY/2.
1752 * Cast is needed because of integer promotion.
1753 */
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001754 pDecodedItem->val.uCount = (uint16_t)(pDecodedItem->val.uCount * 2);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001755 }
1756 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001757
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001758Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001759 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001760}
1761
1762
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001763#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001764/**
1765 * @brief Peek and see if next data item is a break;
1766 *
1767 * @param[in] pUIB UsefulInputBuf to read from.
1768 * @param[out] pbNextIsBreak Indicate if next was a break or not.
1769 *
1770 * @return Any decoding error.
1771 *
1772 * See if next item is a CBOR break. If it is, it is consumed,
1773 * if not it is not consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07001774*/
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001775static QCBORError
1776QCBOR_Private_NextIsBreak(UsefulInputBuf *pUIB, bool *pbNextIsBreak)
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001777{
1778 *pbNextIsBreak = false;
1779 if(UsefulInputBuf_BytesUnconsumed(pUIB) != 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001780 QCBORItem Peek;
1781 size_t uPeek = UsefulInputBuf_Tell(pUIB);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001782 QCBORError uReturn = QCBOR_Private_DecodeAtomicDataItem(pUIB, &Peek, NULL);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001783 if(uReturn != QCBOR_SUCCESS) {
1784 return uReturn;
1785 }
1786 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001787 /* It is not a break, rewind so it can be processed normally. */
Laurence Lundblade02625d42020-06-25 14:41:41 -07001788 UsefulInputBuf_Seek(pUIB, uPeek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001789 } else {
1790 *pbNextIsBreak = true;
1791 }
1792 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001793
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001794 return QCBOR_SUCCESS;
1795}
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001796#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001797
1798
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001799/**
1800 * @brief Ascend up nesting levels if all items in them have been consumed.
1801 *
1802 * @param[in] pMe The decode context.
1803 * @param[in] bMarkEnd If true mark end of maps/arrays with count of zero.
1804 *
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001805 * An item was just consumed, now figure out if it was the
1806 * end of an array/map map that can be closed out. That
1807 * may in turn close out the above array/map...
Laurence Lundblade642282a2020-06-23 12:00:33 -07001808*/
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001809static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001810QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001811{
1812 QCBORError uReturn;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001813
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001814 /* Loop ascending nesting levels as long as there is ascending to do */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001815 while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
1816
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001817 if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) {
1818 /* Nesting level is bstr-wrapped CBOR */
1819
1820 /* Ascent for bstr-wrapped CBOR is always by explicit call
1821 * so no further ascending can happen.
1822 */
1823 break;
1824
1825 } else if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
1826 /* Level is a definite-length array/map */
1827
1828 /* Decrement the item count the definite-length array/map */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001829 DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(&(pMe->nesting));
1830 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001831 /* Didn't close out array/map, so all work here is done */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001832 break;
1833 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001834 /* All items in a definite-length array were consumed so it
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001835 * is time to ascend one level. This happens below.
1836 */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001837
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001838#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001839 } else {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001840 /* Level is an indefinite-length array/map. */
1841
1842 /* Check for a break which is what ends indefinite-length arrays/maps */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001843 bool bIsBreak = false;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001844 uReturn = QCBOR_Private_NextIsBreak(&(pMe->InBuf), &bIsBreak);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001845 if(uReturn != QCBOR_SUCCESS) {
1846 goto Done;
1847 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001848
1849 if(!bIsBreak) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001850 /* Not a break so array/map does not close out. All work is done */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001851 break;
1852 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001853
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001854 /* It was a break in an indefinitelength map / array so
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001855 * it is time to ascend one level.
1856 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001857
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001858#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001859 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001860
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001861
1862 /* All items in the array/map have been consumed. */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001863
Laurence Lundblade93d89472020-10-03 22:30:50 -07001864 /* But ascent in bounded mode is only by explicit call to
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001865 * QCBORDecode_ExitBoundedMode().
1866 */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07001867 if(DecodeNesting_IsCurrentBounded(&(pMe->nesting))) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001868 /* Set the count to zero for definite-length arrays to indicate
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001869 * cursor is at end of bounded array/map */
Laurence Lundbladed0304932020-06-27 10:59:38 -07001870 if(bMarkEnd) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001871 /* Used for definite and indefinite to signal end */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07001872 DecodeNesting_ZeroMapOrArrayCount(&(pMe->nesting));
Laurence Lundbladed0304932020-06-27 10:59:38 -07001873
Laurence Lundblade2c1faf92020-06-26 22:43:56 -07001874 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001875 break;
1876 }
1877
1878 /* Finally, actually ascend one level. */
1879 DecodeNesting_Ascend(&(pMe->nesting));
1880 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001881
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001882 uReturn = QCBOR_SUCCESS;
1883
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001884#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001885Done:
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001886#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1887
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001888 return uReturn;
1889}
1890
1891
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001892/**
1893 * @brief Ascending & Descending out of nesting levels (decode layer 2).
1894 *
1895 * @param[in] pMe Decoder context
1896 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001897
1898 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1899 * features
1900 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1901 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1902 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1903 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1904 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1905 * of half-precision disabled
1906 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1907 * float decode is disabled.
1908 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1909 * simple type in input.
1910 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1911 * in input, but indefinite
1912 * lengths disabled.
1913 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1914 * but no string allocator.
1915 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1916 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1917 * input, but indefinite-length
1918 * strings are disabled.
1919 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1920 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1921 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
1922 * @retval QCBOR_ERR_NO_MORE_ITEMS Need more items for map or array.
1923 * @retval QCBOR_ERR_BAD_BREAK Indefinite-length break in wrong
1924 * place.
1925 * @retval QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP Nesting deeper than QCBOR
1926 * can handle.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001927 *
1928 * This handles the traversal descending into and asecnding out of
1929 * maps, arrays and bstr-wrapped CBOR. It figures out the ends of
1930 * definite- and indefinte-length maps and arrays by looking at the
1931 * item count or finding CBOR breaks. It detects the ends of the
1932 * top-level sequence and of bstr-wrapped CBOR by byte count.
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001933 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001934static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001935QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe,
1936 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001937{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001938 QCBORError uReturn;
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07001939 /* ==== First: figure out if at the end of a traversal ==== */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001940
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001941 /* If out of bytes to consume, it is either the end of the
1942 * top-level sequence of some bstr-wrapped CBOR that was entered.
1943 *
1944 * In the case of bstr-wrapped CBOR, the length of the
1945 * UsefulInputBuf was set to that of the bstr-wrapped CBOR. When
1946 * the bstr-wrapped CBOR is exited, the length is set back to the
1947 * top-level's length or to the next highest bstr-wrapped CBOR.
Laurence Lundblade642282a2020-06-23 12:00:33 -07001948 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001949 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) == 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001950 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001951 goto Done;
1952 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07001953
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001954 /* Check to see if at the end of a bounded definite-length map or
1955 * array. The check for a break ending indefinite-length array is
1956 * later in QCBORDecode_NestLevelAscender().
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001957 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001958 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001959 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07001960 goto Done;
1961 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001962
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001963 /* ==== Next: not at the end, so get another item ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001964 uReturn = QCBORDecode_Private_GetNextMapEntry(pMe, pDecodedItem);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07001965 if(QCBORDecode_IsUnrecoverableError(uReturn)) {
1966 /* Error is so bad that traversal is not possible. */
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001967 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001968 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301969
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001970 /* Breaks ending arrays/maps are processed later in the call to
1971 * QCBORDecode_NestLevelAscender(). They should never show up here.
Laurence Lundblade642282a2020-06-23 12:00:33 -07001972 */
Laurence Lundblade6de37062018-10-15 12:22:42 +05301973 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001974 uReturn = QCBOR_ERR_BAD_BREAK;
Laurence Lundblade6de37062018-10-15 12:22:42 +05301975 goto Done;
Laurence Lundblade5b8c5852018-10-14 21:11:42 +05301976 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001977
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001978 /* Record the nesting level for this data item before processing
1979 * any of decrementing and descending.
Laurence Lundblade642282a2020-06-23 12:00:33 -07001980 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001981 pDecodedItem->uNestingLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001982
Laurence Lundblade642282a2020-06-23 12:00:33 -07001983
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07001984 /* ==== Next: Process the item for descent, ascent, decrement... ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001985 if(QCBORItem_IsMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001986 /* If the new item is a map or array, descend.
1987 *
1988 * Empty indefinite-length maps and arrays are descended into,
1989 * but then ascended out of in the next chunk of code.
1990 *
1991 * Maps and arrays do count as items in the map/array that
1992 * encloses them so a decrement needs to be done for them too,
1993 * but that is done only when all the items in them have been
1994 * processed, not when they are opened with the exception of an
1995 * empty map or array.
Laurence Lundblade642282a2020-06-23 12:00:33 -07001996 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07001997 QCBORError uDescendErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001998 uDescendErr = DecodeNesting_DescendMapOrArray(&(pMe->nesting),
Laurence Lundblade642282a2020-06-23 12:00:33 -07001999 pDecodedItem->uDataType,
2000 pDecodedItem->val.uCount);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002001 if(uDescendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002002 /* This error is probably a traversal error and it overrides
2003 * the non-traversal error.
2004 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002005 uReturn = uDescendErr;
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002006 goto Done;
2007 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002008 }
2009
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002010 if(!QCBORItem_IsMapOrArray(*pDecodedItem) ||
2011 QCBORItem_IsEmptyDefiniteLengthMapOrArray(*pDecodedItem) ||
2012 QCBORItem_IsIndefiniteLengthMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002013 /* The following cases are handled here:
2014 * - A non-aggregate item like an integer or string
2015 * - An empty definite-length map or array
2016 * - An indefinite-length map or array that might be empty or might not.
2017 *
2018 * QCBORDecode_NestLevelAscender() does the work of decrementing the count
2019 * for an definite-length map/array and break detection for an
2020 * indefinite-0length map/array. If the end of the map/array was
2021 * reached, then it ascends nesting levels, possibly all the way
2022 * to the top level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002023 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002024 QCBORError uAscendErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002025 uAscendErr = QCBORDecode_Private_NestLevelAscender(pMe, true);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002026 if(uAscendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002027 /* This error is probably a traversal error and it overrides
2028 * the non-traversal error.
2029 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002030 uReturn = uAscendErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002031 goto Done;
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002032 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05302033 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002034
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002035 /* ==== Last: tell the caller the nest level of the next item ==== */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002036 /* Tell the caller what level is next. This tells them what
2037 * maps/arrays were closed out and makes it possible for them to
2038 * reconstruct the tree with just the information returned in a
2039 * QCBORItem.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002040 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002041 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07002042 /* At end of a bounded map/array; uNextNestLevel 0 to indicate this */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002043 pDecodedItem->uNextNestLevel = 0;
2044 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002045 pDecodedItem->uNextNestLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002046 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002047
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002048Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002049 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002050}
2051
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002052
Laurence Lundblade37286c02022-09-03 10:05:02 -07002053#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002054/**
2055 * @brief Shift 0th tag out of the tag list.
2056 *
2057 * pDecodedItem[in,out] The data item to convert.
2058 *
2059 * The 0th tag is discarded. \ref CBOR_TAG_INVALID16 is
2060 * shifted into empty slot at the end of the tag list.
2061 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002062static void
2063QCBOR_Private_ShiftTags(QCBORItem *pDecodedItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002064{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002065 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM-1; i++) {
2066 pDecodedItem->uTags[i] = pDecodedItem->uTags[i+1];
2067 }
2068 pDecodedItem->uTags[QCBOR_MAX_TAGS_PER_ITEM-1] = CBOR_TAG_INVALID16;
Laurence Lundblade9b334962020-08-27 10:55:53 -07002069}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002070#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002071
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002072
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002073/**
2074 * @brief Convert different epoch date formats in to the QCBOR epoch date format
2075 *
2076 * pDecodedItem[in,out] The data item to convert.
2077 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002078 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2079 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2080 * floating-point date disabled.
2081 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2082 * all floating-point disabled.
2083 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2084 * error decoding date.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002085 *
2086 * The epoch date tag defined in QCBOR allows for floating-point
2087 * dates. It even allows a protocol to flop between date formats when
2088 * ever it wants. Floating-point dates aren't that useful as they are
2089 * only needed for dates beyond the age of the earth.
2090 *
2091 * This converts all the date formats into one format of an unsigned
2092 * integer plus a floating-point fraction.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002093 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002094static QCBORError
2095QCBOR_Private_DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002096{
Laurence Lundbladec7114722020-08-13 05:11:40 -07002097 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002098
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002099#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade59289e52019-12-30 13:44:37 -08002100 pDecodedItem->val.epochDate.fSecondsFraction = 0;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002101#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002102
2103 switch (pDecodedItem->uDataType) {
2104
2105 case QCBOR_TYPE_INT64:
2106 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
2107 break;
2108
2109 case QCBOR_TYPE_UINT64:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002110 /* This only happens for CBOR type 0 > INT64_MAX so it is
2111 * always an overflow.
2112 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07002113 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2114 goto Done;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002115 break;
2116
2117 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade9682a532020-06-06 18:33:04 -07002118 case QCBOR_TYPE_FLOAT:
2119#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade59289e52019-12-30 13:44:37 -08002120 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002121 /* Convert working value to double if input was a float */
Laurence Lundblade3ed0bca2020-07-14 22:50:10 -07002122 const double d = pDecodedItem->uDataType == QCBOR_TYPE_DOUBLE ?
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002123 pDecodedItem->val.dfnum :
2124 (double)pDecodedItem->val.fnum;
2125
2126 /* The conversion from float to integer requires overflow
2127 * detection since floats can be much larger than integers.
2128 * This implementation errors out on these large float values
2129 * since they are beyond the age of the earth.
2130 *
2131 * These constants for the overflow check are computed by the
2132 * compiler. They are not computed at run time.
2133 *
2134 * The factor of 0x7ff is added/subtracted to avoid a
2135 * rounding error in the wrong direction when the compiler
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002136 * computes these constants. There is rounding because a
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002137 * 64-bit integer has 63 bits of precision where a double
2138 * only has 53 bits. Without the 0x7ff factor, the compiler
2139 * may round up and produce a double for the bounds check
2140 * that is larger than can be stored in a 64-bit integer. The
2141 * amount of 0x7ff is picked because it has 11 bits set.
2142 *
2143 * Without the 0x7ff there is a ~30 minute range of time
2144 * values 10 billion years in the past and in the future
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002145 * where this code could go wrong. Some compilers
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002146 * generate a warning or error without the 0x7ff.
2147 */
2148 const double dDateMax = (double)(INT64_MAX - 0x7ff);
2149 const double dDateMin = (double)(INT64_MIN + 0x7ff);
2150
2151 if(isnan(d) || d > dDateMax || d < dDateMin) {
Laurence Lundbladec7114722020-08-13 05:11:40 -07002152 uReturn = QCBOR_ERR_DATE_OVERFLOW;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002153 goto Done;
2154 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002155
2156 /* The actual conversion */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002157 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
Laurence Lundblade2feb1e12020-07-15 03:50:45 -07002158 pDecodedItem->val.epochDate.fSecondsFraction =
2159 d - (double)pDecodedItem->val.epochDate.nSeconds;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002160 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002161#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade4b270642020-08-14 12:53:07 -07002162
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002163 uReturn = QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundblade4b270642020-08-14 12:53:07 -07002164 goto Done;
2165
Laurence Lundblade9682a532020-06-06 18:33:04 -07002166#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002167 break;
2168
2169 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002170 /* It's the arrays and maps that are unrecoverable because
2171 * they are not consumed here. Since this is just an error
2172 * condition, no extra code is added here to make the error
2173 * recoverable for non-arrays and maps like strings. */
2174 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002175 goto Done;
2176 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002177
Laurence Lundblade59289e52019-12-30 13:44:37 -08002178 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
2179
2180Done:
Laurence Lundbladec7114722020-08-13 05:11:40 -07002181 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002182}
2183
2184
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002185/**
2186 * @brief Convert the days epoch date.
2187 *
2188 * pDecodedItem[in,out] The data item to convert.
2189 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002190 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2191 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2192 * floating-point date disabled.
2193 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2194 * all floating-point disabled.
2195 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2196 * error decoding date.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002197 *
2198 * This is much simpler than the other epoch date format because
2199 * floating-porint is not allowed. This is mostly a simple type check.
2200 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002201static QCBORError
2202QCBOR_Private_DecodeDaysEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002203{
2204 QCBORError uReturn = QCBOR_SUCCESS;
2205
2206 switch (pDecodedItem->uDataType) {
2207
2208 case QCBOR_TYPE_INT64:
2209 pDecodedItem->val.epochDays = pDecodedItem->val.int64;
2210 break;
2211
2212 case QCBOR_TYPE_UINT64:
2213 /* This only happens for CBOR type 0 > INT64_MAX so it is
2214 * always an overflow.
2215 */
2216 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2217 goto Done;
2218 break;
2219
2220 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002221 /* It's the arrays and maps that are unrecoverable because
2222 * they are not consumed here. Since this is just an error
2223 * condition, no extra code is added here to make the error
2224 * recoverable for non-arrays and maps like strings. */
2225 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002226 goto Done;
2227 break;
2228 }
2229
2230 pDecodedItem->uDataType = QCBOR_TYPE_DAYS_EPOCH;
2231
2232Done:
2233 return uReturn;
2234}
2235
2236
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002237#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade37286c02022-09-03 10:05:02 -07002238
2239/* Forward declaration is necessary for
2240 * QCBORDecode_MantissaAndExponent(). to be able to decode bignum
2241 * tags in the mantissa. If the mantissa is a decimal fraction or big
2242 * float in error, this will result in a recurive call to
2243 * QCBORDecode_MantissaAndExponent(), but the recursion will unwined
2244 * correctly and the correct error is returned.
2245 */
2246static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002247QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2248 QCBORItem *pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002249
2250
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002251/**
2252 * @brief Decode decimal fractions and big floats.
2253 *
2254 * @param[in] pMe The decode context.
2255 * @param[in,out] pDecodedItem On input the array data item that
2256 * holds the mantissa and exponent. On
2257 * output the decoded mantissa and
2258 * exponent.
2259 *
2260 * @returns Decoding errors from getting primitive data items or
2261 * \ref QCBOR_ERR_BAD_EXP_AND_MANTISSA.
2262 *
Laurence Lundblade37286c02022-09-03 10:05:02 -07002263 * When called pDecodedItem must be the array with two members, the
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002264 * exponent and mantissa.
2265 *
2266 * This will fetch and decode the exponent and mantissa and put the
2267 * result back into pDecodedItem.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002268 *
2269 * This does no checking or processing of tag numbers. That is to be
2270 * done by the code that calls this.
2271 *
2272 * This stuffs the type of the mantissa into pDecodedItem with the expectation
2273 * the caller will process it.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002274 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002275static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002276QCBORDecode_Private_ExpMantissa(QCBORDecodeContext *pMe,
2277 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002278{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002279 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002280
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002281 /* --- Make sure it is an array; track nesting level of members --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002282 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002283 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002284 goto Done;
2285 }
2286
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002287 /* A check for pDecodedItem->val.uCount == 2 would work for
Laurence Lundblade37286c02022-09-03 10:05:02 -07002288 * definite-length arrays, but not for indefinite. Instead remember
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002289 * the nesting level the two integers must be at, which is one
2290 * deeper than that of the array.
2291 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002292 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
2293
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002294 /* --- Get the exponent --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002295 QCBORItem exponentItem;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002296 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, &exponentItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002297 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002298 goto Done;
2299 }
2300 if(exponentItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002301 /* Array is empty or a map/array encountered when expecting an int */
2302 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002303 goto Done;
2304 }
2305 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002306 /* Data arriving as an unsigned int < INT64_MAX has been
2307 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2308 * also means that the only data arriving here of type
2309 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2310 * and thus an error that will get handled in the next else.
2311 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002312 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
2313 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002314 /* Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX */
2315 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002316 goto Done;
2317 }
2318
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002319 /* --- Get the mantissa --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002320 QCBORItem mantissaItem;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002321 uReturn = QCBORDecode_Private_GetNextTagContent(pMe, &mantissaItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002322 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002323 goto Done;
2324 }
2325 if(mantissaItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002326 /* Mantissa missing or map/array encountered when expecting number */
2327 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002328 goto Done;
2329 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002330 /* Stuff the mantissa data type into the item to send it up to the
2331 * the next level. */
2332 pDecodedItem->uDataType = mantissaItem.uDataType;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002333 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002334 /* Data arriving as an unsigned int < INT64_MAX has been
2335 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2336 * also means that the only data arriving here of type
2337 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2338 * and thus an error that will get handled in an else below.
2339 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002340 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002341#ifndef QCBOR_DISABLE_TAGS
2342 /* With tags fully disabled a big number mantissa will error out
2343 * in the call to QCBORDecode_GetNextWithTags() because it has
2344 * a tag number.
2345 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07002346 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM ||
2347 mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002348 /* Got a good big num mantissa */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002349 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002350#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002351 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002352 /* Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX */
2353 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002354 goto Done;
2355 }
2356
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002357 /* --- Check that array only has the two numbers --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002358 if(mantissaItem.uNextNestLevel == nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002359 /* Extra items in the decimal fraction / big float */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002360 /* Improvement: this should probably be an unrecoverable error. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002361 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002362 goto Done;
2363 }
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002364 pDecodedItem->uNextNestLevel = mantissaItem.uNextNestLevel;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002365
2366Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002367 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002368}
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002369#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002370
2371
Laurence Lundblade37286c02022-09-03 10:05:02 -07002372#ifndef QCBOR_DISABLE_TAGS
2373
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002374#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002375/**
2376 * @brief Decode the MIME type tag
2377 *
2378 * @param[in,out] pDecodedItem The item to decode.
2379 *
2380 * Handle the text and binary MIME type tags. Slightly too complicated
2381 * f or ProcessTaggedString() because the RFC 7049 MIME type was
2382 * incorreclty text-only.
2383 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002384static QCBORError
2385QCBOR_Private_DecodeMIME(QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002386{
2387 if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) {
2388 pDecodedItem->uDataType = QCBOR_TYPE_MIME;
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07002389 } else if(pDecodedItem->uDataType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002390 pDecodedItem->uDataType = QCBOR_TYPE_BINARY_MIME;
2391 } else {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002392 /* It's the arrays and maps that are unrecoverable because
2393 * they are not consumed here. Since this is just an error
2394 * condition, no extra code is added here to make the error
2395 * recoverable for non-arrays and maps like strings. */
2396 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002397 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002398
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002399 return QCBOR_SUCCESS;
2400}
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002401#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002402
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002403/**
Laurence Lundblade99615302020-11-29 11:19:47 -08002404 * Table of CBOR tags whose content is either a text string or a byte
2405 * string. The table maps the CBOR tag to the QCBOR type. The high-bit
2406 * of uQCBORtype indicates the content should be a byte string rather
2407 * than a text string
2408 */
2409struct StringTagMapEntry {
2410 uint16_t uTagNumber;
2411 uint8_t uQCBORtype;
2412};
2413
2414#define IS_BYTE_STRING_BIT 0x80
2415#define QCBOR_TYPE_MASK ~IS_BYTE_STRING_BIT
2416
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002417static const struct StringTagMapEntry QCBOR_Private_StringTagMap[] = {
Laurence Lundblade99615302020-11-29 11:19:47 -08002418 {CBOR_TAG_DATE_STRING, QCBOR_TYPE_DATE_STRING},
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002419 {CBOR_TAG_DAYS_STRING, QCBOR_TYPE_DAYS_STRING},
Laurence Lundblade99615302020-11-29 11:19:47 -08002420 {CBOR_TAG_POS_BIGNUM, QCBOR_TYPE_POSBIGNUM | IS_BYTE_STRING_BIT},
2421 {CBOR_TAG_NEG_BIGNUM, QCBOR_TYPE_NEGBIGNUM | IS_BYTE_STRING_BIT},
2422 {CBOR_TAG_CBOR, QBCOR_TYPE_WRAPPED_CBOR | IS_BYTE_STRING_BIT},
2423 {CBOR_TAG_URI, QCBOR_TYPE_URI},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002424#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002425 {CBOR_TAG_B64URL, QCBOR_TYPE_BASE64URL},
2426 {CBOR_TAG_B64, QCBOR_TYPE_BASE64},
2427 {CBOR_TAG_REGEX, QCBOR_TYPE_REGEX},
2428 {CBOR_TAG_BIN_UUID, QCBOR_TYPE_UUID | IS_BYTE_STRING_BIT},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002429#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade99615302020-11-29 11:19:47 -08002430 {CBOR_TAG_CBOR_SEQUENCE, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE | IS_BYTE_STRING_BIT},
2431 {CBOR_TAG_INVALID16, QCBOR_TYPE_NONE}
2432};
2433
2434
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002435/**
2436 * @brief Process standard CBOR tags whose content is a string
2437 *
2438 * @param[in] uTag The tag.
2439 * @param[in,out] pDecodedItem The data item.
2440 *
2441 * @returns This returns QCBOR_SUCCESS if the tag was procssed,
2442 * \ref QCBOR_ERR_UNSUPPORTED if the tag was not processed and
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002443 * \ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT if the content type was wrong for the tag.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002444 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002445 * Process the CBOR tags that whose content is a byte string or a text
2446 * string and for which the string is just passed on to the caller.
2447 *
2448 * This maps the CBOR tag to the QCBOR type and checks the content
2449 * type. Nothing more. It may not be the most important
Laurence Lundbladec02e13e2020-12-06 05:45:41 -08002450 * functionality, but it part of implementing as much of RFC 8949 as
Laurence Lundblade99615302020-11-29 11:19:47 -08002451 * possible.
Laurence Lundblade99615302020-11-29 11:19:47 -08002452 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002453static QCBORError
2454QCBOR_Private_ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002455{
Laurence Lundblade99615302020-11-29 11:19:47 -08002456 /* This only works on tags that were not mapped; no need for other yet */
2457 if(uTag > QCBOR_LAST_UNMAPPED_TAG) {
2458 return QCBOR_ERR_UNSUPPORTED;
2459 }
2460
2461 unsigned uIndex;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002462 for(uIndex = 0; QCBOR_Private_StringTagMap[uIndex].uTagNumber != CBOR_TAG_INVALID16; uIndex++) {
2463 if(QCBOR_Private_StringTagMap[uIndex].uTagNumber == uTag) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002464 break;
2465 }
2466 }
2467
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002468 const uint8_t uQCBORType = QCBOR_Private_StringTagMap[uIndex].uQCBORtype;
Laurence Lundblade99615302020-11-29 11:19:47 -08002469 if(uQCBORType == QCBOR_TYPE_NONE) {
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002470 /* repurpose this error to mean not handled here */
Laurence Lundblade99615302020-11-29 11:19:47 -08002471 return QCBOR_ERR_UNSUPPORTED;
2472 }
2473
2474 uint8_t uExpectedType = QCBOR_TYPE_TEXT_STRING;
2475 if(uQCBORType & IS_BYTE_STRING_BIT) {
2476 uExpectedType = QCBOR_TYPE_BYTE_STRING;
2477 }
2478
2479 if(pDecodedItem->uDataType != uExpectedType) {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002480 /* It's the arrays and maps that are unrecoverable because
2481 * they are not consumed here. Since this is just an error
2482 * condition, no extra code is added here to make the error
2483 * recoverable for non-arrays and maps like strings. */
2484 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002485 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002486
Laurence Lundblade99615302020-11-29 11:19:47 -08002487 pDecodedItem->uDataType = (uint8_t)(uQCBORType & QCBOR_TYPE_MASK);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002488 return QCBOR_SUCCESS;
2489}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002490#endif /* QCBOR_DISABLE_TAGS */
2491
2492
2493#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002494/**
2495 * @brief Figures out data type for exponent mantissa tags.
2496 *
2497 * @param[in] uTagToProcess Either @ref CBOR_TAG_DECIMAL_FRACTION or
2498 * @ref CBOR_TAG_BIG_FLOAT.
2499 * @param[in] pDecodedItem Item being decoded.
2500 *
2501 * @returns One of the 6 values between \ref QCBOR_TYPE_DECIMAL_FRACTION
2502 * and @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM.
2503 *
2504 * Does mapping between a CBOR tag number and a QCBOR type. with a
2505 * little bit of logic and arithmatic.
2506 *
2507 * Used in serveral contexts. Does the work where sometimes the data
2508 * item is explicitly tagged and sometimes not.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002509 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002510static uint8_t
2511QCBOR_Private_ExpMantissaDataType(const uint16_t uTagToProcess,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002512 const QCBORItem *pDecodedItem)
Laurence Lundblade37286c02022-09-03 10:05:02 -07002513{
2514 uint8_t uBase = uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ?
2515 QCBOR_TYPE_DECIMAL_FRACTION :
2516 QCBOR_TYPE_BIGFLOAT;
2517 if(pDecodedItem->uDataType != QCBOR_TYPE_INT64) {
2518 uBase = (uint8_t)(uBase + pDecodedItem->uDataType - QCBOR_TYPE_POSBIGNUM + 1);
2519 }
2520 return uBase;
2521}
2522#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002523
2524
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002525/**
2526 * @brief Decode tag content for select tags (decoding layer 1).
2527 *
2528 * @param[in] pMe The decode context.
2529 * @param[out] pDecodedItem The decoded item.
2530 *
2531 * @return Decoding error code.
2532 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002533 * CBOR tag numbers for the item were decoded in GetNext_TaggedItem(),
2534 * but the whole tag was not decoded. Here, the whole tags (tag number
2535 * and tag content) that are supported by QCBOR are decoded. This is a
2536 * quick pass through for items that are not tags.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002537 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002538static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002539QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2540 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002541{
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002542 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002543
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002544 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pDecodedItem);
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002545 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002546 goto Done;
2547 }
2548
Laurence Lundblade37286c02022-09-03 10:05:02 -07002549#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002550 /* When there are no tag numbers for the item, this exits first
2551 * thing and effectively does nothing.
2552 *
2553 * This loops over all the tag numbers accumulated for this item
2554 * trying to decode and interpret them. This stops at the end of
2555 * the list or at the first tag number that can't be interpreted by
2556 * this code. This is effectively a recursive processing of the
2557 * tags number list that handles nested tags.
2558 */
2559 while(1) {
2560 /* Don't bother to unmap tags via QCBORITem.uTags since this
2561 * code only works on tags less than QCBOR_LAST_UNMAPPED_TAG.
2562 */
2563 const uint16_t uTagToProcess = pDecodedItem->uTags[0];
Laurence Lundblade59289e52019-12-30 13:44:37 -08002564
Laurence Lundblade99615302020-11-29 11:19:47 -08002565 if(uTagToProcess == CBOR_TAG_INVALID16) {
2566 /* Hit the end of the tag list. A successful exit. */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002567 break;
2568
Laurence Lundblade99615302020-11-29 11:19:47 -08002569 } else if(uTagToProcess == CBOR_TAG_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002570 uReturn = QCBOR_Private_DecodeDateEpoch(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002571
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002572 } else if(uTagToProcess == CBOR_TAG_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002573 uReturn = QCBOR_Private_DecodeDaysEpoch(pDecodedItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002574
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002575#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade99615302020-11-29 11:19:47 -08002576 } else if(uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ||
2577 uTagToProcess == CBOR_TAG_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002578 uReturn = QCBORDecode_Private_ExpMantissa(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002579 /* --- Which is it, decimal fraction or a bigfloat? --- */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002580 pDecodedItem->uDataType = QCBOR_Private_ExpMantissaDataType(uTagToProcess, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002581
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002582#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002583#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002584 } else if(uTagToProcess == CBOR_TAG_MIME ||
2585 uTagToProcess == CBOR_TAG_BINARY_MIME) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002586 uReturn = QCBOR_Private_DecodeMIME(pDecodedItem);
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002587#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002588
Laurence Lundblade99615302020-11-29 11:19:47 -08002589 } else {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002590 /* See if it is a passthrough byte/text string tag; process if so */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002591 uReturn = QCBOR_Private_ProcessTaggedString(pDecodedItem->uTags[0], pDecodedItem);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002592
Laurence Lundblade99615302020-11-29 11:19:47 -08002593 if(uReturn == QCBOR_ERR_UNSUPPORTED) {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002594 /* It wasn't a passthrough byte/text string tag so it is
Laurence Lundblade99615302020-11-29 11:19:47 -08002595 * an unknown tag. This is the exit from the loop on the
2596 * first unknown tag. It is a successful exit.
2597 */
2598 uReturn = QCBOR_SUCCESS;
2599 break;
2600 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002601 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002602
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002603 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002604 /* Error exit from the loop */
2605 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002606 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002607
2608 /* A tag was successfully processed, shift it out of the list of
2609 * tags returned. This is the loop increment.
2610 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002611 QCBOR_Private_ShiftTags(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002612 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002613#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002614
2615Done:
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002616 return uReturn;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002617}
2618
2619
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002620/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002621 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002622 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002623QCBORError
2624QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2625{
2626 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002627 uErr = QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002628 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002629 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2630 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
2631 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002632 return uErr;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002633}
2634
2635
2636/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002637 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08002638 */
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002639QCBORError
2640QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2641{
2642 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2643 const UsefulInputBuf Save = pMe->InBuf;
2644
2645 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
2646
2647 pMe->nesting = SaveNesting;
2648 pMe->InBuf = Save;
2649
2650 return uErr;
2651}
2652
2653
2654/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002655 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002656 */
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002657void
2658QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2659{
2660 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002661 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2662 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002663 return;
2664 }
2665
2666 pMe->uLastError = (uint8_t)QCBORDecode_PeekNext(pMe, pDecodedItem);
2667}
2668
2669
2670/*
2671 * Public function, see header qcbor/qcbor_decode.h file
2672 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002673void
2674QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002675{
2676 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002677 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2678 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002679 return;
2680 }
2681
2682 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem);
2683}
2684
2685
2686/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002687 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002688 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002689QCBORError
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002690QCBORDecode_GetNextWithTags(QCBORDecodeContext *pMe,
2691 QCBORItem *pDecodedItem,
2692 QCBORTagListOut *pTags)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002693{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002694#ifndef QCBOR_DISABLE_TAGS
2695
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002696 QCBORError uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002697
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002698 uReturn = QCBORDecode_GetNext(pMe, pDecodedItem);
2699 if(uReturn != QCBOR_SUCCESS) {
2700 return uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002701 }
2702
2703 if(pTags != NULL) {
2704 pTags->uNumUsed = 0;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002705 /* Reverse the order because pTags is reverse of QCBORItem.uTags. */
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002706 for(int nTagIndex = QCBOR_MAX_TAGS_PER_ITEM-1; nTagIndex >=0; nTagIndex--) {
2707 if(pDecodedItem->uTags[nTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07002708 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002709 }
2710 if(pTags->uNumUsed >= pTags->uNumAllocated) {
2711 return QCBOR_ERR_TOO_MANY_TAGS;
2712 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002713 pTags->puTags[pTags->uNumUsed] = QCBORDecode_Private_UnMapTagNumber(pMe,pDecodedItem->uTags[nTagIndex]);
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002714 pTags->uNumUsed++;
2715 }
2716 }
2717
2718 return QCBOR_SUCCESS;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002719
2720#else /* QCBOR_DISABLE_TAGS */
2721 (void)pMe;
2722 (void)pDecodedItem;
2723 (void)pTags;
2724 return QCBOR_ERR_TAGS_DISABLED;
2725#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002726}
2727
2728
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002729/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002730 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05302731 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002732bool
2733QCBORDecode_IsTagged(QCBORDecodeContext *pMe,
2734 const QCBORItem *pItem,
2735 uint64_t uTag)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002736{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002737#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002738 for(unsigned uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) {
2739 if(pItem->uTags[uTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002740 break;
2741 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002742 if(QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uTagIndex]) == uTag) {
Laurence Lundbladef71e1622020-08-06 18:52:13 -07002743 return true;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002744 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002745 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002746#else /* QCBOR_TAGS_DISABLED */
2747 (void)pMe;
2748 (void)pItem;
2749 (void)uTag;
2750#endif /* QCBOR_TAGS_DISABLED */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002751
Laurence Lundbladef71e1622020-08-06 18:52:13 -07002752 return false;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002753}
2754
2755
2756/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002757 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002758 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002759QCBORError
2760QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002761{
Laurence Lundblade87495732021-02-26 10:05:55 -07002762 if(puConsumed != NULL) {
2763 *puConsumed = pMe->InBuf.cursor;
2764 }
2765
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002766 QCBORError uReturn = pMe->uLastError;
Laurence Lundblade085d7952020-07-24 10:26:30 -07002767
2768 if(uReturn != QCBOR_SUCCESS) {
2769 goto Done;
2770 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002771
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002772 /* Error out if all the maps/arrays are not closed out */
2773 if(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002774 uReturn = QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002775 goto Done;
2776 }
2777
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002778 /* Error out if not all the bytes are consumed */
2779 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf))) {
Laurence Lundblade085d7952020-07-24 10:26:30 -07002780 uReturn = QCBOR_ERR_EXTRA_BYTES;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002781 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002782
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002783Done:
Laurence Lundblade87495732021-02-26 10:05:55 -07002784 return uReturn;
2785}
2786
2787
2788/*
2789 * Public function, see header qcbor/qcbor_decode.h file
2790 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002791QCBORError
2792QCBORDecode_Finish(QCBORDecodeContext *pMe)
Laurence Lundblade87495732021-02-26 10:05:55 -07002793{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002794#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002795 /* Call the destructor for the string allocator if there is one.
2796 * Always called, even if there are errors; always have to clean up.
2797 */
2798 StringAllocator_Destruct(&(pMe->StringAllocator));
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002799#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002800
Laurence Lundblade87495732021-02-26 10:05:55 -07002801 return QCBORDecode_PartialFinish(pMe, NULL);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002802}
2803
2804
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002805/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002806 * Public function, see header qcbor/qcbor_decode.h file
2807 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002808uint64_t
2809QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
2810 const QCBORItem *pItem,
2811 uint32_t uIndex)
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002812{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002813#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002814 if(pItem->uDataType == QCBOR_TYPE_NONE) {
2815 return CBOR_TAG_INVALID64;
2816 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002817 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2818 return CBOR_TAG_INVALID64;
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002819 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002820 return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uIndex]);
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002821 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002822#else /* QCBOR_DISABLE_TAGS */
2823 (void)pMe;
2824 (void)pItem;
2825 (void)uIndex;
2826
2827 return CBOR_TAG_INVALID64;
2828#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002829}
2830
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002831
Laurence Lundblade9b334962020-08-27 10:55:53 -07002832/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002833 * Public function, see header qcbor/qcbor_decode.h file
2834 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002835uint64_t
2836QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe,
2837 uint32_t uIndex)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002838{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002839#ifndef QCBOR_DISABLE_TAGS
2840
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002841 if(pMe->uLastError != QCBOR_SUCCESS) {
2842 return CBOR_TAG_INVALID64;
2843 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002844 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2845 return CBOR_TAG_INVALID64;
2846 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002847 return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->uLastTags[uIndex]);
Laurence Lundblade9b334962020-08-27 10:55:53 -07002848 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002849#else /* QCBOR_DISABLE_TAGS */
2850 (void)pMe;
2851 (void)uIndex;
2852
2853 return CBOR_TAG_INVALID64;
2854#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07002855}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002856
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002857
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002858
2859
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002860#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladef6531662018-12-04 10:42:22 +09002861
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002862/* ===========================================================================
2863 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002864
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002865 This implements a simple sting allocator for indefinite-length
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002866 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
2867 implements the function type QCBORStringAllocate and allows easy
2868 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09002869
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002870 This particular allocator is built-in for convenience. The caller
2871 can implement their own. All of this following code will get
2872 dead-stripped if QCBORDecode_SetMemPool() is not called.
2873
2874 This is a very primitive memory allocator. It does not track
2875 individual allocations, only a high-water mark. A free or
2876 reallocation must be of the last chunk allocated.
2877
2878 The size of the pool and offset to free memory are packed into the
2879 first 8 bytes of the memory pool so we don't have to keep them in
2880 the decode context. Since the address of the pool may not be
2881 aligned, they have to be packed and unpacked as if they were
2882 serialized data of the wire or such.
2883
2884 The sizes packed in are uint32_t to be the same on all CPU types
2885 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08002886 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002887
2888
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002889static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08002890MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002891{
2892 // Use of UsefulInputBuf is overkill, but it is convenient.
2893 UsefulInputBuf UIB;
2894
Laurence Lundbladeee851742020-01-08 08:37:05 -08002895 // Just assume the size here. It was checked during SetUp so
2896 // the assumption is safe.
Laurence Lundblade93d89472020-10-03 22:30:50 -07002897 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem,QCBOR_DECODE_MIN_MEM_POOL_SIZE});
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002898 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
2899 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
2900 return UsefulInputBuf_GetError(&UIB);
2901}
2902
2903
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002904static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08002905MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002906{
2907 // Use of UsefulOutBuf is overkill, but convenient. The
2908 // length check performed here is useful.
2909 UsefulOutBuf UOB;
2910
2911 UsefulOutBuf_Init(&UOB, Pool);
2912 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
2913 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
2914 return UsefulOutBuf_GetError(&UOB);
2915}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002916
2917
2918/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002919 Internal function for an allocation, reallocation free and destuct.
2920
2921 Having only one function rather than one each per mode saves space in
2922 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002923
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002924 Code Reviewers: THIS FUNCTION DOES POINTER MATH
2925 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08002926static UsefulBuf
2927MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002928{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002929 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002930
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002931 uint32_t uPoolSize;
2932 uint32_t uFreeOffset;
2933
2934 if(uNewSize > UINT32_MAX) {
2935 // This allocator is only good up to 4GB. This check should
2936 // optimize out if sizeof(size_t) == sizeof(uint32_t)
2937 goto Done;
2938 }
2939 const uint32_t uNewSize32 = (uint32_t)uNewSize;
2940
2941 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
2942 goto Done;
2943 }
2944
2945 if(uNewSize) {
2946 if(pMem) {
2947 // REALLOCATION MODE
2948 // Calculate pointer to the end of the memory pool. It is
2949 // assumed that pPool + uPoolSize won't wrap around by
2950 // assuming the caller won't pass a pool buffer in that is
2951 // not in legitimate memory space.
2952 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
2953
2954 // Check that the pointer for reallocation is in the range of the
2955 // pool. This also makes sure that pointer math further down
2956 // doesn't wrap under or over.
2957 if(pMem >= pPool && pMem < pPoolEnd) {
2958 // Offset to start of chunk for reallocation. This won't
2959 // wrap under because of check that pMem >= pPool. Cast
2960 // is safe because the pool is always less than UINT32_MAX
2961 // because of check in QCBORDecode_SetMemPool().
2962 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
2963
2964 // Check to see if the allocation will fit. uPoolSize -
2965 // uMemOffset will not wrap under because of check that
2966 // pMem is in the range of the uPoolSize by check above.
2967 if(uNewSize <= uPoolSize - uMemOffset) {
2968 ReturnValue.ptr = pMem;
2969 ReturnValue.len = uNewSize;
2970
2971 // Addition won't wrap around over because uNewSize was
2972 // checked to be sure it is less than the pool size.
2973 uFreeOffset = uMemOffset + uNewSize32;
2974 }
2975 }
2976 } else {
2977 // ALLOCATION MODE
2978 // uPoolSize - uFreeOffset will not underflow because this
2979 // pool implementation makes sure uFreeOffset is always
2980 // smaller than uPoolSize through this check here and
2981 // reallocation case.
2982 if(uNewSize <= uPoolSize - uFreeOffset) {
2983 ReturnValue.len = uNewSize;
2984 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08002985 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002986 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002987 }
2988 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002989 if(pMem) {
2990 // FREE MODE
2991 // Cast is safe because of limit on pool size in
2992 // QCBORDecode_SetMemPool()
2993 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
2994 } else {
2995 // DESTRUCT MODE
2996 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002997 }
2998 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002999
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003000 UsefulBuf Pool = {pPool, uPoolSize};
3001 MemPool_Pack(Pool, uFreeOffset);
3002
3003Done:
3004 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003005}
3006
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003007
Laurence Lundbladef6531662018-12-04 10:42:22 +09003008/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003009 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09003010 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003011QCBORError
3012QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
3013 UsefulBuf Pool,
3014 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003015{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003016 // The pool size and free mem offset are packed into the beginning
Dave Thaler93c01182022-08-06 15:08:35 -04003017 // of the pool memory. This compile time check makes sure the
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003018 // constant in the header is correct. This check should optimize
3019 // down to nothing.
Dave Thaler93c01182022-08-06 15:08:35 -04003020#ifdef _MSC_VER
3021#pragma warning(push)
3022#pragma warning(disable:4127) // conditional expression is constant
3023#endif
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003024 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003025 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003026 }
Dave Thaler93c01182022-08-06 15:08:35 -04003027#ifdef _MSC_VER
3028#pragma warning(pop)
3029#endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003030
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003031 // The pool size and free offset packed in to the beginning of pool
3032 // memory are only 32-bits. This check will optimize out on 32-bit
3033 // machines.
3034 if(Pool.len > UINT32_MAX) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003035 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003036 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003037
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003038 // This checks that the pool buffer given is big enough.
3039 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003040 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003041 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003042
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003043 QCBORDecode_SetUpAllocator(pMe, MemPool_Function, Pool.ptr, bAllStrings);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003044
Laurence Lundblade30816f22018-11-10 13:40:22 +07003045 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003046}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003047#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003048
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003049
3050
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003051static void
3052QCBORDecode_Private_CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07003053{
Laurence Lundblade37286c02022-09-03 10:05:02 -07003054#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade9b334962020-08-27 10:55:53 -07003055 memcpy(pMe->uLastTags, pItem->uTags, sizeof(pItem->uTags));
Laurence Lundblade37286c02022-09-03 10:05:02 -07003056#else
3057 (void)pMe;
3058 (void)pItem;
3059#endif
Laurence Lundblade9b334962020-08-27 10:55:53 -07003060}
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003061
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003062
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003063/**
3064 * @brief Consume an entire map or array including its contents.
3065 *
3066 * @param[in] pMe The decoder context.
3067 * @param[in] pItemToConsume The array/map whose contents are to be
3068 * consumed.
3069 * @param[out] puNextNestLevel The next nesting level after the item was
3070 * fully consumed.
3071 *
3072 * This may be called when @c pItemToConsume is not an array or
3073 * map. In that case, this is just a pass through for @c puNextNestLevel
3074 * since there is nothing to do.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003075 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003076static QCBORError
3077QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
3078 const QCBORItem *pItemToConsume,
3079 uint8_t *puNextNestLevel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003080{
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003081 QCBORError uReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003082 QCBORItem Item;
Laurence Lundblade9b334962020-08-27 10:55:53 -07003083
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003084 /* If it is a map or array, this will tell if it is empty. */
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003085 const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel);
3086
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003087 if(QCBORItem_IsMapOrArray(*pItemToConsume) && !bIsEmpty) {
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003088 /* There is only real work to do for non-empty maps and arrays */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003089
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003090 /* This works for definite- and indefinite-length maps and
3091 * arrays by using the nesting level
Laurence Lundblade1341c592020-04-11 14:19:05 -07003092 */
3093 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003094 uReturn = QCBORDecode_GetNext(pMe, &Item);
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003095 if(QCBORDecode_IsUnrecoverableError(uReturn) ||
3096 uReturn == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003097 goto Done;
3098 }
3099 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003100
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003101 *puNextNestLevel = Item.uNextNestLevel;
3102
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003103 uReturn = QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003104
Laurence Lundblade1341c592020-04-11 14:19:05 -07003105 } else {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003106 /* pItemToConsume is not a map or array. Just pass the nesting
3107 * level through. */
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003108 *puNextNestLevel = pItemToConsume->uNextNestLevel;
3109
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003110 uReturn = QCBOR_SUCCESS;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003111 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003112
3113Done:
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003114 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003115}
3116
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003117
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003118/*
3119 * Public function, see header qcbor/qcbor_decode.h file
3120 */
3121void
3122QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003123{
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003124 QCBORDecode_VGetNext(pMe, pDecodedItem);
3125
3126 if(pMe->uLastError == QCBOR_SUCCESS) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003127 pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem,
Máté Tóth-Pálc6d59682021-05-26 18:55:30 +02003128 &pDecodedItem->uNextNestLevel);
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003129 }
3130}
3131
3132
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003133/**
3134 * @brief Rewind cursor to start as if map or array were just entered.
3135 *
3136 * @param[in] pMe The decoding context
3137 *
3138 * This affects the nesting tracking and the UsefulInputBuf.
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003139 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003140static void
3141QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003142{
3143 /* Reset nesting tracking to the deepest bounded level */
3144 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3145
3146 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3147
3148 /* Reposition traversal cursor to the start of the map/array */
3149 UsefulInputBuf_Seek(&(pMe->InBuf),
3150 DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
3151}
3152
3153
3154/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003155 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003156 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003157void
3158QCBORDecode_Rewind(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003159{
3160 if(pMe->nesting.pCurrentBounded != NULL) {
3161 /* In a bounded map, array or bstr-wrapped CBOR */
3162
3163 if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
3164 /* In bstr-wrapped CBOR. */
3165
3166 /* Reposition traversal cursor to start of wrapping byte string */
3167 UsefulInputBuf_Seek(&(pMe->InBuf),
3168 pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
3169 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3170
3171 } else {
3172 /* In a map or array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003173 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003174 }
3175
3176 } else {
3177 /* Not in anything bounded */
3178
3179 /* Reposition traversal cursor to the start of input CBOR */
3180 UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
3181
3182 /* Reset nesting tracking to beginning of input. */
3183 DecodeNesting_Init(&(pMe->nesting));
3184 }
3185
3186 pMe->uLastError = QCBOR_SUCCESS;
3187}
3188
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003189
Laurence Lundblade9b334962020-08-27 10:55:53 -07003190
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003191
3192
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003193/**
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003194 * @brief Search a map for a set of items.
3195 *
3196 * @param[in] pMe The decode context to search.
3197 * @param[in,out] pItemArray The items to search for and the items found.
3198 * @param[out] puOffset Byte offset of last item matched.
3199 * @param[in] pCBContext Context for the not-found item call back.
3200 * @param[in] pfCallback Function to call on items not matched in pItemArray.
3201 *
3202 * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map.
3203 *
3204 * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label)
3205 * were found for one of the labels being
3206 * search for. This duplicate detection is
3207 * only performed for items in pItemArray,
3208 * not every item in the map.
3209 *
3210 * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was
3211 * wrong for the matchd label.
3212 *
3213 * @retval Also errors returned by QCBORDecode_GetNext().
3214 *
3215 * On input, \c pItemArray contains a list of labels and data types of
3216 * items to be found.
3217 *
3218 * On output, the fully retrieved items are filled in with values and
3219 * such. The label was matched, so it never changes.
3220 *
3221 * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE.
3222 *
3223 * This also finds the ends of maps and arrays when they are exited.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003224 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003225static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003226QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
3227 QCBORItem *pItemArray,
3228 size_t *puOffset,
3229 void *pCBContext,
3230 QCBORItemCallback pfCallback)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003231{
Laurence Lundbladee6f15112020-07-23 18:44:16 -07003232 QCBORError uReturn;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003233 uint64_t uFoundItemBitMap = 0;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07003234
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003235 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003236 uReturn = pMe->uLastError;
3237 goto Done2;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003238 }
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003239
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003240 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) &&
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003241 pItemArray->uLabelType != QCBOR_TYPE_NONE) {
3242 /* QCBOR_TYPE_NONE as first item indicates just looking
3243 for the end of an array, so don't give error. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003244 uReturn = QCBOR_ERR_MAP_NOT_ENTERED;
3245 goto Done2;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003246 }
3247
Laurence Lundblade085d7952020-07-24 10:26:30 -07003248 if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) {
3249 // It is an empty bounded array or map
3250 if(pItemArray->uLabelType == QCBOR_TYPE_NONE) {
3251 // Just trying to find the end of the map or array
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003252 pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003253 uReturn = QCBOR_SUCCESS;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003254 } else {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003255 // Nothing is ever found in an empty array or map. All items
3256 // are marked as not found below.
Laurence Lundblade085d7952020-07-24 10:26:30 -07003257 uReturn = QCBOR_SUCCESS;
3258 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003259 goto Done2;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003260 }
3261
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003262 QCBORDecodeNesting SaveNesting;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003263 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3264
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003265 /* Reposition to search from the start of the map / array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003266 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundblade1341c592020-04-11 14:19:05 -07003267
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003268 /*
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003269 Loop over all the items in the map or array. Each item
3270 could be a map or array, but label matching is only at
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003271 the main level. This handles definite- and indefinite-
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003272 length maps and arrays. The only reason this is ever
3273 called on arrays is to find their end position.
3274
3275 This will always run over all items in order to do
3276 duplicate detection.
3277
3278 This will exit with failure if it encounters an
3279 unrecoverable error, but continue on for recoverable
3280 errors.
3281
3282 If a recoverable error occurs on a matched item, then
3283 that error code is returned.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003284 */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07003285 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Máté Tóth-Pál2f2aa5f2021-05-17 21:35:09 +02003286 uint8_t uNextNestLevel;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003287 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003288 /* Remember offset of the item because sometimes it has to be returned */
Laurence Lundblade1341c592020-04-11 14:19:05 -07003289 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003290
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003291 /* Get the item */
3292 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003293 QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003294 if(QCBORDecode_IsUnrecoverableError(uResult)) {
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003295 /* Unrecoverable error so map can't even be decoded. */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003296 uReturn = uResult;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003297 goto Done;
3298 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003299 if(uResult == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003300 // Unexpected end of map or array.
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003301 uReturn = uResult;
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003302 goto Done;
3303 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003304
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003305 /* See if item has one of the labels that are of interest */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003306 bool bMatched = false;
3307 for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003308 if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003309 /* A label match has been found */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003310 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
3311 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003312 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003313 }
Laurence Lundblade63926052021-03-29 16:05:51 -07003314 if(uResult != QCBOR_SUCCESS) {
3315 /* The label matches, but the data item is in error */
3316 uReturn = uResult;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003317 goto Done;
3318 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003319 if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) {
Laurence Lundblade63926052021-03-29 16:05:51 -07003320 /* The data item is not of the type(s) requested */
3321 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003322 goto Done;
3323 }
3324
Laurence Lundblade1341c592020-04-11 14:19:05 -07003325 /* Successful match. Return the item. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003326 pItemArray[nIndex] = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003327 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003328 if(puOffset) {
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003329 *puOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003330 }
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003331 bMatched = true;
3332 }
3333 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003334
3335
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003336 if(!bMatched && pfCallback != NULL) {
3337 /*
3338 Call the callback on unmatched labels.
3339 (It is tempting to do duplicate detection here, but that would
3340 require dynamic memory allocation because the number of labels
3341 that might be encountered is unbounded.)
3342 */
3343 uReturn = (*pfCallback)(pCBContext, &Item);
3344 if(uReturn != QCBOR_SUCCESS) {
3345 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003346 }
3347 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003348
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003349 /*
3350 Consume the item whether matched or not. This
3351 does the work of traversing maps and array and
3352 everything in them. In this loop only the
3353 items at the current nesting level are examined
3354 to match the labels.
3355 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003356 uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, &uNextNestLevel);
Laurence Lundbladec7114722020-08-13 05:11:40 -07003357 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003358 goto Done;
3359 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003360 } while (uNextNestLevel >= uMapNestLevel);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003361
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003362 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003363
3364 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003365
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003366 // Check here makes sure that this won't accidentally be
3367 // QCBOR_MAP_OFFSET_CACHE_INVALID which is larger than
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003368 // QCBOR_MAX_DECODE_INPUT_SIZE.
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -08003369 // Cast to uint32_t to possibly address cases where SIZE_MAX < UINT32_MAX
3370 if((uint32_t)uEndOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003371 uReturn = QCBOR_ERR_INPUT_TOO_LARGE;
3372 goto Done;
3373 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003374 /* Cast OK because encoded CBOR is limited to UINT32_MAX */
3375 pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003376
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003377 Done:
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003378 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
3379
3380 Done2:
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003381 /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */
Laurence Lundbladec7114722020-08-13 05:11:40 -07003382 for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003383 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003384 pItemArray[i].uDataType = QCBOR_TYPE_NONE;
3385 pItemArray[i].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003386 }
3387 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003388
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003389 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003390}
3391
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003392
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003393/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003394 * Public function, see header qcbor/qcbor_decode.h file
3395 */
3396void
3397QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
3398 int64_t nLabel,
3399 uint8_t uQcborType,
3400 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003401{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003402 if(pMe->uLastError != QCBOR_SUCCESS) {
3403 return;
3404 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003405
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003406 QCBORItem OneItemSeach[2];
3407 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3408 OneItemSeach[0].label.int64 = nLabel;
3409 OneItemSeach[0].uDataType = uQcborType;
3410 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003411
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003412 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL, NULL);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003413
3414 *pItem = OneItemSeach[0];
3415
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003416 if(uReturn != QCBOR_SUCCESS) {
3417 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003418 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003419 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003420 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003421 }
3422
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003423 Done:
3424 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003425}
3426
3427
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003428/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003429 * Public function, see header qcbor/qcbor_decode.h file
3430 */
3431void
3432QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
3433 const char *szLabel,
3434 uint8_t uQcborType,
3435 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003436{
Laurence Lundbladeda095972020-06-06 18:35:33 -07003437 if(pMe->uLastError != QCBOR_SUCCESS) {
3438 return;
3439 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003440
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003441 QCBORItem OneItemSeach[2];
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003442 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3443 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3444 OneItemSeach[0].uDataType = uQcborType;
3445 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003446
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003447 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL, NULL);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003448 if(uReturn != QCBOR_SUCCESS) {
3449 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003450 }
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003451 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003452 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003453 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003454 }
3455
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003456 *pItem = OneItemSeach[0];
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003457
3458Done:
3459 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003460}
3461
3462
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003463/**
3464 * @brief Is a QCBOR_TYPE in the type list?
3465 *
3466 * @param[in] uDataType Type to check for.
3467 * @param[in] puTypeList List to check.
3468 *
3469 * @retval QCBOR_SUCCESS If in the list.
3470 * @retval QCBOR_ERR_UNEXPECTED_TYPE Not in the list.
3471 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07003472static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003473QCBOR_Private_CheckTypeList(const int uDataType,
3474 const uint8_t puTypeList[QCBOR_TAGSPEC_NUM_TYPES])
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003475{
3476 for(size_t i = 0; i < QCBOR_TAGSPEC_NUM_TYPES; i++) {
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003477 if(uDataType == puTypeList[i]) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003478 return QCBOR_SUCCESS;
3479 }
3480 }
3481 return QCBOR_ERR_UNEXPECTED_TYPE;
3482}
3483
Laurence Lundblade67257dc2020-07-27 03:33:37 -07003484
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003485/**
Laurence Lundblade37286c02022-09-03 10:05:02 -07003486 * Match a tag/type specification against the type of the item.
3487 *
3488 * @param[in] TagSpec Specification for matching tags.
3489 * @param[in] pItem The item to check.
3490 *
3491 * @retval QCBOR_SUCCESS \c uDataType is allowed by @c TagSpec
3492 * @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec
3493 *
3494 * This checks the item data type of untagged items as well as of
3495 * tagged items against a specification to see if decoding should
3496 * proceed.
3497 *
3498 * This relies on the automatic tag decoding done by QCBOR that turns
3499 * tag numbers into particular QCBOR_TYPEs so there is no actual
3500 * comparsion of tag numbers, just of QCBOR_TYPEs.
3501 *
3502 * This checks the data item type as possibly representing the tag
3503 * number or as the tag content type.
3504 *
3505 * If QCBOR_DISABLE_TAGS is #defined, this primarily checks the item
3506 * data type against the allowed tag content types. It will also error out
3507 * if the caller tries to require a tag because there is no way that can
3508 * ever be fulfilled.
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003509 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07003510static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003511QCBOR_Private_CheckTagRequirement(const QCBOR_Private_TagSpec TagSpec,
3512 const QCBORItem *pItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07003513{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003514 const int nItemType = pItem->uDataType; /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade37286c02022-09-03 10:05:02 -07003515 const int nTagReq = TagSpec.uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
3516
3517#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003518 /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003519 if(!(TagSpec.uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS) &&
3520 pItem->uTags[0] != CBOR_TAG_INVALID16) {
3521 /* There are tags that QCBOR couldn't process on this item and
Laurence Lundblade37286c02022-09-03 10:05:02 -07003522 * the caller has told us there should not be.
3523 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003524 return QCBOR_ERR_UNEXPECTED_TYPE;
3525 }
3526
Laurence Lundblade9b334962020-08-27 10:55:53 -07003527 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
Laurence Lundblade37286c02022-09-03 10:05:02 -07003528 /* Must match the tag number and only the tag */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003529 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003530 }
3531
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003532 QCBORError uReturn = QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003533 if(uReturn == QCBOR_SUCCESS) {
3534 return QCBOR_SUCCESS;
3535 }
3536
3537 if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
3538 /* Must match the content type and only the content type.
Laurence Lundblade37286c02022-09-03 10:05:02 -07003539 * There was no match just above so it is a fail. */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003540 return QCBOR_ERR_UNEXPECTED_TYPE;
3541 }
3542
Laurence Lundblade37286c02022-09-03 10:05:02 -07003543 /* QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG: If here it can match either the tag or the content
3544 * and it hasn't matched the content, so the end
3545 * result is whether it matches the tag. This is
3546 * the tag optional case that the CBOR standard discourages.
3547 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003548
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003549 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003550
Laurence Lundblade37286c02022-09-03 10:05:02 -07003551#else /* QCBOR_DISABLE_TAGS */
3552 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
3553 return QCBOR_ERR_UNEXPECTED_TYPE;
3554 }
3555
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07003556 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade37286c02022-09-03 10:05:02 -07003557
3558#endif /* QCBOR_DISABLE_TAGS */
3559}
Laurence Lundblade9b334962020-08-27 10:55:53 -07003560
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003561
3562/**
3563 * @brief Get an item by label to match a tag specification.
3564 *
3565 * @param[in] pMe The decode context.
3566 * @param[in] nLabel The label to search map for.
3567 * @param[in] TagSpec The tag number specification to match.
3568 * @param[out] pItem The item found.
3569 *
3570 * This finds the item with the given label in currently open
3571 * map. Then checks that its tag number and types matches the tag
3572 * specification. If not, an error is set in the decode context.
3573 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003574static void
3575QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
3576 const int64_t nLabel,
3577 const QCBOR_Private_TagSpec TagSpec,
3578 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003579{
3580 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
3581 if(pMe->uLastError != QCBOR_SUCCESS) {
3582 return;
3583 }
3584
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003585 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003586}
3587
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07003588
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003589/**
3590 * @brief Get an item by label to match a tag specification.
3591 *
3592 * @param[in] pMe The decode context.
3593 * @param[in] szLabel The label to search map for.
3594 * @param[in] TagSpec The tag number specification to match.
3595 * @param[out] pItem The item found.
3596 *
3597 * This finds the item with the given label in currently open
3598 * map. Then checks that its tag number and types matches the tag
3599 * specification. If not, an error is set in the decode context.
3600 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003601static void
3602QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
3603 const char *szLabel,
3604 const QCBOR_Private_TagSpec TagSpec,
3605 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003606{
3607 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
3608 if(pMe->uLastError != QCBOR_SUCCESS) {
3609 return;
3610 }
3611
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003612 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003613}
3614
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003615
3616/**
3617 * @brief Semi-private to get an string by label to match a tag specification.
3618 *
3619 * @param[in] pMe The decode context.
3620 * @param[in] nLabel The label to search map for.
3621 * @param[in] TagSpec The tag number specification to match.
3622 * @param[out] pString The string found.
3623 *
3624 * This finds the string with the given label in currently open
3625 * map. Then checks that its tag number and types matches the tag
3626 * specification. If not, an error is set in the decode context.
3627 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003628void
3629QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
3630 const int64_t nLabel,
3631 const QCBOR_Private_TagSpec TagSpec,
3632 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003633{
3634 QCBORItem Item;
3635 QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
3636 if(pMe->uLastError == QCBOR_SUCCESS) {
3637 *pString = Item.val.string;
3638 }
3639}
3640
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003641
3642/**
3643 * @brief Semi-private to get an string by label to match a tag specification.
3644 *
3645 * @param[in] pMe The decode context.
3646 * @param[in] szLabel The label to search map for.
3647 * @param[in] TagSpec The tag number specification to match.
3648 * @param[out] pString The string found.
3649 *
3650 * This finds the string with the given label in currently open
3651 * map. Then checks that its tag number and types matches the tag
3652 * specification. If not, an error is set in the decode context.
3653 */void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003654QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
3655 const char * szLabel,
3656 const QCBOR_Private_TagSpec TagSpec,
3657 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003658{
3659 QCBORItem Item;
3660 QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
3661 if(pMe->uLastError == QCBOR_SUCCESS) {
3662 *pString = Item.val.string;
3663 }
3664}
Laurence Lundblade1341c592020-04-11 14:19:05 -07003665
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003666
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003667/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003668 * Public function, see header qcbor/qcbor_decode.h file
3669 */
3670void
3671QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003672{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003673 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL, NULL);
Laurence Lundblade5f53f832020-09-03 12:00:14 -07003674 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003675}
3676
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003677/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003678 * Public function, see header qcbor/qcbor_decode.h file
3679 */
3680void
3681QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe,
3682 QCBORItem *pItemList,
3683 void *pCallbackCtx,
3684 QCBORItemCallback pfCB)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003685{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003686 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, pCallbackCtx, pfCB);
Laurence Lundblade5f53f832020-09-03 12:00:14 -07003687 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003688}
3689
3690
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08003691/**
3692 * @brief Search for a map/array by label and enter it
3693 *
3694 * @param[in] pMe The decode context.
3695 * @param[in] pSearch The map/array to search for.
3696 *
3697 * @c pSearch is expected to contain one item of type map or array
3698 * with the label specified. The current bounded map will be searched for
3699 * this and if found will be entered.
3700 *
3701 * If the label is not found, or the item found is not a map or array,
3702 * the error state is set.
3703 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003704static void
3705QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07003706{
Laurence Lundblade323f8a92020-09-06 19:43:09 -07003707 // The first item in pSearch is the one that is to be
3708 // entered. It should be the only one filled in. Any other
3709 // will be ignored unless it causes an error.
Laurence Lundblade34691b92020-05-18 22:25:25 -07003710 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07003711 return;
3712 }
3713
3714 size_t uOffset;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003715 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pSearch, &uOffset, NULL, NULL);
Laurence Lundblade34691b92020-05-18 22:25:25 -07003716 if(pMe->uLastError != QCBOR_SUCCESS) {
3717 return;
3718 }
3719
Laurence Lundblade9b334962020-08-27 10:55:53 -07003720 if(pSearch->uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003721 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade9b334962020-08-27 10:55:53 -07003722 return;
3723 }
3724
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003725
3726 /* The map or array was found. Now enter it.
3727 *
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08003728 * QCBORDecode_EnterBoundedMapOrArray() used here, requires the
3729 * next item for the pre-order traversal cursor to be the map/array
3730 * found by MapSearch(). The next few lines of code force the
3731 * cursor to that.
3732 *
3733 * There is no need to retain the old cursor because
3734 * QCBORDecode_EnterBoundedMapOrArray() will set it to the
3735 * beginning of the map/array being entered.
3736 *
3737 * The cursor is forced by: 1) setting the input buffer position to
3738 * the item offset found by MapSearch(), 2) setting the map/array
3739 * counter to the total in the map/array, 3) setting the nesting
3740 * level. Setting the map/array counter to the total is not
3741 * strictly correct, but this is OK because this cursor only needs
3742 * to be used to get one item and MapSearch() has already found it
3743 * confirming it exists.
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003744 */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003745 UsefulInputBuf_Seek(&(pMe->InBuf), uOffset);
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07003746
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08003747 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3748
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07003749 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003750
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003751 QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003752}
3753
3754
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003755/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003756 * Public function, see header qcbor/qcbor_decode.h file
3757 */
3758void
3759QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003760{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003761 QCBORItem OneItemSeach[2];
3762 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3763 OneItemSeach[0].label.int64 = nLabel;
3764 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
3765 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003766
Laurence Lundblade9b334962020-08-27 10:55:53 -07003767 /* The map to enter was found, now finish off entering it. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003768 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003769}
3770
3771
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003772/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003773 * Public function, see header qcbor/qcbor_decode.h file
3774 */
3775void
3776QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003777{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003778 QCBORItem OneItemSeach[2];
3779 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3780 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3781 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
3782 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade9b334962020-08-27 10:55:53 -07003783
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003784 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003785}
3786
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003787/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003788 * Public function, see header qcbor/qcbor_decode.h file
3789 */
3790void
3791QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07003792{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003793 QCBORItem OneItemSeach[2];
3794 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3795 OneItemSeach[0].label.int64 = nLabel;
3796 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
3797 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003798
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003799 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07003800}
3801
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003802/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003803 * Public function, see header qcbor/qcbor_decode.h file
3804 */
3805void
3806QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundblade34691b92020-05-18 22:25:25 -07003807{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003808 QCBORItem OneItemSeach[2];
3809 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3810 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3811 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
3812 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003813
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003814 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade1341c592020-04-11 14:19:05 -07003815}
3816
3817
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003818/**
3819 * @brief Semi-private to do the the work for EnterMap() and EnterArray().
3820 *
3821 * @param[in] pMe The decode context
3822 * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY.
3823 * @param[out] pItem The data item for the map or array entered.
3824 *
3825 * The next item in the traversal must be a map or array. This
3826 * consumes that item and does the book keeping to enter the map or
3827 * array.
3828 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003829void
3830QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe,
3831 const uint8_t uType,
3832 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003833{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003834 QCBORError uErr;
3835
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07003836 /* Must only be called on maps and arrays. */
Laurence Lundblade34691b92020-05-18 22:25:25 -07003837 if(pMe->uLastError != QCBOR_SUCCESS) {
3838 // Already in error state; do nothing.
3839 return;
3840 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07003841
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003842 /* Get the data item that is the map or array being entered. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07003843 QCBORItem Item;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003844 uErr = QCBORDecode_GetNext(pMe, &Item);
3845 if(uErr != QCBOR_SUCCESS) {
3846 goto Done;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07003847 }
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003848 if(Item.uDataType != uType) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003849 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
3850 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003851 }
3852
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003853 QCBORDecode_Private_CopyTags(pMe, &Item);
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003854
3855
Laurence Lundbladef0499502020-08-01 11:55:57 -07003856 const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
Laurence Lundblade085d7952020-07-24 10:26:30 -07003857 if(bIsEmpty) {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003858 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
3859 // Undo decrement done by QCBORDecode_GetNext() so the the
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003860 // the decrement when exiting the map/array works correctly
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003861 pMe->nesting.pCurrent->u.ma.uCountCursor++;
3862 }
Laurence Lundblade93d89472020-10-03 22:30:50 -07003863 // Special case to increment nesting level for zero-length maps
3864 // and arrays entered in bounded mode.
Laurence Lundbladee6f15112020-07-23 18:44:16 -07003865 DecodeNesting_Descend(&(pMe->nesting), uType);
3866 }
3867
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003868 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003869
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003870 uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty,
3871 UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003872
Laurence Lundblade6545d1b2020-10-14 11:13:13 -07003873 if(pItem != NULL) {
3874 *pItem = Item;
3875 }
3876
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003877Done:
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003878 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003879}
3880
Laurence Lundblade02625d42020-06-25 14:41:41 -07003881
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003882/**
3883 * @brief Exit a bounded map, array or bstr (semi-private).
3884 *
3885 * @param[in] pMe Decode context.
3886 * @param[in] uEndOffset The input buffer offset of the end of item exited.
3887 *
3888 * @returns QCBOR_SUCCESS or an error code.
3889 *
3890 * This is the common work for exiting a level that is a bounded map,
3891 * array or bstr wrapped CBOR.
3892 *
3893 * One chunk of work is to set up the pre-order traversal so it is at
3894 * the item just after the bounded map, array or bstr that is being
3895 * exited. This is somewhat complex.
3896 *
3897 * The other work is to level-up the bounded mode to next higest
3898 * bounded mode or the top level if there isn't one.
Laurence Lundblade02625d42020-06-25 14:41:41 -07003899 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003900static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003901QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
3902 const uint32_t uEndOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003903{
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003904 QCBORError uErr;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003905
Laurence Lundblade02625d42020-06-25 14:41:41 -07003906 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003907 * First the pre-order-traversal byte offset is positioned to the
3908 * item just after the bounded mode item that was just consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07003909 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003910 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
3911
Laurence Lundblade02625d42020-06-25 14:41:41 -07003912 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003913 * Next, set the current nesting level to one above the bounded
3914 * level that was just exited.
3915 *
3916 * DecodeNesting_CheckBoundedType() is always called before this
3917 * and makes sure pCurrentBounded is valid.
Laurence Lundblade02625d42020-06-25 14:41:41 -07003918 */
3919 DecodeNesting_LevelUpCurrent(&(pMe->nesting));
3920
3921 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003922 * This does the complex work of leveling up the pre-order
3923 * traversal when the end of a map or array or another bounded
3924 * level is reached. It may do nothing, or ascend all the way to
3925 * the top level.
Laurence Lundblade02625d42020-06-25 14:41:41 -07003926 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003927 uErr = QCBORDecode_Private_NestLevelAscender(pMe, false);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003928 if(uErr != QCBOR_SUCCESS) {
3929 goto Done;
3930 }
3931
Laurence Lundblade02625d42020-06-25 14:41:41 -07003932 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003933 * This makes the next highest bounded level the current bounded
3934 * level. If there is no next highest level, then no bounded mode
3935 * is in effect.
Laurence Lundblade02625d42020-06-25 14:41:41 -07003936 */
3937 DecodeNesting_LevelUpBounded(&(pMe->nesting));
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003938
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003939 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003940
3941Done:
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003942 return uErr;
3943}
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003944
Laurence Lundblade02625d42020-06-25 14:41:41 -07003945
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003946/**
3947 * @brief Get started exiting a map or array (semi-private)
3948 *
3949 * @param[in] pMe The decode context
3950 * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP
3951 *
3952 * This does some work for map and array exiting (but not
3953 * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel()
3954 * is called to do the rest.
3955 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003956void
3957QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe,
3958 const uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003959{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003960 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07003961 /* Already in error state; do nothing. */
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003962 return;
3963 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003964
Laurence Lundblade02625d42020-06-25 14:41:41 -07003965 QCBORError uErr;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003966
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003967 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003968 uErr = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003969 goto Done;
3970 }
3971
Laurence Lundblade02625d42020-06-25 14:41:41 -07003972 /*
3973 Have to set the offset to the end of the map/array
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003974 that is being exited. If there is no cached value,
Laurence Lundblade02625d42020-06-25 14:41:41 -07003975 from previous map search, then do a dummy search.
3976 */
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003977 if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003978 QCBORItem Dummy;
3979 Dummy.uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003980 uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL, NULL);
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003981 if(uErr != QCBOR_SUCCESS) {
3982 goto Done;
3983 }
3984 }
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003985
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003986 uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003987
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003988Done:
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003989 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003990}
3991
3992
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003993/**
3994 * @brief The main work of entering some byte-string wrapped CBOR.
3995 *
3996 * @param[in] pMe The decode context.
3997 * @param[in] pItem The byte string item.
3998 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX
3999 * @param[out] pBstr Pointer and length of byte string entered.
4000 *
4001 * This is called once the byte string item has been decoded to do all
4002 * the book keeping work for descending a nesting level into the
4003 * nested CBOR.
4004 *
4005 * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement.
4006 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004007static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004008QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe,
4009 const QCBORItem *pItem,
4010 const uint8_t uTagRequirement,
4011 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004012{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004013 if(pBstr) {
4014 *pBstr = NULLUsefulBufC;
4015 }
4016
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004017 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004018 /* Already in error state; do nothing. */
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004019 return pMe->uLastError;
4020 }
4021
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004022 QCBORError uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004023
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004024 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004025 {
4026 uTagRequirement,
4027 {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE},
4028 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4029 };
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004030
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004031 uError = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004032 if(uError != QCBOR_SUCCESS) {
4033 goto Done;
4034 }
4035
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004036 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004037 /* Reverse the decrement done by GetNext() for the bstr so the
4038 * increment in QCBORDecode_NestLevelAscender() called by
4039 * ExitBoundedLevel() will work right.
4040 */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004041 DecodeNesting_ReverseDecrement(&(pMe->nesting));
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07004042 }
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004043
4044 if(pBstr) {
4045 *pBstr = pItem->val.string;
4046 }
4047
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004048 /* This saves the current length of the UsefulInputBuf and then
4049 * narrows the UsefulInputBuf to start and length of the wrapped
4050 * CBOR that is being entered.
4051 *
4052 * Most of these calls are simple inline accessors so this doesn't
4053 * amount to much code.
4054 */
4055
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004056 const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004057 /* This check makes the cast of uPreviousLength to uint32_t below safe. */
4058 if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004059 uError = QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladef76a2622020-08-06 19:51:03 -07004060 goto Done;
4061 }
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004062
4063 const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
4064 pItem->val.string.ptr);
4065 /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
4066 if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
4067 /* This should never happen because pItem->val.string.ptr should
4068 * always be valid since it was just returned.
4069 */
4070 uError = QCBOR_ERR_INPUT_TOO_LARGE;
4071 goto Done;
4072 }
4073
4074 const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
4075
4076 UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004077 UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004078
Laurence Lundblade02625d42020-06-25 14:41:41 -07004079 uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004080 (uint32_t)uPreviousLength,
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004081 (uint32_t)uStartOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004082Done:
4083 return uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004084}
4085
4086
Laurence Lundblade02625d42020-06-25 14:41:41 -07004087/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004088 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004089 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004090void
4091QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe,
4092 const uint8_t uTagRequirement,
4093 UsefulBufC *pBstr)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004094{
4095 if(pMe->uLastError != QCBOR_SUCCESS) {
4096 // Already in error state; do nothing.
4097 return;
4098 }
4099
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004100 /* Get the data item that is the byte string being entered */
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004101 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004102 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4103 if(pMe->uLastError != QCBOR_SUCCESS) {
4104 return;
4105 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004106
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004107 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4108 &Item,
4109 uTagRequirement,
4110 pBstr);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004111}
4112
4113
Laurence Lundblade02625d42020-06-25 14:41:41 -07004114/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004115 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004116 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004117void
4118QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe,
4119 const int64_t nLabel,
4120 const uint8_t uTagRequirement,
4121 UsefulBufC *pBstr)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004122{
4123 QCBORItem Item;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004124 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004125
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004126 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4127 &Item,
4128 uTagRequirement,
4129 pBstr);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004130}
4131
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004132
Laurence Lundblade02625d42020-06-25 14:41:41 -07004133/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004134 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004135 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004136void
4137QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe,
4138 const char *szLabel,
4139 const uint8_t uTagRequirement,
4140 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004141{
4142 QCBORItem Item;
4143 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4144
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004145 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4146 &Item,
4147 uTagRequirement,
4148 pBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004149}
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004150
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004151
Laurence Lundblade02625d42020-06-25 14:41:41 -07004152/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004153 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004154 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004155void
4156QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004157{
Laurence Lundblade02625d42020-06-25 14:41:41 -07004158 if(pMe->uLastError != QCBOR_SUCCESS) {
4159 // Already in error state; do nothing.
4160 return;
4161 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004162
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004163 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004164 pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade02625d42020-06-25 14:41:41 -07004165 return;
4166 }
4167
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004168 const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
4169
Laurence Lundblade02625d42020-06-25 14:41:41 -07004170 /*
4171 Reset the length of the UsefulInputBuf to what it was before
4172 the bstr wrapped CBOR was entered.
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004173 */
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004174 UsefulInputBuf_SetBufferLength(&(pMe->InBuf),
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004175 DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004176
4177
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004178 QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004179 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004180}
4181
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004182
Laurence Lundbladee6430642020-03-14 21:15:44 -07004183
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004184/**
4185 * @brief Process simple type true and false, a boolean
4186 *
4187 * @param[in] pMe The decode context.
4188 * @param[in] pItem The item with either true or false.
4189 * @param[out] pBool The boolean value output.
4190 *
4191 * Sets the internal error if the item isn't a true or a false. Also
4192 * records any tag numbers as the tag numbers of the last item.
4193 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004194static void
4195QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe,
4196 const QCBORItem *pItem,
4197 bool *pBool)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004198{
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004199 if(pMe->uLastError != QCBOR_SUCCESS) {
4200 /* Already in error state, do nothing */
4201 return;
4202 }
4203
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004204 switch(pItem->uDataType) {
4205 case QCBOR_TYPE_TRUE:
4206 *pBool = true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004207 break;
4208
4209 case QCBOR_TYPE_FALSE:
4210 *pBool = false;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004211 break;
4212
4213 default:
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004214 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004215 break;
4216 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004217 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004218}
Laurence Lundbladee6430642020-03-14 21:15:44 -07004219
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004220
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004221/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004222 * Public function, see header qcbor/qcbor_decode.h file
4223 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004224void
4225QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004226{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004227 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004228 /* Already in error state, do nothing */
Laurence Lundbladee6430642020-03-14 21:15:44 -07004229 return;
4230 }
4231
Laurence Lundbladec4537442020-04-14 18:53:22 -07004232 QCBORItem Item;
4233
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004234 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4235
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004236 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004237}
4238
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004239
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004240/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004241 * Public function, see header qcbor/qcbor_decode.h file
4242 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004243void
4244QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe,
4245 const int64_t nLabel,
4246 bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004247{
4248 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004249 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004250
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004251 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004252}
4253
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004254
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004255/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004256 * Public function, see header qcbor/qcbor_decode.h file
4257 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004258void
4259QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe,
4260 const char *szLabel,
4261 bool *pValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004262{
4263 QCBORItem Item;
4264 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4265
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004266 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004267}
4268
4269
4270
Laurence Lundbladec7114722020-08-13 05:11:40 -07004271
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004272/**
4273 * @brief Common processing for an epoch date.
4274 *
4275 * @param[in] pMe The decode context.
4276 * @param[in] pItem The item with the date.
4277 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4278 * @param[out] pnTime The returned date.
4279 *
4280 * Common processing for the date tag. Mostly make sure the tag
4281 * content is correct and copy forward any further other tag numbers.
4282 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004283static void
4284QCBORDecode_Private_ProcessEpochDate(QCBORDecodeContext *pMe,
4285 QCBORItem *pItem,
4286 const uint8_t uTagRequirement,
4287 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004288{
4289 if(pMe->uLastError != QCBOR_SUCCESS) {
4290 // Already in error state, do nothing
4291 return;
4292 }
4293
4294 QCBORError uErr;
4295
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004296 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladec7114722020-08-13 05:11:40 -07004297 {
4298 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004299 {QCBOR_TYPE_DATE_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4300 {QCBOR_TYPE_INT64, QCBOR_TYPE_DOUBLE, QCBOR_TYPE_FLOAT, QCBOR_TYPE_UINT64}
Laurence Lundbladec7114722020-08-13 05:11:40 -07004301 };
4302
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004303 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004304 if(uErr != QCBOR_SUCCESS) {
4305 goto Done;
4306 }
4307
4308 if(pItem->uDataType != QCBOR_TYPE_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004309 uErr = QCBOR_Private_DecodeDateEpoch(pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004310 if(uErr != QCBOR_SUCCESS) {
4311 goto Done;
4312 }
4313 }
4314
Laurence Lundblade9b334962020-08-27 10:55:53 -07004315 // Save the tags in the last item's tags in the decode context
4316 // for QCBORDecode_GetNthTagOfLast()
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004317 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07004318
Laurence Lundbladec7114722020-08-13 05:11:40 -07004319 *pnTime = pItem->val.epochDate.nSeconds;
4320
4321Done:
4322 pMe->uLastError = (uint8_t)uErr;
4323}
4324
4325
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004326
4327/*
4328 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4329 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004330void
4331QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
4332 uint8_t uTagRequirement,
4333 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004334{
4335 if(pMe->uLastError != QCBOR_SUCCESS) {
4336 // Already in error state, do nothing
4337 return;
4338 }
4339
4340 QCBORItem Item;
4341 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4342
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004343 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004344}
4345
4346
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004347/*
4348 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4349 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07004350void
4351QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
4352 int64_t nLabel,
4353 uint8_t uTagRequirement,
4354 int64_t *pnTime)
4355{
4356 QCBORItem Item;
4357 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004358 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004359}
4360
4361
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004362/*
4363 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4364 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07004365void
4366QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
4367 const char *szLabel,
4368 uint8_t uTagRequirement,
4369 int64_t *pnTime)
4370{
4371 QCBORItem Item;
4372 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004373 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004374}
4375
4376
4377
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004378/**
4379 * @brief Common processing for an epoch date.
4380 *
4381 * @param[in] pMe The decode context.
4382 * @param[in] pItem The item with the date.
4383 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4384 * @param[out] pnDays The returned day count.
4385 *
4386 * Common processing for the RFC 8943 day-count tag. Mostly make sure
4387 * the tag content is correct and copy forward any further other tag
4388 * numbers.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004389 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004390static void
4391QCBORDecode_Private_ProcessEpochDays(QCBORDecodeContext *pMe,
4392 QCBORItem *pItem,
4393 uint8_t uTagRequirement,
4394 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004395{
4396 if(pMe->uLastError != QCBOR_SUCCESS) {
4397 /* Already in error state, do nothing */
4398 return;
4399 }
4400
4401 QCBORError uErr;
4402
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004403 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004404 {
4405 uTagRequirement,
4406 {QCBOR_TYPE_DAYS_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4407 {QCBOR_TYPE_INT64, QCBOR_TYPE_UINT64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4408 };
4409
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004410 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004411 if(uErr != QCBOR_SUCCESS) {
4412 goto Done;
4413 }
4414
4415 if(pItem->uDataType != QCBOR_TYPE_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004416 uErr = QCBOR_Private_DecodeDaysEpoch(pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004417 if(uErr != QCBOR_SUCCESS) {
4418 goto Done;
4419 }
4420 }
4421
4422 /* Save the tags in the last item's tags in the decode context
4423 * for QCBORDecode_GetNthTagOfLast()
4424 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004425 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004426
4427 *pnDays = pItem->val.epochDays;
4428
4429Done:
4430 pMe->uLastError = (uint8_t)uErr;
4431}
4432
4433
4434/*
4435 * Public function, see header qcbor/qcbor_decode.h
4436 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004437void
4438QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe,
4439 uint8_t uTagRequirement,
4440 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004441{
4442 if(pMe->uLastError != QCBOR_SUCCESS) {
4443 /* Already in error state, do nothing */
4444 return;
4445 }
4446
4447 QCBORItem Item;
4448 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4449
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004450 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004451}
4452
4453
4454/*
4455 * Public function, see header qcbor/qcbor_decode.h
4456 */
4457void
4458QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe,
4459 int64_t nLabel,
4460 uint8_t uTagRequirement,
4461 int64_t *pnDays)
4462{
4463 QCBORItem Item;
4464 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004465 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004466}
4467
4468
4469/*
4470 * Public function, see header qcbor/qcbor_decode.h
4471 */
4472void
4473QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe,
4474 const char *szLabel,
4475 uint8_t uTagRequirement,
4476 int64_t *pnDays)
4477{
4478 QCBORItem Item;
4479 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004480 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004481}
4482
4483
4484
Laurence Lundblade37286c02022-09-03 10:05:02 -07004485/*
4486 * @brief Get a string that matches the type/tag specification.
4487 */
4488void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004489QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
4490 const QCBOR_Private_TagSpec TagSpec,
4491 UsefulBufC *pBstr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004492{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004493 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade37286c02022-09-03 10:05:02 -07004494 /* Already in error state, do nothing */
Laurence Lundbladec4537442020-04-14 18:53:22 -07004495 return;
4496 }
4497
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004498 QCBORError uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004499 QCBORItem Item;
4500
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004501 uError = QCBORDecode_GetNext(pMe, &Item);
4502 if(uError != QCBOR_SUCCESS) {
4503 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004504 return;
4505 }
4506
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004507 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004508
4509 if(pMe->uLastError == QCBOR_SUCCESS) {
4510 *pBstr = Item.val.string;
Laurence Lundbladeab40c6f2020-08-28 11:24:58 -07004511 } else {
4512 *pBstr = NULLUsefulBufC;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004513 }
4514}
4515
Laurence Lundbladec4537442020-04-14 18:53:22 -07004516
4517
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004518
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004519/**
4520 * @brief Common processing for a big number tag.
4521 *
4522 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4523 * @param[in] pItem The item with the date.
4524 * @param[out] pValue The returned big number
4525 * @param[out] pbIsNegative The returned sign of the big number.
4526 *
4527 * Common processing for the big number tag. Mostly make sure
4528 * the tag content is correct and copy forward any further other tag
4529 * numbers.
4530 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004531static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004532QCBOR_Private_ProcessBigNum(const uint8_t uTagRequirement,
4533 const QCBORItem *pItem,
4534 UsefulBufC *pValue,
4535 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004536{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004537 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004538 {
4539 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004540 {QCBOR_TYPE_POSBIGNUM, QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4541 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004542 };
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004543
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004544 QCBORError uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004545 if(uErr != QCBOR_SUCCESS) {
4546 return uErr;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004547 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004548
4549 *pValue = pItem->val.string;
4550
4551 if(pItem->uDataType == QCBOR_TYPE_POSBIGNUM) {
4552 *pbIsNegative = false;
4553 } else if(pItem->uDataType == QCBOR_TYPE_NEGBIGNUM) {
4554 *pbIsNegative = true;
4555 }
4556
4557 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004558}
4559
4560
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004561/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004562 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004563 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004564void
4565QCBORDecode_GetBignum(QCBORDecodeContext *pMe,
4566 const uint8_t uTagRequirement,
4567 UsefulBufC *pValue,
4568 bool *pbIsNegative)
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004569{
4570 if(pMe->uLastError != QCBOR_SUCCESS) {
4571 // Already in error state, do nothing
4572 return;
4573 }
4574
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004575 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004576 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
4577 if(uError != QCBOR_SUCCESS) {
4578 pMe->uLastError = (uint8_t)uError;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004579 return;
4580 }
4581
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004582 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4583 &Item,
4584 pValue,
4585 pbIsNegative);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004586}
4587
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004588
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004589/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004590 * Public function, see header qcbor/qcbor_spiffy_decode.h
4591 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004592void
4593QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe,
4594 const int64_t nLabel,
4595 const uint8_t uTagRequirement,
4596 UsefulBufC *pValue,
4597 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004598{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004599 QCBORItem Item;
4600 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004601 if(pMe->uLastError != QCBOR_SUCCESS) {
4602 return;
4603 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004604
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004605 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4606 &Item,
4607 pValue,
4608 pbIsNegative);
Laurence Lundbladec4537442020-04-14 18:53:22 -07004609}
4610
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004611
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004612/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004613 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004614 */
4615void
4616QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe,
4617 const char *szLabel,
4618 const uint8_t uTagRequirement,
4619 UsefulBufC *pValue,
4620 bool *pbIsNegative)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004621{
4622 QCBORItem Item;
4623 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004624 if(pMe->uLastError != QCBOR_SUCCESS) {
4625 return;
4626 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004627
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004628 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4629 &Item,
4630 pValue,
4631 pbIsNegative);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004632}
4633
4634
4635
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004636/**
4637 * @brief Common processing for MIME tag (semi-private).
4638 *
4639 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4640 * @param[in] pItem The item with the date.
4641 * @param[out] pMessage The returned MIME message.
4642 * @param[out] pbIsTag257 If true, binary MIME, if not, text MIME.
4643 *
4644 * Common processing for the MIME tag. Mostly make sure the tag
4645 * content is correct and copy forward any further other tag
4646 * numbers. See QCBORDecode_GetMIMEMessage().
4647 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004648QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004649QCBORDecode_Private_GetMIME(const uint8_t uTagRequirement,
Laurence Lundblade37286c02022-09-03 10:05:02 -07004650 const QCBORItem *pItem,
4651 UsefulBufC *pMessage,
4652 bool *pbIsTag257)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004653{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004654 const QCBOR_Private_TagSpec TagSpecText =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004655 {
4656 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004657 {QCBOR_TYPE_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4658 {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004659 };
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004660 const QCBOR_Private_TagSpec TagSpecBinary =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004661 {
4662 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004663 {QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4664 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004665 };
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004666
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004667 QCBORError uReturn;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004668
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004669 if(QCBOR_Private_CheckTagRequirement(TagSpecText, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004670 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07004671 if(pbIsTag257 != NULL) {
4672 *pbIsTag257 = false;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004673 }
4674 uReturn = QCBOR_SUCCESS;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004675 } else if(QCBOR_Private_CheckTagRequirement(TagSpecBinary, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004676 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07004677 if(pbIsTag257 != NULL) {
4678 *pbIsTag257 = true;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004679 }
4680 uReturn = QCBOR_SUCCESS;
4681
4682 } else {
4683 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
4684 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07004685
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004686 return uReturn;
4687}
4688
Laurence Lundblade93d89472020-10-03 22:30:50 -07004689// Improvement: add methods for wrapped CBOR, a simple alternate
4690// to EnterBstrWrapped
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004691
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004692
4693
4694
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07004695#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundbladee6430642020-03-14 21:15:44 -07004696
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004697/**
4698 * @brief Prototype for conversion of exponent and mantissa to unsigned integer.
4699 *
4700 * @param[in] uMantissa The mantissa.
4701 * @param[in] nExponent The exponent.
4702 * @param[out] puResult The resulting integer.
4703 *
4704 * Concrete implementations of this are for exponent base 10 and 2 supporting
4705 * decimal fractions and big floats.
4706 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004707typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004708
4709
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004710/**
4711 * @brief Base 10 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
4712 *
4713 * @param[in] uMantissa The unsigned integer mantissa.
4714 * @param[in] nExponent The signed integer exponent.
4715 * @param[out] puResult Place to return the unsigned integer result.
4716 *
4717 * This computes: mantissa * 10 ^^ exponent as for a decimal fraction. The output is a 64-bit
4718 * unsigned integer.
4719 *
4720 * There are many inputs for which the result will not fit in the
4721 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
4722 * be returned.
4723 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07004724static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004725QCBOR_Private_Exponentitate10(const uint64_t uMantissa,
4726 int64_t nExponent,
4727 uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004728{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07004729 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004730
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07004731 if(uResult != 0) {
4732 /* This loop will run a maximum of 19 times because
4733 * UINT64_MAX < 10 ^^ 19. More than that will cause
4734 * exit with the overflow error
4735 */
4736 for(; nExponent > 0; nExponent--) {
4737 if(uResult > UINT64_MAX / 10) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004738 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07004739 }
4740 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004741 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07004742
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07004743 for(; nExponent < 0; nExponent++) {
4744 uResult = uResult / 10;
4745 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004746 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07004747 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07004748 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07004749 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07004750 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07004751
4752 *puResult = uResult;
4753
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004754 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004755}
4756
4757
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004758/**
4759 * @brief Base 2 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
4760 *
4761 * @param[in] uMantissa The unsigned integer mantissa.
4762 * @param[in] nExponent The signed integer exponent.
4763 * @param[out] puResult Place to return the unsigned integer result.
4764 *
4765 * This computes: mantissa * 2 ^^ exponent as for a big float. The
4766 * output is a 64-bit unsigned integer.
4767 *
4768 * There are many inputs for which the result will not fit in the
4769 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
4770 * be returned.
4771 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07004772static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004773QCBOR_Private_Exponentitate2(const uint64_t uMantissa,
4774 int64_t nExponent,
4775 uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004776{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004777 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07004778
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004779 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07004780
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004781 /* This loop will run a maximum of 64 times because INT64_MAX <
4782 * 2^31. More than that will cause exit with the overflow error
Laurence Lundbladee6430642020-03-14 21:15:44 -07004783 */
4784 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004785 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004786 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07004787 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004788 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07004789 nExponent--;
4790 }
4791
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004792 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004793 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004794 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004795 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004796 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07004797 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004798 }
4799
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004800 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07004801
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004802 return QCBOR_SUCCESS;
4803}
4804
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004805
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004806/**
4807 * @brief Exponentiate a signed mantissa and signed exponent to produce a signed result.
4808 *
4809 * @param[in] nMantissa Signed integer mantissa.
4810 * @param[in] nExponent Signed integer exponent.
4811 * @param[out] pnResult Place to put the signed integer result.
4812 * @param[in] pfExp Exponentiation function.
4813 *
4814 * @returns Error code
4815 *
4816 * \c pfExp performs exponentiation on and unsigned mantissa and
4817 * produces an unsigned result. This converts the mantissa from signed
4818 * and converts the result to signed. The exponentiation function is
4819 * either for base 2 or base 10 (and could be other if needed).
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07004820 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004821static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004822QCBOR_Private_ExponentiateNN(const int64_t nMantissa,
4823 const int64_t nExponent,
4824 int64_t *pnResult,
4825 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004826{
4827 uint64_t uResult;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004828 uint64_t uMantissa;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004829
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004830 /* Take the absolute value and put it into an unsigned. */
4831 if(nMantissa >= 0) {
4832 /* Positive case is straightforward */
4833 uMantissa = (uint64_t)nMantissa;
4834 } else if(nMantissa != INT64_MIN) {
4835 /* The common negative case. See next. */
4836 uMantissa = (uint64_t)-nMantissa;
4837 } else {
4838 /* int64_t and uint64_t are always two's complement per the
4839 * C standard (and since QCBOR uses these it only works with
4840 * two's complement, which is pretty much universal these
4841 * days). The range of a negative two's complement integer is
4842 * one more that than a positive, so the simple code above might
4843 * not work all the time because you can't simply negate the
4844 * value INT64_MIN because it can't be represented in an
4845 * int64_t. -INT64_MIN can however be represented in a
4846 * uint64_t. Some compilers seem to recognize this case for the
4847 * above code and put the correct value in uMantissa, however
4848 * they are not required to do this by the C standard. This next
4849 * line does however work for all compilers.
4850 *
4851 * This does assume two's complement where -INT64_MIN ==
4852 * INT64_MAX + 1 (which wouldn't be true for one's complement or
4853 * sign and magnitude (but we know we're using two's complement
4854 * because int64_t requires it)).
4855 *
4856 * See these, particularly the detailed commentary:
4857 * https://stackoverflow.com/questions/54915742/does-c99-mandate-a-int64-t-type-be-available-always
4858 * https://stackoverflow.com/questions/37301078/is-negating-int-min-undefined-behaviour
4859 */
4860 uMantissa = (uint64_t)INT64_MAX+1;
4861 }
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004862
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004863 /* Call the exponentiator passed for either base 2 or base 10.
4864 * Here is where most of the overflow errors are caught. */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004865 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
4866 if(uReturn) {
4867 return uReturn;
4868 }
4869
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004870 /* Convert back to the sign of the original mantissa */
4871 if(nMantissa >= 0) {
4872 if(uResult > INT64_MAX) {
4873 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
4874 }
4875 *pnResult = (int64_t)uResult;
4876 } else {
4877 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
4878 * of INT64_MIN. This assumes two's compliment representation
4879 * where INT64_MIN is one increment farther from 0 than
4880 * INT64_MAX. Trying to write -INT64_MIN doesn't work to get
4881 * this because the compiler makes it an int64_t which can't
4882 * represent -INT64_MIN. Also see above.
4883 */
4884 if(uResult > (uint64_t)INT64_MAX+1) {
4885 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
4886 }
4887 *pnResult = -(int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004888 }
4889
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004890 return QCBOR_SUCCESS;
4891}
4892
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004893
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004894/**
4895 * @brief Exponentiate an unsigned mantissa and signed exponent to produce an unsigned result.
4896 *
4897 * @param[in] nMantissa Signed integer mantissa.
4898 * @param[in] nExponent Signed integer exponent.
4899 * @param[out] puResult Place to put the signed integer result.
4900 * @param[in] pfExp Exponentiation function.
4901 *
4902 * @returns Error code
4903 *
4904 * \c pfExp performs exponentiation on and unsigned mantissa and
4905 * produces an unsigned result. This errors out if the mantissa
4906 * is negative because the output is unsigned.
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07004907 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004908static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004909QCBOR_Private_ExponentitateNU(const int64_t nMantissa,
4910 const int64_t nExponent,
4911 uint64_t *puResult,
4912 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004913{
4914 if(nMantissa < 0) {
4915 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
4916 }
4917
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004918 /* Cast to unsigned is OK because of check for negative.
4919 * Cast to unsigned is OK because UINT64_MAX > INT64_MAX.
4920 * Exponentiation is straight forward
4921 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004922 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
4923}
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004924
4925
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004926/**
4927 * @brief Exponentiate an usnigned mantissa and unsigned exponent to produce an unsigned result.
4928 *
4929 * @param[in] uMantissa Unsigned integer mantissa.
4930 * @param[in] nExponent Unsigned integer exponent.
4931 * @param[out] puResult Place to put the unsigned integer result.
4932 * @param[in] pfExp Exponentiation function.
4933 *
4934 * @returns Error code
4935 *
4936 * \c pfExp performs exponentiation on and unsigned mantissa and
4937 * produces an unsigned result so this is just a wrapper that does
4938 * nothing (and is likely inlined).
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004939 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004940static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004941QCBOR_Private_ExponentitateUU(const uint64_t uMantissa,
4942 const int64_t nExponent,
4943 uint64_t *puResult,
4944 fExponentiator pfExp)
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004945{
4946 return (*pfExp)(uMantissa, nExponent, puResult);
4947}
4948
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07004949#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07004950
4951
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004952
4953
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004954/**
4955 * @brief Convert a CBOR big number to a uint64_t.
4956 *
4957 * @param[in] BigNum Bytes of the big number to convert.
4958 * @param[in] uMax Maximum value allowed for the result.
4959 * @param[out] pResult Place to put the unsigned integer result.
4960 *
4961 * @returns Error code
4962 *
4963 * Many values will overflow because a big num can represent a much
4964 * larger range than uint64_t.
4965 */
4966static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004967QCBOR_Private_ConvertBigNumToUnsigned(const UsefulBufC BigNum,
4968 const uint64_t uMax,
4969 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004970{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004971 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07004972
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004973 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07004974 const uint8_t *pByte = BigNum.ptr;
4975 size_t uLen = BigNum.len;
4976 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07004977 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07004978 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07004979 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07004980 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07004981 }
4982
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004983 *pResult = uResult;
4984 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07004985}
4986
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004987
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004988/**
4989 * @brief Convert a CBOR postive big number to a uint64_t.
4990 *
4991 * @param[in] BigNum Bytes of the big number to convert.
4992 * @param[out] pResult Place to put the unsigned integer result.
4993 *
4994 * @returns Error code
4995 *
4996 * Many values will overflow because a big num can represent a much
4997 * larger range than uint64_t.
4998 */
4999static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005000QCBOR_Private_ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum,
5001 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005002{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005003 return QCBOR_Private_ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005004}
5005
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005006
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005007/**
5008 * @brief Convert a CBOR positive big number to an int64_t.
5009 *
5010 * @param[in] BigNum Bytes of the big number to convert.
5011 * @param[out] pResult Place to put the signed integer result.
5012 *
5013 * @returns Error code
5014 *
5015 * Many values will overflow because a big num can represent a much
5016 * larger range than int64_t.
5017 */
5018static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005019QCBOR_Private_ConvertPositiveBigNumToSigned(const UsefulBufC BigNum,
5020 int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005021{
5022 uint64_t uResult;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005023 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5024 INT64_MAX,
5025 &uResult);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005026 if(uError) {
5027 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005028 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005029 /* Cast is safe because ConvertBigNumToUnsigned limits to INT64_MAX */
Laurence Lundbladee6430642020-03-14 21:15:44 -07005030 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005031 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005032}
5033
5034
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005035/**
5036 * @brief Convert a CBOR negative big number to an int64_t.
5037 *
5038 * @param[in] BigNum Bytes of the big number to convert.
5039 * @param[out] pnResult Place to put the signed integer result.
5040 *
5041 * @returns Error code
5042 *
5043 * Many values will overflow because a big num can represent a much
5044 * larger range than int64_t.
5045 */
5046static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005047QCBOR_Private_ConvertNegativeBigNumToSigned(const UsefulBufC BigNum,
5048 int64_t *pnResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005049{
5050 uint64_t uResult;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005051 /* The negative integer furthest from zero for a C int64_t is
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005052 * INT64_MIN which is expressed as -INT64_MAX - 1. The value of a
5053 * negative number in CBOR is computed as -n - 1 where n is the
5054 * encoded integer, where n is what is in the variable BigNum. When
5055 * converting BigNum to a uint64_t, the maximum value is thus
5056 * INT64_MAX, so that when it -n - 1 is applied to it the result
5057 * will never be further from 0 than INT64_MIN.
5058 *
5059 * -n - 1 <= INT64_MIN.
5060 * -n - 1 <= -INT64_MAX - 1
5061 * n <= INT64_MAX.
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005062 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005063 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5064 INT64_MAX,
5065 &uResult);
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005066 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005067 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005068 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005069
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005070 /* Now apply -n - 1. The cast is safe because
5071 * ConvertBigNumToUnsigned() is limited to INT64_MAX which does fit
5072 * is the largest positive integer that an int64_t can
5073 * represent. */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005074 *pnResult = -(int64_t)uResult - 1;
5075
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005076 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005077}
5078
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005079
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005080
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005081
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005082/**
5083 * @brief Convert integers and floats to an int64_t.
5084 *
5085 * @param[in] pItem The item to convert.
5086 * @param[in] uConvertTypes Bit mask list of conversion options.
5087 * @param[out] pnValue The resulting converted value.
5088 *
5089 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5090 * in uConvertTypes.
5091 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5092 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5093 * or too small.
5094 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005095static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005096QCBOR_Private_ConvertInt64(const QCBORItem *pItem,
5097 const uint32_t uConvertTypes,
5098 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005099{
5100 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005101 case QCBOR_TYPE_FLOAT:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005102 case QCBOR_TYPE_DOUBLE:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005103#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005104 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005105 /* https://pubs.opengroup.org/onlinepubs/009695399/functions/llround.html
5106 http://www.cplusplus.com/reference/cmath/llround/
5107 */
5108 // Not interested in FE_INEXACT
5109 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005110 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5111 *pnValue = llround(pItem->val.dfnum);
5112 } else {
5113 *pnValue = lroundf(pItem->val.fnum);
5114 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005115 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5116 // llround() shouldn't result in divide by zero, but catch
5117 // it here in case it unexpectedly does. Don't try to
5118 // distinguish between the various exceptions because it seems
5119 // they vary by CPU, compiler and OS.
5120 return QCBOR_ERR_FLOAT_EXCEPTION;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005121 }
5122 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005123 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005124 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005125#else
5126 return QCBOR_ERR_HW_FLOAT_DISABLED;
5127#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005128 break;
5129
5130 case QCBOR_TYPE_INT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005131 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005132 *pnValue = pItem->val.int64;
5133 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005134 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005135 }
5136 break;
5137
5138 case QCBOR_TYPE_UINT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005139 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005140 if(pItem->val.uint64 < INT64_MAX) {
5141 *pnValue = pItem->val.int64;
5142 } else {
5143 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5144 }
5145 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005146 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005147 }
5148 break;
5149
Laurence Lundblade2d493002024-02-01 11:09:17 -07005150 case QCBOR_TYPE_65BIT_NEG_INT:
5151 /* This type occurs if the value won't fit into int64_t
5152 * so this is always an error. */
5153 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5154 break;
5155
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005156 default:
5157 return QCBOR_ERR_UNEXPECTED_TYPE;
5158 }
5159 return QCBOR_SUCCESS;
5160}
5161
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005162
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005163/**
5164 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5165 *
5166 * @param[in] pMe The decode context.
5167 * @param[in] uConvertTypes Bit mask list of conversion options.
5168 * @param[out] pnValue Result of the conversion.
5169 * @param[in,out] pItem Temporary space to store Item, returned item.
5170 *
5171 * See QCBORDecode_GetInt64Convert().
5172 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005173void
5174QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pMe,
5175 uint32_t uConvertTypes,
5176 int64_t *pnValue,
5177 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005178{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07005179 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005180 return;
5181 }
5182
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005183 QCBORError uError = QCBORDecode_GetNext(pMe, pItem);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005184 if(uError) {
5185 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005186 return;
5187 }
5188
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005189 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005190 uConvertTypes,
5191 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005192}
5193
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005194/**
5195 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5196 *
5197 * @param[in] pMe The decode context.
5198 * @param[in] nLabel Label to find in map.
5199 * @param[in] uConvertTypes Bit mask list of conversion options.
5200 * @param[out] pnValue Result of the conversion.
5201 * @param[in,out] pItem Temporary space to store Item, returned item.
5202 *
5203 * See QCBORDecode_GetInt64ConvertInMapN().
5204 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005205void
5206QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pMe,
5207 int64_t nLabel,
5208 uint32_t uConvertTypes,
5209 int64_t *pnValue,
5210 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005211{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005212 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005213 if(pMe->uLastError != QCBOR_SUCCESS) {
5214 return;
5215 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005216
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005217 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5218 uConvertTypes,
5219 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005220}
5221
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005222/**
5223 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5224 *
5225 * @param[in] pMe The decode context.
5226 * @param[in] szLabel Label to find in map.
5227 * @param[in] uConvertTypes Bit mask list of conversion options.
5228 * @param[out] pnValue Result of the conversion.
5229 * @param[in,out] pItem Temporary space to store Item, returned item.
5230 *
5231 * See QCBORDecode_GetInt64ConvertInMapSZ().
5232 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005233void
5234QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5235 const char * szLabel,
5236 uint32_t uConvertTypes,
5237 int64_t *pnValue,
5238 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005239{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005240 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005241 if(pMe->uLastError != QCBOR_SUCCESS) {
5242 return;
5243 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005244
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005245 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5246 uConvertTypes,
5247 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005248}
5249
5250
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005251/**
5252 * @brief Convert many number types to an int64_t.
5253 *
5254 * @param[in] pItem The item to convert.
5255 * @param[in] uConvertTypes Bit mask list of conversion options.
5256 * @param[out] pnValue The resulting converted value.
5257 *
5258 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5259 * in uConvertTypes.
5260 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5261 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5262 * or too small.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005263 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005264static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005265QCBOR_Private_Int64ConvertAll(const QCBORItem *pItem,
5266 const uint32_t uConvertTypes,
5267 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005268{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005269 switch(pItem->uDataType) {
5270
5271 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005272 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005273 return QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005274 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005275 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005276 }
5277 break;
5278
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005279 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005280 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005281 return QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005282 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005283 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005284 }
5285 break;
5286
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005287#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005288 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005289 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005290 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005291 pItem->val.expAndMantissa.nExponent,
5292 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005293 &QCBOR_Private_Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005294 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005295 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005296 }
5297 break;
5298
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005299 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005300 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005301 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005302 pItem->val.expAndMantissa.nExponent,
5303 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005304 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005305 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005306 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005307 }
5308 break;
5309
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005310 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005311 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005312 int64_t nMantissa;
5313 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005314 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005315 if(uErr) {
5316 return uErr;
5317 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005318 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005319 pItem->val.expAndMantissa.nExponent,
5320 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005321 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005322 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005323 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005324 }
5325 break;
5326
5327 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005328 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005329 int64_t nMantissa;
5330 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005331 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005332 if(uErr) {
5333 return uErr;
5334 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005335 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005336 pItem->val.expAndMantissa.nExponent,
5337 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005338 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005339 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005340 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005341 }
5342 break;
5343
5344 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005345 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005346 int64_t nMantissa;
5347 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005348 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005349 if(uErr) {
5350 return uErr;
5351 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005352 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005353 pItem->val.expAndMantissa.nExponent,
5354 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005355 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005356 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005357 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005358 }
5359 break;
5360
5361 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005362 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005363 int64_t nMantissa;
5364 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005365 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005366 if(uErr) {
5367 return uErr;
5368 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005369 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005370 pItem->val.expAndMantissa.nExponent,
5371 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005372 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005373 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005374 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005375 }
5376 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005377#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005378
Laurence Lundbladee6430642020-03-14 21:15:44 -07005379
Laurence Lundbladec4537442020-04-14 18:53:22 -07005380 default:
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005381 return QCBOR_ERR_UNEXPECTED_TYPE; }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005382}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005383
5384
Laurence Lundbladec4537442020-04-14 18:53:22 -07005385/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005386 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005387 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005388void
5389QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe,
5390 const uint32_t uConvertTypes,
5391 int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005392{
5393 QCBORItem Item;
5394
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005395 QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005396
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005397 if(pMe->uLastError == QCBOR_SUCCESS) {
5398 // The above conversion succeeded
5399 return;
5400 }
5401
Laurence Lundbladef6c86662020-05-12 02:08:00 -07005402 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005403 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07005404 return;
5405 }
5406
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005407 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5408 uConvertTypes,
5409 pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005410}
5411
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005412
5413/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005414 * Public function, see header qcbor/qcbor_decode.h file
5415 */
5416void
5417QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
5418 const int64_t nLabel,
5419 const uint32_t uConvertTypes,
5420 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005421{
5422 QCBORItem Item;
5423
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005424 QCBORDecode_Private_GetInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07005425 nLabel,
5426 uConvertTypes,
5427 pnValue,
5428 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005429
5430 if(pMe->uLastError == QCBOR_SUCCESS) {
5431 // The above conversion succeeded
5432 return;
5433 }
5434
5435 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5436 // The above conversion failed in a way that code below can't correct
5437 return;
5438 }
5439
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005440 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5441 uConvertTypes,
5442 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005443}
5444
5445
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005446/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005447 * Public function, see header qcbor/qcbor_decode.h file
5448 */
5449void
5450QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
5451 const char *szLabel,
5452 const uint32_t uConvertTypes,
5453 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005454{
5455 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005456 QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07005457 szLabel,
5458 uConvertTypes,
5459 pnValue,
5460 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005461
5462 if(pMe->uLastError == QCBOR_SUCCESS) {
5463 // The above conversion succeeded
5464 return;
5465 }
5466
5467 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5468 // The above conversion failed in a way that code below can't correct
5469 return;
5470 }
5471
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005472 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5473 uConvertTypes,
5474 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005475}
5476
5477
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005478/**
5479 * @brief Convert many number types to an uint64_t.
5480 *
5481 * @param[in] pItem The item to convert.
5482 * @param[in] uConvertTypes Bit mask list of conversion options.
5483 * @param[out] puValue The resulting converted value.
5484 *
5485 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5486 * in uConvertTypes.
5487 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5488 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5489 * or too small.
5490 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005491static QCBORError
5492QCBOR_Private_ConvertUInt64(const QCBORItem *pItem,
5493 const uint32_t uConvertTypes,
5494 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005495{
5496 switch(pItem->uDataType) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005497 case QCBOR_TYPE_DOUBLE:
5498 case QCBOR_TYPE_FLOAT:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005499#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005500 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005501 // Can't use llround here because it will not convert values
5502 // greater than INT64_MAX and less than UINT64_MAX that
5503 // need to be converted so it is more complicated.
5504 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
5505 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5506 if(isnan(pItem->val.dfnum)) {
5507 return QCBOR_ERR_FLOAT_EXCEPTION;
5508 } else if(pItem->val.dfnum < 0) {
5509 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5510 } else {
5511 double dRounded = round(pItem->val.dfnum);
5512 // See discussion in DecodeDateEpoch() for
5513 // explanation of - 0x7ff
5514 if(dRounded > (double)(UINT64_MAX- 0x7ff)) {
5515 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5516 }
5517 *puValue = (uint64_t)dRounded;
5518 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005519 } else {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005520 if(isnan(pItem->val.fnum)) {
5521 return QCBOR_ERR_FLOAT_EXCEPTION;
5522 } else if(pItem->val.fnum < 0) {
5523 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5524 } else {
5525 float fRounded = roundf(pItem->val.fnum);
5526 // See discussion in DecodeDateEpoch() for
5527 // explanation of - 0x7ff
5528 if(fRounded > (float)(UINT64_MAX- 0x7ff)) {
5529 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5530 }
5531 *puValue = (uint64_t)fRounded;
5532 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005533 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005534 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5535 // round() and roundf() shouldn't result in exceptions here, but
5536 // catch them to be robust and thorough. Don't try to
5537 // distinguish between the various exceptions because it seems
5538 // they vary by CPU, compiler and OS.
5539 return QCBOR_ERR_FLOAT_EXCEPTION;
5540 }
5541
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005542 } else {
5543 return QCBOR_ERR_UNEXPECTED_TYPE;
5544 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005545#else
5546 return QCBOR_ERR_HW_FLOAT_DISABLED;
5547#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005548 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005549
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005550 case QCBOR_TYPE_INT64:
5551 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
5552 if(pItem->val.int64 >= 0) {
5553 *puValue = (uint64_t)pItem->val.int64;
5554 } else {
5555 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5556 }
5557 } else {
5558 return QCBOR_ERR_UNEXPECTED_TYPE;
5559 }
5560 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005561
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005562 case QCBOR_TYPE_UINT64:
5563 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade2d493002024-02-01 11:09:17 -07005564 *puValue = pItem->val.uint64;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005565 } else {
5566 return QCBOR_ERR_UNEXPECTED_TYPE;
5567 }
5568 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005569
Laurence Lundblade2d493002024-02-01 11:09:17 -07005570 case QCBOR_TYPE_65BIT_NEG_INT:
5571 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5572
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005573 default:
5574 return QCBOR_ERR_UNEXPECTED_TYPE;
5575 }
5576
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005577 return QCBOR_SUCCESS;
5578}
Laurence Lundbladec4537442020-04-14 18:53:22 -07005579
5580
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005581/**
5582 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5583 *
5584 * @param[in] pMe The decode context.
5585 * @param[in] uConvertTypes Bit mask list of conversion options.
5586 * @param[out] puValue Result of the conversion.
5587 * @param[in,out] pItem Temporary space to store Item, returned item.
5588 *
5589 * See QCBORDecode_GetUInt64Convert().
5590 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005591void
5592QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pMe,
5593 const uint32_t uConvertTypes,
5594 uint64_t *puValue,
5595 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005596{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005597 if(pMe->uLastError != QCBOR_SUCCESS) {
5598 return;
5599 }
5600
Laurence Lundbladec4537442020-04-14 18:53:22 -07005601 QCBORItem Item;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005602
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005603 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
5604 if(uError) {
5605 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005606 return;
5607 }
5608
Laurence Lundbladea826c502020-05-10 21:07:00 -07005609 if(pItem) {
5610 *pItem = Item;
5611 }
5612
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005613 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(&Item,
5614 uConvertTypes,
5615 puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005616}
5617
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005618
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005619/**
5620 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5621 *
5622 * @param[in] pMe The decode context.
5623 * @param[in] nLabel Label to find in map.
5624 * @param[in] uConvertTypes Bit mask list of conversion options.
5625 * @param[out] puValue Result of the conversion.
5626 * @param[in,out] pItem Temporary space to store Item, returned item.
5627 *
5628 * See QCBORDecode_GetUInt64ConvertInMapN().
5629 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005630void
5631QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe,
5632 const int64_t nLabel,
5633 const uint32_t uConvertTypes,
5634 uint64_t *puValue,
5635 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005636{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005637 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005638 if(pMe->uLastError != QCBOR_SUCCESS) {
5639 return;
5640 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005641
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005642 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
5643 uConvertTypes,
5644 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005645}
5646
5647
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005648/**
5649 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5650 *
5651 * @param[in] pMe The decode context.
5652 * @param[in] szLabel Label to find in map.
5653 * @param[in] uConvertTypes Bit mask list of conversion options.
5654 * @param[out] puValue Result of the conversion.
5655 * @param[in,out] pItem Temporary space to store Item, returned item.
5656 *
5657 * See QCBORDecode_GetUInt64ConvertInMapSZ().
5658 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005659void
5660QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5661 const char *szLabel,
5662 const uint32_t uConvertTypes,
5663 uint64_t *puValue,
5664 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005665{
5666 if(pMe->uLastError != QCBOR_SUCCESS) {
5667 return;
5668 }
5669
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005670 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005671 if(pMe->uLastError != QCBOR_SUCCESS) {
5672 return;
5673 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005674
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005675 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
5676 uConvertTypes,
5677 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005678}
5679
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005680
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005681/**
5682 * @brief Convert many number types to an unt64_t.
5683 *
5684 * @param[in] pItem The item to convert.
5685 * @param[in] uConvertTypes Bit mask list of conversion options.
5686 * @param[out] puValue The resulting converted value.
5687 *
5688 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5689 * in uConvertTypes.
5690 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5691 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5692 * or too small.
5693 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005694static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005695QCBOR_Private_UInt64ConvertAll(const QCBORItem *pItem,
5696 const uint32_t uConvertTypes,
5697 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005698{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08005699 switch(pItem->uDataType) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005700
5701 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005702 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005703 return QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005704 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005705 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005706 }
5707 break;
5708
5709 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005710 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005711 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5712 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005713 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005714 }
5715 break;
5716
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005717#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005718
5719 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005720 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005721 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005722 pItem->val.expAndMantissa.nExponent,
5723 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005724 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005725 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005726 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005727 }
5728 break;
5729
5730 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005731 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005732 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005733 pItem->val.expAndMantissa.nExponent,
5734 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005735 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005736 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005737 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005738 }
5739 break;
5740
5741 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005742 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005743 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005744 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005745 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005746 if(uErr != QCBOR_SUCCESS) {
5747 return uErr;
5748 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005749 return QCBOR_Private_ExponentitateUU(uMantissa,
5750 pItem->val.expAndMantissa.nExponent,
5751 puValue,
5752 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005753 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005754 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005755 }
5756 break;
5757
5758 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005759 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005760 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5761 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005762 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005763 }
5764 break;
5765
5766 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005767 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005768 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005769 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005770 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum,
5771 &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005772 if(uErr != QCBOR_SUCCESS) {
5773 return uErr;
5774 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005775 return QCBOR_Private_ExponentitateUU(uMantissa,
5776 pItem->val.expAndMantissa.nExponent,
5777 puValue,
5778 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005779 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005780 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005781 }
5782 break;
5783
5784 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005785 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005786 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5787 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005788 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005789 }
5790 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005791#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005792 default:
5793 return QCBOR_ERR_UNEXPECTED_TYPE;
5794 }
5795}
5796
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005797
Laurence Lundblade4e2da002020-06-13 23:08:31 -07005798/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005799 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07005800 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005801void
5802QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe,
5803 const uint32_t uConvertTypes,
5804 uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005805{
5806 QCBORItem Item;
5807
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005808 QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005809
Laurence Lundbladef6c86662020-05-12 02:08:00 -07005810 if(pMe->uLastError == QCBOR_SUCCESS) {
5811 // The above conversion succeeded
5812 return;
5813 }
5814
5815 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5816 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07005817 return;
5818 }
5819
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005820 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
5821 uConvertTypes,
5822 puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005823}
5824
Laurence Lundbladec4537442020-04-14 18:53:22 -07005825
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005826/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005827 * Public function, see header qcbor/qcbor_decode.h file
5828 */
5829void
5830QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
5831 const int64_t nLabel,
5832 const uint32_t uConvertTypes,
5833 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005834{
5835 QCBORItem Item;
5836
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005837 QCBORDecode_Private_GetUInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07005838 nLabel,
5839 uConvertTypes,
5840 puValue,
5841 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005842
5843 if(pMe->uLastError == QCBOR_SUCCESS) {
5844 // The above conversion succeeded
5845 return;
5846 }
5847
5848 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5849 // The above conversion failed in a way that code below can't correct
5850 return;
5851 }
5852
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005853 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
5854 uConvertTypes,
5855 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005856}
5857
5858
5859/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005860 * Public function, see header qcbor/qcbor_decode.h file
5861 */
5862void
5863QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
5864 const char *szLabel,
5865 const uint32_t uConvertTypes,
5866 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005867{
5868 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005869 QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07005870 szLabel,
5871 uConvertTypes,
5872 puValue,
5873 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005874
5875 if(pMe->uLastError == QCBOR_SUCCESS) {
5876 // The above conversion succeeded
5877 return;
5878 }
5879
5880 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5881 // The above conversion failed in a way that code below can't correct
5882 return;
5883 }
5884
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005885 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
5886 uConvertTypes,
5887 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005888}
5889
5890
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07005891
5892
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02005893#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005894/**
5895 * @brief Basic conversions to a double.
5896 *
5897 * @param[in] pItem The item to convert
5898 * @param[in] uConvertTypes Bit flags indicating source types for conversion
5899 * @param[out] pdValue The value converted to a double
5900 *
5901 * This does the conversions that don't need much object code,
5902 * the conversions from int, uint and float to double.
5903 *
5904 * See QCBOR_Private_DoubleConvertAll() for the full set
5905 * of conversions.
5906 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005907static QCBORError
5908QCBOR_Private_ConvertDouble(const QCBORItem *pItem,
5909 const uint32_t uConvertTypes,
5910 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005911{
5912 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005913 case QCBOR_TYPE_FLOAT:
5914#ifndef QCBOR_DISABLE_FLOAT_HW_USE
5915 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
5916 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005917 // Simple cast does the job.
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005918 *pdValue = (double)pItem->val.fnum;
5919 } else {
5920 return QCBOR_ERR_UNEXPECTED_TYPE;
5921 }
5922 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08005923#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005924 return QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08005925#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005926 break;
5927
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005928 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005929 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
5930 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005931 *pdValue = pItem->val.dfnum;
5932 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005933 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005934 }
5935 }
5936 break;
5937
5938 case QCBOR_TYPE_INT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005939#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005940 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005941 // A simple cast seems to do the job with no worry of exceptions.
5942 // There will be precision loss for some values.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005943 *pdValue = (double)pItem->val.int64;
5944
5945 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005946 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005947 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005948#else
5949 return QCBOR_ERR_HW_FLOAT_DISABLED;
5950#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005951 break;
5952
5953 case QCBOR_TYPE_UINT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005954#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005955 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005956 // A simple cast seems to do the job with no worry of exceptions.
5957 // There will be precision loss for some values.
5958 *pdValue = (double)pItem->val.uint64;
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;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005963#else
5964 return QCBOR_ERR_HW_FLOAT_DISABLED;
5965#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005966
Laurence Lundblade2d493002024-02-01 11:09:17 -07005967 case QCBOR_TYPE_65BIT_NEG_INT:
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -08005968#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade2d493002024-02-01 11:09:17 -07005969 *pdValue = -(double)pItem->val.uint64 - 1;
5970 break;
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -08005971#else
5972 return QCBOR_ERR_HW_FLOAT_DISABLED;
5973#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade2d493002024-02-01 11:09:17 -07005974
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005975 default:
5976 return QCBOR_ERR_UNEXPECTED_TYPE;
5977 }
5978
5979 return QCBOR_SUCCESS;
5980}
5981
5982
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005983/**
5984 * @brief Almost-public method to decode a number and convert to double (semi-private).
5985 *
5986 * @param[in] pMe The decode context.
5987 * @param[in] uConvertTypes Bit mask list of conversion options
5988 * @param[out] pdValue The output of the conversion.
5989 * @param[in,out] pItem Temporary space to store Item, returned item.
5990 *
5991 * See QCBORDecode_GetDoubleConvert().
5992 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005993void
5994QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pMe,
5995 const uint32_t uConvertTypes,
5996 double *pdValue,
5997 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005998{
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07005999 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07006000 return;
6001 }
6002
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006003 QCBORError uError = QCBORDecode_GetNext(pMe, pItem);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006004 if(uError) {
6005 pMe->uLastError = (uint8_t)uError;
6006 return;
6007 }
6008
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006009 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006010 uConvertTypes,
6011 pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006012}
Laurence Lundbladec4537442020-04-14 18:53:22 -07006013
Laurence Lundbladec4537442020-04-14 18:53:22 -07006014
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006015/**
6016 * @brief Almost-public method to decode a number and convert to double (semi-private).
6017 *
6018 * @param[in] pMe The decode context.
6019 * @param[in] nLabel Label to find in map.
6020 * @param[in] uConvertTypes Bit mask list of conversion options
6021 * @param[out] pdValue The output of the conversion.
6022 * @param[in,out] pItem Temporary space to store Item, returned item.
6023 *
6024 * See QCBORDecode_GetDoubleConvertInMapN().
6025 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006026void
6027QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pMe,
6028 const int64_t nLabel,
6029 const uint32_t uConvertTypes,
6030 double *pdValue,
6031 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006032{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006033 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006034 if(pMe->uLastError != QCBOR_SUCCESS) {
6035 return;
6036 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006037
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006038 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6039 uConvertTypes,
6040 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006041}
6042
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006043
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006044/**
6045 * @brief Almost-public method to decode a number and convert to double (semi-private).
6046 *
6047 * @param[in] pMe The decode context.
6048 * @param[in] szLabel Label to find in map.
6049 * @param[in] uConvertTypes Bit mask list of conversion options
6050 * @param[out] pdValue The output of the conversion.
6051 * @param[in,out] pItem Temporary space to store Item, returned item.
6052 *
6053 * See QCBORDecode_GetDoubleConvertInMapSZ().
6054 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006055void
6056QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe,
6057 const char *szLabel,
6058 const uint32_t uConvertTypes,
6059 double *pdValue,
6060 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006061{
6062 if(pMe->uLastError != QCBOR_SUCCESS) {
6063 return;
6064 }
6065
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006066 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006067 if(pMe->uLastError != QCBOR_SUCCESS) {
6068 return;
6069 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006070
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006071 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6072 uConvertTypes,
6073 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006074}
6075
6076
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006077#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006078/**
6079 * @brief Convert a big number to double-precision float.
6080 *
6081 * @param[in] BigNum The big number to convert
6082 *
6083 * @returns The double value.
6084 *
6085 * This will always succeed. It will lose precision for larger
6086 * numbers. If the big number is too large to fit (more than
6087 * 1.7976931348623157E+308) infinity will be returned. NaN is never
6088 * returned.
6089 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006090static double
6091QCBOR_Private_ConvertBigNumToDouble(const UsefulBufC BigNum)
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006092{
6093 double dResult;
6094
6095 dResult = 0.0;
6096 const uint8_t *pByte = BigNum.ptr;
6097 size_t uLen = BigNum.len;
6098 /* This will overflow and become the float value INFINITY if the number
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006099 * is too large to fit. */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006100 while(uLen--) {
6101 dResult = (dResult * 256.0) + (double)*pByte++;
6102 }
6103
6104 return dResult;
6105}
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006106#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6107
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006108
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006109
6110
6111/**
6112 * @brief Convert many number types to a double.
6113 *
6114 * @param[in] pItem The item to convert.
6115 * @param[in] uConvertTypes Bit mask list of conversion options.
6116 * @param[out] pdValue The resulting converted value.
6117 *
6118 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6119 * in uConvertTypes.
6120 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6121 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6122 * or too small.
6123 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006124static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006125QCBOR_Private_DoubleConvertAll(const QCBORItem *pItem,
6126 const uint32_t uConvertTypes,
6127 double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006128{
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006129#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07006130 /*
Laurence Lundblade16a207a2021-09-18 17:22:46 -07006131 * What Every Computer Scientist Should Know About Floating-Point Arithmetic
6132 * https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
6133 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006134 switch(pItem->uDataType) {
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006135
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006136#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006137 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006138 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006139 // Underflow gives 0, overflow gives infinity
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006140 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6141 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
6142 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006143 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006144 }
6145 break;
6146
6147 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006148 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006149 // Underflow gives 0, overflow gives infinity
6150 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6151 exp2((double)pItem->val.expAndMantissa.nExponent);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006152 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006153 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006154 }
6155 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006156#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006157
6158 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006159 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006160 *pdValue = QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006161 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006162 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006163 }
6164 break;
6165
6166 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006167 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006168 *pdValue = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006169 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006170 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006171 }
6172 break;
6173
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006174#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006175 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006176 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006177 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006178 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6179 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006180 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006181 }
6182 break;
6183
6184 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006185 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006186 double dMantissa = -QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006187 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6188 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006189 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006190 }
6191 break;
6192
6193 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006194 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006195 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006196 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6197 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006198 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006199 }
6200 break;
6201
6202 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006203 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006204 double dMantissa = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006205 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6206 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006207 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006208 }
6209 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006210#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006211
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006212 default:
6213 return QCBOR_ERR_UNEXPECTED_TYPE;
6214 }
6215
6216 return QCBOR_SUCCESS;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006217
6218#else
6219 (void)pItem;
6220 (void)uConvertTypes;
6221 (void)pdValue;
6222 return QCBOR_ERR_HW_FLOAT_DISABLED;
6223#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6224
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006225}
6226
6227
6228/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006229 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006230 */
6231void
6232QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe,
6233 const uint32_t uConvertTypes,
6234 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006235{
6236
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006237 QCBORItem Item;
6238
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006239 QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006240
6241 if(pMe->uLastError == QCBOR_SUCCESS) {
6242 // The above conversion succeeded
6243 return;
6244 }
6245
6246 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6247 // The above conversion failed in a way that code below can't correct
6248 return;
6249 }
6250
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006251 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6252 uConvertTypes,
6253 pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006254}
6255
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006256
6257/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006258 * Public function, see header qcbor/qcbor_decode.h file
6259 */
6260void
6261QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe,
6262 const int64_t nLabel,
6263 const uint32_t uConvertTypes,
6264 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006265{
6266 QCBORItem Item;
6267
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006268 QCBORDecode_Private_GetDoubleConvertInMapN(pMe,
6269 nLabel,
6270 uConvertTypes,
6271 pdValue,
6272 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006273
6274 if(pMe->uLastError == QCBOR_SUCCESS) {
6275 // The above conversion succeeded
6276 return;
6277 }
6278
6279 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6280 // The above conversion failed in a way that code below can't correct
6281 return;
6282 }
6283
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006284 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6285 uConvertTypes,
6286 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006287}
6288
6289
6290/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006291 * Public function, see header qcbor/qcbor_decode.h file
6292 */
6293void
6294QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe,
6295 const char *szLabel,
6296 const uint32_t uConvertTypes,
6297 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006298{
6299 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006300 QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe,
6301 szLabel,
6302 uConvertTypes,
6303 pdValue,
6304 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006305
6306 if(pMe->uLastError == QCBOR_SUCCESS) {
6307 // The above conversion succeeded
6308 return;
6309 }
6310
6311 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6312 // The above conversion failed in a way that code below can't correct
6313 return;
6314 }
6315
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006316 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6317 uConvertTypes,
6318 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006319}
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006320#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006321
6322
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006323
6324
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006325#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006326/**
6327 * @brief Convert an integer to a big number
6328 *
6329 * @param[in] uInt The integer to convert.
6330 * @param[in] Buffer The buffer to output the big number to.
6331 *
6332 * @returns The big number or NULLUsefulBufC is the buffer is to small.
6333 *
6334 * This always succeeds unless the buffer is too small.
6335 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006336static UsefulBufC
6337QCBOR_Private_ConvertIntToBigNum(uint64_t uInt, const UsefulBuf Buffer)
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006338{
6339 while((uInt & 0xff00000000000000UL) == 0) {
6340 uInt = uInt << 8;
6341 };
6342
6343 UsefulOutBuf UOB;
6344
6345 UsefulOutBuf_Init(&UOB, Buffer);
6346
6347 while(uInt) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006348 UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff00000000000000UL) >> 56));
6349 uInt = uInt << 8;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006350 }
6351
6352 return UsefulOutBuf_OutUBuf(&UOB);
6353}
6354
6355
Laurence Lundblade37286c02022-09-03 10:05:02 -07006356/**
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006357 * @brief Check and/or complete exponent and mantissa item.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006358 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006359 * @param[in] pMe The decoder context.
6360 * @param[in] TagSpec Expected type(s).
6361 * @param[in,out] pItem See below.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006362 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006363 * This is for decimal fractions and big floats, both of which are an
6364 * exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006365 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006366 * If the item item had a tag number indicating it was a
6367 * decimal fraction or big float, then the input @c pItem will
6368 * have been decoded as exponent and mantissa. If there was
6369 * no tag number, the caller is asking this be decoded as a
6370 * big float or decimal fraction and @c pItem just has the
6371 * first item in an exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006372 *
6373 * On output, the item is always a fully decoded decimal fraction or
6374 * big float.
6375 *
6376 * This errors out if the input type does not meet the TagSpec.
6377 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07006378static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006379QCBOR_Private_ExpMantissaTypeHandler(QCBORDecodeContext *pMe,
6380 const QCBOR_Private_TagSpec TagSpec,
6381 QCBORItem *pItem)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006382{
6383 QCBORError uErr;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006384
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006385 /* pItem could either be a decoded exponent and mantissa or
6386 * the opening array of an undecoded exponent and mantissa. This
Laurence Lundblade37286c02022-09-03 10:05:02 -07006387 * check will succeed on either, but doesn't say which it was.
6388 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006389 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07006390 if(uErr != QCBOR_SUCCESS) {
6391 goto Done;
6392 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006393
Laurence Lundblade37286c02022-09-03 10:05:02 -07006394 if(pItem->uDataType == QCBOR_TYPE_ARRAY) {
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006395 /* The item is an array, which means is is an undecoded exponent
6396 * and mantissa. This call consumes the items in the array and
6397 * results in a decoded exponent and mantissa in pItem. This is
Laurence Lundblade37286c02022-09-03 10:05:02 -07006398 * the case where there was no tag.
6399 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006400 uErr = QCBORDecode_Private_ExpMantissa(pMe, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006401 if(uErr != QCBOR_SUCCESS) {
6402 goto Done;
6403 }
6404
Laurence Lundblade37286c02022-09-03 10:05:02 -07006405 /* The above decode didn't determine whether it is a decimal
6406 * fraction or big num. Which of these two depends on what the
6407 * caller wants it decoded as since there is no tag, so fish the
6408 * type out of the TagSpec. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006409 pItem->uDataType = QCBOR_Private_ExpMantissaDataType(TagSpec.uTaggedTypes[0], pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07006410
6411 /* No need to check the type again. All that we need to know was
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006412 * that it decoded correctly as a exponent and mantissa. The
Laurence Lundblade37286c02022-09-03 10:05:02 -07006413 * QCBOR type is set out by what was requested.
6414 */
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006415 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07006416
6417 /* If the item was not an array and the check passed, then
6418 * it is a fully decoded big float or decimal fraction and
6419 * matches what is requested.
6420 */
6421
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006422Done:
6423 return uErr;
6424}
6425
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006426
Laurence Lundblade37286c02022-09-03 10:05:02 -07006427/* Some notes from the work to disable tags.
6428 *
6429 * The API for big floats and decimal fractions seems good.
6430 * If there's any issue with it it's that the code size to
6431 * implement is a bit large because of the conversion
6432 * to/from int and bignum that is required. There is no API
6433 * that doesn't do the conversion so dead stripping will never
6434 * leave that code out.
6435 *
6436 * The implementation itself seems correct, but not as clean
6437 * and neat as it could be. It could probably be smaller too.
6438 *
6439 * The implementation has three main parts / functions
6440 * - The decoding of the array of two
6441 * - All the tag and type checking for the various API functions
6442 * - Conversion to/from bignum and int
6443 *
6444 * The type checking seems like it wastes the most code for
6445 * what it needs to do.
6446 *
6447 * The inlining for the conversion is probably making the
6448 * overall code base larger.
6449 *
6450 * The tests cases could be organized a lot better and be
6451 * more thorough.
6452 *
6453 * Seems also like there could be more common code in the
6454 * first tier part of the public API. Some functions only
6455 * vary by a TagSpec.
6456 */
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006457
6458/**
6459 * @brief Common processor for exponent and mantissa.
6460 *
6461 * @param[in] pMe The decode context.
6462 * @param[in] TagSpec The expected/allowed tags.
6463 * @param[in] pItem The data item to process.
6464 * @param[out] pnMantissa The returned mantissa as an int64_t.
6465 * @param[out] pnExponent The returned exponent as an int64_t.
6466 *
6467 * This handles exponent and mantissa for base 2 and 10. This
6468 * is limited to a mantissa that is an int64_t. See also
6469 * QCBORDecode_Private_ProcessExpMantissaBig().
6470 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006471static void
6472QCBOR_Private_ProcessExpMantissa(QCBORDecodeContext *pMe,
6473 const QCBOR_Private_TagSpec TagSpec,
6474 QCBORItem *pItem,
6475 int64_t *pnMantissa,
6476 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006477{
6478 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006479
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006480 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006481 if(uErr != QCBOR_SUCCESS) {
6482 goto Done;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006483 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006484
Laurence Lundblade9b334962020-08-27 10:55:53 -07006485 switch (pItem->uDataType) {
6486
6487 case QCBOR_TYPE_DECIMAL_FRACTION:
6488 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade9b334962020-08-27 10:55:53 -07006489 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006490 *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
Laurence Lundblade9b334962020-08-27 10:55:53 -07006491 break;
6492
Laurence Lundblade37286c02022-09-03 10:05:02 -07006493#ifndef QCBOR_DISABLE_TAGS
6494 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006495 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
6496 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
6497 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006498 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006499 break;
6500
6501 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
6502 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
6503 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006504 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006505 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006506#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006507
6508 default:
6509 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
6510 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006511
6512 Done:
6513 pMe->uLastError = (uint8_t)uErr;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006514}
6515
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006516
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006517/**
6518 * @brief Decode exponent and mantissa into a big number.
6519 *
6520 * @param[in] pMe The decode context.
6521 * @param[in] TagSpec The expected/allowed tags.
6522 * @param[in] pItem Item to decode and convert.
6523 * @param[in] BufferForMantissa Buffer to output mantissa into.
6524 * @param[out] pMantissa The output mantissa.
6525 * @param[out] pbIsNegative The sign of the output.
6526 * @param[out] pnExponent The mantissa of the output.
6527 *
6528 * This is the common processing of a decimal fraction or a big float
6529 * into a big number. This will decode and consume all the CBOR items
6530 * that make up the decimal fraction or big float.
6531 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006532static void
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006533QCBORDecode_Private_ProcessExpMantissaBig(QCBORDecodeContext *pMe,
6534 const QCBOR_Private_TagSpec TagSpec,
6535 QCBORItem *pItem,
6536 const UsefulBuf BufferForMantissa,
6537 UsefulBufC *pMantissa,
6538 bool *pbIsNegative,
6539 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006540{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006541 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006542
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006543 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006544 if(uErr != QCBOR_SUCCESS) {
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006545 goto Done;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006546 }
6547
6548 uint64_t uMantissa;
6549
6550 switch (pItem->uDataType) {
6551
6552 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006553 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006554 /* See comments in ExponentiateNN() on handling INT64_MIN */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006555 if(pItem->val.expAndMantissa.Mantissa.nInt >= 0) {
6556 uMantissa = (uint64_t)pItem->val.expAndMantissa.Mantissa.nInt;
6557 *pbIsNegative = false;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006558 } else if(pItem->val.expAndMantissa.Mantissa.nInt != INT64_MIN) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006559 uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt;
6560 *pbIsNegative = true;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006561 } else {
6562 uMantissa = (uint64_t)INT64_MAX+1;
6563 *pbIsNegative = true;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006564 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006565 *pMantissa = QCBOR_Private_ConvertIntToBigNum(uMantissa,
6566 BufferForMantissa);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006567 *pnExponent = pItem->val.expAndMantissa.nExponent;
6568 break;
6569
Laurence Lundblade37286c02022-09-03 10:05:02 -07006570#ifndef QCBOR_DISABLE_TAGS
6571 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006572 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006573 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006574 *pnExponent = pItem->val.expAndMantissa.nExponent;
6575 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6576 *pbIsNegative = false;
6577 break;
6578
6579 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006580 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006581 *pnExponent = pItem->val.expAndMantissa.nExponent;
6582 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6583 *pbIsNegative = true;
6584 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006585#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006586
6587 default:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006588 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006589 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006590
6591Done:
6592 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006593}
6594
6595
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006596/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006597 * Public function, see header qcbor/qcbor_decode.h file
6598 */
6599void
6600QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe,
6601 const uint8_t uTagRequirement,
6602 int64_t *pnMantissa,
6603 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006604{
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006605 if(pMe->uLastError != QCBOR_SUCCESS) {
6606 return;
6607 }
6608
6609 QCBORItem Item;
6610 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
6611 if(uError) {
6612 pMe->uLastError = (uint8_t)uError;
6613 return;
6614 }
6615
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006616 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006617 {
6618 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006619 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6620 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6621 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006622 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006623
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006624 QCBOR_Private_ProcessExpMantissa(pMe,
6625 TagSpec,
6626 &Item,
6627 pnMantissa,
6628 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006629}
6630
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006631
6632/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006633 * Public function, see header qcbor/qcbor_decode.h file
6634 */
6635void
6636QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe,
6637 const int64_t nLabel,
6638 const uint8_t uTagRequirement,
6639 int64_t *pnMantissa,
6640 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006641{
6642 if(pMe->uLastError != QCBOR_SUCCESS) {
6643 return;
6644 }
6645
6646 QCBORItem Item;
6647 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
6648
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006649 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006650 {
6651 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006652 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6653 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6654 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006655 };
6656
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006657 QCBOR_Private_ProcessExpMantissa(pMe,
6658 TagSpec,
6659 &Item,
6660 pnMantissa,
6661 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006662}
6663
6664
6665/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006666 * Public function, see header qcbor/qcbor_decode.h file
6667 */
6668void
6669QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
6670 const char *szLabel,
6671 const uint8_t uTagRequirement,
6672 int64_t *pnMantissa,
6673 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006674{
6675 if(pMe->uLastError != QCBOR_SUCCESS) {
6676 return;
6677 }
6678
6679 QCBORItem Item;
6680 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
6681
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006682 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006683 {
6684 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006685 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6686 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6687 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006688 };
Laurence Lundblade9b334962020-08-27 10:55:53 -07006689
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006690 QCBOR_Private_ProcessExpMantissa(pMe,
6691 TagSpec,
6692 &Item,
6693 pnMantissa,
6694 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006695}
6696
6697
6698/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006699 * Public function, see header qcbor/qcbor_decode.h file
6700 */
6701void
6702QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe,
6703 const uint8_t uTagRequirement,
6704 const UsefulBuf MantissaBuffer,
6705 UsefulBufC *pMantissa,
6706 bool *pbMantissaIsNegative,
6707 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006708{
6709 if(pMe->uLastError != QCBOR_SUCCESS) {
6710 return;
6711 }
6712
6713 QCBORItem Item;
6714 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
6715 if(uError) {
6716 pMe->uLastError = (uint8_t)uError;
6717 return;
6718 }
6719
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006720 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006721 {
6722 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006723 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6724 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6725 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006726 };
6727
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006728 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
6729 TagSpec,
6730 &Item,
6731 MantissaBuffer,
6732 pMantissa,
6733 pbMantissaIsNegative,
6734 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006735}
6736
6737
6738/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006739 * Public function, see header qcbor/qcbor_decode.h file
6740 */
6741void
6742QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe,
6743 const int64_t nLabel,
6744 const uint8_t uTagRequirement,
6745 const UsefulBuf BufferForMantissa,
6746 UsefulBufC *pMantissa,
6747 bool *pbIsNegative,
6748 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006749{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006750 if(pMe->uLastError != QCBOR_SUCCESS) {
6751 return;
6752 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006753
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006754 QCBORItem Item;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006755 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006756 if(pMe->uLastError != QCBOR_SUCCESS) {
6757 return;
6758 }
6759
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006760 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006761 {
6762 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006763 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6764 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6765 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006766 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006767
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006768 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
6769 TagSpec,
6770 &Item,
6771 BufferForMantissa,
6772 pMantissa,
6773 pbIsNegative,
6774 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006775}
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006776
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006777
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006778/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006779 * Public function, see header qcbor/qcbor_decode.h file
6780 */
6781void
6782QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe,
6783 const char *szLabel,
6784 const uint8_t uTagRequirement,
6785 const UsefulBuf BufferForMantissa,
6786 UsefulBufC *pMantissa,
6787 bool *pbIsNegative,
6788 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006789{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006790 if(pMe->uLastError != QCBOR_SUCCESS) {
6791 return;
6792 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006793
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006794 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006795 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
6796 if(pMe->uLastError != QCBOR_SUCCESS) {
6797 return;
6798 }
6799
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006800 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006801 {
6802 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006803 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6804 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6805 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006806 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006807
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006808 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
6809 TagSpec,
6810 &Item,
6811 BufferForMantissa,
6812 pMantissa,
6813 pbIsNegative,
6814 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006815}
6816
6817
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006818/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006819 * Public function, see header qcbor/qcbor_decode.h file
6820 */
6821void
6822QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe,
6823 const uint8_t uTagRequirement,
6824 int64_t *pnMantissa,
6825 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006826{
6827 if(pMe->uLastError != QCBOR_SUCCESS) {
6828 return;
6829 }
6830
6831 QCBORItem Item;
6832 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
6833 if(uError) {
6834 pMe->uLastError = (uint8_t)uError;
6835 return;
6836 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006837 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006838 {
6839 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006840 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
6841 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
6842 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006843 };
6844
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006845 QCBOR_Private_ProcessExpMantissa(pMe,
6846 TagSpec,
6847 &Item,
6848 pnMantissa,
6849 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006850}
6851
6852
6853/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006854 * Public function, see header qcbor/qcbor_decode.h file
6855 */
6856void
6857QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe,
6858 const int64_t nLabel,
6859 const uint8_t uTagRequirement,
6860 int64_t *pnMantissa,
6861 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006862{
6863 if(pMe->uLastError != QCBOR_SUCCESS) {
6864 return;
6865 }
6866
6867 QCBORItem Item;
6868 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
6869 if(pMe->uLastError != QCBOR_SUCCESS) {
6870 return;
6871 }
6872
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006873 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006874 {
6875 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006876 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
6877 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
6878 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006879 };
6880
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006881 QCBOR_Private_ProcessExpMantissa(pMe,
6882 TagSpec,
6883 &Item,
6884 pnMantissa,
6885 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006886}
6887
6888
6889/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006890 * Public function, see header qcbor/qcbor_decode.h file
6891 */
6892void
6893QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe,
6894 const char *szLabel,
6895 const uint8_t uTagRequirement,
6896 int64_t *pnMantissa,
6897 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006898{
6899 if(pMe->uLastError != QCBOR_SUCCESS) {
6900 return;
6901 }
6902
6903 QCBORItem Item;
6904 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
6905 if(pMe->uLastError != QCBOR_SUCCESS) {
6906 return;
6907 }
6908
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006909 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006910 {
6911 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006912 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
6913 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
6914 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006915 };
6916
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006917 QCBOR_Private_ProcessExpMantissa(pMe,
6918 TagSpec,
6919 &Item,
6920 pnMantissa,
6921 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006922}
6923
6924
6925/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006926 * Public function, see header qcbor/qcbor_decode.h file
6927 */
6928void
6929QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe,
6930 const uint8_t uTagRequirement,
6931 const UsefulBuf MantissaBuffer,
6932 UsefulBufC *pMantissa,
6933 bool *pbMantissaIsNegative,
6934 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006935{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006936 if(pMe->uLastError != QCBOR_SUCCESS) {
6937 return;
6938 }
6939
6940 QCBORItem Item;
6941 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
6942 if(uError) {
6943 pMe->uLastError = (uint8_t)uError;
6944 return;
6945 }
6946
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006947 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006948 {
6949 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006950 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
6951 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
6952 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006953 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006954
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006955 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
6956 TagSpec,
6957 &Item,
6958 MantissaBuffer,
6959 pMantissa,
6960 pbMantissaIsNegative,
6961 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006962}
6963
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006964
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006965/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006966 * Public function, see header qcbor/qcbor_decode.h file
6967 */
6968void
6969QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe,
6970 const int64_t nLabel,
6971 const uint8_t uTagRequirement,
6972 const UsefulBuf BufferForMantissa,
6973 UsefulBufC *pMantissa,
6974 bool *pbIsNegative,
6975 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006976{
6977 if(pMe->uLastError != QCBOR_SUCCESS) {
6978 return;
6979 }
6980
6981 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006982 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
6983 if(pMe->uLastError != QCBOR_SUCCESS) {
6984 return;
6985 }
6986
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006987 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006988 {
6989 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006990 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
6991 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
6992 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006993 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006994
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006995 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
6996 TagSpec,
6997 &Item,
6998 BufferForMantissa,
6999 pMantissa,
7000 pbIsNegative,
7001 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007002}
7003
7004
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007005/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007006 * Public function, see header qcbor/qcbor_decode.h file
7007 */
7008void
7009QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe,
7010 const char *szLabel,
7011 const uint8_t uTagRequirement,
7012 const UsefulBuf BufferForMantissa,
7013 UsefulBufC *pMantissa,
7014 bool *pbIsNegative,
7015 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007016{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007017 if(pMe->uLastError != QCBOR_SUCCESS) {
7018 return;
7019 }
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007020
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007021 QCBORItem Item;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007022 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7023 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007024 return;
7025 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007026
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007027 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007028 {
7029 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007030 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7031 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7032 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007033 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007034
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007035 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7036 TagSpec,
7037 &Item,
7038 BufferForMantissa,
7039 pMantissa,
7040 pbIsNegative,
7041 pnExponent);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007042}
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007043
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07007044#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007045
7046
7047#if !defined(USEFULBUF_DISABLE_ALL_FLOAT) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
7048/*
7049 * Public function, see header qcbor/qcbor_spiffy_decode.h file
7050 */
7051void
7052QCBORDecode_GetNumberConvertPrecisely(QCBORDecodeContext *pMe,
7053 QCBORItem *pNumber)
7054{
7055 QCBORItem Item;
7056 struct IEEE754_ToInt ToInt;
7057 double d;
7058 QCBORError uError;
7059
7060 if(pMe->uLastError != QCBOR_SUCCESS) {
7061 return;
7062 }
7063
7064 uError = QCBORDecode_GetNext(pMe, &Item);
7065 if(uError != QCBOR_SUCCESS) {
7066 pMe->uLastError = (uint8_t)uError;
7067 return;
7068 }
7069
7070 switch(Item.uDataType) {
7071 case QCBOR_TYPE_INT64:
7072 case QCBOR_TYPE_UINT64:
7073 *pNumber = Item;
7074 break;
7075
7076 case QCBOR_TYPE_DOUBLE:
7077 ToInt = IEEE754_DoubleToInt(Item.val.dfnum);
7078 if(ToInt.type == IEEE754_ToInt_IS_INT) {
7079 pNumber->uDataType = QCBOR_TYPE_INT64;
7080 pNumber->val.int64 = ToInt.integer.is_signed;
7081 } else if(ToInt.type == IEEE754_ToInt_IS_UINT) {
7082 if(ToInt.integer.un_signed <= INT64_MAX) {
7083 /* Do the same as base QCBOR integer decoding */
7084 pNumber->uDataType = QCBOR_TYPE_INT64;
7085 pNumber->val.int64 = (int64_t)ToInt.integer.un_signed;
7086 } else {
7087 pNumber->uDataType = QCBOR_TYPE_UINT64;
7088 pNumber->val.uint64 = ToInt.integer.un_signed;
7089 }
7090 } else {
7091 *pNumber = Item;
7092 }
7093 break;
7094
7095 case QCBOR_TYPE_FLOAT:
7096 ToInt = IEEE754_SingleToInt(Item.val.fnum);
7097 if(ToInt.type == IEEE754_ToInt_IS_INT) {
7098 pNumber->uDataType = QCBOR_TYPE_INT64;
7099 pNumber->val.int64 = ToInt.integer.is_signed;
7100 } else if(ToInt.type == IEEE754_ToInt_IS_UINT) {
7101 if(ToInt.integer.un_signed <= INT64_MAX) {
7102 /* Do the same as base QCBOR integer decoding */
7103 pNumber->uDataType = QCBOR_TYPE_INT64;
7104 pNumber->val.int64 = (int64_t)ToInt.integer.un_signed;
7105 } else {
7106 pNumber->uDataType = QCBOR_TYPE_UINT64;
7107 pNumber->val.uint64 = ToInt.integer.un_signed;
7108 }
7109 } else {
7110 *pNumber = Item;
7111 }
7112 break;
7113
7114
7115 case QCBOR_TYPE_65BIT_NEG_INT:
7116 d = IEEE754_UintToDouble(Item.val.uint64, 1);
7117 if(d == IEEE754_UINT_TO_DOUBLE_OOB) {
7118 *pNumber = Item;
7119 } else {
7120 pNumber->uDataType = QCBOR_TYPE_DOUBLE;
7121 /* -1 is because of CBOR offset of negative numbers */
7122 pNumber->val.dfnum = d - 1;
7123 }
7124 break;
7125
7126 default:
7127 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
7128 pNumber->uDataType = QCBOR_TYPE_NONE;
7129 break;
7130 }
7131}
7132
7133#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT && ! QCBOR_DISABLE_PREFERRED_FLOAT */