blob: 74465d04bdacf3e669be5ab8b292b804a970cf4a [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 Lundblade3f1318a2021-01-04 18:26:44 -0800888 /* C can't represent a negative integer in this range so it
889 * is an error.
890 */
891 uReturn = QCBOR_ERR_INT_OVERFLOW;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700892 }
893 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800894
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800895 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700896}
897
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800898
899/* Make sure #define value line up as DecodeSimple counts on this. */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700900#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
901#error QCBOR_TYPE_FALSE macro value wrong
902#endif
903
904#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
905#error QCBOR_TYPE_TRUE macro value wrong
906#endif
907
908#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
909#error QCBOR_TYPE_NULL macro value wrong
910#endif
911
912#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
913#error QCBOR_TYPE_UNDEF macro value wrong
914#endif
915
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700916#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
917#error QCBOR_TYPE_BREAK macro value wrong
918#endif
919
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700920#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
921#error QCBOR_TYPE_DOUBLE macro value wrong
922#endif
923
924#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
925#error QCBOR_TYPE_FLOAT macro value wrong
926#endif
927
Laurence Lundblade9b334962020-08-27 10:55:53 -0700928
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800929/**
930 * @brief Decode major type 7 -- true, false, floating-point, break...
931 *
932 * @param[in] nAdditionalInfo The lower five bits from the initial byte.
933 * @param[in] uArgument The argument from the head.
934 * @param[out] pDecodedItem The filled in decoded item.
935 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -0700936 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
937 * of half-precision disabled
938 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all float
939 * decode is disabled.
940 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of simple
941 * type in input.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700942 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700943static QCBORError
944QCBOR_Private_DecodeType7(const int nAdditionalInfo,
945 const uint64_t uArgument,
946 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800947{
948 QCBORError uReturn = QCBOR_SUCCESS;
949
950 /* uAdditionalInfo is 5 bits from the initial byte. Compile time
951 * checks above make sure uAdditionalInfo values line up with
952 * uDataType values. DecodeHead() never returns an AdditionalInfo
953 * > 0x1f so cast is safe.
954 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800955 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800956
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800957 switch(nAdditionalInfo) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800958 /* No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they
959 * are caught before this is called.
960 */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800961
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800962 case HALF_PREC_FLOAT: /* 25 */
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700963#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800964 /* Half-precision is returned as a double. The cast to
965 * uint16_t is safe because the encoded value was 16 bits. It
966 * was widened to 64 bits to be passed in here.
967 */
968 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uArgument);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700969 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800970#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200971 uReturn = FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700972 break;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800973 case SINGLE_PREC_FLOAT: /* 26 */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200974#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800975 /* Single precision is normally returned as a double since
976 * double is widely supported, there is no loss of precision,
977 * it makes it easy for the caller in most cases and it can
978 * be converted back to single with no loss of precision
979 *
980 * The cast to uint32_t is safe because the encoded value was
981 * 32 bits. It was widened to 64 bits to be passed in here.
982 */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700983 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800984 const float f = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uArgument);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700985#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800986 /* In the normal case, use HW to convert float to
987 * double. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700988 pDecodedItem->val.dfnum = (double)f;
989 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800990#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800991 /* Use of float HW is disabled, return as a float. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700992 pDecodedItem->val.fnum = f;
993 pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
994
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800995 /* IEEE754_FloatToDouble() could be used here to return as
996 * a double, but it adds object code and most likely
997 * anyone disabling FLOAT HW use doesn't care about floats
998 * and wants to save object code.
999 */
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001000#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001001 }
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001002#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1003 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001004 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001005
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001006 case DOUBLE_PREC_FLOAT: /* 27 */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001007#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001008 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uArgument);
Laurence Lundblade67bd5512018-11-02 21:44:06 +07001009 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001010#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1011 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001012 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001013
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001014 case CBOR_SIMPLEV_FALSE: /* 20 */
1015 case CBOR_SIMPLEV_TRUE: /* 21 */
1016 case CBOR_SIMPLEV_NULL: /* 22 */
1017 case CBOR_SIMPLEV_UNDEF: /* 23 */
1018 case CBOR_SIMPLE_BREAK: /* 31 */
1019 break; /* nothing to do */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001020
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001021 case CBOR_SIMPLEV_ONEBYTE: /* 24 */
1022 if(uArgument <= CBOR_SIMPLE_BREAK) {
1023 /* This takes out f8 00 ... f8 1f which should be encoded
1024 * as e0 … f7
1025 */
1026 uReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001027 goto Done;
1028 }
Laurence Lundblade5e390822019-01-06 12:35:01 -08001029 /* FALLTHROUGH */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001030
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001031 default: /* 0-19 */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001032 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001033 /* DecodeHead() will make uArgument equal to
1034 * nAdditionalInfo when nAdditionalInfo is < 24. This cast is
1035 * safe because the 2, 4 and 8 byte lengths of uNumber are in
1036 * the double/float cases above
Laurence Lundbladeee851742020-01-08 08:37:05 -08001037 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001038 pDecodedItem->val.uSimple = (uint8_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001039 break;
1040 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001041
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001042Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001043 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001044}
1045
1046
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001047/**
1048 * @brief Decode text and byte strings
1049 *
1050 * @param[in] pAllocator The string allocator or NULL.
1051 * @param[in] uStrLen The length of the string.
1052 * @param[in] pUInBuf The surce from which to read the string's bytes.
1053 * @param[out] pDecodedItem The filled in decoded item.
1054 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001055 * @retval QCBOR_ERR_HIT_END Unexpected end of input.
1056 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1057 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001058 *
1059 * The reads @c uStrlen bytes from @c pUInBuf and fills in @c
1060 * pDecodedItem. If @c pAllocator is not NULL then memory for the
1061 * string is allocated.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001062 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001063static QCBORError
1064QCBOR_Private_DecodeBytes(const QCBORInternalAllocator *pAllocator,
1065 const uint64_t uStrLen,
1066 UsefulInputBuf *pUInBuf,
1067 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001068{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001069 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001070
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001071 /* CBOR lengths can be 64 bits, but size_t is not 64 bits on all
1072 * CPUs. This check makes the casts to size_t below safe.
1073 *
1074 * The max is 4 bytes less than the largest sizeof() so this can be
1075 * tested by putting a SIZE_MAX length in the CBOR test input (no
1076 * one will care the limit on strings is 4 bytes shorter).
1077 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001078 if(uStrLen > SIZE_MAX-4) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001079 uReturn = QCBOR_ERR_STRING_TOO_LONG;
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001080 goto Done;
1081 }
1082
1083 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, (size_t)uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +05301084 if(UsefulBuf_IsNULLC(Bytes)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001085 /* Failed to get the bytes for this string item */
1086 uReturn = QCBOR_ERR_HIT_END;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +05301087 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001088 }
Laurence Lundblade471a3fd2018-10-18 21:27:45 +05301089
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001090#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001091 /* Note that this is not where allocation to coalesce
1092 * indefinite-length strings is done. This is for when the caller
1093 * has requested all strings be allocated. Disabling indefinite
1094 * length strings also disables this allocate-all option.
1095 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001096 if(pAllocator) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001097 /* request to use the string allocator to make a copy */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001098 UsefulBuf NewMem = StringAllocator_Allocate(pAllocator, (size_t)uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +05301099 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001100 uReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +05301101 goto Done;
1102 }
1103 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001104 pDecodedItem->uDataAlloc = 1;
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001105 goto Done;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +05301106 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001107#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1108 (void)pAllocator;
1109#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1110
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001111 /* Normal case with no string allocator */
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001112 pDecodedItem->val.string = Bytes;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001113
Laurence Lundblade471a3fd2018-10-18 21:27:45 +05301114Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001115 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001116}
1117
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001118
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001119/**
1120 * @brief Map the CBOR major types for strings to the QCBOR types.
1121 *
1122 * @param[in] nCBORMajorType The CBOR major type to convert.
1123 * @retturns QCBOR type number.
1124 *
1125 * This only works for the two string types.
1126 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001127static uint8_t
1128QCBOR_Private_ConvertStringMajorTypes(int nCBORMajorType)
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001129{
1130 #if CBOR_MAJOR_TYPE_BYTE_STRING + 4 != QCBOR_TYPE_BYTE_STRING
1131 #error QCBOR_TYPE_BYTE_STRING no lined up with major type
1132 #endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001133
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001134 #if CBOR_MAJOR_TYPE_TEXT_STRING + 4 != QCBOR_TYPE_TEXT_STRING
1135 #error QCBOR_TYPE_TEXT_STRING no lined up with major type
1136 #endif
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001137
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001138 return (uint8_t)(nCBORMajorType + 4);
1139}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001140
1141
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001142/**
1143 * @brief Map the CBOR major types for arrays/maps to the QCBOR types.
1144 *
1145 * @param[in] nCBORMajorType The CBOR major type to convert.
1146 * @retturns QCBOR type number.
1147 *
1148 * This only works for the two aggregate types.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001149 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001150static uint8_t
1151QCBORDecode_Private_ConvertArrayOrMapType(int nCBORMajorType)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001152{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001153 #if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
1154 #error QCBOR_TYPE_ARRAY value not lined up with major type
1155 #endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001156
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001157 #if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
1158 #error QCBOR_TYPE_MAP value not lined up with major type
1159 #endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001160
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001161 return (uint8_t)(nCBORMajorType);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001162}
1163
1164
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001165/**
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001166 * @brief Decode a single primitive data item (decode layer 6).
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001167 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001168 * @param[in] pUInBuf Input buffer to read data item from.
1169 * @param[out] pDecodedItem The filled-in decoded item.
1170 * @param[in] pAllocator The allocator to use for strings or NULL.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001171 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001172 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1173 * features
1174 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1175 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1176 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1177 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1178 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1179 * of half-precision disabled
1180 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1181 * float decode is disabled.
1182 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1183 * simple type in input.
1184 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1185 * in input, but indefinite
1186 * lengths disabled.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001187 *
1188 * This decodes the most primitive / atomic data item. It does
1189 * no combing of data items.
1190 */
1191static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001192QCBOR_Private_DecodeAtomicDataItem(UsefulInputBuf *pUInBuf,
1193 QCBORItem *pDecodedItem,
1194 const QCBORInternalAllocator *pAllocator)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001195{
1196 QCBORError uReturn;
1197
1198 /* Get the major type and the argument. The argument could be
1199 * length of more bytes or the value depending on the major
1200 * type. nAdditionalInfo is an encoding of the length of the
1201 * uNumber and is needed to decode floats and doubles.
1202 */
1203 int nMajorType = 0;
1204 uint64_t uArgument = 0;
1205 int nAdditionalInfo = 0;
1206
1207 memset(pDecodedItem, 0, sizeof(QCBORItem));
1208
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001209 uReturn = QCBOR_Private_DecodeHead(pUInBuf, &nMajorType, &uArgument, &nAdditionalInfo);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001210 if(uReturn) {
1211 goto Done;
1212 }
1213
1214 /* At this point the major type and the argument are valid. We've
1215 * got the type and the argument that starts every CBOR data item.
1216 */
1217 switch (nMajorType) {
1218 case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
1219 case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
1220 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1221 uReturn = QCBOR_ERR_BAD_INT;
1222 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001223 uReturn = QCBOR_Private_DecodeInteger(nMajorType, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001224 }
1225 break;
1226
1227 case CBOR_MAJOR_TYPE_BYTE_STRING: /* Major type 2 */
1228 case CBOR_MAJOR_TYPE_TEXT_STRING: /* Major type 3 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001229 pDecodedItem->uDataType = QCBOR_Private_ConvertStringMajorTypes(nMajorType);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001230 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1231 pDecodedItem->val.string = (UsefulBufC){NULL, QCBOR_STRING_LENGTH_INDEFINITE};
1232 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001233 uReturn = QCBOR_Private_DecodeBytes(pAllocator, uArgument, pUInBuf, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001234 }
1235 break;
1236
1237 case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */
1238 case CBOR_MAJOR_TYPE_MAP: /* Major type 5 */
1239 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1240 /* Indefinite-length string. */
1241#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
1242 pDecodedItem->val.uCount = QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH;
1243#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1244 uReturn = QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED;
1245 break;
1246#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1247 } else {
1248 /* Definite-length string. */
1249 if(uArgument > QCBOR_MAX_ITEMS_IN_ARRAY) {
1250 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
1251 goto Done;
1252 }
1253 /* cast OK because of check above */
1254 pDecodedItem->val.uCount = (uint16_t)uArgument;
1255 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001256 pDecodedItem->uDataType = QCBORDecode_Private_ConvertArrayOrMapType(nMajorType);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001257 break;
1258
1259 case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */
Laurence Lundblade37286c02022-09-03 10:05:02 -07001260#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001261 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1262 uReturn = QCBOR_ERR_BAD_INT;
1263 } else {
1264 pDecodedItem->val.uTagV = uArgument;
1265 pDecodedItem->uDataType = QCBOR_TYPE_TAG;
1266 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07001267#else /* QCBOR_DISABLE_TAGS */
1268 uReturn = QCBOR_ERR_TAGS_DISABLED;
1269#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001270 break;
1271
1272 case CBOR_MAJOR_TYPE_SIMPLE:
1273 /* Major type 7: float, double, true, false, null... */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001274 uReturn = QCBOR_Private_DecodeType7(nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001275 break;
1276
1277 default:
1278 /* Never happens because DecodeHead() should never return > 7 */
1279 uReturn = QCBOR_ERR_UNSUPPORTED;
1280 break;
1281 }
1282
1283Done:
1284 return uReturn;
1285}
1286
1287
1288/**
1289 * @brief Process indefinite-length strings (decode layer 5).
1290 *
1291 * @param[in] pMe Decoder context
1292 * @param[out] pDecodedItem The decoded item that work is done on.
1293 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001294 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1295 * features
1296 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1297 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1298 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1299 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1300 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1301 * of half-precision disabled
1302 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1303 * float decode is disabled.
1304 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1305 * simple type in input.
1306 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1307 * in input, but indefinite
1308 * lengths disabled.
1309 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1310 * but no string allocator.
1311 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1312 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1313 * input, but indefinite-length
1314 * strings are disabled.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001315 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001316 * If @c pDecodedItem is not an indefinite-length string, this does nothing.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001317 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001318 * If it is, this loops getting the subsequent chunk data items that
1319 * make up the string. The string allocator is used to make a
1320 * contiguous buffer for the chunks. When this completes @c
1321 * pDecodedItem contains the put-together string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001322 *
1323 * Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001324 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001325static QCBORError
1326QCBORDecode_Private_GetNextFullString(QCBORDecodeContext *pMe,
1327 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001328{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001329 /* Aproximate stack usage
1330 * 64-bit 32-bit
1331 * local vars 32 16
1332 * 2 UsefulBufs 32 16
1333 * QCBORItem 56 52
1334 * TOTAL 120 74
1335 */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001336
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001337 /* The string allocator is used here for two purposes: 1)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001338 * coalescing the chunks of an indefinite-length string, 2)
1339 * allocating storage for every string returned when requested.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001340 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001341 * The first use is below in this function. Indefinite-length
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001342 * strings cannot be processed at all without a string allocator.
1343 *
1344 * The second used is in DecodeBytes() which is called by
1345 * GetNext_Item() below. This second use unneccessary for most use
1346 * and only happens when requested in the call to
1347 * QCBORDecode_SetMemPool(). If the second use not requested then
1348 * NULL is passed for the string allocator to GetNext_Item().
1349 *
1350 * QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS disables the string
1351 * allocator altogether and thus both of these uses. It reduced the
1352 * decoder object code by about 400 bytes.
1353 */
Laurence Lundblade3a691a02020-12-28 04:15:16 -08001354 const QCBORInternalAllocator *pAllocatorForGetNext = NULL;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001355
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001356#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3a691a02020-12-28 04:15:16 -08001357 const QCBORInternalAllocator *pAllocator = NULL;
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001358
1359 if(pMe->StringAllocator.pfAllocator) {
1360 pAllocator = &(pMe->StringAllocator);
1361 if(pMe->bStringAllocateAll) {
1362 pAllocatorForGetNext = pAllocator;
1363 }
1364 }
1365#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1366
1367 QCBORError uReturn;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001368 uReturn = QCBOR_Private_DecodeAtomicDataItem(&(pMe->InBuf), pDecodedItem, pAllocatorForGetNext);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001369 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001370 goto Done;
1371 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001372
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001373 /* Only do indefinite-length processing on strings */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001374 const uint8_t uStringType = pDecodedItem->uDataType;
1375 if(uStringType!= QCBOR_TYPE_BYTE_STRING && uStringType != QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001376 goto Done;
1377 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001378
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001379 /* Is this a string with an indefinite length? */
1380 if(pDecodedItem->val.string.len != QCBOR_STRING_LENGTH_INDEFINITE) {
1381 goto Done;
1382 }
1383
1384#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001385 /* Can't decode indefinite-length strings without a string allocator */
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001386 if(pAllocator == NULL) {
1387 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1388 goto Done;
1389 }
1390
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001391 /* Loop getting chunks of the indefinite-length string */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001392 UsefulBufC FullString = NULLUsefulBufC;
1393
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001394 for(;;) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001395 /* Get QCBORItem for next chunk */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001396 QCBORItem StringChunkItem;
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001397 /* Pass a NULL string allocator to GetNext_Item() because the
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001398 * individual string chunks in an indefinite-length should not
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001399 * be allocated. They are always copied in the the contiguous
1400 * buffer allocated here.
1401 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001402 uReturn = QCBOR_Private_DecodeAtomicDataItem(&(pMe->InBuf), &StringChunkItem, NULL);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001403 if(uReturn) {
1404 break;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001405 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001406
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001407 /* Is item is the marker for end of the indefinite-length string? */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001408 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001409 /* String is complete */
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001410 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301411 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001412 break;
1413 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001414
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001415 /* All chunks must be of the same type, the type of the item
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001416 * that introduces the indefinite-length string. This also
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001417 * catches errors where the chunk is not a string at all and an
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001418 * indefinite-length string inside an indefinite-length string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001419 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001420 if(StringChunkItem.uDataType != uStringType ||
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001421 StringChunkItem.val.string.len == QCBOR_STRING_LENGTH_INDEFINITE) {
1422 uReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001423 break;
1424 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001425
David Navarro9123e5b2022-03-28 16:04:03 +02001426 if (StringChunkItem.val.string.len > 0) {
1427 /* The first time throurgh FullString.ptr is NULL and this is
1428 * equivalent to StringAllocator_Allocate(). Subsequently it is
1429 * not NULL and a reallocation happens.
1430 */
1431 UsefulBuf NewMem = StringAllocator_Reallocate(pAllocator,
1432 FullString.ptr,
1433 FullString.len + StringChunkItem.val.string.len);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001434
David Navarro9123e5b2022-03-28 16:04:03 +02001435 if(UsefulBuf_IsNULL(NewMem)) {
1436 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1437 break;
1438 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001439
David Navarro9123e5b2022-03-28 16:04:03 +02001440 /* Copy new string chunk to the end of accumulated string */
1441 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001442 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001443 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001444
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001445 if(uReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
1446 /* Getting the item failed, clean up the allocated memory */
Laurence Lundbladeb9702452021-03-08 21:02:57 -08001447 StringAllocator_Free(pAllocator, FullString.ptr);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001448 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001449#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1450 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1451#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001452
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001453Done:
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001454 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001455}
1456
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001457
Laurence Lundblade37286c02022-09-03 10:05:02 -07001458#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001459/**
1460 * @brief This converts a tag number to a shorter mapped value for storage.
1461 *
1462 * @param[in] pMe The decode context.
1463 * @param[in] uUnMappedTag The tag number to map
1464 * @param[out] puMappedTagNumer The stored tag number.
1465 *
1466 * @return error code.
1467 *
1468 * The main point of mapping tag numbers is make QCBORItem
1469 * smaller. With this mapping storage of 4 tags takes up 8
1470 * bytes. Without, it would take up 32 bytes.
1471 *
1472 * This maps tag numbers greater than QCBOR_LAST_UNMAPPED_TAG.
1473 * QCBOR_LAST_UNMAPPED_TAG is a little smaller than MAX_UINT16.
1474 *
1475 * See also UnMapTagNumber() and @ref QCBORItem.
1476 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001477static QCBORError
1478QCBORDecode_Private_MapTagNumber(QCBORDecodeContext *pMe,
1479 const uint64_t uUnMappedTag,
1480 uint16_t *puMappedTagNumer)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001481{
1482 if(uUnMappedTag > QCBOR_LAST_UNMAPPED_TAG) {
1483 unsigned uTagMapIndex;
1484 /* Is there room in the tag map, or is it in it already? */
1485 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
1486 if(pMe->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID64) {
1487 break;
1488 }
1489 if(pMe->auMappedTags[uTagMapIndex] == uUnMappedTag) {
1490 break;
1491 }
1492 }
1493 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
1494 return QCBOR_ERR_TOO_MANY_TAGS;
1495 }
1496
1497 /* Covers the cases where tag is new and were it is already in the map */
1498 pMe->auMappedTags[uTagMapIndex] = uUnMappedTag;
1499 *puMappedTagNumer = (uint16_t)(uTagMapIndex + QCBOR_LAST_UNMAPPED_TAG + 1);
1500
1501 } else {
1502 *puMappedTagNumer = (uint16_t)uUnMappedTag;
1503 }
1504
1505 return QCBOR_SUCCESS;
1506}
1507
1508
1509/**
1510 * @brief This converts a mapped tag number to the actual tag number.
1511 *
1512 * @param[in] pMe The decode context.
1513 * @param[in] uMappedTagNumber The stored tag number.
1514 *
1515 * @return The actual tag number is returned or
1516 * @ref CBOR_TAG_INVALID64 on error.
1517 *
1518 * This is the reverse of MapTagNumber()
1519 */
1520static uint64_t
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001521QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe,
1522 const uint16_t uMappedTagNumber)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001523{
1524 if(uMappedTagNumber <= QCBOR_LAST_UNMAPPED_TAG) {
1525 return uMappedTagNumber;
1526 } else if(uMappedTagNumber == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07001527 return CBOR_TAG_INVALID64;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001528 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001529 /* This won't be negative because of code below in
1530 * MapTagNumber()
1531 */
1532 const unsigned uIndex = uMappedTagNumber - (QCBOR_LAST_UNMAPPED_TAG + 1);
1533 return pMe->auMappedTags[uIndex];
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001534 }
1535}
Laurence Lundblade37286c02022-09-03 10:05:02 -07001536#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001537
Laurence Lundblade9b334962020-08-27 10:55:53 -07001538
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001539/**
1540 * @brief Aggregate all tags wrapping a data item (decode layer 4).
1541 *
1542 * @param[in] pMe Decoder context
1543 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001544 *
1545 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1546 * features
1547 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1548 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1549 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1550 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1551 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1552 * of half-precision disabled
1553 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1554 * float decode is disabled.
1555 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1556 * simple type in input.
1557 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1558 * in input, but indefinite
1559 * lengths disabled.
1560 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1561 * but no string allocator.
1562 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1563 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1564 * input, but indefinite-length
1565 * strings are disabled.
1566 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001567 *
1568 * This loops getting atomic data items until one is not a tag
1569 * number. Usually this is largely pass-through because most
1570 * item are not tag numbers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001571 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001572static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001573QCBORDecode_Private_GetNextTagNumber(QCBORDecodeContext *pMe,
1574 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001575{
Laurence Lundblade37286c02022-09-03 10:05:02 -07001576#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001577 /* Accummulate the tags from multiple items here and then copy them
1578 * into the last item, the non-tag item.
1579 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001580 uint16_t auItemsTags[QCBOR_MAX_TAGS_PER_ITEM];
1581
1582 /* Initialize to CBOR_TAG_INVALID16 */
1583 #if CBOR_TAG_INVALID16 != 0xffff
1584 /* Be sure the memset does the right thing. */
1585 #err CBOR_TAG_INVALID16 tag not defined as expected
1586 #endif
1587 memset(auItemsTags, 0xff, sizeof(auItemsTags));
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001588
Laurence Lundblade9b334962020-08-27 10:55:53 -07001589 QCBORError uReturn = QCBOR_SUCCESS;
1590
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001591 /* Loop fetching data items until the item fetched is not a tag */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001592 for(;;) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001593 QCBORError uErr = QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07001594 if(uErr != QCBOR_SUCCESS) {
1595 uReturn = uErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001596 goto Done;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001597 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001598
Laurence Lundblade9b334962020-08-27 10:55:53 -07001599 if(pDecodedItem->uDataType != QCBOR_TYPE_TAG) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001600 /* Successful exit from loop; maybe got some tags, maybe not */
1601 memcpy(pDecodedItem->uTags, auItemsTags, sizeof(auItemsTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001602 break;
1603 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001604
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001605 if(auItemsTags[QCBOR_MAX_TAGS_PER_ITEM - 1] != CBOR_TAG_INVALID16) {
1606 /* No room in the tag list */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001607 uReturn = QCBOR_ERR_TOO_MANY_TAGS;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001608 /* Continue on to get all tags wrapping this item even though
1609 * it is erroring out in the end. This allows decoding to
1610 * continue. This is a resource limit error, not a problem
1611 * with being well-formed CBOR.
1612 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001613 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001614 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001615 /* Slide tags over one in the array to make room at index 0.
1616 * Must use memmove because the move source and destination
1617 * overlap.
1618 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001619 memmove(&auItemsTags[1],
1620 auItemsTags,
1621 sizeof(auItemsTags) - sizeof(auItemsTags[0]));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001622
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001623 /* Map the tag */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001624 uint16_t uMappedTagNumber = 0;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001625 uReturn = QCBORDecode_Private_MapTagNumber(pMe, pDecodedItem->val.uTagV, &uMappedTagNumber);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001626 /* Continue even on error so as to consume all tags wrapping
1627 * this data item so decoding can go on. If MapTagNumber()
1628 * errors once it will continue to error.
1629 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001630 auItemsTags[0] = uMappedTagNumber;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001631 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001632
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001633Done:
Laurence Lundblade9b334962020-08-27 10:55:53 -07001634 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001635
Laurence Lundblade37286c02022-09-03 10:05:02 -07001636#else /* QCBOR_DISABLE_TAGS */
1637
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07001638 return QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07001639
1640#endif /* QCBOR_DISABLE_TAGS */
1641}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001642
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001643
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001644/**
1645 * @brief Combine a map entry label and value into one item (decode layer 3).
1646 *
1647 * @param[in] pMe Decoder context
1648 * @param[out] pDecodedItem The decoded item that work is done on.
1649 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001650 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1651 * features
1652 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1653 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1654 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1655 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1656 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1657 * of half-precision disabled
1658 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1659 * float decode is disabled.
1660 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1661 * simple type in input.
1662 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1663 * in input, but indefinite
1664 * lengths disabled.
1665 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1666 * but no string allocator.
1667 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1668 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1669 * input, but indefinite-length
1670 * strings are disabled.
1671 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1672 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1673 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001674 *
1675 * If a the current nesting level is a map, then this
1676 * combines pairs of items into one data item with a label
1677 * and value.
1678 *
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07001679 * This is passthrough if the current nesting level is
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001680 * not a map.
1681 *
1682 * This also implements maps-as-array mode where a map
1683 * is treated like an array to allow caller to do their
1684 * own label processing.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001685 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001686static QCBORError
1687QCBORDecode_Private_GetNextMapEntry(QCBORDecodeContext *pMe,
1688 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001689{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001690 QCBORError uReturn = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001691 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001692 goto Done;
1693 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001694
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001695 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
1696 /* Break can't be a map entry */
1697 goto Done;
1698 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001699
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001700 if(pMe->uDecodeMode != QCBOR_DECODE_MODE_MAP_AS_ARRAY) {
1701 /* Normal decoding of maps -- combine label and value into one item. */
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001702
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001703 if(DecodeNesting_IsCurrentTypeMap(&(pMe->nesting))) {
1704 /* Save label in pDecodedItem and get the next which will
1705 * be the real data item.
1706 */
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001707 QCBORItem LabelItem = *pDecodedItem;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001708 uReturn = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001709 if(QCBORDecode_IsUnrecoverableError(uReturn)) {
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001710 goto Done;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07001711 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001712
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301713 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001714
1715 if(LabelItem.uDataType == QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001716 /* strings are always good labels */
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001717 pDecodedItem->label.string = LabelItem.val.string;
1718 pDecodedItem->uLabelType = QCBOR_TYPE_TEXT_STRING;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001719 } else if (QCBOR_DECODE_MODE_MAP_STRINGS_ONLY == pMe->uDecodeMode) {
1720 /* It's not a string and we only want strings */
1721 uReturn = QCBOR_ERR_MAP_LABEL_TYPE;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001722 goto Done;
1723 } else if(LabelItem.uDataType == QCBOR_TYPE_INT64) {
1724 pDecodedItem->label.int64 = LabelItem.val.int64;
1725 pDecodedItem->uLabelType = QCBOR_TYPE_INT64;
1726 } else if(LabelItem.uDataType == QCBOR_TYPE_UINT64) {
1727 pDecodedItem->label.uint64 = LabelItem.val.uint64;
1728 pDecodedItem->uLabelType = QCBOR_TYPE_UINT64;
1729 } else if(LabelItem.uDataType == QCBOR_TYPE_BYTE_STRING) {
1730 pDecodedItem->label.string = LabelItem.val.string;
1731 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
1732 pDecodedItem->uLabelType = QCBOR_TYPE_BYTE_STRING;
1733 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001734 /* label is not an int or a string. It is an arrray
1735 * or a float or such and this implementation doesn't handle that.
1736 * Also, tags on labels are ignored.
1737 */
1738 uReturn = QCBOR_ERR_MAP_LABEL_TYPE;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001739 goto Done;
1740 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001741 }
1742 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001743 /* Decoding of maps as arrays to let the caller decide what to do
1744 * about labels, particularly lables that are not integers or
1745 * strings.
1746 */
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001747 if(pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001748 if(pDecodedItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001749 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001750 goto Done;
1751 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001752 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001753 /* Cast is safe because of check against QCBOR_MAX_ITEMS_IN_ARRAY/2.
1754 * Cast is needed because of integer promotion.
1755 */
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001756 pDecodedItem->val.uCount = (uint16_t)(pDecodedItem->val.uCount * 2);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001757 }
1758 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001759
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001760Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001761 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001762}
1763
1764
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001765#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001766/**
1767 * @brief Peek and see if next data item is a break;
1768 *
1769 * @param[in] pUIB UsefulInputBuf to read from.
1770 * @param[out] pbNextIsBreak Indicate if next was a break or not.
1771 *
1772 * @return Any decoding error.
1773 *
1774 * See if next item is a CBOR break. If it is, it is consumed,
1775 * if not it is not consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07001776*/
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001777static QCBORError
1778QCBOR_Private_NextIsBreak(UsefulInputBuf *pUIB, bool *pbNextIsBreak)
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001779{
1780 *pbNextIsBreak = false;
1781 if(UsefulInputBuf_BytesUnconsumed(pUIB) != 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001782 QCBORItem Peek;
1783 size_t uPeek = UsefulInputBuf_Tell(pUIB);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001784 QCBORError uReturn = QCBOR_Private_DecodeAtomicDataItem(pUIB, &Peek, NULL);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001785 if(uReturn != QCBOR_SUCCESS) {
1786 return uReturn;
1787 }
1788 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001789 /* It is not a break, rewind so it can be processed normally. */
Laurence Lundblade02625d42020-06-25 14:41:41 -07001790 UsefulInputBuf_Seek(pUIB, uPeek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001791 } else {
1792 *pbNextIsBreak = true;
1793 }
1794 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001795
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001796 return QCBOR_SUCCESS;
1797}
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001798#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001799
1800
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001801/**
1802 * @brief Ascend up nesting levels if all items in them have been consumed.
1803 *
1804 * @param[in] pMe The decode context.
1805 * @param[in] bMarkEnd If true mark end of maps/arrays with count of zero.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001806 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001807 *
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001808 * An item was just consumed, now figure out if it was the
1809 * end of an array/map map that can be closed out. That
1810 * may in turn close out the above array/map...
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001811 *
1812 * When ascending indefinite-length arrays and maps, this will correctly
1813 * consume the break for the level above. This is a problem for the
1814 * implementation of QCBORDecode_GetArray() that must not return
1815 * that break. @c pbBreak is set to true to indicate that one
1816 * byte should be removed.
1817 *
1818 * Improvement: this could reduced further if indef is disabled
1819 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001820static QCBORError
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001821QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd, bool *pbBreak)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001822{
1823 QCBORError uReturn;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001824
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001825 /* Loop ascending nesting levels as long as there is ascending to do */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001826 while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001827 if(pbBreak) {
1828 *pbBreak = false;
1829 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001830
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001831 if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) {
1832 /* Nesting level is bstr-wrapped CBOR */
1833
1834 /* Ascent for bstr-wrapped CBOR is always by explicit call
1835 * so no further ascending can happen.
1836 */
1837 break;
1838
1839 } else if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
1840 /* Level is a definite-length array/map */
1841
1842 /* Decrement the item count the definite-length array/map */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001843 DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(&(pMe->nesting));
1844 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001845 /* Didn't close out array/map, so all work here is done */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001846 break;
1847 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001848 /* All items in a definite-length array were consumed so it
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001849 * is time to ascend one level. This happens below.
1850 */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001851
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001852#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001853 } else {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001854 /* Level is an indefinite-length array/map. */
1855
1856 /* Check for a break which is what ends indefinite-length arrays/maps */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001857 bool bIsBreak = false;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001858 uReturn = QCBOR_Private_NextIsBreak(&(pMe->InBuf), &bIsBreak);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001859 if(uReturn != QCBOR_SUCCESS) {
1860 goto Done;
1861 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001862
1863 if(!bIsBreak) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001864 /* Not a break so array/map does not close out. All work is done */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001865 break;
1866 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001867
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001868 /* It was a break in an indefinitelength map / array so
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001869 * it is time to ascend one level.
1870 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001871 if(pbBreak) {
1872 *pbBreak = true;
1873 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001874
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001875#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001876 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001877
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001878
1879 /* All items in the array/map have been consumed. */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001880
Laurence Lundblade93d89472020-10-03 22:30:50 -07001881 /* But ascent in bounded mode is only by explicit call to
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001882 * QCBORDecode_ExitBoundedMode().
1883 */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07001884 if(DecodeNesting_IsCurrentBounded(&(pMe->nesting))) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001885 /* Set the count to zero for definite-length arrays to indicate
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001886 * cursor is at end of bounded array/map */
Laurence Lundbladed0304932020-06-27 10:59:38 -07001887 if(bMarkEnd) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001888 /* Used for definite and indefinite to signal end */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07001889 DecodeNesting_ZeroMapOrArrayCount(&(pMe->nesting));
Laurence Lundbladed0304932020-06-27 10:59:38 -07001890
Laurence Lundblade2c1faf92020-06-26 22:43:56 -07001891 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001892 break;
1893 }
1894
1895 /* Finally, actually ascend one level. */
1896 DecodeNesting_Ascend(&(pMe->nesting));
1897 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001898
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001899 uReturn = QCBOR_SUCCESS;
1900
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001901#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001902Done:
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001903#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1904
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001905 return uReturn;
1906}
1907
1908
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001909/**
1910 * @brief Ascending & Descending out of nesting levels (decode layer 2).
1911 *
1912 * @param[in] pMe Decoder context
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001913 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001914 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001915
1916 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1917 * features
1918 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1919 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1920 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1921 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1922 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1923 * of half-precision disabled
1924 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1925 * float decode is disabled.
1926 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1927 * simple type in input.
1928 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1929 * in input, but indefinite
1930 * lengths disabled.
1931 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1932 * but no string allocator.
1933 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1934 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1935 * input, but indefinite-length
1936 * strings are disabled.
1937 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1938 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1939 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
1940 * @retval QCBOR_ERR_NO_MORE_ITEMS Need more items for map or array.
1941 * @retval QCBOR_ERR_BAD_BREAK Indefinite-length break in wrong
1942 * place.
1943 * @retval QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP Nesting deeper than QCBOR
1944 * can handle.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001945 *
1946 * This handles the traversal descending into and asecnding out of
1947 * maps, arrays and bstr-wrapped CBOR. It figures out the ends of
1948 * definite- and indefinte-length maps and arrays by looking at the
1949 * item count or finding CBOR breaks. It detects the ends of the
1950 * top-level sequence and of bstr-wrapped CBOR by byte count.
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001951 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001952static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001953QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001954 bool *pbBreak,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001955 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001956{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001957 QCBORError uReturn;
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07001958 /* ==== First: figure out if at the end of a traversal ==== */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001959
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001960 /* If out of bytes to consume, it is either the end of the
1961 * top-level sequence of some bstr-wrapped CBOR that was entered.
1962 *
1963 * In the case of bstr-wrapped CBOR, the length of the
1964 * UsefulInputBuf was set to that of the bstr-wrapped CBOR. When
1965 * the bstr-wrapped CBOR is exited, the length is set back to the
1966 * top-level's length or to the next highest bstr-wrapped CBOR.
Laurence Lundblade642282a2020-06-23 12:00:33 -07001967 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001968 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) == 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001969 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001970 goto Done;
1971 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07001972
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001973 /* Check to see if at the end of a bounded definite-length map or
1974 * array. The check for a break ending indefinite-length array is
1975 * later in QCBORDecode_NestLevelAscender().
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001976 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001977 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001978 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07001979 goto Done;
1980 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001981
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001982 /* ==== Next: not at the end, so get another item ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001983 uReturn = QCBORDecode_Private_GetNextMapEntry(pMe, pDecodedItem);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07001984 if(QCBORDecode_IsUnrecoverableError(uReturn)) {
1985 /* Error is so bad that traversal is not possible. */
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001986 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001987 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301988
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001989 /* Breaks ending arrays/maps are processed later in the call to
1990 * QCBORDecode_NestLevelAscender(). They should never show up here.
Laurence Lundblade642282a2020-06-23 12:00:33 -07001991 */
Laurence Lundblade6de37062018-10-15 12:22:42 +05301992 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001993 uReturn = QCBOR_ERR_BAD_BREAK;
Laurence Lundblade6de37062018-10-15 12:22:42 +05301994 goto Done;
Laurence Lundblade5b8c5852018-10-14 21:11:42 +05301995 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001996
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001997 /* Record the nesting level for this data item before processing
1998 * any of decrementing and descending.
Laurence Lundblade642282a2020-06-23 12:00:33 -07001999 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002000 pDecodedItem->uNestingLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002001
Laurence Lundblade642282a2020-06-23 12:00:33 -07002002
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002003 /* ==== Next: Process the item for descent, ascent, decrement... ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002004 if(QCBORItem_IsMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002005 /* If the new item is a map or array, descend.
2006 *
2007 * Empty indefinite-length maps and arrays are descended into,
2008 * but then ascended out of in the next chunk of code.
2009 *
2010 * Maps and arrays do count as items in the map/array that
2011 * encloses them so a decrement needs to be done for them too,
2012 * but that is done only when all the items in them have been
2013 * processed, not when they are opened with the exception of an
2014 * empty map or array.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002015 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002016 QCBORError uDescendErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002017 uDescendErr = DecodeNesting_DescendMapOrArray(&(pMe->nesting),
Laurence Lundblade642282a2020-06-23 12:00:33 -07002018 pDecodedItem->uDataType,
2019 pDecodedItem->val.uCount);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002020 if(uDescendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002021 /* This error is probably a traversal error and it overrides
2022 * the non-traversal error.
2023 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002024 uReturn = uDescendErr;
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002025 goto Done;
2026 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002027 }
2028
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002029 if(!QCBORItem_IsMapOrArray(*pDecodedItem) ||
2030 QCBORItem_IsEmptyDefiniteLengthMapOrArray(*pDecodedItem) ||
2031 QCBORItem_IsIndefiniteLengthMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002032 /* The following cases are handled here:
2033 * - A non-aggregate item like an integer or string
2034 * - An empty definite-length map or array
2035 * - An indefinite-length map or array that might be empty or might not.
2036 *
2037 * QCBORDecode_NestLevelAscender() does the work of decrementing the count
2038 * for an definite-length map/array and break detection for an
2039 * indefinite-0length map/array. If the end of the map/array was
2040 * reached, then it ascends nesting levels, possibly all the way
2041 * to the top level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002042 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002043 QCBORError uAscendErr;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002044 uAscendErr = QCBORDecode_Private_NestLevelAscender(pMe, true, pbBreak);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002045 if(uAscendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002046 /* This error is probably a traversal error and it overrides
2047 * the non-traversal error.
2048 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002049 uReturn = uAscendErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002050 goto Done;
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002051 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05302052 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002053
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002054 /* ==== Last: tell the caller the nest level of the next item ==== */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002055 /* Tell the caller what level is next. This tells them what
2056 * maps/arrays were closed out and makes it possible for them to
2057 * reconstruct the tree with just the information returned in a
2058 * QCBORItem.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002059 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002060 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07002061 /* At end of a bounded map/array; uNextNestLevel 0 to indicate this */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002062 pDecodedItem->uNextNestLevel = 0;
2063 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002064 pDecodedItem->uNextNestLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002065 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002066
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002067Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002068 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002069}
2070
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002071
Laurence Lundblade37286c02022-09-03 10:05:02 -07002072#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002073/**
2074 * @brief Shift 0th tag out of the tag list.
2075 *
2076 * pDecodedItem[in,out] The data item to convert.
2077 *
2078 * The 0th tag is discarded. \ref CBOR_TAG_INVALID16 is
2079 * shifted into empty slot at the end of the tag list.
2080 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002081static void
2082QCBOR_Private_ShiftTags(QCBORItem *pDecodedItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002083{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002084 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM-1; i++) {
2085 pDecodedItem->uTags[i] = pDecodedItem->uTags[i+1];
2086 }
2087 pDecodedItem->uTags[QCBOR_MAX_TAGS_PER_ITEM-1] = CBOR_TAG_INVALID16;
Laurence Lundblade9b334962020-08-27 10:55:53 -07002088}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002089#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002090
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002091
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002092/**
2093 * @brief Convert different epoch date formats in to the QCBOR epoch date format
2094 *
2095 * pDecodedItem[in,out] The data item to convert.
2096 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002097 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2098 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2099 * floating-point date disabled.
2100 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2101 * all floating-point disabled.
2102 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2103 * error decoding date.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002104 *
2105 * The epoch date tag defined in QCBOR allows for floating-point
2106 * dates. It even allows a protocol to flop between date formats when
2107 * ever it wants. Floating-point dates aren't that useful as they are
2108 * only needed for dates beyond the age of the earth.
2109 *
2110 * This converts all the date formats into one format of an unsigned
2111 * integer plus a floating-point fraction.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002112 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002113static QCBORError
2114QCBOR_Private_DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002115{
Laurence Lundbladec7114722020-08-13 05:11:40 -07002116 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002117
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002118#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade59289e52019-12-30 13:44:37 -08002119 pDecodedItem->val.epochDate.fSecondsFraction = 0;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002120#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002121
2122 switch (pDecodedItem->uDataType) {
2123
2124 case QCBOR_TYPE_INT64:
2125 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
2126 break;
2127
2128 case QCBOR_TYPE_UINT64:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002129 /* This only happens for CBOR type 0 > INT64_MAX so it is
2130 * always an overflow.
2131 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07002132 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2133 goto Done;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002134 break;
2135
2136 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade9682a532020-06-06 18:33:04 -07002137 case QCBOR_TYPE_FLOAT:
2138#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade59289e52019-12-30 13:44:37 -08002139 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002140 /* Convert working value to double if input was a float */
Laurence Lundblade3ed0bca2020-07-14 22:50:10 -07002141 const double d = pDecodedItem->uDataType == QCBOR_TYPE_DOUBLE ?
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002142 pDecodedItem->val.dfnum :
2143 (double)pDecodedItem->val.fnum;
2144
2145 /* The conversion from float to integer requires overflow
2146 * detection since floats can be much larger than integers.
2147 * This implementation errors out on these large float values
2148 * since they are beyond the age of the earth.
2149 *
2150 * These constants for the overflow check are computed by the
2151 * compiler. They are not computed at run time.
2152 *
2153 * The factor of 0x7ff is added/subtracted to avoid a
2154 * rounding error in the wrong direction when the compiler
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002155 * computes these constants. There is rounding because a
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002156 * 64-bit integer has 63 bits of precision where a double
2157 * only has 53 bits. Without the 0x7ff factor, the compiler
2158 * may round up and produce a double for the bounds check
2159 * that is larger than can be stored in a 64-bit integer. The
2160 * amount of 0x7ff is picked because it has 11 bits set.
2161 *
2162 * Without the 0x7ff there is a ~30 minute range of time
2163 * values 10 billion years in the past and in the future
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002164 * where this code could go wrong. Some compilers
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002165 * generate a warning or error without the 0x7ff.
2166 */
2167 const double dDateMax = (double)(INT64_MAX - 0x7ff);
2168 const double dDateMin = (double)(INT64_MIN + 0x7ff);
2169
2170 if(isnan(d) || d > dDateMax || d < dDateMin) {
Laurence Lundbladec7114722020-08-13 05:11:40 -07002171 uReturn = QCBOR_ERR_DATE_OVERFLOW;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002172 goto Done;
2173 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002174
2175 /* The actual conversion */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002176 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
Laurence Lundblade2feb1e12020-07-15 03:50:45 -07002177 pDecodedItem->val.epochDate.fSecondsFraction =
2178 d - (double)pDecodedItem->val.epochDate.nSeconds;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002179 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002180#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade4b270642020-08-14 12:53:07 -07002181
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002182 uReturn = QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundblade4b270642020-08-14 12:53:07 -07002183 goto Done;
2184
Laurence Lundblade9682a532020-06-06 18:33:04 -07002185#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002186 break;
2187
2188 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002189 /* It's the arrays and maps that are unrecoverable because
2190 * they are not consumed here. Since this is just an error
2191 * condition, no extra code is added here to make the error
2192 * recoverable for non-arrays and maps like strings. */
2193 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002194 goto Done;
2195 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002196
Laurence Lundblade59289e52019-12-30 13:44:37 -08002197 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
2198
2199Done:
Laurence Lundbladec7114722020-08-13 05:11:40 -07002200 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002201}
2202
2203
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002204/**
2205 * @brief Convert the days epoch date.
2206 *
2207 * pDecodedItem[in,out] The data item to convert.
2208 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002209 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2210 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2211 * floating-point date disabled.
2212 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2213 * all floating-point disabled.
2214 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2215 * error decoding date.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002216 *
2217 * This is much simpler than the other epoch date format because
2218 * floating-porint is not allowed. This is mostly a simple type check.
2219 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002220static QCBORError
2221QCBOR_Private_DecodeDaysEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002222{
2223 QCBORError uReturn = QCBOR_SUCCESS;
2224
2225 switch (pDecodedItem->uDataType) {
2226
2227 case QCBOR_TYPE_INT64:
2228 pDecodedItem->val.epochDays = pDecodedItem->val.int64;
2229 break;
2230
2231 case QCBOR_TYPE_UINT64:
2232 /* This only happens for CBOR type 0 > INT64_MAX so it is
2233 * always an overflow.
2234 */
2235 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2236 goto Done;
2237 break;
2238
2239 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002240 /* It's the arrays and maps that are unrecoverable because
2241 * they are not consumed here. Since this is just an error
2242 * condition, no extra code is added here to make the error
2243 * recoverable for non-arrays and maps like strings. */
2244 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002245 goto Done;
2246 break;
2247 }
2248
2249 pDecodedItem->uDataType = QCBOR_TYPE_DAYS_EPOCH;
2250
2251Done:
2252 return uReturn;
2253}
2254
2255
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002256#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade37286c02022-09-03 10:05:02 -07002257
2258/* Forward declaration is necessary for
2259 * QCBORDecode_MantissaAndExponent(). to be able to decode bignum
2260 * tags in the mantissa. If the mantissa is a decimal fraction or big
2261 * float in error, this will result in a recurive call to
2262 * QCBORDecode_MantissaAndExponent(), but the recursion will unwined
2263 * correctly and the correct error is returned.
2264 */
2265static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002266QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2267 QCBORItem *pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002268
2269
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002270/**
2271 * @brief Decode decimal fractions and big floats.
2272 *
2273 * @param[in] pMe The decode context.
2274 * @param[in,out] pDecodedItem On input the array data item that
2275 * holds the mantissa and exponent. On
2276 * output the decoded mantissa and
2277 * exponent.
2278 *
2279 * @returns Decoding errors from getting primitive data items or
2280 * \ref QCBOR_ERR_BAD_EXP_AND_MANTISSA.
2281 *
Laurence Lundblade37286c02022-09-03 10:05:02 -07002282 * When called pDecodedItem must be the array with two members, the
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002283 * exponent and mantissa.
2284 *
2285 * This will fetch and decode the exponent and mantissa and put the
2286 * result back into pDecodedItem.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002287 *
2288 * This does no checking or processing of tag numbers. That is to be
2289 * done by the code that calls this.
2290 *
2291 * This stuffs the type of the mantissa into pDecodedItem with the expectation
2292 * the caller will process it.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002293 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002294static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002295QCBORDecode_Private_ExpMantissa(QCBORDecodeContext *pMe,
2296 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002297{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002298 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002299
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002300 /* --- Make sure it is an array; track nesting level of members --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002301 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002302 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002303 goto Done;
2304 }
2305
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002306 /* A check for pDecodedItem->val.uCount == 2 would work for
Laurence Lundblade37286c02022-09-03 10:05:02 -07002307 * definite-length arrays, but not for indefinite. Instead remember
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002308 * the nesting level the two integers must be at, which is one
2309 * deeper than that of the array.
2310 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002311 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
2312
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002313 /* --- Get the exponent --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002314 QCBORItem exponentItem;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002315 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, &exponentItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002316 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002317 goto Done;
2318 }
2319 if(exponentItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002320 /* Array is empty or a map/array encountered when expecting an int */
2321 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002322 goto Done;
2323 }
2324 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002325 /* Data arriving as an unsigned int < INT64_MAX has been
2326 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2327 * also means that the only data arriving here of type
2328 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2329 * and thus an error that will get handled in the next else.
2330 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002331 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
2332 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002333 /* Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX */
2334 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002335 goto Done;
2336 }
2337
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002338 /* --- Get the mantissa --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002339 QCBORItem mantissaItem;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002340 uReturn = QCBORDecode_Private_GetNextTagContent(pMe, &mantissaItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002341 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002342 goto Done;
2343 }
2344 if(mantissaItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002345 /* Mantissa missing or map/array encountered when expecting number */
2346 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002347 goto Done;
2348 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002349 /* Stuff the mantissa data type into the item to send it up to the
2350 * the next level. */
2351 pDecodedItem->uDataType = mantissaItem.uDataType;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002352 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002353 /* Data arriving as an unsigned int < INT64_MAX has been
2354 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2355 * also means that the only data arriving here of type
2356 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2357 * and thus an error that will get handled in an else below.
2358 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002359 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002360#ifndef QCBOR_DISABLE_TAGS
2361 /* With tags fully disabled a big number mantissa will error out
2362 * in the call to QCBORDecode_GetNextWithTags() because it has
2363 * a tag number.
2364 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07002365 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM ||
2366 mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002367 /* Got a good big num mantissa */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002368 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002369#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002370 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002371 /* Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX */
2372 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002373 goto Done;
2374 }
2375
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002376 /* --- Check that array only has the two numbers --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002377 if(mantissaItem.uNextNestLevel == nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002378 /* Extra items in the decimal fraction / big float */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002379 /* Improvement: this should probably be an unrecoverable error. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002380 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002381 goto Done;
2382 }
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002383 pDecodedItem->uNextNestLevel = mantissaItem.uNextNestLevel;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002384
2385Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002386 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002387}
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002388#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002389
2390
Laurence Lundblade37286c02022-09-03 10:05:02 -07002391#ifndef QCBOR_DISABLE_TAGS
2392
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002393#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002394/**
2395 * @brief Decode the MIME type tag
2396 *
2397 * @param[in,out] pDecodedItem The item to decode.
2398 *
2399 * Handle the text and binary MIME type tags. Slightly too complicated
2400 * f or ProcessTaggedString() because the RFC 7049 MIME type was
2401 * incorreclty text-only.
2402 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002403static QCBORError
2404QCBOR_Private_DecodeMIME(QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002405{
2406 if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) {
2407 pDecodedItem->uDataType = QCBOR_TYPE_MIME;
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07002408 } else if(pDecodedItem->uDataType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002409 pDecodedItem->uDataType = QCBOR_TYPE_BINARY_MIME;
2410 } else {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002411 /* It's the arrays and maps that are unrecoverable because
2412 * they are not consumed here. Since this is just an error
2413 * condition, no extra code is added here to make the error
2414 * recoverable for non-arrays and maps like strings. */
2415 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002416 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002417
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002418 return QCBOR_SUCCESS;
2419}
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002420#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002421
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002422/**
Laurence Lundblade99615302020-11-29 11:19:47 -08002423 * Table of CBOR tags whose content is either a text string or a byte
2424 * string. The table maps the CBOR tag to the QCBOR type. The high-bit
2425 * of uQCBORtype indicates the content should be a byte string rather
2426 * than a text string
2427 */
2428struct StringTagMapEntry {
2429 uint16_t uTagNumber;
2430 uint8_t uQCBORtype;
2431};
2432
2433#define IS_BYTE_STRING_BIT 0x80
2434#define QCBOR_TYPE_MASK ~IS_BYTE_STRING_BIT
2435
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002436static const struct StringTagMapEntry QCBOR_Private_StringTagMap[] = {
Laurence Lundblade99615302020-11-29 11:19:47 -08002437 {CBOR_TAG_DATE_STRING, QCBOR_TYPE_DATE_STRING},
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002438 {CBOR_TAG_DAYS_STRING, QCBOR_TYPE_DAYS_STRING},
Laurence Lundblade99615302020-11-29 11:19:47 -08002439 {CBOR_TAG_POS_BIGNUM, QCBOR_TYPE_POSBIGNUM | IS_BYTE_STRING_BIT},
2440 {CBOR_TAG_NEG_BIGNUM, QCBOR_TYPE_NEGBIGNUM | IS_BYTE_STRING_BIT},
2441 {CBOR_TAG_CBOR, QBCOR_TYPE_WRAPPED_CBOR | IS_BYTE_STRING_BIT},
2442 {CBOR_TAG_URI, QCBOR_TYPE_URI},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002443#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002444 {CBOR_TAG_B64URL, QCBOR_TYPE_BASE64URL},
2445 {CBOR_TAG_B64, QCBOR_TYPE_BASE64},
2446 {CBOR_TAG_REGEX, QCBOR_TYPE_REGEX},
2447 {CBOR_TAG_BIN_UUID, QCBOR_TYPE_UUID | IS_BYTE_STRING_BIT},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002448#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade99615302020-11-29 11:19:47 -08002449 {CBOR_TAG_CBOR_SEQUENCE, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE | IS_BYTE_STRING_BIT},
2450 {CBOR_TAG_INVALID16, QCBOR_TYPE_NONE}
2451};
2452
2453
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002454/**
2455 * @brief Process standard CBOR tags whose content is a string
2456 *
2457 * @param[in] uTag The tag.
2458 * @param[in,out] pDecodedItem The data item.
2459 *
2460 * @returns This returns QCBOR_SUCCESS if the tag was procssed,
2461 * \ref QCBOR_ERR_UNSUPPORTED if the tag was not processed and
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002462 * \ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT if the content type was wrong for the tag.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002463 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002464 * Process the CBOR tags that whose content is a byte string or a text
2465 * string and for which the string is just passed on to the caller.
2466 *
2467 * This maps the CBOR tag to the QCBOR type and checks the content
2468 * type. Nothing more. It may not be the most important
Laurence Lundbladec02e13e2020-12-06 05:45:41 -08002469 * functionality, but it part of implementing as much of RFC 8949 as
Laurence Lundblade99615302020-11-29 11:19:47 -08002470 * possible.
Laurence Lundblade99615302020-11-29 11:19:47 -08002471 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002472static QCBORError
2473QCBOR_Private_ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002474{
Laurence Lundblade99615302020-11-29 11:19:47 -08002475 /* This only works on tags that were not mapped; no need for other yet */
2476 if(uTag > QCBOR_LAST_UNMAPPED_TAG) {
2477 return QCBOR_ERR_UNSUPPORTED;
2478 }
2479
2480 unsigned uIndex;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002481 for(uIndex = 0; QCBOR_Private_StringTagMap[uIndex].uTagNumber != CBOR_TAG_INVALID16; uIndex++) {
2482 if(QCBOR_Private_StringTagMap[uIndex].uTagNumber == uTag) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002483 break;
2484 }
2485 }
2486
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002487 const uint8_t uQCBORType = QCBOR_Private_StringTagMap[uIndex].uQCBORtype;
Laurence Lundblade99615302020-11-29 11:19:47 -08002488 if(uQCBORType == QCBOR_TYPE_NONE) {
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002489 /* repurpose this error to mean not handled here */
Laurence Lundblade99615302020-11-29 11:19:47 -08002490 return QCBOR_ERR_UNSUPPORTED;
2491 }
2492
2493 uint8_t uExpectedType = QCBOR_TYPE_TEXT_STRING;
2494 if(uQCBORType & IS_BYTE_STRING_BIT) {
2495 uExpectedType = QCBOR_TYPE_BYTE_STRING;
2496 }
2497
2498 if(pDecodedItem->uDataType != uExpectedType) {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002499 /* It's the arrays and maps that are unrecoverable because
2500 * they are not consumed here. Since this is just an error
2501 * condition, no extra code is added here to make the error
2502 * recoverable for non-arrays and maps like strings. */
2503 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002504 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002505
Laurence Lundblade99615302020-11-29 11:19:47 -08002506 pDecodedItem->uDataType = (uint8_t)(uQCBORType & QCBOR_TYPE_MASK);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002507 return QCBOR_SUCCESS;
2508}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002509#endif /* QCBOR_DISABLE_TAGS */
2510
2511
2512#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002513/**
2514 * @brief Figures out data type for exponent mantissa tags.
2515 *
2516 * @param[in] uTagToProcess Either @ref CBOR_TAG_DECIMAL_FRACTION or
2517 * @ref CBOR_TAG_BIG_FLOAT.
2518 * @param[in] pDecodedItem Item being decoded.
2519 *
2520 * @returns One of the 6 values between \ref QCBOR_TYPE_DECIMAL_FRACTION
2521 * and @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM.
2522 *
2523 * Does mapping between a CBOR tag number and a QCBOR type. with a
2524 * little bit of logic and arithmatic.
2525 *
2526 * Used in serveral contexts. Does the work where sometimes the data
2527 * item is explicitly tagged and sometimes not.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002528 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002529static uint8_t
2530QCBOR_Private_ExpMantissaDataType(const uint16_t uTagToProcess,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002531 const QCBORItem *pDecodedItem)
Laurence Lundblade37286c02022-09-03 10:05:02 -07002532{
2533 uint8_t uBase = uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ?
2534 QCBOR_TYPE_DECIMAL_FRACTION :
2535 QCBOR_TYPE_BIGFLOAT;
2536 if(pDecodedItem->uDataType != QCBOR_TYPE_INT64) {
2537 uBase = (uint8_t)(uBase + pDecodedItem->uDataType - QCBOR_TYPE_POSBIGNUM + 1);
2538 }
2539 return uBase;
2540}
2541#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002542
2543
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002544/**
2545 * @brief Decode tag content for select tags (decoding layer 1).
2546 *
2547 * @param[in] pMe The decode context.
2548 * @param[out] pDecodedItem The decoded item.
2549 *
2550 * @return Decoding error code.
2551 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002552 * CBOR tag numbers for the item were decoded in GetNext_TaggedItem(),
2553 * but the whole tag was not decoded. Here, the whole tags (tag number
2554 * and tag content) that are supported by QCBOR are decoded. This is a
2555 * quick pass through for items that are not tags.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002556 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002557static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002558QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2559 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002560{
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002561 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002562
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002563 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pDecodedItem);
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002564 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002565 goto Done;
2566 }
2567
Laurence Lundblade37286c02022-09-03 10:05:02 -07002568#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002569 /* When there are no tag numbers for the item, this exits first
2570 * thing and effectively does nothing.
2571 *
2572 * This loops over all the tag numbers accumulated for this item
2573 * trying to decode and interpret them. This stops at the end of
2574 * the list or at the first tag number that can't be interpreted by
2575 * this code. This is effectively a recursive processing of the
2576 * tags number list that handles nested tags.
2577 */
2578 while(1) {
2579 /* Don't bother to unmap tags via QCBORITem.uTags since this
2580 * code only works on tags less than QCBOR_LAST_UNMAPPED_TAG.
2581 */
2582 const uint16_t uTagToProcess = pDecodedItem->uTags[0];
Laurence Lundblade59289e52019-12-30 13:44:37 -08002583
Laurence Lundblade99615302020-11-29 11:19:47 -08002584 if(uTagToProcess == CBOR_TAG_INVALID16) {
2585 /* Hit the end of the tag list. A successful exit. */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002586 break;
2587
Laurence Lundblade99615302020-11-29 11:19:47 -08002588 } else if(uTagToProcess == CBOR_TAG_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002589 uReturn = QCBOR_Private_DecodeDateEpoch(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002590
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002591 } else if(uTagToProcess == CBOR_TAG_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002592 uReturn = QCBOR_Private_DecodeDaysEpoch(pDecodedItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002593
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002594#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade99615302020-11-29 11:19:47 -08002595 } else if(uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ||
2596 uTagToProcess == CBOR_TAG_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002597 uReturn = QCBORDecode_Private_ExpMantissa(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002598 /* --- Which is it, decimal fraction or a bigfloat? --- */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002599 pDecodedItem->uDataType = QCBOR_Private_ExpMantissaDataType(uTagToProcess, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002600
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002601#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002602#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002603 } else if(uTagToProcess == CBOR_TAG_MIME ||
2604 uTagToProcess == CBOR_TAG_BINARY_MIME) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002605 uReturn = QCBOR_Private_DecodeMIME(pDecodedItem);
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002606#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002607
Laurence Lundblade99615302020-11-29 11:19:47 -08002608 } else {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002609 /* See if it is a passthrough byte/text string tag; process if so */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002610 uReturn = QCBOR_Private_ProcessTaggedString(pDecodedItem->uTags[0], pDecodedItem);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002611
Laurence Lundblade99615302020-11-29 11:19:47 -08002612 if(uReturn == QCBOR_ERR_UNSUPPORTED) {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002613 /* It wasn't a passthrough byte/text string tag so it is
Laurence Lundblade99615302020-11-29 11:19:47 -08002614 * an unknown tag. This is the exit from the loop on the
2615 * first unknown tag. It is a successful exit.
2616 */
2617 uReturn = QCBOR_SUCCESS;
2618 break;
2619 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002620 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002621
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002622 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002623 /* Error exit from the loop */
2624 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002625 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002626
2627 /* A tag was successfully processed, shift it out of the list of
2628 * tags returned. This is the loop increment.
2629 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002630 QCBOR_Private_ShiftTags(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002631 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002632#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002633
2634Done:
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002635 return uReturn;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002636}
2637
2638
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002639/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002640 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002641 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002642QCBORError
2643QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2644{
2645 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002646 uErr = QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002647 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002648 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2649 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
2650 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002651 return uErr;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002652}
2653
2654
2655/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002656 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08002657 */
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002658QCBORError
2659QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2660{
2661 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2662 const UsefulInputBuf Save = pMe->InBuf;
2663
2664 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
2665
2666 pMe->nesting = SaveNesting;
2667 pMe->InBuf = Save;
2668
2669 return uErr;
2670}
2671
2672
2673/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002674 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002675 */
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002676void
2677QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2678{
2679 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002680 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2681 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002682 return;
2683 }
2684
2685 pMe->uLastError = (uint8_t)QCBORDecode_PeekNext(pMe, pDecodedItem);
2686}
2687
2688
2689/*
2690 * Public function, see header qcbor/qcbor_decode.h file
2691 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002692void
2693QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002694{
2695 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002696 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2697 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002698 return;
2699 }
2700
2701 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem);
2702}
2703
2704
2705/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002706 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002707 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002708QCBORError
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002709QCBORDecode_GetNextWithTags(QCBORDecodeContext *pMe,
2710 QCBORItem *pDecodedItem,
2711 QCBORTagListOut *pTags)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002712{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002713#ifndef QCBOR_DISABLE_TAGS
2714
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002715 QCBORError uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002716
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002717 uReturn = QCBORDecode_GetNext(pMe, pDecodedItem);
2718 if(uReturn != QCBOR_SUCCESS) {
2719 return uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002720 }
2721
2722 if(pTags != NULL) {
2723 pTags->uNumUsed = 0;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002724 /* Reverse the order because pTags is reverse of QCBORItem.uTags. */
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002725 for(int nTagIndex = QCBOR_MAX_TAGS_PER_ITEM-1; nTagIndex >=0; nTagIndex--) {
2726 if(pDecodedItem->uTags[nTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07002727 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002728 }
2729 if(pTags->uNumUsed >= pTags->uNumAllocated) {
2730 return QCBOR_ERR_TOO_MANY_TAGS;
2731 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002732 pTags->puTags[pTags->uNumUsed] = QCBORDecode_Private_UnMapTagNumber(pMe,pDecodedItem->uTags[nTagIndex]);
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002733 pTags->uNumUsed++;
2734 }
2735 }
2736
2737 return QCBOR_SUCCESS;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002738
2739#else /* QCBOR_DISABLE_TAGS */
2740 (void)pMe;
2741 (void)pDecodedItem;
2742 (void)pTags;
2743 return QCBOR_ERR_TAGS_DISABLED;
2744#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002745}
2746
2747
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002748/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002749 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05302750 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002751bool
2752QCBORDecode_IsTagged(QCBORDecodeContext *pMe,
2753 const QCBORItem *pItem,
2754 uint64_t uTag)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002755{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002756#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002757 for(unsigned uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) {
2758 if(pItem->uTags[uTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002759 break;
2760 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002761 if(QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uTagIndex]) == uTag) {
Laurence Lundbladef71e1622020-08-06 18:52:13 -07002762 return true;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002763 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002764 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002765#else /* QCBOR_TAGS_DISABLED */
2766 (void)pMe;
2767 (void)pItem;
2768 (void)uTag;
2769#endif /* QCBOR_TAGS_DISABLED */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002770
Laurence Lundbladef71e1622020-08-06 18:52:13 -07002771 return false;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002772}
2773
2774
2775/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002776 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002777 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002778QCBORError
2779QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002780{
Laurence Lundblade87495732021-02-26 10:05:55 -07002781 if(puConsumed != NULL) {
2782 *puConsumed = pMe->InBuf.cursor;
2783 }
2784
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002785 QCBORError uReturn = pMe->uLastError;
Laurence Lundblade085d7952020-07-24 10:26:30 -07002786
2787 if(uReturn != QCBOR_SUCCESS) {
2788 goto Done;
2789 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002790
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002791 /* Error out if all the maps/arrays are not closed out */
2792 if(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002793 uReturn = QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002794 goto Done;
2795 }
2796
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002797 /* Error out if not all the bytes are consumed */
2798 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf))) {
Laurence Lundblade085d7952020-07-24 10:26:30 -07002799 uReturn = QCBOR_ERR_EXTRA_BYTES;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002800 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002801
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002802Done:
Laurence Lundblade87495732021-02-26 10:05:55 -07002803 return uReturn;
2804}
2805
2806
2807/*
2808 * Public function, see header qcbor/qcbor_decode.h file
2809 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002810QCBORError
2811QCBORDecode_Finish(QCBORDecodeContext *pMe)
Laurence Lundblade87495732021-02-26 10:05:55 -07002812{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002813#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002814 /* Call the destructor for the string allocator if there is one.
2815 * Always called, even if there are errors; always have to clean up.
2816 */
2817 StringAllocator_Destruct(&(pMe->StringAllocator));
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002818#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002819
Laurence Lundblade87495732021-02-26 10:05:55 -07002820 return QCBORDecode_PartialFinish(pMe, NULL);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002821}
2822
2823
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002824/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002825 * Public function, see header qcbor/qcbor_decode.h file
2826 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002827uint64_t
2828QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
2829 const QCBORItem *pItem,
2830 uint32_t uIndex)
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002831{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002832#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002833 if(pItem->uDataType == QCBOR_TYPE_NONE) {
2834 return CBOR_TAG_INVALID64;
2835 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002836 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2837 return CBOR_TAG_INVALID64;
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002838 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002839 return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uIndex]);
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002840 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002841#else /* QCBOR_DISABLE_TAGS */
2842 (void)pMe;
2843 (void)pItem;
2844 (void)uIndex;
2845
2846 return CBOR_TAG_INVALID64;
2847#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002848}
2849
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002850
Laurence Lundblade9b334962020-08-27 10:55:53 -07002851/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002852 * Public function, see header qcbor/qcbor_decode.h file
2853 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002854uint64_t
2855QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe,
2856 uint32_t uIndex)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002857{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002858#ifndef QCBOR_DISABLE_TAGS
2859
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002860 if(pMe->uLastError != QCBOR_SUCCESS) {
2861 return CBOR_TAG_INVALID64;
2862 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002863 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2864 return CBOR_TAG_INVALID64;
2865 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002866 return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->uLastTags[uIndex]);
Laurence Lundblade9b334962020-08-27 10:55:53 -07002867 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002868#else /* QCBOR_DISABLE_TAGS */
2869 (void)pMe;
2870 (void)uIndex;
2871
2872 return CBOR_TAG_INVALID64;
2873#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07002874}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002875
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002876
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002877
2878
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002879#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladef6531662018-12-04 10:42:22 +09002880
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002881/* ===========================================================================
2882 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002883
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002884 This implements a simple sting allocator for indefinite-length
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002885 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
2886 implements the function type QCBORStringAllocate and allows easy
2887 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09002888
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002889 This particular allocator is built-in for convenience. The caller
2890 can implement their own. All of this following code will get
2891 dead-stripped if QCBORDecode_SetMemPool() is not called.
2892
2893 This is a very primitive memory allocator. It does not track
2894 individual allocations, only a high-water mark. A free or
2895 reallocation must be of the last chunk allocated.
2896
2897 The size of the pool and offset to free memory are packed into the
2898 first 8 bytes of the memory pool so we don't have to keep them in
2899 the decode context. Since the address of the pool may not be
2900 aligned, they have to be packed and unpacked as if they were
2901 serialized data of the wire or such.
2902
2903 The sizes packed in are uint32_t to be the same on all CPU types
2904 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08002905 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002906
2907
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002908static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08002909MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002910{
2911 // Use of UsefulInputBuf is overkill, but it is convenient.
2912 UsefulInputBuf UIB;
2913
Laurence Lundbladeee851742020-01-08 08:37:05 -08002914 // Just assume the size here. It was checked during SetUp so
2915 // the assumption is safe.
Laurence Lundblade93d89472020-10-03 22:30:50 -07002916 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem,QCBOR_DECODE_MIN_MEM_POOL_SIZE});
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002917 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
2918 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
2919 return UsefulInputBuf_GetError(&UIB);
2920}
2921
2922
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002923static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08002924MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002925{
2926 // Use of UsefulOutBuf is overkill, but convenient. The
2927 // length check performed here is useful.
2928 UsefulOutBuf UOB;
2929
2930 UsefulOutBuf_Init(&UOB, Pool);
2931 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
2932 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
2933 return UsefulOutBuf_GetError(&UOB);
2934}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002935
2936
2937/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002938 Internal function for an allocation, reallocation free and destuct.
2939
2940 Having only one function rather than one each per mode saves space in
2941 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002942
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002943 Code Reviewers: THIS FUNCTION DOES POINTER MATH
2944 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08002945static UsefulBuf
2946MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002947{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002948 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002949
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002950 uint32_t uPoolSize;
2951 uint32_t uFreeOffset;
2952
2953 if(uNewSize > UINT32_MAX) {
2954 // This allocator is only good up to 4GB. This check should
2955 // optimize out if sizeof(size_t) == sizeof(uint32_t)
2956 goto Done;
2957 }
2958 const uint32_t uNewSize32 = (uint32_t)uNewSize;
2959
2960 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
2961 goto Done;
2962 }
2963
2964 if(uNewSize) {
2965 if(pMem) {
2966 // REALLOCATION MODE
2967 // Calculate pointer to the end of the memory pool. It is
2968 // assumed that pPool + uPoolSize won't wrap around by
2969 // assuming the caller won't pass a pool buffer in that is
2970 // not in legitimate memory space.
2971 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
2972
2973 // Check that the pointer for reallocation is in the range of the
2974 // pool. This also makes sure that pointer math further down
2975 // doesn't wrap under or over.
2976 if(pMem >= pPool && pMem < pPoolEnd) {
2977 // Offset to start of chunk for reallocation. This won't
2978 // wrap under because of check that pMem >= pPool. Cast
2979 // is safe because the pool is always less than UINT32_MAX
2980 // because of check in QCBORDecode_SetMemPool().
2981 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
2982
2983 // Check to see if the allocation will fit. uPoolSize -
2984 // uMemOffset will not wrap under because of check that
2985 // pMem is in the range of the uPoolSize by check above.
2986 if(uNewSize <= uPoolSize - uMemOffset) {
2987 ReturnValue.ptr = pMem;
2988 ReturnValue.len = uNewSize;
2989
2990 // Addition won't wrap around over because uNewSize was
2991 // checked to be sure it is less than the pool size.
2992 uFreeOffset = uMemOffset + uNewSize32;
2993 }
2994 }
2995 } else {
2996 // ALLOCATION MODE
2997 // uPoolSize - uFreeOffset will not underflow because this
2998 // pool implementation makes sure uFreeOffset is always
2999 // smaller than uPoolSize through this check here and
3000 // reallocation case.
3001 if(uNewSize <= uPoolSize - uFreeOffset) {
3002 ReturnValue.len = uNewSize;
3003 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08003004 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003005 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003006 }
3007 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003008 if(pMem) {
3009 // FREE MODE
3010 // Cast is safe because of limit on pool size in
3011 // QCBORDecode_SetMemPool()
3012 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3013 } else {
3014 // DESTRUCT MODE
3015 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003016 }
3017 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003018
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003019 UsefulBuf Pool = {pPool, uPoolSize};
3020 MemPool_Pack(Pool, uFreeOffset);
3021
3022Done:
3023 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003024}
3025
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003026
Laurence Lundbladef6531662018-12-04 10:42:22 +09003027/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003028 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09003029 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003030QCBORError
3031QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
3032 UsefulBuf Pool,
3033 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003034{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003035 // The pool size and free mem offset are packed into the beginning
Dave Thaler93c01182022-08-06 15:08:35 -04003036 // of the pool memory. This compile time check makes sure the
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003037 // constant in the header is correct. This check should optimize
3038 // down to nothing.
Dave Thaler93c01182022-08-06 15:08:35 -04003039#ifdef _MSC_VER
3040#pragma warning(push)
3041#pragma warning(disable:4127) // conditional expression is constant
3042#endif
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003043 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003044 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003045 }
Dave Thaler93c01182022-08-06 15:08:35 -04003046#ifdef _MSC_VER
3047#pragma warning(pop)
3048#endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003049
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003050 // The pool size and free offset packed in to the beginning of pool
3051 // memory are only 32-bits. This check will optimize out on 32-bit
3052 // machines.
3053 if(Pool.len > UINT32_MAX) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003054 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003055 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003056
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003057 // This checks that the pool buffer given is big enough.
3058 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003059 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003060 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003061
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003062 QCBORDecode_SetUpAllocator(pMe, MemPool_Function, Pool.ptr, bAllStrings);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003063
Laurence Lundblade30816f22018-11-10 13:40:22 +07003064 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003065}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003066#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003067
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003068
3069
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003070static void
3071QCBORDecode_Private_CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07003072{
Laurence Lundblade37286c02022-09-03 10:05:02 -07003073#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade9b334962020-08-27 10:55:53 -07003074 memcpy(pMe->uLastTags, pItem->uTags, sizeof(pItem->uTags));
Laurence Lundblade37286c02022-09-03 10:05:02 -07003075#else
3076 (void)pMe;
3077 (void)pItem;
3078#endif
Laurence Lundblade9b334962020-08-27 10:55:53 -07003079}
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003080
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003081
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003082/**
3083 * @brief Consume an entire map or array including its contents.
3084 *
3085 * @param[in] pMe The decoder context.
3086 * @param[in] pItemToConsume The array/map whose contents are to be
3087 * consumed.
3088 * @param[out] puNextNestLevel The next nesting level after the item was
3089 * fully consumed.
3090 *
3091 * This may be called when @c pItemToConsume is not an array or
3092 * map. In that case, this is just a pass through for @c puNextNestLevel
3093 * since there is nothing to do.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003094 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003095static QCBORError
3096QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
3097 const QCBORItem *pItemToConsume,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003098 bool *pbBreak,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003099 uint8_t *puNextNestLevel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003100{
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003101 QCBORError uReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003102 QCBORItem Item;
Laurence Lundblade9b334962020-08-27 10:55:53 -07003103
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003104 /* If it is a map or array, this will tell if it is empty. */
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003105 const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel);
3106
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003107 if(QCBORItem_IsMapOrArray(*pItemToConsume) && !bIsEmpty) {
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003108 /* There is only real work to do for non-empty maps and arrays */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003109
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003110 /* This works for definite- and indefinite-length maps and
3111 * arrays by using the nesting level
Laurence Lundblade1341c592020-04-11 14:19:05 -07003112 */
3113 do {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003114 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pbBreak, &Item);
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003115 if(QCBORDecode_IsUnrecoverableError(uReturn) ||
3116 uReturn == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003117 goto Done;
3118 }
3119 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003120
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003121 *puNextNestLevel = Item.uNextNestLevel;
3122
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003123 uReturn = QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003124
Laurence Lundblade1341c592020-04-11 14:19:05 -07003125 } else {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003126 /* pItemToConsume is not a map or array. Just pass the nesting
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003127 * level through. */
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003128 *puNextNestLevel = pItemToConsume->uNextNestLevel;
3129
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003130 uReturn = QCBOR_SUCCESS;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003131 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003132
3133Done:
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003134 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003135}
3136
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003137
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003138/*
3139 * Public function, see header qcbor/qcbor_decode.h file
3140 */
3141void
3142QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003143{
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003144 QCBORDecode_VGetNext(pMe, pDecodedItem);
3145
3146 if(pMe->uLastError == QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003147 pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL,
Máté Tóth-Pálc6d59682021-05-26 18:55:30 +02003148 &pDecodedItem->uNextNestLevel);
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003149 }
3150}
3151
3152
Laurence Lundblade11654912024-05-09 11:49:24 -07003153/*
3154 * Public function, see header qcbor/qcbor_decode.h file
3155 */
3156uint32_t
3157QCBORDecode_Tell(QCBORDecodeContext *pMe)
3158{
3159 size_t uCursorOffset;
3160
3161 if(pMe->uLastError != QCBOR_SUCCESS) {
3162 return UINT32_MAX;
3163 }
3164
3165 uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
3166
3167 if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
3168 return UINT32_MAX;
3169 } else {
3170 /* Cast is safe because decoder input size is restricted. */
3171 return (uint32_t)uCursorOffset;
3172 }
3173}
3174
3175
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003176/**
3177 * @brief Rewind cursor to start as if map or array were just entered.
3178 *
3179 * @param[in] pMe The decoding context
3180 *
3181 * This affects the nesting tracking and the UsefulInputBuf.
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003182 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003183static void
3184QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003185{
3186 /* Reset nesting tracking to the deepest bounded level */
3187 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3188
3189 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3190
3191 /* Reposition traversal cursor to the start of the map/array */
3192 UsefulInputBuf_Seek(&(pMe->InBuf),
3193 DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
3194}
3195
3196
3197/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003198 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003199 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003200void
3201QCBORDecode_Rewind(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003202{
3203 if(pMe->nesting.pCurrentBounded != NULL) {
3204 /* In a bounded map, array or bstr-wrapped CBOR */
3205
3206 if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
3207 /* In bstr-wrapped CBOR. */
3208
3209 /* Reposition traversal cursor to start of wrapping byte string */
3210 UsefulInputBuf_Seek(&(pMe->InBuf),
3211 pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
3212 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3213
3214 } else {
3215 /* In a map or array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003216 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003217 }
3218
3219 } else {
3220 /* Not in anything bounded */
3221
3222 /* Reposition traversal cursor to the start of input CBOR */
3223 UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
3224
3225 /* Reset nesting tracking to beginning of input. */
3226 DecodeNesting_Init(&(pMe->nesting));
3227 }
3228
3229 pMe->uLastError = QCBOR_SUCCESS;
3230}
3231
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003232
Laurence Lundblade9b334962020-08-27 10:55:53 -07003233
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003234
3235
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003236typedef struct {
3237 void *pCBContext;
3238 QCBORItemCallback pfCallback;
3239} MapSearchCallBack;
3240
3241typedef struct {
3242 size_t uStartOffset;
3243 uint16_t uItemCount;
3244} MapSearchInfo;
3245
3246
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003247/**
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003248 * @brief Search a map for a set of items.
3249 *
3250 * @param[in] pMe The decode context to search.
3251 * @param[in,out] pItemArray The items to search for and the items found.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003252 * @param[out] pInfo Several bits of meta-info returned by search.
3253 * @param[in] pCallBack Callback object or @c NULL.
3254 * TODO: fix params
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003255 *
3256 * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map.
3257 *
3258 * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label)
3259 * were found for one of the labels being
3260 * search for. This duplicate detection is
3261 * only performed for items in pItemArray,
3262 * not every item in the map.
3263 *
3264 * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was
3265 * wrong for the matchd label.
3266 *
3267 * @retval Also errors returned by QCBORDecode_GetNext().
3268 *
3269 * On input, \c pItemArray contains a list of labels and data types of
3270 * items to be found.
3271 *
3272 * On output, the fully retrieved items are filled in with values and
3273 * such. The label was matched, so it never changes.
3274 *
3275 * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE.
3276 *
3277 * This also finds the ends of maps and arrays when they are exited.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003278 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003279static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003280QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
3281 QCBORItem *pItemArray,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003282 MapSearchInfo *pInfo,
3283 MapSearchCallBack *pCallBack)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003284{
Laurence Lundbladee6f15112020-07-23 18:44:16 -07003285 QCBORError uReturn;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003286 uint64_t uFoundItemBitMap = 0;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07003287
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003288 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003289 uReturn = pMe->uLastError;
3290 goto Done2;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003291 }
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003292
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003293 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) &&
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003294 pItemArray->uLabelType != QCBOR_TYPE_NONE) {
3295 /* QCBOR_TYPE_NONE as first item indicates just looking
3296 for the end of an array, so don't give error. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003297 uReturn = QCBOR_ERR_MAP_NOT_ENTERED;
3298 goto Done2;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003299 }
3300
Laurence Lundblade085d7952020-07-24 10:26:30 -07003301 if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) {
3302 // It is an empty bounded array or map
3303 if(pItemArray->uLabelType == QCBOR_TYPE_NONE) {
3304 // Just trying to find the end of the map or array
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003305 pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003306 uReturn = QCBOR_SUCCESS;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003307 } else {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003308 // Nothing is ever found in an empty array or map. All items
3309 // are marked as not found below.
Laurence Lundblade085d7952020-07-24 10:26:30 -07003310 uReturn = QCBOR_SUCCESS;
3311 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003312 goto Done2;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003313 }
3314
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003315 QCBORDecodeNesting SaveNesting;
Laurence Lundblade11654912024-05-09 11:49:24 -07003316 size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003317 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3318
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003319 /* Reposition to search from the start of the map / array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003320 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundblade1341c592020-04-11 14:19:05 -07003321
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003322 /*
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003323 Loop over all the items in the map or array. Each item
3324 could be a map or array, but label matching is only at
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003325 the main level. This handles definite- and indefinite-
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003326 length maps and arrays. The only reason this is ever
3327 called on arrays is to find their end position.
3328
3329 This will always run over all items in order to do
3330 duplicate detection.
3331
3332 This will exit with failure if it encounters an
3333 unrecoverable error, but continue on for recoverable
3334 errors.
3335
3336 If a recoverable error occurs on a matched item, then
3337 that error code is returned.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003338 */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07003339 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003340 if(pInfo) {
3341 pInfo->uItemCount = 0;
3342 }
Máté Tóth-Pál2f2aa5f2021-05-17 21:35:09 +02003343 uint8_t uNextNestLevel;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003344 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003345 /* Remember offset of the item because sometimes it has to be returned */
Laurence Lundblade1341c592020-04-11 14:19:05 -07003346 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003347
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003348 /* Get the item */
3349 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003350 QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003351 if(QCBORDecode_IsUnrecoverableError(uResult)) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003352 /* The map/array can't be decoded when unrecoverable errors occur */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003353 uReturn = uResult;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003354 goto Done;
3355 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003356 if(uResult == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003357 /* Unexpected end of map or array. */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003358 uReturn = uResult;
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003359 goto Done;
3360 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003361
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003362 /* See if item has one of the labels that are of interest */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003363 bool bMatched = false;
3364 for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003365 if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003366 /* A label match has been found */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003367 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
3368 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003369 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003370 }
Laurence Lundblade63926052021-03-29 16:05:51 -07003371 if(uResult != QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003372 /* The label matches, but the data item is in error.
3373 * It is OK to have recoverable errors on items that are not
3374 * matched. */
Laurence Lundblade63926052021-03-29 16:05:51 -07003375 uReturn = uResult;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003376 goto Done;
3377 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003378 if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) {
Laurence Lundblade63926052021-03-29 16:05:51 -07003379 /* The data item is not of the type(s) requested */
3380 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003381 goto Done;
3382 }
3383
Laurence Lundblade1341c592020-04-11 14:19:05 -07003384 /* Successful match. Return the item. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003385 pItemArray[nIndex] = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003386 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003387 if(pInfo) {
3388 pInfo->uStartOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003389 }
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003390 bMatched = true;
3391 }
3392 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003393
3394
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003395 if(!bMatched && pCallBack != NULL) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003396 /*
3397 Call the callback on unmatched labels.
3398 (It is tempting to do duplicate detection here, but that would
3399 require dynamic memory allocation because the number of labels
3400 that might be encountered is unbounded.)
3401 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003402 uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item);
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003403 if(uReturn != QCBOR_SUCCESS) {
3404 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003405 }
3406 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003407
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003408 /*
3409 Consume the item whether matched or not. This
3410 does the work of traversing maps and array and
3411 everything in them. In this loop only the
3412 items at the current nesting level are examined
3413 to match the labels.
3414 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003415 uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel);
Laurence Lundbladec7114722020-08-13 05:11:40 -07003416 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003417 goto Done;
3418 }
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003419
3420 if(pInfo) {
3421 pInfo->uItemCount++;
3422 }
3423
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003424 } while (uNextNestLevel >= uMapNestLevel);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003425
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003426 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003427
3428 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003429
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003430 // Check here makes sure that this won't accidentally be
3431 // QCBOR_MAP_OFFSET_CACHE_INVALID which is larger than
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003432 // QCBOR_MAX_DECODE_INPUT_SIZE.
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -08003433 // Cast to uint32_t to possibly address cases where SIZE_MAX < UINT32_MAX
3434 if((uint32_t)uEndOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003435 uReturn = QCBOR_ERR_INPUT_TOO_LARGE;
3436 goto Done;
3437 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003438 /* Cast OK because encoded CBOR is limited to UINT32_MAX */
3439 pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003440
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003441 Done:
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003442 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade11654912024-05-09 11:49:24 -07003443 UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos);
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003444
3445 Done2:
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003446 /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */
Laurence Lundbladec7114722020-08-13 05:11:40 -07003447 for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003448 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003449 pItemArray[i].uDataType = QCBOR_TYPE_NONE;
3450 pItemArray[i].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003451 }
3452 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003453
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003454 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003455}
3456
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003457
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003458/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003459 * Public function, see header qcbor/qcbor_decode.h file
3460 */
3461void
3462QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
3463 int64_t nLabel,
3464 uint8_t uQcborType,
3465 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003466{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003467 if(pMe->uLastError != QCBOR_SUCCESS) {
3468 return;
3469 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003470
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003471 QCBORItem OneItemSeach[2];
3472 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3473 OneItemSeach[0].label.int64 = nLabel;
3474 OneItemSeach[0].uDataType = uQcborType;
3475 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003476
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003477 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003478
3479 *pItem = OneItemSeach[0];
3480
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003481 if(uReturn != QCBOR_SUCCESS) {
3482 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003483 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003484 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003485 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003486 }
3487
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003488 Done:
3489 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003490}
3491
3492
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003493/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003494 * Public function, see header qcbor/qcbor_decode.h file
3495 */
3496void
3497QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
3498 const char *szLabel,
3499 uint8_t uQcborType,
3500 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003501{
Laurence Lundbladeda095972020-06-06 18:35:33 -07003502 if(pMe->uLastError != QCBOR_SUCCESS) {
3503 return;
3504 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003505
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003506 QCBORItem OneItemSeach[2];
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003507 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3508 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3509 OneItemSeach[0].uDataType = uQcborType;
3510 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003511
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003512 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
3513
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003514 if(uReturn != QCBOR_SUCCESS) {
3515 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003516 }
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003517 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003518 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003519 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003520 }
3521
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003522 *pItem = OneItemSeach[0];
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003523
3524Done:
3525 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003526}
3527
3528
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003529
3530/**
3531 * @brief Semi-private. Get pointer, length and item for an array or map.
3532 *
3533 * @param[in] pMe The decode context.
3534 * @param[in] uType CBOR major type, either array/map.
3535 * @param[out] pItem The item for the array/map.
3536 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3537 *
3538 * The next item to be decoded must be a map or array as specified by \c uType.
3539 *
3540 * \c pItem will be filled in with the label and tags of the array or map
3541 * in addition to \c pEncodedCBOR giving the pointer and length of the
3542 * encoded CBOR.
3543 *
3544 * When this is complete, the traversal cursor is at the end of the array or
3545 * map that was retrieved.
3546 */
3547void
3548QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe,
3549 const uint8_t uType,
3550 QCBORItem *pItem,
3551 UsefulBufC *pEncodedCBOR)
3552{
3553 QCBORError uErr;
3554 uint8_t uNestLevel;
3555 size_t uStartingCursor;
3556 size_t uStartOfReturned;
3557 size_t uEndOfReturned;
3558 size_t uTempSaveCursor;
3559 bool bInMap;
3560 QCBORItem LabelItem;
3561 bool EndedByBreak;
3562
3563 uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3564 bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting));
3565
3566 /* Could call GetNext here, but don't need to because this
3567 * is only interested in arrays and maps. */
3568 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem);
3569 if(uErr != QCBOR_SUCCESS) {
3570 pMe->uLastError = (uint8_t)uErr;
3571 return;
3572 }
3573
3574 if(pItem->uDataType != uType) {
3575 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
3576 return;
3577 }
3578
3579 if(bInMap) {
3580 /* If the item is in a map, the start of the array/map
3581 * itself, not the label, must be found. Do this by
3582 * rewinding to the starting position and fetching
3583 * just the label data item. QCBORDecode_Private_GetNextTagNumber()
3584 * doesn't do any of the array/map item counting or nesting
3585 * level tracking. Used here it will just fetech the label
3586 * data item.
3587 *
3588 * Have to save the cursor and put it back to the position
3589 * after the full item once the label as been fetched by
3590 * itself.
3591 */
3592 uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3593 UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor);
3594
3595 /* Item has been fetched once so safe to ignore error */
3596 (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem);
3597
3598 uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3599 UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor);
3600 } else {
3601 uStartOfReturned = uStartingCursor;
3602 }
3603
3604 /* Consume the entire array/map to find the end */
3605 uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel);
3606 if(uErr != QCBOR_SUCCESS) {
3607 pMe->uLastError = (uint8_t)uErr;
3608 goto Done;
3609 }
3610
3611 /* Fill in returned values */
3612 uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3613 if(EndedByBreak) {
3614 /* When ascending nesting levels, a break for the level above
3615 * was consumed. That break is not a part of what is consumed here. */
3616 uEndOfReturned--;
3617 }
3618 pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned);
3619 pEncodedCBOR->len = uEndOfReturned - uStartOfReturned;
3620
3621Done:
3622 return;
3623}
3624
3625
3626/**
3627 * @brief Semi-private. Get pointer, length and item count of an array or map.
3628 *
3629 * @param[in] pMe The decode context.
3630 * @param[in] pTarget The label and type of the array or map to retrieve.
3631 * @param[out] pItem The item for the array/map.
3632 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3633 *
3634 * The next item to be decoded must be a map or array as specified by \c uType.
3635 *
3636 * When this is complete, the traversal cursor is unchanged.
3637 */void
3638QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe,
3639 QCBORItem *pTarget,
3640 QCBORItem *pItem,
3641 UsefulBufC *pEncodedCBOR)
3642{
3643 MapSearchInfo Info;
3644 QCBORDecodeNesting SaveNesting;
3645 size_t uSaveCursor;
3646
3647 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL);
3648 if(pMe->uLastError != QCBOR_SUCCESS) {
3649 return;
3650 }
3651
3652 /* Save the whole position of things so they can be restored.
3653 * so the cursor position is unchanged by this operation, like
3654 * all the other GetXxxxInMap() operations. */
3655 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3656 uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3657
3658 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3659 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
3660 QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR);
3661
3662 UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor);
3663 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
3664}
3665
3666
3667
3668
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003669/**
3670 * @brief Is a QCBOR_TYPE in the type list?
3671 *
3672 * @param[in] uDataType Type to check for.
3673 * @param[in] puTypeList List to check.
3674 *
3675 * @retval QCBOR_SUCCESS If in the list.
3676 * @retval QCBOR_ERR_UNEXPECTED_TYPE Not in the list.
3677 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07003678static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003679QCBOR_Private_CheckTypeList(const int uDataType,
3680 const uint8_t puTypeList[QCBOR_TAGSPEC_NUM_TYPES])
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003681{
3682 for(size_t i = 0; i < QCBOR_TAGSPEC_NUM_TYPES; i++) {
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003683 if(uDataType == puTypeList[i]) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003684 return QCBOR_SUCCESS;
3685 }
3686 }
3687 return QCBOR_ERR_UNEXPECTED_TYPE;
3688}
3689
Laurence Lundblade67257dc2020-07-27 03:33:37 -07003690
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003691/**
Laurence Lundblade37286c02022-09-03 10:05:02 -07003692 * Match a tag/type specification against the type of the item.
3693 *
3694 * @param[in] TagSpec Specification for matching tags.
3695 * @param[in] pItem The item to check.
3696 *
3697 * @retval QCBOR_SUCCESS \c uDataType is allowed by @c TagSpec
3698 * @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec
3699 *
3700 * This checks the item data type of untagged items as well as of
3701 * tagged items against a specification to see if decoding should
3702 * proceed.
3703 *
3704 * This relies on the automatic tag decoding done by QCBOR that turns
3705 * tag numbers into particular QCBOR_TYPEs so there is no actual
3706 * comparsion of tag numbers, just of QCBOR_TYPEs.
3707 *
3708 * This checks the data item type as possibly representing the tag
3709 * number or as the tag content type.
3710 *
3711 * If QCBOR_DISABLE_TAGS is #defined, this primarily checks the item
3712 * data type against the allowed tag content types. It will also error out
3713 * if the caller tries to require a tag because there is no way that can
3714 * ever be fulfilled.
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003715 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07003716static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003717QCBOR_Private_CheckTagRequirement(const QCBOR_Private_TagSpec TagSpec,
3718 const QCBORItem *pItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07003719{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003720 const int nItemType = pItem->uDataType; /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade37286c02022-09-03 10:05:02 -07003721 const int nTagReq = TagSpec.uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
3722
3723#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003724 /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003725 if(!(TagSpec.uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS) &&
3726 pItem->uTags[0] != CBOR_TAG_INVALID16) {
3727 /* There are tags that QCBOR couldn't process on this item and
Laurence Lundblade37286c02022-09-03 10:05:02 -07003728 * the caller has told us there should not be.
3729 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003730 return QCBOR_ERR_UNEXPECTED_TYPE;
3731 }
3732
Laurence Lundblade9b334962020-08-27 10:55:53 -07003733 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
Laurence Lundblade37286c02022-09-03 10:05:02 -07003734 /* Must match the tag number and only the tag */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003735 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003736 }
3737
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003738 QCBORError uReturn = QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003739 if(uReturn == QCBOR_SUCCESS) {
3740 return QCBOR_SUCCESS;
3741 }
3742
3743 if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
3744 /* Must match the content type and only the content type.
Laurence Lundblade37286c02022-09-03 10:05:02 -07003745 * There was no match just above so it is a fail. */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003746 return QCBOR_ERR_UNEXPECTED_TYPE;
3747 }
3748
Laurence Lundblade37286c02022-09-03 10:05:02 -07003749 /* QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG: If here it can match either the tag or the content
3750 * and it hasn't matched the content, so the end
3751 * result is whether it matches the tag. This is
3752 * the tag optional case that the CBOR standard discourages.
3753 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003754
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003755 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003756
Laurence Lundblade37286c02022-09-03 10:05:02 -07003757#else /* QCBOR_DISABLE_TAGS */
3758 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
3759 return QCBOR_ERR_UNEXPECTED_TYPE;
3760 }
3761
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07003762 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade37286c02022-09-03 10:05:02 -07003763
3764#endif /* QCBOR_DISABLE_TAGS */
3765}
Laurence Lundblade9b334962020-08-27 10:55:53 -07003766
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003767
3768/**
3769 * @brief Get an item by label to match a tag specification.
3770 *
3771 * @param[in] pMe The decode context.
3772 * @param[in] nLabel The label to search map for.
3773 * @param[in] TagSpec The tag number specification to match.
3774 * @param[out] pItem The item found.
3775 *
3776 * This finds the item with the given label in currently open
3777 * map. Then checks that its tag number and types matches the tag
3778 * specification. If not, an error is set in the decode context.
3779 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003780static void
3781QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
3782 const int64_t nLabel,
3783 const QCBOR_Private_TagSpec TagSpec,
3784 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003785{
3786 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
3787 if(pMe->uLastError != QCBOR_SUCCESS) {
3788 return;
3789 }
3790
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003791 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003792}
3793
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07003794
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003795/**
3796 * @brief Get an item by label to match a tag specification.
3797 *
3798 * @param[in] pMe The decode context.
3799 * @param[in] szLabel The label to search map for.
3800 * @param[in] TagSpec The tag number specification to match.
3801 * @param[out] pItem The item found.
3802 *
3803 * This finds the item with the given label in currently open
3804 * map. Then checks that its tag number and types matches the tag
3805 * specification. If not, an error is set in the decode context.
3806 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003807static void
3808QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
3809 const char *szLabel,
3810 const QCBOR_Private_TagSpec TagSpec,
3811 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003812{
3813 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
3814 if(pMe->uLastError != QCBOR_SUCCESS) {
3815 return;
3816 }
3817
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003818 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003819}
3820
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003821
3822/**
3823 * @brief Semi-private to get an string by label to match a tag specification.
3824 *
3825 * @param[in] pMe The decode context.
3826 * @param[in] nLabel The label to search map for.
3827 * @param[in] TagSpec The tag number specification to match.
3828 * @param[out] pString The string found.
3829 *
3830 * This finds the string with the given label in currently open
3831 * map. Then checks that its tag number and types matches the tag
3832 * specification. If not, an error is set in the decode context.
3833 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003834void
3835QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
3836 const int64_t nLabel,
3837 const QCBOR_Private_TagSpec TagSpec,
3838 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003839{
3840 QCBORItem Item;
3841 QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
3842 if(pMe->uLastError == QCBOR_SUCCESS) {
3843 *pString = Item.val.string;
3844 }
3845}
3846
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003847
3848/**
3849 * @brief Semi-private to get an string by label to match a tag specification.
3850 *
3851 * @param[in] pMe The decode context.
3852 * @param[in] szLabel The label to search map for.
3853 * @param[in] TagSpec The tag number specification to match.
3854 * @param[out] pString The string found.
3855 *
3856 * This finds the string with the given label in currently open
3857 * map. Then checks that its tag number and types matches the tag
3858 * specification. If not, an error is set in the decode context.
3859 */void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003860QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
3861 const char * szLabel,
3862 const QCBOR_Private_TagSpec TagSpec,
3863 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003864{
3865 QCBORItem Item;
3866 QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
3867 if(pMe->uLastError == QCBOR_SUCCESS) {
3868 *pString = Item.val.string;
3869 }
3870}
Laurence Lundblade1341c592020-04-11 14:19:05 -07003871
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003872
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003873/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003874 * Public function, see header qcbor/qcbor_decode.h file
3875 */
3876void
3877QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003878{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003879 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL);
Laurence Lundblade5f53f832020-09-03 12:00:14 -07003880 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003881}
3882
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003883/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003884 * Public function, see header qcbor/qcbor_decode.h file
3885 */
3886void
3887QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe,
3888 QCBORItem *pItemList,
3889 void *pCallbackCtx,
3890 QCBORItemCallback pfCB)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003891{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003892 MapSearchCallBack CallBack;
3893 CallBack.pCBContext = pCallbackCtx;
3894 CallBack.pfCallback = pfCB;
3895
3896 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack);
3897
Laurence Lundblade5f53f832020-09-03 12:00:14 -07003898 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003899}
3900
3901
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08003902/**
3903 * @brief Search for a map/array by label and enter it
3904 *
3905 * @param[in] pMe The decode context.
3906 * @param[in] pSearch The map/array to search for.
3907 *
3908 * @c pSearch is expected to contain one item of type map or array
3909 * with the label specified. The current bounded map will be searched for
3910 * this and if found will be entered.
3911 *
3912 * If the label is not found, or the item found is not a map or array,
3913 * the error state is set.
3914 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003915static void
3916QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07003917{
Laurence Lundblade323f8a92020-09-06 19:43:09 -07003918 // The first item in pSearch is the one that is to be
3919 // entered. It should be the only one filled in. Any other
3920 // will be ignored unless it causes an error.
Laurence Lundblade34691b92020-05-18 22:25:25 -07003921 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07003922 return;
3923 }
3924
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003925 MapSearchInfo Info;
3926 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pSearch, &Info, NULL);
Laurence Lundblade34691b92020-05-18 22:25:25 -07003927 if(pMe->uLastError != QCBOR_SUCCESS) {
3928 return;
3929 }
3930
Laurence Lundblade9b334962020-08-27 10:55:53 -07003931 if(pSearch->uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003932 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade9b334962020-08-27 10:55:53 -07003933 return;
3934 }
3935
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003936
3937 /* The map or array was found. Now enter it.
3938 *
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08003939 * QCBORDecode_EnterBoundedMapOrArray() used here, requires the
3940 * next item for the pre-order traversal cursor to be the map/array
3941 * found by MapSearch(). The next few lines of code force the
3942 * cursor to that.
3943 *
3944 * There is no need to retain the old cursor because
3945 * QCBORDecode_EnterBoundedMapOrArray() will set it to the
3946 * beginning of the map/array being entered.
3947 *
3948 * The cursor is forced by: 1) setting the input buffer position to
3949 * the item offset found by MapSearch(), 2) setting the map/array
3950 * counter to the total in the map/array, 3) setting the nesting
3951 * level. Setting the map/array counter to the total is not
3952 * strictly correct, but this is OK because this cursor only needs
3953 * to be used to get one item and MapSearch() has already found it
3954 * confirming it exists.
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003955 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003956 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07003957
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08003958 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3959
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07003960 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003961
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003962 QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003963}
3964
3965
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003966/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003967 * Public function, see header qcbor/qcbor_decode.h file
3968 */
3969void
3970QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003971{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003972 QCBORItem OneItemSeach[2];
3973 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3974 OneItemSeach[0].label.int64 = nLabel;
3975 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
3976 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003977
Laurence Lundblade9b334962020-08-27 10:55:53 -07003978 /* The map to enter was found, now finish off entering it. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003979 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003980}
3981
3982
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003983/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003984 * Public function, see header qcbor/qcbor_decode.h file
3985 */
3986void
3987QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003988{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003989 QCBORItem OneItemSeach[2];
3990 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3991 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3992 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
3993 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade9b334962020-08-27 10:55:53 -07003994
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003995 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003996}
3997
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003998/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003999 * Public function, see header qcbor/qcbor_decode.h file
4000 */
4001void
4002QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07004003{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004004 QCBORItem OneItemSeach[2];
4005 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4006 OneItemSeach[0].label.int64 = nLabel;
4007 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4008 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004009
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004010 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07004011}
4012
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004013/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004014 * Public function, see header qcbor/qcbor_decode.h file
4015 */
4016void
4017QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundblade34691b92020-05-18 22:25:25 -07004018{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004019 QCBORItem OneItemSeach[2];
4020 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4021 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4022 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4023 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004024
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004025 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade1341c592020-04-11 14:19:05 -07004026}
4027
4028
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004029/**
4030 * @brief Semi-private to do the the work for EnterMap() and EnterArray().
4031 *
4032 * @param[in] pMe The decode context
4033 * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY.
4034 * @param[out] pItem The data item for the map or array entered.
4035 *
4036 * The next item in the traversal must be a map or array. This
4037 * consumes that item and does the book keeping to enter the map or
4038 * array.
4039 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004040void
4041QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe,
4042 const uint8_t uType,
4043 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004044{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004045 QCBORError uErr;
4046
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004047 /* Must only be called on maps and arrays. */
Laurence Lundblade34691b92020-05-18 22:25:25 -07004048 if(pMe->uLastError != QCBOR_SUCCESS) {
4049 // Already in error state; do nothing.
4050 return;
4051 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07004052
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004053 /* Get the data item that is the map or array being entered. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004054 QCBORItem Item;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004055 uErr = QCBORDecode_GetNext(pMe, &Item);
4056 if(uErr != QCBOR_SUCCESS) {
4057 goto Done;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07004058 }
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004059 if(Item.uDataType != uType) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004060 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
4061 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004062 }
4063
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004064 QCBORDecode_Private_CopyTags(pMe, &Item);
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004065
4066
Laurence Lundbladef0499502020-08-01 11:55:57 -07004067 const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
Laurence Lundblade085d7952020-07-24 10:26:30 -07004068 if(bIsEmpty) {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004069 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
4070 // Undo decrement done by QCBORDecode_GetNext() so the the
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004071 // the decrement when exiting the map/array works correctly
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004072 pMe->nesting.pCurrent->u.ma.uCountCursor++;
4073 }
Laurence Lundblade93d89472020-10-03 22:30:50 -07004074 // Special case to increment nesting level for zero-length maps
4075 // and arrays entered in bounded mode.
Laurence Lundbladee6f15112020-07-23 18:44:16 -07004076 DecodeNesting_Descend(&(pMe->nesting), uType);
4077 }
4078
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004079 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004080
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004081 uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty,
4082 UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004083
Laurence Lundblade6545d1b2020-10-14 11:13:13 -07004084 if(pItem != NULL) {
4085 *pItem = Item;
4086 }
4087
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004088Done:
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004089 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004090}
4091
Laurence Lundblade02625d42020-06-25 14:41:41 -07004092
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004093/**
4094 * @brief Exit a bounded map, array or bstr (semi-private).
4095 *
4096 * @param[in] pMe Decode context.
4097 * @param[in] uEndOffset The input buffer offset of the end of item exited.
4098 *
4099 * @returns QCBOR_SUCCESS or an error code.
4100 *
4101 * This is the common work for exiting a level that is a bounded map,
4102 * array or bstr wrapped CBOR.
4103 *
4104 * One chunk of work is to set up the pre-order traversal so it is at
4105 * the item just after the bounded map, array or bstr that is being
4106 * exited. This is somewhat complex.
4107 *
4108 * The other work is to level-up the bounded mode to next higest
4109 * bounded mode or the top level if there isn't one.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004110 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004111static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004112QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
4113 const uint32_t uEndOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004114{
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004115 QCBORError uErr;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004116
Laurence Lundblade02625d42020-06-25 14:41:41 -07004117 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004118 * First the pre-order-traversal byte offset is positioned to the
4119 * item just after the bounded mode item that was just consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004120 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004121 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
4122
Laurence Lundblade02625d42020-06-25 14:41:41 -07004123 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004124 * Next, set the current nesting level to one above the bounded
4125 * level that was just exited.
4126 *
4127 * DecodeNesting_CheckBoundedType() is always called before this
4128 * and makes sure pCurrentBounded is valid.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004129 */
4130 DecodeNesting_LevelUpCurrent(&(pMe->nesting));
4131
4132 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004133 * This does the complex work of leveling up the pre-order
4134 * traversal when the end of a map or array or another bounded
4135 * level is reached. It may do nothing, or ascend all the way to
4136 * the top level.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004137 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004138 uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004139 if(uErr != QCBOR_SUCCESS) {
4140 goto Done;
4141 }
4142
Laurence Lundblade02625d42020-06-25 14:41:41 -07004143 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004144 * This makes the next highest bounded level the current bounded
4145 * level. If there is no next highest level, then no bounded mode
4146 * is in effect.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004147 */
4148 DecodeNesting_LevelUpBounded(&(pMe->nesting));
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004149
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004150 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004151
4152Done:
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004153 return uErr;
4154}
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004155
Laurence Lundblade02625d42020-06-25 14:41:41 -07004156
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004157/**
4158 * @brief Get started exiting a map or array (semi-private)
4159 *
4160 * @param[in] pMe The decode context
4161 * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP
4162 *
4163 * This does some work for map and array exiting (but not
4164 * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel()
4165 * is called to do the rest.
4166 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004167void
4168QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe,
4169 const uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004170{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004171 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07004172 /* Already in error state; do nothing. */
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004173 return;
4174 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004175
Laurence Lundblade02625d42020-06-25 14:41:41 -07004176 QCBORError uErr;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004177
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004178 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004179 uErr = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004180 goto Done;
4181 }
4182
Laurence Lundblade02625d42020-06-25 14:41:41 -07004183 /*
4184 Have to set the offset to the end of the map/array
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004185 that is being exited. If there is no cached value,
Laurence Lundblade02625d42020-06-25 14:41:41 -07004186 from previous map search, then do a dummy search.
4187 */
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004188 if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004189 QCBORItem Dummy;
4190 Dummy.uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004191 uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL);
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004192 if(uErr != QCBOR_SUCCESS) {
4193 goto Done;
4194 }
4195 }
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004196
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004197 uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004198
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004199Done:
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004200 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004201}
4202
4203
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004204/**
4205 * @brief The main work of entering some byte-string wrapped CBOR.
4206 *
4207 * @param[in] pMe The decode context.
4208 * @param[in] pItem The byte string item.
4209 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX
4210 * @param[out] pBstr Pointer and length of byte string entered.
4211 *
4212 * This is called once the byte string item has been decoded to do all
4213 * the book keeping work for descending a nesting level into the
4214 * nested CBOR.
4215 *
4216 * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement.
4217 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004218static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004219QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe,
4220 const QCBORItem *pItem,
4221 const uint8_t uTagRequirement,
4222 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004223{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004224 if(pBstr) {
4225 *pBstr = NULLUsefulBufC;
4226 }
4227
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004228 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004229 /* Already in error state; do nothing. */
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004230 return pMe->uLastError;
4231 }
4232
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004233 QCBORError uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004234
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004235 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004236 {
4237 uTagRequirement,
4238 {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE},
4239 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4240 };
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004241
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004242 uError = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004243 if(uError != QCBOR_SUCCESS) {
4244 goto Done;
4245 }
4246
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004247 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004248 /* Reverse the decrement done by GetNext() for the bstr so the
4249 * increment in QCBORDecode_NestLevelAscender() called by
4250 * ExitBoundedLevel() will work right.
4251 */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004252 DecodeNesting_ReverseDecrement(&(pMe->nesting));
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07004253 }
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004254
4255 if(pBstr) {
4256 *pBstr = pItem->val.string;
4257 }
4258
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004259 /* This saves the current length of the UsefulInputBuf and then
4260 * narrows the UsefulInputBuf to start and length of the wrapped
4261 * CBOR that is being entered.
4262 *
4263 * Most of these calls are simple inline accessors so this doesn't
4264 * amount to much code.
4265 */
4266
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004267 const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004268 /* This check makes the cast of uPreviousLength to uint32_t below safe. */
4269 if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004270 uError = QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladef76a2622020-08-06 19:51:03 -07004271 goto Done;
4272 }
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004273
4274 const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
4275 pItem->val.string.ptr);
4276 /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
4277 if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
4278 /* This should never happen because pItem->val.string.ptr should
4279 * always be valid since it was just returned.
4280 */
4281 uError = QCBOR_ERR_INPUT_TOO_LARGE;
4282 goto Done;
4283 }
4284
4285 const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
4286
4287 UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004288 UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004289
Laurence Lundblade02625d42020-06-25 14:41:41 -07004290 uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004291 (uint32_t)uPreviousLength,
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004292 (uint32_t)uStartOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004293Done:
4294 return uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004295}
4296
4297
Laurence Lundblade02625d42020-06-25 14:41:41 -07004298/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004299 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004300 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004301void
4302QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe,
4303 const uint8_t uTagRequirement,
4304 UsefulBufC *pBstr)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004305{
4306 if(pMe->uLastError != QCBOR_SUCCESS) {
4307 // Already in error state; do nothing.
4308 return;
4309 }
4310
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004311 /* Get the data item that is the byte string being entered */
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004312 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004313 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4314 if(pMe->uLastError != QCBOR_SUCCESS) {
4315 return;
4316 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004317
Laurence Lundblade31fddb72024-05-13 13:03:35 -07004318 if(Item.uDataAlloc) {
4319 pMe->uLastError = QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
4320 return;
4321 }
4322
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004323 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4324 &Item,
4325 uTagRequirement,
4326 pBstr);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004327}
4328
4329
Laurence Lundblade02625d42020-06-25 14:41:41 -07004330/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004331 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004332 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004333void
4334QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe,
4335 const int64_t nLabel,
4336 const uint8_t uTagRequirement,
4337 UsefulBufC *pBstr)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004338{
4339 QCBORItem Item;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004340 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004341
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004342 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4343 &Item,
4344 uTagRequirement,
4345 pBstr);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004346}
4347
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004348
Laurence Lundblade02625d42020-06-25 14:41:41 -07004349/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004350 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004351 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004352void
4353QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe,
4354 const char *szLabel,
4355 const uint8_t uTagRequirement,
4356 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004357{
4358 QCBORItem Item;
4359 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4360
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004361 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4362 &Item,
4363 uTagRequirement,
4364 pBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004365}
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004366
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004367
Laurence Lundblade02625d42020-06-25 14:41:41 -07004368/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004369 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004370 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004371void
4372QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004373{
Laurence Lundblade02625d42020-06-25 14:41:41 -07004374 if(pMe->uLastError != QCBOR_SUCCESS) {
4375 // Already in error state; do nothing.
4376 return;
4377 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004378
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004379 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004380 pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade02625d42020-06-25 14:41:41 -07004381 return;
4382 }
4383
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004384 const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
4385
Laurence Lundblade02625d42020-06-25 14:41:41 -07004386 /*
4387 Reset the length of the UsefulInputBuf to what it was before
4388 the bstr wrapped CBOR was entered.
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004389 */
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004390 UsefulInputBuf_SetBufferLength(&(pMe->InBuf),
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004391 DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004392
4393
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004394 QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004395 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004396}
4397
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004398
Laurence Lundbladee6430642020-03-14 21:15:44 -07004399
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004400/**
4401 * @brief Process simple type true and false, a boolean
4402 *
4403 * @param[in] pMe The decode context.
4404 * @param[in] pItem The item with either true or false.
4405 * @param[out] pBool The boolean value output.
4406 *
4407 * Sets the internal error if the item isn't a true or a false. Also
4408 * records any tag numbers as the tag numbers of the last item.
4409 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004410static void
4411QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe,
4412 const QCBORItem *pItem,
4413 bool *pBool)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004414{
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004415 if(pMe->uLastError != QCBOR_SUCCESS) {
4416 /* Already in error state, do nothing */
4417 return;
4418 }
4419
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004420 switch(pItem->uDataType) {
4421 case QCBOR_TYPE_TRUE:
4422 *pBool = true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004423 break;
4424
4425 case QCBOR_TYPE_FALSE:
4426 *pBool = false;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004427 break;
4428
4429 default:
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004430 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004431 break;
4432 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004433 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004434}
Laurence Lundbladee6430642020-03-14 21:15:44 -07004435
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004436
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004437/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004438 * Public function, see header qcbor/qcbor_decode.h file
4439 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004440void
4441QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004442{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004443 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004444 /* Already in error state, do nothing */
Laurence Lundbladee6430642020-03-14 21:15:44 -07004445 return;
4446 }
4447
Laurence Lundbladec4537442020-04-14 18:53:22 -07004448 QCBORItem Item;
4449
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004450 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4451
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004452 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004453}
4454
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004455
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004456/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004457 * Public function, see header qcbor/qcbor_decode.h file
4458 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004459void
4460QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe,
4461 const int64_t nLabel,
4462 bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004463{
4464 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004465 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004466
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004467 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004468}
4469
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004470
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004471/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004472 * Public function, see header qcbor/qcbor_decode.h file
4473 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004474void
4475QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe,
4476 const char *szLabel,
4477 bool *pValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004478{
4479 QCBORItem Item;
4480 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4481
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004482 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004483}
4484
4485
4486
Laurence Lundbladec7114722020-08-13 05:11:40 -07004487
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004488/**
4489 * @brief Common processing for an epoch date.
4490 *
4491 * @param[in] pMe The decode context.
4492 * @param[in] pItem The item with the date.
4493 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4494 * @param[out] pnTime The returned date.
4495 *
4496 * Common processing for the date tag. Mostly make sure the tag
4497 * content is correct and copy forward any further other tag numbers.
4498 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004499static void
4500QCBORDecode_Private_ProcessEpochDate(QCBORDecodeContext *pMe,
4501 QCBORItem *pItem,
4502 const uint8_t uTagRequirement,
4503 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004504{
4505 if(pMe->uLastError != QCBOR_SUCCESS) {
4506 // Already in error state, do nothing
4507 return;
4508 }
4509
4510 QCBORError uErr;
4511
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004512 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladec7114722020-08-13 05:11:40 -07004513 {
4514 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004515 {QCBOR_TYPE_DATE_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4516 {QCBOR_TYPE_INT64, QCBOR_TYPE_DOUBLE, QCBOR_TYPE_FLOAT, QCBOR_TYPE_UINT64}
Laurence Lundbladec7114722020-08-13 05:11:40 -07004517 };
4518
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004519 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004520 if(uErr != QCBOR_SUCCESS) {
4521 goto Done;
4522 }
4523
4524 if(pItem->uDataType != QCBOR_TYPE_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004525 uErr = QCBOR_Private_DecodeDateEpoch(pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004526 if(uErr != QCBOR_SUCCESS) {
4527 goto Done;
4528 }
4529 }
4530
Laurence Lundblade9b334962020-08-27 10:55:53 -07004531 // Save the tags in the last item's tags in the decode context
4532 // for QCBORDecode_GetNthTagOfLast()
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004533 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07004534
Laurence Lundbladec7114722020-08-13 05:11:40 -07004535 *pnTime = pItem->val.epochDate.nSeconds;
4536
4537Done:
4538 pMe->uLastError = (uint8_t)uErr;
4539}
4540
4541
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004542
4543/*
4544 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4545 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004546void
4547QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
4548 uint8_t uTagRequirement,
4549 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004550{
4551 if(pMe->uLastError != QCBOR_SUCCESS) {
4552 // Already in error state, do nothing
4553 return;
4554 }
4555
4556 QCBORItem Item;
4557 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4558
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004559 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004560}
4561
4562
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004563/*
4564 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4565 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07004566void
4567QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
4568 int64_t nLabel,
4569 uint8_t uTagRequirement,
4570 int64_t *pnTime)
4571{
4572 QCBORItem Item;
4573 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004574 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004575}
4576
4577
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004578/*
4579 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4580 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07004581void
4582QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
4583 const char *szLabel,
4584 uint8_t uTagRequirement,
4585 int64_t *pnTime)
4586{
4587 QCBORItem Item;
4588 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004589 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004590}
4591
4592
4593
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004594/**
4595 * @brief Common processing for an epoch date.
4596 *
4597 * @param[in] pMe The decode context.
4598 * @param[in] pItem The item with the date.
4599 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4600 * @param[out] pnDays The returned day count.
4601 *
4602 * Common processing for the RFC 8943 day-count tag. Mostly make sure
4603 * the tag content is correct and copy forward any further other tag
4604 * numbers.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004605 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004606static void
4607QCBORDecode_Private_ProcessEpochDays(QCBORDecodeContext *pMe,
4608 QCBORItem *pItem,
4609 uint8_t uTagRequirement,
4610 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004611{
4612 if(pMe->uLastError != QCBOR_SUCCESS) {
4613 /* Already in error state, do nothing */
4614 return;
4615 }
4616
4617 QCBORError uErr;
4618
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004619 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004620 {
4621 uTagRequirement,
4622 {QCBOR_TYPE_DAYS_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4623 {QCBOR_TYPE_INT64, QCBOR_TYPE_UINT64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4624 };
4625
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004626 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004627 if(uErr != QCBOR_SUCCESS) {
4628 goto Done;
4629 }
4630
4631 if(pItem->uDataType != QCBOR_TYPE_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004632 uErr = QCBOR_Private_DecodeDaysEpoch(pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004633 if(uErr != QCBOR_SUCCESS) {
4634 goto Done;
4635 }
4636 }
4637
4638 /* Save the tags in the last item's tags in the decode context
4639 * for QCBORDecode_GetNthTagOfLast()
4640 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004641 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004642
4643 *pnDays = pItem->val.epochDays;
4644
4645Done:
4646 pMe->uLastError = (uint8_t)uErr;
4647}
4648
4649
4650/*
4651 * Public function, see header qcbor/qcbor_decode.h
4652 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004653void
4654QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe,
4655 uint8_t uTagRequirement,
4656 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004657{
4658 if(pMe->uLastError != QCBOR_SUCCESS) {
4659 /* Already in error state, do nothing */
4660 return;
4661 }
4662
4663 QCBORItem Item;
4664 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4665
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004666 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004667}
4668
4669
4670/*
4671 * Public function, see header qcbor/qcbor_decode.h
4672 */
4673void
4674QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe,
4675 int64_t nLabel,
4676 uint8_t uTagRequirement,
4677 int64_t *pnDays)
4678{
4679 QCBORItem Item;
4680 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004681 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004682}
4683
4684
4685/*
4686 * Public function, see header qcbor/qcbor_decode.h
4687 */
4688void
4689QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe,
4690 const char *szLabel,
4691 uint8_t uTagRequirement,
4692 int64_t *pnDays)
4693{
4694 QCBORItem Item;
4695 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004696 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004697}
4698
4699
4700
Laurence Lundblade37286c02022-09-03 10:05:02 -07004701/*
4702 * @brief Get a string that matches the type/tag specification.
4703 */
4704void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004705QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
4706 const QCBOR_Private_TagSpec TagSpec,
4707 UsefulBufC *pBstr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004708{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004709 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade37286c02022-09-03 10:05:02 -07004710 /* Already in error state, do nothing */
Laurence Lundbladec4537442020-04-14 18:53:22 -07004711 return;
4712 }
4713
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004714 QCBORError uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004715 QCBORItem Item;
4716
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004717 uError = QCBORDecode_GetNext(pMe, &Item);
4718 if(uError != QCBOR_SUCCESS) {
4719 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004720 return;
4721 }
4722
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004723 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004724
4725 if(pMe->uLastError == QCBOR_SUCCESS) {
4726 *pBstr = Item.val.string;
Laurence Lundbladeab40c6f2020-08-28 11:24:58 -07004727 } else {
4728 *pBstr = NULLUsefulBufC;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004729 }
4730}
4731
Laurence Lundbladec4537442020-04-14 18:53:22 -07004732
4733
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004734
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004735/**
4736 * @brief Common processing for a big number tag.
4737 *
4738 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4739 * @param[in] pItem The item with the date.
4740 * @param[out] pValue The returned big number
4741 * @param[out] pbIsNegative The returned sign of the big number.
4742 *
4743 * Common processing for the big number tag. Mostly make sure
4744 * the tag content is correct and copy forward any further other tag
4745 * numbers.
4746 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004747static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004748QCBOR_Private_ProcessBigNum(const uint8_t uTagRequirement,
4749 const QCBORItem *pItem,
4750 UsefulBufC *pValue,
4751 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004752{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004753 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004754 {
4755 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004756 {QCBOR_TYPE_POSBIGNUM, QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4757 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004758 };
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004759
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004760 QCBORError uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004761 if(uErr != QCBOR_SUCCESS) {
4762 return uErr;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004763 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004764
4765 *pValue = pItem->val.string;
4766
4767 if(pItem->uDataType == QCBOR_TYPE_POSBIGNUM) {
4768 *pbIsNegative = false;
4769 } else if(pItem->uDataType == QCBOR_TYPE_NEGBIGNUM) {
4770 *pbIsNegative = true;
4771 }
4772
4773 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004774}
4775
4776
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004777/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004778 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004779 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004780void
4781QCBORDecode_GetBignum(QCBORDecodeContext *pMe,
4782 const uint8_t uTagRequirement,
4783 UsefulBufC *pValue,
4784 bool *pbIsNegative)
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004785{
4786 if(pMe->uLastError != QCBOR_SUCCESS) {
4787 // Already in error state, do nothing
4788 return;
4789 }
4790
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004791 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004792 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
4793 if(uError != QCBOR_SUCCESS) {
4794 pMe->uLastError = (uint8_t)uError;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004795 return;
4796 }
4797
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004798 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4799 &Item,
4800 pValue,
4801 pbIsNegative);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004802}
4803
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004804
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004805/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004806 * Public function, see header qcbor/qcbor_spiffy_decode.h
4807 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004808void
4809QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe,
4810 const int64_t nLabel,
4811 const uint8_t uTagRequirement,
4812 UsefulBufC *pValue,
4813 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004814{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004815 QCBORItem Item;
4816 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004817 if(pMe->uLastError != QCBOR_SUCCESS) {
4818 return;
4819 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004820
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004821 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4822 &Item,
4823 pValue,
4824 pbIsNegative);
Laurence Lundbladec4537442020-04-14 18:53:22 -07004825}
4826
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004827
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004828/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004829 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004830 */
4831void
4832QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe,
4833 const char *szLabel,
4834 const uint8_t uTagRequirement,
4835 UsefulBufC *pValue,
4836 bool *pbIsNegative)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004837{
4838 QCBORItem Item;
4839 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004840 if(pMe->uLastError != QCBOR_SUCCESS) {
4841 return;
4842 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004843
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004844 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4845 &Item,
4846 pValue,
4847 pbIsNegative);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004848}
4849
4850
4851
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004852/**
4853 * @brief Common processing for MIME tag (semi-private).
4854 *
4855 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4856 * @param[in] pItem The item with the date.
4857 * @param[out] pMessage The returned MIME message.
4858 * @param[out] pbIsTag257 If true, binary MIME, if not, text MIME.
4859 *
4860 * Common processing for the MIME tag. Mostly make sure the tag
4861 * content is correct and copy forward any further other tag
4862 * numbers. See QCBORDecode_GetMIMEMessage().
4863 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004864QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004865QCBORDecode_Private_GetMIME(const uint8_t uTagRequirement,
Laurence Lundblade37286c02022-09-03 10:05:02 -07004866 const QCBORItem *pItem,
4867 UsefulBufC *pMessage,
4868 bool *pbIsTag257)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004869{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004870 const QCBOR_Private_TagSpec TagSpecText =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004871 {
4872 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004873 {QCBOR_TYPE_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4874 {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004875 };
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004876 const QCBOR_Private_TagSpec TagSpecBinary =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004877 {
4878 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004879 {QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4880 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004881 };
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004882
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004883 QCBORError uReturn;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004884
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004885 if(QCBOR_Private_CheckTagRequirement(TagSpecText, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004886 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07004887 if(pbIsTag257 != NULL) {
4888 *pbIsTag257 = false;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004889 }
4890 uReturn = QCBOR_SUCCESS;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004891 } else if(QCBOR_Private_CheckTagRequirement(TagSpecBinary, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004892 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07004893 if(pbIsTag257 != NULL) {
4894 *pbIsTag257 = true;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004895 }
4896 uReturn = QCBOR_SUCCESS;
4897
4898 } else {
4899 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
4900 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07004901
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004902 return uReturn;
4903}
4904
Laurence Lundblade93d89472020-10-03 22:30:50 -07004905// Improvement: add methods for wrapped CBOR, a simple alternate
4906// to EnterBstrWrapped
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004907
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004908
4909
4910
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07004911#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundbladee6430642020-03-14 21:15:44 -07004912
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004913/**
4914 * @brief Prototype for conversion of exponent and mantissa to unsigned integer.
4915 *
4916 * @param[in] uMantissa The mantissa.
4917 * @param[in] nExponent The exponent.
4918 * @param[out] puResult The resulting integer.
4919 *
4920 * Concrete implementations of this are for exponent base 10 and 2 supporting
4921 * decimal fractions and big floats.
4922 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004923typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004924
4925
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004926/**
4927 * @brief Base 10 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
4928 *
4929 * @param[in] uMantissa The unsigned integer mantissa.
4930 * @param[in] nExponent The signed integer exponent.
4931 * @param[out] puResult Place to return the unsigned integer result.
4932 *
4933 * This computes: mantissa * 10 ^^ exponent as for a decimal fraction. The output is a 64-bit
4934 * unsigned integer.
4935 *
4936 * There are many inputs for which the result will not fit in the
4937 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
4938 * be returned.
4939 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07004940static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004941QCBOR_Private_Exponentitate10(const uint64_t uMantissa,
4942 int64_t nExponent,
4943 uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004944{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07004945 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004946
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07004947 if(uResult != 0) {
4948 /* This loop will run a maximum of 19 times because
4949 * UINT64_MAX < 10 ^^ 19. More than that will cause
4950 * exit with the overflow error
4951 */
4952 for(; nExponent > 0; nExponent--) {
4953 if(uResult > UINT64_MAX / 10) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004954 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07004955 }
4956 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004957 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07004958
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07004959 for(; nExponent < 0; nExponent++) {
4960 uResult = uResult / 10;
4961 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004962 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07004963 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07004964 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07004965 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07004966 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07004967
4968 *puResult = uResult;
4969
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004970 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004971}
4972
4973
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004974/**
4975 * @brief Base 2 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
4976 *
4977 * @param[in] uMantissa The unsigned integer mantissa.
4978 * @param[in] nExponent The signed integer exponent.
4979 * @param[out] puResult Place to return the unsigned integer result.
4980 *
4981 * This computes: mantissa * 2 ^^ exponent as for a big float. The
4982 * output is a 64-bit unsigned integer.
4983 *
4984 * There are many inputs for which the result will not fit in the
4985 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
4986 * be returned.
4987 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07004988static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004989QCBOR_Private_Exponentitate2(const uint64_t uMantissa,
4990 int64_t nExponent,
4991 uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004992{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004993 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07004994
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004995 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07004996
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004997 /* This loop will run a maximum of 64 times because INT64_MAX <
4998 * 2^31. More than that will cause exit with the overflow error
Laurence Lundbladee6430642020-03-14 21:15:44 -07004999 */
5000 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005001 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005002 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005003 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005004 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005005 nExponent--;
5006 }
5007
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005008 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005009 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005010 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005011 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005012 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005013 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005014 }
5015
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005016 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005017
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005018 return QCBOR_SUCCESS;
5019}
5020
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005021
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005022/**
5023 * @brief Exponentiate a signed mantissa and signed exponent to produce a signed result.
5024 *
5025 * @param[in] nMantissa Signed integer mantissa.
5026 * @param[in] nExponent Signed integer exponent.
5027 * @param[out] pnResult Place to put the signed integer result.
5028 * @param[in] pfExp Exponentiation function.
5029 *
5030 * @returns Error code
5031 *
5032 * \c pfExp performs exponentiation on and unsigned mantissa and
5033 * produces an unsigned result. This converts the mantissa from signed
5034 * and converts the result to signed. The exponentiation function is
5035 * either for base 2 or base 10 (and could be other if needed).
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005036 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005037static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005038QCBOR_Private_ExponentiateNN(const int64_t nMantissa,
5039 const int64_t nExponent,
5040 int64_t *pnResult,
5041 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005042{
5043 uint64_t uResult;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005044 uint64_t uMantissa;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005045
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005046 /* Take the absolute value and put it into an unsigned. */
5047 if(nMantissa >= 0) {
5048 /* Positive case is straightforward */
5049 uMantissa = (uint64_t)nMantissa;
5050 } else if(nMantissa != INT64_MIN) {
5051 /* The common negative case. See next. */
5052 uMantissa = (uint64_t)-nMantissa;
5053 } else {
5054 /* int64_t and uint64_t are always two's complement per the
5055 * C standard (and since QCBOR uses these it only works with
5056 * two's complement, which is pretty much universal these
5057 * days). The range of a negative two's complement integer is
5058 * one more that than a positive, so the simple code above might
5059 * not work all the time because you can't simply negate the
5060 * value INT64_MIN because it can't be represented in an
5061 * int64_t. -INT64_MIN can however be represented in a
5062 * uint64_t. Some compilers seem to recognize this case for the
5063 * above code and put the correct value in uMantissa, however
5064 * they are not required to do this by the C standard. This next
5065 * line does however work for all compilers.
5066 *
5067 * This does assume two's complement where -INT64_MIN ==
5068 * INT64_MAX + 1 (which wouldn't be true for one's complement or
5069 * sign and magnitude (but we know we're using two's complement
5070 * because int64_t requires it)).
5071 *
5072 * See these, particularly the detailed commentary:
5073 * https://stackoverflow.com/questions/54915742/does-c99-mandate-a-int64-t-type-be-available-always
5074 * https://stackoverflow.com/questions/37301078/is-negating-int-min-undefined-behaviour
5075 */
5076 uMantissa = (uint64_t)INT64_MAX+1;
5077 }
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005078
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005079 /* Call the exponentiator passed for either base 2 or base 10.
5080 * Here is where most of the overflow errors are caught. */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005081 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
5082 if(uReturn) {
5083 return uReturn;
5084 }
5085
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005086 /* Convert back to the sign of the original mantissa */
5087 if(nMantissa >= 0) {
5088 if(uResult > INT64_MAX) {
5089 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5090 }
5091 *pnResult = (int64_t)uResult;
5092 } else {
5093 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
5094 * of INT64_MIN. This assumes two's compliment representation
5095 * where INT64_MIN is one increment farther from 0 than
5096 * INT64_MAX. Trying to write -INT64_MIN doesn't work to get
5097 * this because the compiler makes it an int64_t which can't
5098 * represent -INT64_MIN. Also see above.
5099 */
5100 if(uResult > (uint64_t)INT64_MAX+1) {
5101 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5102 }
5103 *pnResult = -(int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005104 }
5105
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005106 return QCBOR_SUCCESS;
5107}
5108
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005109
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005110/**
5111 * @brief Exponentiate an unsigned mantissa and signed exponent to produce an unsigned result.
5112 *
5113 * @param[in] nMantissa Signed integer mantissa.
5114 * @param[in] nExponent Signed integer exponent.
5115 * @param[out] puResult Place to put the signed integer result.
5116 * @param[in] pfExp Exponentiation function.
5117 *
5118 * @returns Error code
5119 *
5120 * \c pfExp performs exponentiation on and unsigned mantissa and
5121 * produces an unsigned result. This errors out if the mantissa
5122 * is negative because the output is unsigned.
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005123 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005124static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005125QCBOR_Private_ExponentitateNU(const int64_t nMantissa,
5126 const int64_t nExponent,
5127 uint64_t *puResult,
5128 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005129{
5130 if(nMantissa < 0) {
5131 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5132 }
5133
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005134 /* Cast to unsigned is OK because of check for negative.
5135 * Cast to unsigned is OK because UINT64_MAX > INT64_MAX.
5136 * Exponentiation is straight forward
5137 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005138 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
5139}
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005140
5141
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005142/**
5143 * @brief Exponentiate an usnigned mantissa and unsigned exponent to produce an unsigned result.
5144 *
5145 * @param[in] uMantissa Unsigned integer mantissa.
5146 * @param[in] nExponent Unsigned integer exponent.
5147 * @param[out] puResult Place to put the unsigned integer result.
5148 * @param[in] pfExp Exponentiation function.
5149 *
5150 * @returns Error code
5151 *
5152 * \c pfExp performs exponentiation on and unsigned mantissa and
5153 * produces an unsigned result so this is just a wrapper that does
5154 * nothing (and is likely inlined).
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005155 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005156static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005157QCBOR_Private_ExponentitateUU(const uint64_t uMantissa,
5158 const int64_t nExponent,
5159 uint64_t *puResult,
5160 fExponentiator pfExp)
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005161{
5162 return (*pfExp)(uMantissa, nExponent, puResult);
5163}
5164
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005165#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005166
5167
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005168
5169
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005170/**
5171 * @brief Convert a CBOR big number to a uint64_t.
5172 *
5173 * @param[in] BigNum Bytes of the big number to convert.
5174 * @param[in] uMax Maximum value allowed for the result.
5175 * @param[out] pResult Place to put the unsigned integer result.
5176 *
5177 * @returns Error code
5178 *
5179 * Many values will overflow because a big num can represent a much
5180 * larger range than uint64_t.
5181 */
5182static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005183QCBOR_Private_ConvertBigNumToUnsigned(const UsefulBufC BigNum,
5184 const uint64_t uMax,
5185 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005186{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005187 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005188
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005189 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005190 const uint8_t *pByte = BigNum.ptr;
5191 size_t uLen = BigNum.len;
5192 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07005193 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005194 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005195 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07005196 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005197 }
5198
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005199 *pResult = uResult;
5200 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005201}
5202
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005203
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005204/**
5205 * @brief Convert a CBOR postive big number to a uint64_t.
5206 *
5207 * @param[in] BigNum Bytes of the big number to convert.
5208 * @param[out] pResult Place to put the unsigned integer result.
5209 *
5210 * @returns Error code
5211 *
5212 * Many values will overflow because a big num can represent a much
5213 * larger range than uint64_t.
5214 */
5215static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005216QCBOR_Private_ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum,
5217 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005218{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005219 return QCBOR_Private_ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005220}
5221
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005222
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005223/**
5224 * @brief Convert a CBOR positive big number to an int64_t.
5225 *
5226 * @param[in] BigNum Bytes of the big number to convert.
5227 * @param[out] pResult Place to put the signed integer result.
5228 *
5229 * @returns Error code
5230 *
5231 * Many values will overflow because a big num can represent a much
5232 * larger range than int64_t.
5233 */
5234static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005235QCBOR_Private_ConvertPositiveBigNumToSigned(const UsefulBufC BigNum,
5236 int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005237{
5238 uint64_t uResult;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005239 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5240 INT64_MAX,
5241 &uResult);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005242 if(uError) {
5243 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005244 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005245 /* Cast is safe because ConvertBigNumToUnsigned limits to INT64_MAX */
Laurence Lundbladee6430642020-03-14 21:15:44 -07005246 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005247 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005248}
5249
5250
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005251/**
5252 * @brief Convert a CBOR negative big number to an int64_t.
5253 *
5254 * @param[in] BigNum Bytes of the big number to convert.
5255 * @param[out] pnResult Place to put the signed integer result.
5256 *
5257 * @returns Error code
5258 *
5259 * Many values will overflow because a big num can represent a much
5260 * larger range than int64_t.
5261 */
5262static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005263QCBOR_Private_ConvertNegativeBigNumToSigned(const UsefulBufC BigNum,
5264 int64_t *pnResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005265{
5266 uint64_t uResult;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005267 /* The negative integer furthest from zero for a C int64_t is
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005268 * INT64_MIN which is expressed as -INT64_MAX - 1. The value of a
5269 * negative number in CBOR is computed as -n - 1 where n is the
5270 * encoded integer, where n is what is in the variable BigNum. When
5271 * converting BigNum to a uint64_t, the maximum value is thus
5272 * INT64_MAX, so that when it -n - 1 is applied to it the result
5273 * will never be further from 0 than INT64_MIN.
5274 *
5275 * -n - 1 <= INT64_MIN.
5276 * -n - 1 <= -INT64_MAX - 1
5277 * n <= INT64_MAX.
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005278 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005279 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5280 INT64_MAX,
5281 &uResult);
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005282 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005283 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005284 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005285
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005286 /* Now apply -n - 1. The cast is safe because
5287 * ConvertBigNumToUnsigned() is limited to INT64_MAX which does fit
5288 * is the largest positive integer that an int64_t can
5289 * represent. */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005290 *pnResult = -(int64_t)uResult - 1;
5291
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005292 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005293}
5294
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005295
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005296
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005297
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005298/**
5299 * @brief Convert integers and floats to an int64_t.
5300 *
5301 * @param[in] pItem The item to convert.
5302 * @param[in] uConvertTypes Bit mask list of conversion options.
5303 * @param[out] pnValue The resulting converted value.
5304 *
5305 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5306 * in uConvertTypes.
5307 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5308 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5309 * or too small.
5310 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005311static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005312QCBOR_Private_ConvertInt64(const QCBORItem *pItem,
5313 const uint32_t uConvertTypes,
5314 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005315{
5316 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005317 case QCBOR_TYPE_FLOAT:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005318 case QCBOR_TYPE_DOUBLE:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005319#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005320 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005321 /* https://pubs.opengroup.org/onlinepubs/009695399/functions/llround.html
5322 http://www.cplusplus.com/reference/cmath/llround/
5323 */
5324 // Not interested in FE_INEXACT
5325 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005326 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5327 *pnValue = llround(pItem->val.dfnum);
5328 } else {
5329 *pnValue = lroundf(pItem->val.fnum);
5330 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005331 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5332 // llround() shouldn't result in divide by zero, but catch
5333 // it here in case it unexpectedly does. Don't try to
5334 // distinguish between the various exceptions because it seems
5335 // they vary by CPU, compiler and OS.
5336 return QCBOR_ERR_FLOAT_EXCEPTION;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005337 }
5338 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005339 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005340 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005341#else
5342 return QCBOR_ERR_HW_FLOAT_DISABLED;
5343#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005344 break;
5345
5346 case QCBOR_TYPE_INT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005347 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005348 *pnValue = pItem->val.int64;
5349 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005350 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005351 }
5352 break;
5353
5354 case QCBOR_TYPE_UINT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005355 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005356 if(pItem->val.uint64 < INT64_MAX) {
5357 *pnValue = pItem->val.int64;
5358 } else {
5359 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5360 }
5361 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005362 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005363 }
5364 break;
5365
5366 default:
5367 return QCBOR_ERR_UNEXPECTED_TYPE;
5368 }
5369 return QCBOR_SUCCESS;
5370}
5371
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005372
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005373/**
5374 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5375 *
5376 * @param[in] pMe The decode context.
5377 * @param[in] uConvertTypes Bit mask list of conversion options.
5378 * @param[out] pnValue Result of the conversion.
5379 * @param[in,out] pItem Temporary space to store Item, returned item.
5380 *
5381 * See QCBORDecode_GetInt64Convert().
5382 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005383void
5384QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pMe,
5385 uint32_t uConvertTypes,
5386 int64_t *pnValue,
5387 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005388{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07005389 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005390 return;
5391 }
5392
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005393 QCBORError uError = QCBORDecode_GetNext(pMe, pItem);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005394 if(uError) {
5395 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005396 return;
5397 }
5398
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005399 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005400 uConvertTypes,
5401 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005402}
5403
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005404/**
5405 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5406 *
5407 * @param[in] pMe The decode context.
5408 * @param[in] nLabel Label to find in map.
5409 * @param[in] uConvertTypes Bit mask list of conversion options.
5410 * @param[out] pnValue Result of the conversion.
5411 * @param[in,out] pItem Temporary space to store Item, returned item.
5412 *
5413 * See QCBORDecode_GetInt64ConvertInMapN().
5414 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005415void
5416QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pMe,
5417 int64_t nLabel,
5418 uint32_t uConvertTypes,
5419 int64_t *pnValue,
5420 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005421{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005422 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005423 if(pMe->uLastError != QCBOR_SUCCESS) {
5424 return;
5425 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005426
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005427 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5428 uConvertTypes,
5429 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005430}
5431
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005432/**
5433 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5434 *
5435 * @param[in] pMe The decode context.
5436 * @param[in] szLabel Label to find in map.
5437 * @param[in] uConvertTypes Bit mask list of conversion options.
5438 * @param[out] pnValue Result of the conversion.
5439 * @param[in,out] pItem Temporary space to store Item, returned item.
5440 *
5441 * See QCBORDecode_GetInt64ConvertInMapSZ().
5442 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005443void
5444QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5445 const char * szLabel,
5446 uint32_t uConvertTypes,
5447 int64_t *pnValue,
5448 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005449{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005450 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005451 if(pMe->uLastError != QCBOR_SUCCESS) {
5452 return;
5453 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005454
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005455 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5456 uConvertTypes,
5457 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005458}
5459
5460
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005461/**
5462 * @brief Convert many number types to an int64_t.
5463 *
5464 * @param[in] pItem The item to convert.
5465 * @param[in] uConvertTypes Bit mask list of conversion options.
5466 * @param[out] pnValue The resulting converted value.
5467 *
5468 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5469 * in uConvertTypes.
5470 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5471 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5472 * or too small.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005473 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005474static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005475QCBOR_Private_Int64ConvertAll(const QCBORItem *pItem,
5476 const uint32_t uConvertTypes,
5477 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005478{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005479 switch(pItem->uDataType) {
5480
5481 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005482 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005483 return QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005484 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005485 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005486 }
5487 break;
5488
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005489 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005490 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005491 return QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005492 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005493 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005494 }
5495 break;
5496
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005497#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005498 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005499 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005500 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005501 pItem->val.expAndMantissa.nExponent,
5502 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005503 &QCBOR_Private_Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005504 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005505 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005506 }
5507 break;
5508
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005509 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005510 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005511 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005512 pItem->val.expAndMantissa.nExponent,
5513 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005514 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005515 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005516 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005517 }
5518 break;
5519
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005520 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005521 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005522 int64_t nMantissa;
5523 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005524 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005525 if(uErr) {
5526 return uErr;
5527 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005528 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005529 pItem->val.expAndMantissa.nExponent,
5530 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005531 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005532 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005533 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005534 }
5535 break;
5536
5537 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005538 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005539 int64_t nMantissa;
5540 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005541 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005542 if(uErr) {
5543 return uErr;
5544 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005545 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005546 pItem->val.expAndMantissa.nExponent,
5547 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005548 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005549 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005550 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005551 }
5552 break;
5553
5554 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005555 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005556 int64_t nMantissa;
5557 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005558 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005559 if(uErr) {
5560 return uErr;
5561 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005562 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005563 pItem->val.expAndMantissa.nExponent,
5564 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005565 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005566 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005567 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005568 }
5569 break;
5570
5571 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005572 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005573 int64_t nMantissa;
5574 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005575 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005576 if(uErr) {
5577 return uErr;
5578 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005579 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005580 pItem->val.expAndMantissa.nExponent,
5581 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005582 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005583 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005584 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005585 }
5586 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005587#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005588
Laurence Lundbladee6430642020-03-14 21:15:44 -07005589
Laurence Lundbladec4537442020-04-14 18:53:22 -07005590 default:
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005591 return QCBOR_ERR_UNEXPECTED_TYPE; }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005592}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005593
5594
Laurence Lundbladec4537442020-04-14 18:53:22 -07005595/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005596 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005597 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005598void
5599QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe,
5600 const uint32_t uConvertTypes,
5601 int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005602{
5603 QCBORItem Item;
5604
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005605 QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005606
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005607 if(pMe->uLastError == QCBOR_SUCCESS) {
5608 // The above conversion succeeded
5609 return;
5610 }
5611
Laurence Lundbladef6c86662020-05-12 02:08:00 -07005612 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005613 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07005614 return;
5615 }
5616
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005617 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5618 uConvertTypes,
5619 pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005620}
5621
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005622
5623/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005624 * Public function, see header qcbor/qcbor_decode.h file
5625 */
5626void
5627QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
5628 const int64_t nLabel,
5629 const uint32_t uConvertTypes,
5630 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005631{
5632 QCBORItem Item;
5633
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005634 QCBORDecode_Private_GetInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07005635 nLabel,
5636 uConvertTypes,
5637 pnValue,
5638 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005639
5640 if(pMe->uLastError == QCBOR_SUCCESS) {
5641 // The above conversion succeeded
5642 return;
5643 }
5644
5645 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5646 // The above conversion failed in a way that code below can't correct
5647 return;
5648 }
5649
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005650 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5651 uConvertTypes,
5652 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005653}
5654
5655
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005656/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005657 * Public function, see header qcbor/qcbor_decode.h file
5658 */
5659void
5660QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
5661 const char *szLabel,
5662 const uint32_t uConvertTypes,
5663 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005664{
5665 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005666 QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07005667 szLabel,
5668 uConvertTypes,
5669 pnValue,
5670 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005671
5672 if(pMe->uLastError == QCBOR_SUCCESS) {
5673 // The above conversion succeeded
5674 return;
5675 }
5676
5677 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5678 // The above conversion failed in a way that code below can't correct
5679 return;
5680 }
5681
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005682 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5683 uConvertTypes,
5684 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005685}
5686
5687
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005688/**
5689 * @brief Convert many number types to an uint64_t.
5690 *
5691 * @param[in] pItem The item to convert.
5692 * @param[in] uConvertTypes Bit mask list of conversion options.
5693 * @param[out] puValue The resulting converted value.
5694 *
5695 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5696 * in uConvertTypes.
5697 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5698 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5699 * or too small.
5700 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005701static QCBORError
5702QCBOR_Private_ConvertUInt64(const QCBORItem *pItem,
5703 const uint32_t uConvertTypes,
5704 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005705{
5706 switch(pItem->uDataType) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005707 case QCBOR_TYPE_DOUBLE:
5708 case QCBOR_TYPE_FLOAT:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005709#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005710 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005711 // Can't use llround here because it will not convert values
5712 // greater than INT64_MAX and less than UINT64_MAX that
5713 // need to be converted so it is more complicated.
5714 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
5715 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5716 if(isnan(pItem->val.dfnum)) {
5717 return QCBOR_ERR_FLOAT_EXCEPTION;
5718 } else if(pItem->val.dfnum < 0) {
5719 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5720 } else {
5721 double dRounded = round(pItem->val.dfnum);
5722 // See discussion in DecodeDateEpoch() for
5723 // explanation of - 0x7ff
5724 if(dRounded > (double)(UINT64_MAX- 0x7ff)) {
5725 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5726 }
5727 *puValue = (uint64_t)dRounded;
5728 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005729 } else {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005730 if(isnan(pItem->val.fnum)) {
5731 return QCBOR_ERR_FLOAT_EXCEPTION;
5732 } else if(pItem->val.fnum < 0) {
5733 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5734 } else {
5735 float fRounded = roundf(pItem->val.fnum);
5736 // See discussion in DecodeDateEpoch() for
5737 // explanation of - 0x7ff
5738 if(fRounded > (float)(UINT64_MAX- 0x7ff)) {
5739 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5740 }
5741 *puValue = (uint64_t)fRounded;
5742 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005743 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005744 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5745 // round() and roundf() shouldn't result in exceptions here, but
5746 // catch them to be robust and thorough. Don't try to
5747 // distinguish between the various exceptions because it seems
5748 // they vary by CPU, compiler and OS.
5749 return QCBOR_ERR_FLOAT_EXCEPTION;
5750 }
5751
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005752 } else {
5753 return QCBOR_ERR_UNEXPECTED_TYPE;
5754 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005755#else
5756 return QCBOR_ERR_HW_FLOAT_DISABLED;
5757#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005758 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005759
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005760 case QCBOR_TYPE_INT64:
5761 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
5762 if(pItem->val.int64 >= 0) {
5763 *puValue = (uint64_t)pItem->val.int64;
5764 } else {
5765 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5766 }
5767 } else {
5768 return QCBOR_ERR_UNEXPECTED_TYPE;
5769 }
5770 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005771
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005772 case QCBOR_TYPE_UINT64:
5773 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
5774 *puValue = pItem->val.uint64;
5775 } else {
5776 return QCBOR_ERR_UNEXPECTED_TYPE;
5777 }
5778 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005779
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005780 default:
5781 return QCBOR_ERR_UNEXPECTED_TYPE;
5782 }
5783
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005784 return QCBOR_SUCCESS;
5785}
Laurence Lundbladec4537442020-04-14 18:53:22 -07005786
5787
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005788/**
5789 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5790 *
5791 * @param[in] pMe The decode context.
5792 * @param[in] uConvertTypes Bit mask list of conversion options.
5793 * @param[out] puValue Result of the conversion.
5794 * @param[in,out] pItem Temporary space to store Item, returned item.
5795 *
5796 * See QCBORDecode_GetUInt64Convert().
5797 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005798void
5799QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pMe,
5800 const uint32_t uConvertTypes,
5801 uint64_t *puValue,
5802 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005803{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005804 if(pMe->uLastError != QCBOR_SUCCESS) {
5805 return;
5806 }
5807
Laurence Lundbladec4537442020-04-14 18:53:22 -07005808 QCBORItem Item;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005809
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005810 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
5811 if(uError) {
5812 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005813 return;
5814 }
5815
Laurence Lundbladea826c502020-05-10 21:07:00 -07005816 if(pItem) {
5817 *pItem = Item;
5818 }
5819
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005820 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(&Item,
5821 uConvertTypes,
5822 puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005823}
5824
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005825
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005826/**
5827 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5828 *
5829 * @param[in] pMe The decode context.
5830 * @param[in] nLabel Label to find in map.
5831 * @param[in] uConvertTypes Bit mask list of conversion options.
5832 * @param[out] puValue Result of the conversion.
5833 * @param[in,out] pItem Temporary space to store Item, returned item.
5834 *
5835 * See QCBORDecode_GetUInt64ConvertInMapN().
5836 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005837void
5838QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe,
5839 const int64_t nLabel,
5840 const uint32_t uConvertTypes,
5841 uint64_t *puValue,
5842 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005843{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005844 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005845 if(pMe->uLastError != QCBOR_SUCCESS) {
5846 return;
5847 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005848
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005849 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
5850 uConvertTypes,
5851 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005852}
5853
5854
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005855/**
5856 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5857 *
5858 * @param[in] pMe The decode context.
5859 * @param[in] szLabel Label to find in map.
5860 * @param[in] uConvertTypes Bit mask list of conversion options.
5861 * @param[out] puValue Result of the conversion.
5862 * @param[in,out] pItem Temporary space to store Item, returned item.
5863 *
5864 * See QCBORDecode_GetUInt64ConvertInMapSZ().
5865 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005866void
5867QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5868 const char *szLabel,
5869 const uint32_t uConvertTypes,
5870 uint64_t *puValue,
5871 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005872{
5873 if(pMe->uLastError != QCBOR_SUCCESS) {
5874 return;
5875 }
5876
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005877 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005878 if(pMe->uLastError != QCBOR_SUCCESS) {
5879 return;
5880 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005881
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005882 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
5883 uConvertTypes,
5884 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005885}
5886
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005887
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005888/**
5889 * @brief Convert many number types to an unt64_t.
5890 *
5891 * @param[in] pItem The item to convert.
5892 * @param[in] uConvertTypes Bit mask list of conversion options.
5893 * @param[out] puValue The resulting converted value.
5894 *
5895 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5896 * in uConvertTypes.
5897 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5898 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5899 * or too small.
5900 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005901static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005902QCBOR_Private_UInt64ConvertAll(const QCBORItem *pItem,
5903 const uint32_t uConvertTypes,
5904 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005905{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08005906 switch(pItem->uDataType) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005907
5908 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005909 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005910 return QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005911 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005912 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005913 }
5914 break;
5915
5916 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005917 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005918 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5919 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005920 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005921 }
5922 break;
5923
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005924#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005925
5926 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005927 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005928 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005929 pItem->val.expAndMantissa.nExponent,
5930 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005931 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005932 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005933 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005934 }
5935 break;
5936
5937 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005938 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005939 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005940 pItem->val.expAndMantissa.nExponent,
5941 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005942 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005943 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005944 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005945 }
5946 break;
5947
5948 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005949 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005950 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005951 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005952 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005953 if(uErr != QCBOR_SUCCESS) {
5954 return uErr;
5955 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005956 return QCBOR_Private_ExponentitateUU(uMantissa,
5957 pItem->val.expAndMantissa.nExponent,
5958 puValue,
5959 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005960 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005961 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005962 }
5963 break;
5964
5965 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005966 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005967 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5968 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005969 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005970 }
5971 break;
5972
5973 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005974 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005975 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005976 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005977 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum,
5978 &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005979 if(uErr != QCBOR_SUCCESS) {
5980 return uErr;
5981 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005982 return QCBOR_Private_ExponentitateUU(uMantissa,
5983 pItem->val.expAndMantissa.nExponent,
5984 puValue,
5985 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005986 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005987 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005988 }
5989 break;
5990
5991 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005992 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005993 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5994 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005995 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005996 }
5997 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005998#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005999 default:
6000 return QCBOR_ERR_UNEXPECTED_TYPE;
6001 }
6002}
6003
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006004
Laurence Lundblade4e2da002020-06-13 23:08:31 -07006005/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006006 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006007 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006008void
6009QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe,
6010 const uint32_t uConvertTypes,
6011 uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006012{
6013 QCBORItem Item;
6014
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006015 QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006016
Laurence Lundbladef6c86662020-05-12 02:08:00 -07006017 if(pMe->uLastError == QCBOR_SUCCESS) {
6018 // The above conversion succeeded
6019 return;
6020 }
6021
6022 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6023 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07006024 return;
6025 }
6026
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006027 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6028 uConvertTypes,
6029 puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006030}
6031
Laurence Lundbladec4537442020-04-14 18:53:22 -07006032
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006033/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006034 * Public function, see header qcbor/qcbor_decode.h file
6035 */
6036void
6037QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
6038 const int64_t nLabel,
6039 const uint32_t uConvertTypes,
6040 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006041{
6042 QCBORItem Item;
6043
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006044 QCBORDecode_Private_GetUInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006045 nLabel,
6046 uConvertTypes,
6047 puValue,
6048 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006049
6050 if(pMe->uLastError == QCBOR_SUCCESS) {
6051 // The above conversion succeeded
6052 return;
6053 }
6054
6055 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6056 // The above conversion failed in a way that code below can't correct
6057 return;
6058 }
6059
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006060 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6061 uConvertTypes,
6062 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006063}
6064
6065
6066/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006067 * Public function, see header qcbor/qcbor_decode.h file
6068 */
6069void
6070QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
6071 const char *szLabel,
6072 const uint32_t uConvertTypes,
6073 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006074{
6075 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006076 QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006077 szLabel,
6078 uConvertTypes,
6079 puValue,
6080 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006081
6082 if(pMe->uLastError == QCBOR_SUCCESS) {
6083 // The above conversion succeeded
6084 return;
6085 }
6086
6087 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6088 // The above conversion failed in a way that code below can't correct
6089 return;
6090 }
6091
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006092 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6093 uConvertTypes,
6094 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006095}
6096
6097
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006098
6099
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006100#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006101/**
6102 * @brief Basic conversions to a double.
6103 *
6104 * @param[in] pItem The item to convert
6105 * @param[in] uConvertTypes Bit flags indicating source types for conversion
6106 * @param[out] pdValue The value converted to a double
6107 *
6108 * This does the conversions that don't need much object code,
6109 * the conversions from int, uint and float to double.
6110 *
6111 * See QCBOR_Private_DoubleConvertAll() for the full set
6112 * of conversions.
6113 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006114static QCBORError
6115QCBOR_Private_ConvertDouble(const QCBORItem *pItem,
6116 const uint32_t uConvertTypes,
6117 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006118{
6119 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006120 case QCBOR_TYPE_FLOAT:
6121#ifndef QCBOR_DISABLE_FLOAT_HW_USE
6122 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6123 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006124 // Simple cast does the job.
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006125 *pdValue = (double)pItem->val.fnum;
6126 } else {
6127 return QCBOR_ERR_UNEXPECTED_TYPE;
6128 }
6129 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006130#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006131 return QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006132#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006133 break;
6134
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006135 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006136 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6137 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006138 *pdValue = pItem->val.dfnum;
6139 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006140 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006141 }
6142 }
6143 break;
6144
6145 case QCBOR_TYPE_INT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006146#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006147 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006148 // A simple cast seems to do the job with no worry of exceptions.
6149 // There will be precision loss for some values.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006150 *pdValue = (double)pItem->val.int64;
6151
6152 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006153 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006154 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006155#else
6156 return QCBOR_ERR_HW_FLOAT_DISABLED;
6157#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006158 break;
6159
6160 case QCBOR_TYPE_UINT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006161#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006162 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006163 // A simple cast seems to do the job with no worry of exceptions.
6164 // There will be precision loss for some values.
6165 *pdValue = (double)pItem->val.uint64;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006166 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006167 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006168 }
6169 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006170#else
6171 return QCBOR_ERR_HW_FLOAT_DISABLED;
6172#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006173
6174 default:
6175 return QCBOR_ERR_UNEXPECTED_TYPE;
6176 }
6177
6178 return QCBOR_SUCCESS;
6179}
6180
6181
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006182/**
6183 * @brief Almost-public method to decode a number and convert to double (semi-private).
6184 *
6185 * @param[in] pMe The decode context.
6186 * @param[in] uConvertTypes Bit mask list of conversion options
6187 * @param[out] pdValue The output of the conversion.
6188 * @param[in,out] pItem Temporary space to store Item, returned item.
6189 *
6190 * See QCBORDecode_GetDoubleConvert().
6191 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006192void
6193QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pMe,
6194 const uint32_t uConvertTypes,
6195 double *pdValue,
6196 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07006197{
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006198 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07006199 return;
6200 }
6201
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006202 QCBORError uError = QCBORDecode_GetNext(pMe, pItem);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006203 if(uError) {
6204 pMe->uLastError = (uint8_t)uError;
6205 return;
6206 }
6207
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006208 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006209 uConvertTypes,
6210 pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006211}
Laurence Lundbladec4537442020-04-14 18:53:22 -07006212
Laurence Lundbladec4537442020-04-14 18:53:22 -07006213
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006214/**
6215 * @brief Almost-public method to decode a number and convert to double (semi-private).
6216 *
6217 * @param[in] pMe The decode context.
6218 * @param[in] nLabel Label to find in map.
6219 * @param[in] uConvertTypes Bit mask list of conversion options
6220 * @param[out] pdValue The output of the conversion.
6221 * @param[in,out] pItem Temporary space to store Item, returned item.
6222 *
6223 * See QCBORDecode_GetDoubleConvertInMapN().
6224 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006225void
6226QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pMe,
6227 const int64_t nLabel,
6228 const uint32_t uConvertTypes,
6229 double *pdValue,
6230 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006231{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006232 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006233 if(pMe->uLastError != QCBOR_SUCCESS) {
6234 return;
6235 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006236
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006237 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6238 uConvertTypes,
6239 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006240}
6241
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006242
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006243/**
6244 * @brief Almost-public method to decode a number and convert to double (semi-private).
6245 *
6246 * @param[in] pMe The decode context.
6247 * @param[in] szLabel Label to find in map.
6248 * @param[in] uConvertTypes Bit mask list of conversion options
6249 * @param[out] pdValue The output of the conversion.
6250 * @param[in,out] pItem Temporary space to store Item, returned item.
6251 *
6252 * See QCBORDecode_GetDoubleConvertInMapSZ().
6253 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006254void
6255QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe,
6256 const char *szLabel,
6257 const uint32_t uConvertTypes,
6258 double *pdValue,
6259 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006260{
6261 if(pMe->uLastError != QCBOR_SUCCESS) {
6262 return;
6263 }
6264
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006265 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006266 if(pMe->uLastError != QCBOR_SUCCESS) {
6267 return;
6268 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006269
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006270 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6271 uConvertTypes,
6272 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006273}
6274
6275
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006276#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006277/**
6278 * @brief Convert a big number to double-precision float.
6279 *
6280 * @param[in] BigNum The big number to convert
6281 *
6282 * @returns The double value.
6283 *
6284 * This will always succeed. It will lose precision for larger
6285 * numbers. If the big number is too large to fit (more than
6286 * 1.7976931348623157E+308) infinity will be returned. NaN is never
6287 * returned.
6288 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006289static double
6290QCBOR_Private_ConvertBigNumToDouble(const UsefulBufC BigNum)
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006291{
6292 double dResult;
6293
6294 dResult = 0.0;
6295 const uint8_t *pByte = BigNum.ptr;
6296 size_t uLen = BigNum.len;
6297 /* This will overflow and become the float value INFINITY if the number
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006298 * is too large to fit. */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006299 while(uLen--) {
6300 dResult = (dResult * 256.0) + (double)*pByte++;
6301 }
6302
6303 return dResult;
6304}
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006305#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6306
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006307
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006308
6309
6310/**
6311 * @brief Convert many number types to a double.
6312 *
6313 * @param[in] pItem The item to convert.
6314 * @param[in] uConvertTypes Bit mask list of conversion options.
6315 * @param[out] pdValue The resulting converted value.
6316 *
6317 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6318 * in uConvertTypes.
6319 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6320 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6321 * or too small.
6322 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006323static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006324QCBOR_Private_DoubleConvertAll(const QCBORItem *pItem,
6325 const uint32_t uConvertTypes,
6326 double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006327{
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006328#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07006329 /*
Laurence Lundblade16a207a2021-09-18 17:22:46 -07006330 * What Every Computer Scientist Should Know About Floating-Point Arithmetic
6331 * https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
6332 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006333 switch(pItem->uDataType) {
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006334
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006335#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006336 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006337 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006338 // Underflow gives 0, overflow gives infinity
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006339 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6340 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
6341 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006342 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006343 }
6344 break;
6345
6346 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006347 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006348 // Underflow gives 0, overflow gives infinity
6349 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6350 exp2((double)pItem->val.expAndMantissa.nExponent);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006351 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006352 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006353 }
6354 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006355#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006356
6357 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006358 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006359 *pdValue = QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006360 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006361 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006362 }
6363 break;
6364
6365 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006366 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006367 *pdValue = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006368 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006369 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006370 }
6371 break;
6372
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006373#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006374 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006375 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006376 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006377 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6378 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006379 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006380 }
6381 break;
6382
6383 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006384 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006385 double dMantissa = -QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006386 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6387 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006388 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006389 }
6390 break;
6391
6392 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006393 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006394 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006395 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6396 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006397 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006398 }
6399 break;
6400
6401 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006402 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006403 double dMantissa = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006404 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6405 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006406 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006407 }
6408 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006409#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006410
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006411 default:
6412 return QCBOR_ERR_UNEXPECTED_TYPE;
6413 }
6414
6415 return QCBOR_SUCCESS;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006416
6417#else
6418 (void)pItem;
6419 (void)uConvertTypes;
6420 (void)pdValue;
6421 return QCBOR_ERR_HW_FLOAT_DISABLED;
6422#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6423
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006424}
6425
6426
6427/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006428 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006429 */
6430void
6431QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe,
6432 const uint32_t uConvertTypes,
6433 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006434{
6435
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006436 QCBORItem Item;
6437
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006438 QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006439
6440 if(pMe->uLastError == QCBOR_SUCCESS) {
6441 // The above conversion succeeded
6442 return;
6443 }
6444
6445 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6446 // The above conversion failed in a way that code below can't correct
6447 return;
6448 }
6449
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006450 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6451 uConvertTypes,
6452 pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006453}
6454
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006455
6456/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006457 * Public function, see header qcbor/qcbor_decode.h file
6458 */
6459void
6460QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe,
6461 const int64_t nLabel,
6462 const uint32_t uConvertTypes,
6463 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006464{
6465 QCBORItem Item;
6466
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006467 QCBORDecode_Private_GetDoubleConvertInMapN(pMe,
6468 nLabel,
6469 uConvertTypes,
6470 pdValue,
6471 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006472
6473 if(pMe->uLastError == QCBOR_SUCCESS) {
6474 // The above conversion succeeded
6475 return;
6476 }
6477
6478 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6479 // The above conversion failed in a way that code below can't correct
6480 return;
6481 }
6482
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006483 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6484 uConvertTypes,
6485 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006486}
6487
6488
6489/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006490 * Public function, see header qcbor/qcbor_decode.h file
6491 */
6492void
6493QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe,
6494 const char *szLabel,
6495 const uint32_t uConvertTypes,
6496 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006497{
6498 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006499 QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe,
6500 szLabel,
6501 uConvertTypes,
6502 pdValue,
6503 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006504
6505 if(pMe->uLastError == QCBOR_SUCCESS) {
6506 // The above conversion succeeded
6507 return;
6508 }
6509
6510 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6511 // The above conversion failed in a way that code below can't correct
6512 return;
6513 }
6514
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006515 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6516 uConvertTypes,
6517 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006518}
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006519#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006520
6521
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006522
6523
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006524#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006525/**
6526 * @brief Convert an integer to a big number
6527 *
6528 * @param[in] uInt The integer to convert.
6529 * @param[in] Buffer The buffer to output the big number to.
6530 *
6531 * @returns The big number or NULLUsefulBufC is the buffer is to small.
6532 *
6533 * This always succeeds unless the buffer is too small.
6534 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006535static UsefulBufC
6536QCBOR_Private_ConvertIntToBigNum(uint64_t uInt, const UsefulBuf Buffer)
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006537{
6538 while((uInt & 0xff00000000000000UL) == 0) {
6539 uInt = uInt << 8;
6540 };
6541
6542 UsefulOutBuf UOB;
6543
6544 UsefulOutBuf_Init(&UOB, Buffer);
6545
6546 while(uInt) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006547 UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff00000000000000UL) >> 56));
6548 uInt = uInt << 8;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006549 }
6550
6551 return UsefulOutBuf_OutUBuf(&UOB);
6552}
6553
6554
Laurence Lundblade37286c02022-09-03 10:05:02 -07006555/**
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006556 * @brief Check and/or complete exponent and mantissa item.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006557 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006558 * @param[in] pMe The decoder context.
6559 * @param[in] TagSpec Expected type(s).
6560 * @param[in,out] pItem See below.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006561 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006562 * This is for decimal fractions and big floats, both of which are an
6563 * exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006564 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006565 * If the item item had a tag number indicating it was a
6566 * decimal fraction or big float, then the input @c pItem will
6567 * have been decoded as exponent and mantissa. If there was
6568 * no tag number, the caller is asking this be decoded as a
6569 * big float or decimal fraction and @c pItem just has the
6570 * first item in an exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006571 *
6572 * On output, the item is always a fully decoded decimal fraction or
6573 * big float.
6574 *
6575 * This errors out if the input type does not meet the TagSpec.
6576 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07006577static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006578QCBOR_Private_ExpMantissaTypeHandler(QCBORDecodeContext *pMe,
6579 const QCBOR_Private_TagSpec TagSpec,
6580 QCBORItem *pItem)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006581{
6582 QCBORError uErr;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006583
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006584 /* pItem could either be a decoded exponent and mantissa or
6585 * the opening array of an undecoded exponent and mantissa. This
Laurence Lundblade37286c02022-09-03 10:05:02 -07006586 * check will succeed on either, but doesn't say which it was.
6587 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006588 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07006589 if(uErr != QCBOR_SUCCESS) {
6590 goto Done;
6591 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006592
Laurence Lundblade37286c02022-09-03 10:05:02 -07006593 if(pItem->uDataType == QCBOR_TYPE_ARRAY) {
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006594 /* The item is an array, which means is is an undecoded exponent
6595 * and mantissa. This call consumes the items in the array and
6596 * results in a decoded exponent and mantissa in pItem. This is
Laurence Lundblade37286c02022-09-03 10:05:02 -07006597 * the case where there was no tag.
6598 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006599 uErr = QCBORDecode_Private_ExpMantissa(pMe, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006600 if(uErr != QCBOR_SUCCESS) {
6601 goto Done;
6602 }
6603
Laurence Lundblade37286c02022-09-03 10:05:02 -07006604 /* The above decode didn't determine whether it is a decimal
6605 * fraction or big num. Which of these two depends on what the
6606 * caller wants it decoded as since there is no tag, so fish the
6607 * type out of the TagSpec. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006608 pItem->uDataType = QCBOR_Private_ExpMantissaDataType(TagSpec.uTaggedTypes[0], pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07006609
6610 /* No need to check the type again. All that we need to know was
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006611 * that it decoded correctly as a exponent and mantissa. The
Laurence Lundblade37286c02022-09-03 10:05:02 -07006612 * QCBOR type is set out by what was requested.
6613 */
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006614 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07006615
6616 /* If the item was not an array and the check passed, then
6617 * it is a fully decoded big float or decimal fraction and
6618 * matches what is requested.
6619 */
6620
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006621Done:
6622 return uErr;
6623}
6624
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006625
Laurence Lundblade37286c02022-09-03 10:05:02 -07006626/* Some notes from the work to disable tags.
6627 *
6628 * The API for big floats and decimal fractions seems good.
6629 * If there's any issue with it it's that the code size to
6630 * implement is a bit large because of the conversion
6631 * to/from int and bignum that is required. There is no API
6632 * that doesn't do the conversion so dead stripping will never
6633 * leave that code out.
6634 *
6635 * The implementation itself seems correct, but not as clean
6636 * and neat as it could be. It could probably be smaller too.
6637 *
6638 * The implementation has three main parts / functions
6639 * - The decoding of the array of two
6640 * - All the tag and type checking for the various API functions
6641 * - Conversion to/from bignum and int
6642 *
6643 * The type checking seems like it wastes the most code for
6644 * what it needs to do.
6645 *
6646 * The inlining for the conversion is probably making the
6647 * overall code base larger.
6648 *
6649 * The tests cases could be organized a lot better and be
6650 * more thorough.
6651 *
6652 * Seems also like there could be more common code in the
6653 * first tier part of the public API. Some functions only
6654 * vary by a TagSpec.
6655 */
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006656
6657/**
6658 * @brief Common processor for exponent and mantissa.
6659 *
6660 * @param[in] pMe The decode context.
6661 * @param[in] TagSpec The expected/allowed tags.
6662 * @param[in] pItem The data item to process.
6663 * @param[out] pnMantissa The returned mantissa as an int64_t.
6664 * @param[out] pnExponent The returned exponent as an int64_t.
6665 *
6666 * This handles exponent and mantissa for base 2 and 10. This
6667 * is limited to a mantissa that is an int64_t. See also
6668 * QCBORDecode_Private_ProcessExpMantissaBig().
6669 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006670static void
6671QCBOR_Private_ProcessExpMantissa(QCBORDecodeContext *pMe,
6672 const QCBOR_Private_TagSpec TagSpec,
6673 QCBORItem *pItem,
6674 int64_t *pnMantissa,
6675 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006676{
6677 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006678
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006679 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006680 if(uErr != QCBOR_SUCCESS) {
6681 goto Done;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006682 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006683
Laurence Lundblade9b334962020-08-27 10:55:53 -07006684 switch (pItem->uDataType) {
6685
6686 case QCBOR_TYPE_DECIMAL_FRACTION:
6687 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade9b334962020-08-27 10:55:53 -07006688 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006689 *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
Laurence Lundblade9b334962020-08-27 10:55:53 -07006690 break;
6691
Laurence Lundblade37286c02022-09-03 10:05:02 -07006692#ifndef QCBOR_DISABLE_TAGS
6693 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006694 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
6695 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
6696 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006697 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006698 break;
6699
6700 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
6701 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
6702 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006703 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006704 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006705#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006706
6707 default:
6708 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
6709 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006710
6711 Done:
6712 pMe->uLastError = (uint8_t)uErr;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006713}
6714
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006715
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006716/**
6717 * @brief Decode exponent and mantissa into a big number.
6718 *
6719 * @param[in] pMe The decode context.
6720 * @param[in] TagSpec The expected/allowed tags.
6721 * @param[in] pItem Item to decode and convert.
6722 * @param[in] BufferForMantissa Buffer to output mantissa into.
6723 * @param[out] pMantissa The output mantissa.
6724 * @param[out] pbIsNegative The sign of the output.
6725 * @param[out] pnExponent The mantissa of the output.
6726 *
6727 * This is the common processing of a decimal fraction or a big float
6728 * into a big number. This will decode and consume all the CBOR items
6729 * that make up the decimal fraction or big float.
6730 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006731static void
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006732QCBORDecode_Private_ProcessExpMantissaBig(QCBORDecodeContext *pMe,
6733 const QCBOR_Private_TagSpec TagSpec,
6734 QCBORItem *pItem,
6735 const UsefulBuf BufferForMantissa,
6736 UsefulBufC *pMantissa,
6737 bool *pbIsNegative,
6738 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006739{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006740 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006741
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006742 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006743 if(uErr != QCBOR_SUCCESS) {
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006744 goto Done;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006745 }
6746
6747 uint64_t uMantissa;
6748
6749 switch (pItem->uDataType) {
6750
6751 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006752 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006753 /* See comments in ExponentiateNN() on handling INT64_MIN */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006754 if(pItem->val.expAndMantissa.Mantissa.nInt >= 0) {
6755 uMantissa = (uint64_t)pItem->val.expAndMantissa.Mantissa.nInt;
6756 *pbIsNegative = false;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006757 } else if(pItem->val.expAndMantissa.Mantissa.nInt != INT64_MIN) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006758 uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt;
6759 *pbIsNegative = true;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006760 } else {
6761 uMantissa = (uint64_t)INT64_MAX+1;
6762 *pbIsNegative = true;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006763 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006764 *pMantissa = QCBOR_Private_ConvertIntToBigNum(uMantissa,
6765 BufferForMantissa);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006766 *pnExponent = pItem->val.expAndMantissa.nExponent;
6767 break;
6768
Laurence Lundblade37286c02022-09-03 10:05:02 -07006769#ifndef QCBOR_DISABLE_TAGS
6770 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006771 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006772 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006773 *pnExponent = pItem->val.expAndMantissa.nExponent;
6774 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6775 *pbIsNegative = false;
6776 break;
6777
6778 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006779 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006780 *pnExponent = pItem->val.expAndMantissa.nExponent;
6781 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6782 *pbIsNegative = true;
6783 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006784#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006785
6786 default:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006787 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006788 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006789
6790Done:
6791 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006792}
6793
6794
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006795/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006796 * Public function, see header qcbor/qcbor_decode.h file
6797 */
6798void
6799QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe,
6800 const uint8_t uTagRequirement,
6801 int64_t *pnMantissa,
6802 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006803{
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006804 if(pMe->uLastError != QCBOR_SUCCESS) {
6805 return;
6806 }
6807
6808 QCBORItem Item;
6809 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
6810 if(uError) {
6811 pMe->uLastError = (uint8_t)uError;
6812 return;
6813 }
6814
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006815 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006816 {
6817 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006818 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6819 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6820 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006821 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006822
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006823 QCBOR_Private_ProcessExpMantissa(pMe,
6824 TagSpec,
6825 &Item,
6826 pnMantissa,
6827 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006828}
6829
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006830
6831/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006832 * Public function, see header qcbor/qcbor_decode.h file
6833 */
6834void
6835QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe,
6836 const int64_t nLabel,
6837 const uint8_t uTagRequirement,
6838 int64_t *pnMantissa,
6839 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006840{
6841 if(pMe->uLastError != QCBOR_SUCCESS) {
6842 return;
6843 }
6844
6845 QCBORItem Item;
6846 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
6847
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006848 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006849 {
6850 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006851 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6852 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6853 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006854 };
6855
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006856 QCBOR_Private_ProcessExpMantissa(pMe,
6857 TagSpec,
6858 &Item,
6859 pnMantissa,
6860 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006861}
6862
6863
6864/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006865 * Public function, see header qcbor/qcbor_decode.h file
6866 */
6867void
6868QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
6869 const char *szLabel,
6870 const uint8_t uTagRequirement,
6871 int64_t *pnMantissa,
6872 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006873{
6874 if(pMe->uLastError != QCBOR_SUCCESS) {
6875 return;
6876 }
6877
6878 QCBORItem Item;
6879 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
6880
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006881 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006882 {
6883 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006884 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6885 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6886 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006887 };
Laurence Lundblade9b334962020-08-27 10:55:53 -07006888
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006889 QCBOR_Private_ProcessExpMantissa(pMe,
6890 TagSpec,
6891 &Item,
6892 pnMantissa,
6893 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006894}
6895
6896
6897/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006898 * Public function, see header qcbor/qcbor_decode.h file
6899 */
6900void
6901QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe,
6902 const uint8_t uTagRequirement,
6903 const UsefulBuf MantissaBuffer,
6904 UsefulBufC *pMantissa,
6905 bool *pbMantissaIsNegative,
6906 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006907{
6908 if(pMe->uLastError != QCBOR_SUCCESS) {
6909 return;
6910 }
6911
6912 QCBORItem Item;
6913 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
6914 if(uError) {
6915 pMe->uLastError = (uint8_t)uError;
6916 return;
6917 }
6918
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006919 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006920 {
6921 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006922 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6923 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6924 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006925 };
6926
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006927 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
6928 TagSpec,
6929 &Item,
6930 MantissaBuffer,
6931 pMantissa,
6932 pbMantissaIsNegative,
6933 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006934}
6935
6936
6937/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006938 * Public function, see header qcbor/qcbor_decode.h file
6939 */
6940void
6941QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe,
6942 const int64_t nLabel,
6943 const uint8_t uTagRequirement,
6944 const UsefulBuf BufferForMantissa,
6945 UsefulBufC *pMantissa,
6946 bool *pbIsNegative,
6947 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006948{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006949 if(pMe->uLastError != QCBOR_SUCCESS) {
6950 return;
6951 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006952
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006953 QCBORItem Item;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006954 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006955 if(pMe->uLastError != QCBOR_SUCCESS) {
6956 return;
6957 }
6958
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006959 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006960 {
6961 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006962 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6963 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6964 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006965 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006966
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006967 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
6968 TagSpec,
6969 &Item,
6970 BufferForMantissa,
6971 pMantissa,
6972 pbIsNegative,
6973 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006974}
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006975
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006976
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006977/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006978 * Public function, see header qcbor/qcbor_decode.h file
6979 */
6980void
6981QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe,
6982 const char *szLabel,
6983 const uint8_t uTagRequirement,
6984 const UsefulBuf BufferForMantissa,
6985 UsefulBufC *pMantissa,
6986 bool *pbIsNegative,
6987 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006988{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006989 if(pMe->uLastError != QCBOR_SUCCESS) {
6990 return;
6991 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006992
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006993 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006994 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
6995 if(pMe->uLastError != QCBOR_SUCCESS) {
6996 return;
6997 }
6998
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006999 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007000 {
7001 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007002 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7003 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7004 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007005 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007006
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007007 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7008 TagSpec,
7009 &Item,
7010 BufferForMantissa,
7011 pMantissa,
7012 pbIsNegative,
7013 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007014}
7015
7016
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007017/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007018 * Public function, see header qcbor/qcbor_decode.h file
7019 */
7020void
7021QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe,
7022 const uint8_t uTagRequirement,
7023 int64_t *pnMantissa,
7024 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007025{
7026 if(pMe->uLastError != QCBOR_SUCCESS) {
7027 return;
7028 }
7029
7030 QCBORItem Item;
7031 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
7032 if(uError) {
7033 pMe->uLastError = (uint8_t)uError;
7034 return;
7035 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007036 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007037 {
7038 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007039 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7040 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7041 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007042 };
7043
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007044 QCBOR_Private_ProcessExpMantissa(pMe,
7045 TagSpec,
7046 &Item,
7047 pnMantissa,
7048 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007049}
7050
7051
7052/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007053 * Public function, see header qcbor/qcbor_decode.h file
7054 */
7055void
7056QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe,
7057 const int64_t nLabel,
7058 const uint8_t uTagRequirement,
7059 int64_t *pnMantissa,
7060 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007061{
7062 if(pMe->uLastError != QCBOR_SUCCESS) {
7063 return;
7064 }
7065
7066 QCBORItem Item;
7067 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7068 if(pMe->uLastError != QCBOR_SUCCESS) {
7069 return;
7070 }
7071
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007072 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007073 {
7074 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007075 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7076 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7077 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007078 };
7079
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007080 QCBOR_Private_ProcessExpMantissa(pMe,
7081 TagSpec,
7082 &Item,
7083 pnMantissa,
7084 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007085}
7086
7087
7088/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007089 * Public function, see header qcbor/qcbor_decode.h file
7090 */
7091void
7092QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe,
7093 const char *szLabel,
7094 const uint8_t uTagRequirement,
7095 int64_t *pnMantissa,
7096 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007097{
7098 if(pMe->uLastError != QCBOR_SUCCESS) {
7099 return;
7100 }
7101
7102 QCBORItem Item;
7103 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7104 if(pMe->uLastError != QCBOR_SUCCESS) {
7105 return;
7106 }
7107
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007108 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007109 {
7110 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007111 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7112 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7113 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007114 };
7115
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007116 QCBOR_Private_ProcessExpMantissa(pMe,
7117 TagSpec,
7118 &Item,
7119 pnMantissa,
7120 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007121}
7122
7123
7124/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007125 * Public function, see header qcbor/qcbor_decode.h file
7126 */
7127void
7128QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe,
7129 const uint8_t uTagRequirement,
7130 const UsefulBuf MantissaBuffer,
7131 UsefulBufC *pMantissa,
7132 bool *pbMantissaIsNegative,
7133 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007134{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007135 if(pMe->uLastError != QCBOR_SUCCESS) {
7136 return;
7137 }
7138
7139 QCBORItem Item;
7140 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
7141 if(uError) {
7142 pMe->uLastError = (uint8_t)uError;
7143 return;
7144 }
7145
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007146 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007147 {
7148 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007149 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7150 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7151 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007152 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007153
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007154 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7155 TagSpec,
7156 &Item,
7157 MantissaBuffer,
7158 pMantissa,
7159 pbMantissaIsNegative,
7160 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007161}
7162
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007163
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007164/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007165 * Public function, see header qcbor/qcbor_decode.h file
7166 */
7167void
7168QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe,
7169 const int64_t nLabel,
7170 const uint8_t uTagRequirement,
7171 const UsefulBuf BufferForMantissa,
7172 UsefulBufC *pMantissa,
7173 bool *pbIsNegative,
7174 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007175{
7176 if(pMe->uLastError != QCBOR_SUCCESS) {
7177 return;
7178 }
7179
7180 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007181 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7182 if(pMe->uLastError != QCBOR_SUCCESS) {
7183 return;
7184 }
7185
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007186 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007187 {
7188 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007189 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7190 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7191 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007192 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007193
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007194 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7195 TagSpec,
7196 &Item,
7197 BufferForMantissa,
7198 pMantissa,
7199 pbIsNegative,
7200 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007201}
7202
7203
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007204/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007205 * Public function, see header qcbor/qcbor_decode.h file
7206 */
7207void
7208QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe,
7209 const char *szLabel,
7210 const uint8_t uTagRequirement,
7211 const UsefulBuf BufferForMantissa,
7212 UsefulBufC *pMantissa,
7213 bool *pbIsNegative,
7214 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007215{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007216 if(pMe->uLastError != QCBOR_SUCCESS) {
7217 return;
7218 }
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007219
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007220 QCBORItem Item;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007221 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7222 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007223 return;
7224 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007225
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007226 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007227 {
7228 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007229 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7230 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7231 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007232 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007233
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007234 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7235 TagSpec,
7236 &Item,
7237 BufferForMantissa,
7238 pMantissa,
7239 pbIsNegative,
7240 pnExponent);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007241}
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007242
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07007243#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */