blob: 41e6b2172e606369c135f95caa04ae834a2d1170 [file] [log] [blame]
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001/*==============================================================================
Laurence Lundbladed92a6162018-11-01 11:38:35 +07002 Copyright (c) 2016-2018, The Linux Foundation.
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003 Copyright (c) 2018-2024, Laurence Lundblade.
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02004 Copyright (c) 2021, Arm Limited.
Laurence Lundbladed92a6162018-11-01 11:38:35 +07005 All rights reserved.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08006
Laurence Lundblade0dbc9172018-11-01 14:17:21 +07007Redistribution and use in source and binary forms, with or without
8modification, are permitted provided that the following conditions are
9met:
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above
13 copyright notice, this list of conditions and the following
14 disclaimer in the documentation and/or other materials provided
15 with the distribution.
16 * Neither the name of The Linux Foundation nor the names of its
17 contributors, nor the name "Laurence Lundblade" may be used to
18 endorse or promote products derived from this software without
19 specific prior written permission.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080020
Laurence Lundblade0dbc9172018-11-01 14:17:21 +070021THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
22WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
24ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
25BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
30OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Laurence Lundbladeee851742020-01-08 08:37:05 -080032 =============================================================================*/
Laurence Lundblade624405d2018-09-18 20:10:47 -070033
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080034
Laurence Lundblade844bb5c2020-03-01 17:27:25 -080035#include "qcbor/qcbor_decode.h"
Laurence Lundblade67257dc2020-07-27 03:33:37 -070036#include "qcbor/qcbor_spiffy_decode.h"
Laurence Lundblade3f1318a2021-01-04 18:26:44 -080037#include "ieee754.h" /* Does not use math.h */
Laurence Lundbladec7114722020-08-13 05:11:40 -070038
39#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade3f1318a2021-01-04 18:26:44 -080040
41#include <math.h> /* For isnan(), llround(), llroudf(), round(), roundf(),
42 * pow(), exp2()
43 */
44#include <fenv.h> /* feclearexcept(), fetestexcept() */
45
Laurence Lundbladee2c893c2020-12-26 17:41:53 -080046#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070047
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070048
Laurence Lundblade68cb61c2023-02-12 13:21:44 -080049#if (defined(__GNUC__) && !defined(__clang__))
Laurence Lundblade8e36f812024-01-26 10:59:29 -070050/*
Laurence Lundblade68cb61c2023-02-12 13:21:44 -080051 * This is how the -Wmaybe-uninitialized compiler warning is
52 * handled. It can’t be ignored because some version of gcc enable it
53 * with -Wall which is a common and useful gcc warning option. It also
54 * can’t be ignored because it is the goal of QCBOR to compile clean
55 * out of the box in all environments.
56 *
57 * The big problem with -Wmaybe-uninitialized is that it generates
58 * false positives. It complains things are uninitialized when they
59 * are not. This is because it is not a thorough static analyzer. This
60 * is why “maybe” is in its name. The problem is it is just not
61 * thorough enough to understand all the code (and someone saw fit to
62 * put it in gcc and worse to enable it with -Wall).
63 *
64 * One solution would be to change the code so -Wmaybe-uninitialized
65 * doesn’t get confused, for example adding an unnecessary extra
66 * initialization to zero. (If variables were truly uninitialized, the
67 * correct path is to understand the code thoroughly and set them to
68 * the correct value at the correct time; in essence this is already
69 * done; -Wmaybe-uninitialized just can’t tell). This path is not
70 * taken because it makes the code bigger and is kind of the tail
71 * wagging the dog.
72 *
73 * The solution here is to just use a pragma to disable it for the
74 * whole file. Disabling it for each line makes the code fairly ugly
75 * requiring #pragma to push, pop and ignore. Another reason is the
76 * warnings issues vary by version of gcc and which optimization
77 * optimizations are selected. Another reason is that compilers other
78 * than gcc don’t have -Wmaybe-uninitialized.
79 *
80 * One may ask how to be sure these warnings are false positives and
81 * not real issues. 1) The code has been read carefully to check. 2)
82 * Testing is pretty thorough. 3) This code has been run through
83 * thorough high-quality static analyzers.
84 *
85 * In particularly, most of the warnings are about
86 * Item.Item->uDataType being uninitialized. QCBORDecode_GetNext()
87 * *always* sets this value and test case confirm
88 * this. -Wmaybe-uninitialized just can't tell.
89 *
90 * https://stackoverflow.com/questions/5080848/disable-gcc-may-be-used-uninitialized-on-a-particular-variable
91 */
92#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
Laurence Lundblade8e36f812024-01-26 10:59:29 -070093#endif
Laurence Lundblade68cb61c2023-02-12 13:21:44 -080094
95
96
Laurence Lundblade3f1318a2021-01-04 18:26:44 -080097
Laurence Lundbladea9489f82020-09-12 13:50:56 -070098#define SIZEOF_C_ARRAY(array,type) (sizeof(array)/sizeof(type))
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070099
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700100
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800101
102
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700103static bool
104QCBORItem_IsMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700105{
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700106 const uint8_t uDataType = Item.uDataType;
Laurence Lundblade02625d42020-06-25 14:41:41 -0700107 return uDataType == QCBOR_TYPE_MAP ||
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700108#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
109 uDataType == QCBOR_TYPE_MAP_AS_ARRAY ||
110#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
111 uDataType == QCBOR_TYPE_ARRAY;
Laurence Lundblade02625d42020-06-25 14:41:41 -0700112}
113
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700114static bool
115QCBORItem_IsEmptyDefiniteLengthMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700116{
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700117 if(!QCBORItem_IsMapOrArray(Item)){
Laurence Lundblade02625d42020-06-25 14:41:41 -0700118 return false;
119 }
120
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700121 if(Item.val.uCount != 0) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700122 return false;
123 }
124 return true;
125}
126
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700127static bool
128QCBORItem_IsIndefiniteLengthMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700129{
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800130#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700131 if(!QCBORItem_IsMapOrArray(Item)){
Laurence Lundblade02625d42020-06-25 14:41:41 -0700132 return false;
133 }
134
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700135 if(Item.val.uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700136 return false;
137 }
138 return true;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800139#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700140 (void)Item;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800141 return false;
142#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700143}
144
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700145/* Return true if the labels in Item1 and Item2 are the same.
146 Works only for integer and string labels. Returns false
147 for any other type. */
148static bool
149QCBORItem_MatchLabel(const QCBORItem Item1, const QCBORItem Item2)
150{
151 if(Item1.uLabelType == QCBOR_TYPE_INT64) {
152 if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
153 return true;
154 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700155#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700156 } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
157 if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
158 return true;
159 }
160 } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
161 if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
162 return true;
163 }
164 } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
165 if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
166 return true;
167 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700168#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700169 }
170
171 /* Other label types are never matched */
172 return false;
173}
174
175
176/*
177 Returns true if Item1 and Item2 are the same type
178 or if either are of QCBOR_TYPE_ANY.
179 */
180static bool
181QCBORItem_MatchType(const QCBORItem Item1, const QCBORItem Item2)
182{
183 if(Item1.uDataType == Item2.uDataType) {
184 return true;
185 } else if(Item1.uDataType == QCBOR_TYPE_ANY) {
186 return true;
187 } else if(Item2.uDataType == QCBOR_TYPE_ANY) {
188 return true;
189 }
190 return false;
191}
192
Laurence Lundblade02625d42020-06-25 14:41:41 -0700193
Laurence Lundbladeee851742020-01-08 08:37:05 -0800194/*===========================================================================
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700195 DecodeNesting -- Tracking array/map/sequence/bstr-wrapped nesting
Laurence Lundbladeee851742020-01-08 08:37:05 -0800196 ===========================================================================*/
197
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700198/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800199 * See comments about and typedef of QCBORDecodeNesting in qcbor_private.h,
200 * the data structure all these functions work on.
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700201 */
202
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700203
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700204static uint8_t
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700205DecodeNesting_GetCurrentLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700206{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700207 const ptrdiff_t nLevel = pNesting->pCurrent - &(pNesting->pLevels[0]);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800208 /* Limit in DecodeNesting_Descend against more than
209 * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
Laurence Lundblade02625d42020-06-25 14:41:41 -0700210 */
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700211 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700212}
213
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700214
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700215static uint8_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700216DecodeNesting_GetBoundedModeLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700217{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700218 const ptrdiff_t nLevel = pNesting->pCurrentBounded - &(pNesting->pLevels[0]);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800219 /* Limit in DecodeNesting_Descend against more than
220 * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
Laurence Lundblade02625d42020-06-25 14:41:41 -0700221 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700222 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700223}
224
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700225
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700226static uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700227DecodeNesting_GetMapOrArrayStart(const QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700228{
229 return pNesting->pCurrentBounded->u.ma.uStartOffset;
230}
231
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700232
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700233static bool
Laurence Lundblade085d7952020-07-24 10:26:30 -0700234DecodeNesting_IsBoundedEmpty(const QCBORDecodeNesting *pNesting)
235{
236 if(pNesting->pCurrentBounded->u.ma.uCountCursor == QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
237 return true;
238 } else {
239 return false;
240 }
241}
242
243
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700244static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700245DecodeNesting_IsCurrentAtTop(const QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700246{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700247 if(pNesting->pCurrent == &(pNesting->pLevels[0])) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700248 return true;
249 } else {
250 return false;
251 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700252}
253
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700254
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700255static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700256DecodeNesting_IsCurrentDefiniteLength(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700257{
258 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800259 /* Not a map or array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700260 return false;
261 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800262
263#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700264 if(pNesting->pCurrent->u.ma.uCountTotal == QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800265 /* Is indefinite */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700266 return false;
267 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800268
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800269#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
270
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800271 /* All checks passed; is a definte length map or array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700272 return true;
273}
274
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700275static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700276DecodeNesting_IsCurrentBstrWrapped(const QCBORDecodeNesting *pNesting)
Laurence Lundblade642282a2020-06-23 12:00:33 -0700277{
278 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800279 /* is a byte string */
Laurence Lundblade642282a2020-06-23 12:00:33 -0700280 return true;
281 }
282 return false;
283}
284
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700285
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700286static bool
287DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700288{
289 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
290 return true;
291 }
Laurence Lundblade02625d42020-06-25 14:41:41 -0700292 if(pNesting->pCurrent->u.ma.uStartOffset != QCBOR_NON_BOUNDED_OFFSET) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700293 return true;
294 }
295 return false;
296}
297
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700298
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700299static void
300DecodeNesting_SetMapOrArrayBoundedMode(QCBORDecodeNesting *pNesting, bool bIsEmpty, size_t uStart)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700301{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800302 /* Should be only called on maps and arrays */
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700303 /*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800304 * DecodeNesting_EnterBoundedMode() checks to be sure uStart is not
305 * larger than DecodeNesting_EnterBoundedMode which keeps it less than
306 * uin32_t so the cast is safe.
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700307 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700308 pNesting->pCurrent->u.ma.uStartOffset = (uint32_t)uStart;
Laurence Lundblade085d7952020-07-24 10:26:30 -0700309
310 if(bIsEmpty) {
311 pNesting->pCurrent->u.ma.uCountCursor = QCBOR_COUNT_INDICATES_ZERO_LENGTH;
312 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700313}
314
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700315
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700316static void
317DecodeNesting_ClearBoundedMode(QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700318{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700319 pNesting->pCurrent->u.ma.uStartOffset = QCBOR_NON_BOUNDED_OFFSET;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700320}
321
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700322
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700323static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700324DecodeNesting_IsAtEndOfBoundedLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700325{
326 if(pNesting->pCurrentBounded == NULL) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800327 /* No bounded map or array set up */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700328 return false;
329 }
330 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800331 /* Not a map or array; end of those is by byte count */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700332 return false;
333 }
Laurence Lundblade6ab01fb2020-10-01 13:04:49 -0700334 if(!DecodeNesting_IsCurrentBounded(pNesting)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800335 /* In a traveral at a level deeper than the bounded level */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700336 return false;
337 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800338 /* Works for both definite- and indefinitelength maps/arrays */
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800339 if(pNesting->pCurrentBounded->u.ma.uCountCursor != 0 &&
340 pNesting->pCurrentBounded->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800341 /* Count is not zero, still unconsumed item */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700342 return false;
343 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800344 /* All checks passed, got to the end of an array or map*/
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700345 return true;
346}
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700347
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700348
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700349static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700350DecodeNesting_IsEndOfDefiniteLengthMapOrArray(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700351{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800352 /* Must only be called on map / array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700353 if(pNesting->pCurrent->u.ma.uCountCursor == 0) {
354 return true;
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700355 } else {
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700356 return false;
357 }
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700358}
359
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700360
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700361static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700362DecodeNesting_IsCurrentTypeMap(const QCBORDecodeNesting *pNesting)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700363{
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700364 if(pNesting->pCurrent->uLevelType == CBOR_MAJOR_TYPE_MAP) {
365 return true;
366 } else {
367 return false;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700368 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700369}
370
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700371
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700372static bool
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700373DecodeNesting_IsBoundedType(const QCBORDecodeNesting *pNesting, uint8_t uType)
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700374{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700375 if(pNesting->pCurrentBounded == NULL) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700376 return false;
377 }
Laurence Lundblade02625d42020-06-25 14:41:41 -0700378
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700379 uint8_t uItemDataType = pNesting->pCurrentBounded->uLevelType;
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700380#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700381 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
382 uItemDataType = QCBOR_TYPE_ARRAY;
383 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700384#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700385
386 if(uItemDataType != uType) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700387 return false;
388 }
389
390 return true;
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700391}
392
Laurence Lundblade02625d42020-06-25 14:41:41 -0700393
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700394static void
Laurence Lundblade6c8a4442020-06-22 22:16:11 -0700395DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700396{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800397 /* Only call on a definite-length array / map */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700398 pNesting->pCurrent->u.ma.uCountCursor--;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700399}
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700400
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700401
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700402static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700403DecodeNesting_ReverseDecrement(QCBORDecodeNesting *pNesting)
404{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800405 /* Only call on a definite-length array / map */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700406 pNesting->pCurrent->u.ma.uCountCursor++;
407}
408
409
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700410static void
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700411DecodeNesting_Ascend(QCBORDecodeNesting *pNesting)
412{
413 pNesting->pCurrent--;
414}
415
Laurence Lundblade02625d42020-06-25 14:41:41 -0700416
417static QCBORError
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700418DecodeNesting_Descend(QCBORDecodeNesting *pNesting, uint8_t uType)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700419{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800420 /* Error out if nesting is too deep */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700421 if(pNesting->pCurrent >= &(pNesting->pLevels[QCBOR_MAX_ARRAY_NESTING])) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700422 return QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP;
Laurence Lundblade02625d42020-06-25 14:41:41 -0700423 }
424
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800425 /* The actual descend */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700426 pNesting->pCurrent++;
427
428 pNesting->pCurrent->uLevelType = uType;
429
430 return QCBOR_SUCCESS;
431}
432
433
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700434static QCBORError
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800435DecodeNesting_EnterBoundedMapOrArray(QCBORDecodeNesting *pNesting,
436 bool bIsEmpty,
437 size_t uOffset)
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700438{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700439 /*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800440 * Should only be called on map/array.
441 *
442 * Have descended into this before this is called. The job here is
443 * just to mark it in bounded mode.
444 *
445 * Check against QCBOR_MAX_DECODE_INPUT_SIZE make sure that
446 * uOffset doesn't collide with QCBOR_NON_BOUNDED_OFFSET.
447 *
448 * Cast of uOffset to uint32_t for cases where SIZE_MAX < UINT32_MAX.
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700449 */
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -0800450 if((uint32_t)uOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700451 return QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700452 }
453
Laurence Lundblade0750fc42020-06-20 21:02:34 -0700454 pNesting->pCurrentBounded = pNesting->pCurrent;
Laurence Lundblade085d7952020-07-24 10:26:30 -0700455
456 DecodeNesting_SetMapOrArrayBoundedMode(pNesting, bIsEmpty, uOffset);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700457
458 return QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700459}
460
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700461
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700462static QCBORError
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700463DecodeNesting_DescendMapOrArray(QCBORDecodeNesting *pNesting,
Laurence Lundblade02625d42020-06-25 14:41:41 -0700464 uint8_t uQCBORType,
465 uint64_t uCount)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700466{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700467 QCBORError uError = QCBOR_SUCCESS;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700468
469 if(uCount == 0) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800470 /* Nothing to do for empty definite-length arrays. They are just are
471 * effectively the same as an item that is not a map or array.
472 */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700473 goto Done;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800474 /* Empty indefinite-length maps and arrays are handled elsewhere */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700475 }
476
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800477 /* Error out if arrays is too long to handle */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700478 if(uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH &&
479 uCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700480 uError = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700481 goto Done;
482 }
483
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700484 uError = DecodeNesting_Descend(pNesting, uQCBORType);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700485 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700486 goto Done;
487 }
488
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800489 /* Fill in the new map/array level. Check above makes casts OK. */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -0700490 pNesting->pCurrent->u.ma.uCountCursor = (uint16_t)uCount;
491 pNesting->pCurrent->u.ma.uCountTotal = (uint16_t)uCount;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700492
493 DecodeNesting_ClearBoundedMode(pNesting);
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700494
495Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700496 return uError;;
497}
498
499
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700500static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700501DecodeNesting_LevelUpCurrent(QCBORDecodeNesting *pNesting)
502{
503 pNesting->pCurrent = pNesting->pCurrentBounded - 1;
504}
505
506
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700507static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700508DecodeNesting_LevelUpBounded(QCBORDecodeNesting *pNesting)
509{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700510 while(pNesting->pCurrentBounded != &(pNesting->pLevels[0])) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700511 pNesting->pCurrentBounded--;
512 if(DecodeNesting_IsCurrentBounded(pNesting)) {
513 break;
514 }
515 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700516}
517
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800518
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700519static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700520DecodeNesting_SetCurrentToBoundedLevel(QCBORDecodeNesting *pNesting)
521{
522 pNesting->pCurrent = pNesting->pCurrentBounded;
523}
524
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700525
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700526static QCBORError
Laurence Lundblade02625d42020-06-25 14:41:41 -0700527DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting,
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700528 uint32_t uEndOffset,
529 uint32_t uStartOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700530{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700531 QCBORError uError;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700532
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700533 uError = DecodeNesting_Descend(pNesting, QCBOR_TYPE_BYTE_STRING);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700534 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700535 goto Done;
536 }
537
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800538 /* Fill in the new byte string level */
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700539 pNesting->pCurrent->u.bs.uSavedEndOffset = uEndOffset;
540 pNesting->pCurrent->u.bs.uBstrStartOffset = uStartOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700541
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800542 /* Bstr wrapped levels are always bounded */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700543 pNesting->pCurrentBounded = pNesting->pCurrent;
544
545Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700546 return uError;;
547}
548
Laurence Lundbladed0304932020-06-27 10:59:38 -0700549
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700550static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700551DecodeNesting_ZeroMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700552{
553 pNesting->pCurrent->u.ma.uCountCursor = 0;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700554}
555
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700556
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700557static void
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800558DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting)
559{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700560 if(pNesting->pCurrent->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
561 pNesting->pCurrentBounded->u.ma.uCountCursor = pNesting->pCurrentBounded->u.ma.uCountTotal;
562 }
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800563}
564
565
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700566static void
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700567DecodeNesting_Init(QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700568{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700569 /* Assumes that *pNesting has been zero'd before this call. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700570 pNesting->pLevels[0].uLevelType = QCBOR_TYPE_BYTE_STRING;
571 pNesting->pCurrent = &(pNesting->pLevels[0]);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700572}
573
574
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700575static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800576DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting,
577 QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700578{
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700579 *pSave = *pNesting;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700580}
581
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700582
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700583static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800584DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting,
585 const QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700586{
587 *pNesting = *pSave;
588}
589
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700590
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700591static uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700592DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700593{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700594 return pMe->pCurrentBounded->u.bs.uSavedEndOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700595}
596
597
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800598
599
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800600#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladeee851742020-01-08 08:37:05 -0800601/*===========================================================================
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800602 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
603
604 The following four functions are pretty wrappers for invocation of
605 the string allocator supplied by the caller.
606
Laurence Lundbladeee851742020-01-08 08:37:05 -0800607 ===========================================================================*/
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800608
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700609static void
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800610StringAllocator_Free(const QCBORInternalAllocator *pMe, const void *pMem)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800611{
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300612 /* This cast to uintptr_t suppresses the "-Wcast-qual" warnings.
613 * This is the one place where the const needs to be cast away so const can
614 * be use in the rest of the code.
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800615 */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300616 (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, 0);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800617}
618
Laurence Lundbladeee851742020-01-08 08:37:05 -0800619// StringAllocator_Reallocate called with pMem NULL is
620// equal to StringAllocator_Allocate()
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700621static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800622StringAllocator_Reallocate(const QCBORInternalAllocator *pMe,
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800623 const void *pMem,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800624 size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800625{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800626 /* See comment in StringAllocator_Free() */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300627 return (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, uSize);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800628}
629
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700630static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800631StringAllocator_Allocate(const QCBORInternalAllocator *pMe, size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800632{
633 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
634}
635
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700636static void
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800637StringAllocator_Destruct(const QCBORInternalAllocator *pMe)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800638{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800639 /* See comment in StringAllocator_Free() */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800640 if(pMe->pfAllocator) {
641 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
642 }
643}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800644#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800645
646
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800647
648
Laurence Lundbladeee851742020-01-08 08:37:05 -0800649/*===========================================================================
650 QCBORDecode -- The main implementation of CBOR decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700651
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800652 See qcbor/qcbor_decode.h for definition of the object
653 used here: QCBORDecodeContext
Laurence Lundbladeee851742020-01-08 08:37:05 -0800654 ===========================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700655/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800656 * Public function, see header file
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700657 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700658void
659QCBORDecode_Init(QCBORDecodeContext *pMe,
660 UsefulBufC EncodedCBOR,
661 QCBORDecodeMode nDecodeMode)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700662{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800663 memset(pMe, 0, sizeof(QCBORDecodeContext));
664 UsefulInputBuf_Init(&(pMe->InBuf), EncodedCBOR);
665 /* Don't bother with error check on decode mode. If a bad value is
666 * passed it will just act as if the default normal mode of 0 was set.
667 */
668 pMe->uDecodeMode = (uint8_t)nDecodeMode;
669 DecodeNesting_Init(&(pMe->nesting));
670
671 /* Inialize me->auMappedTags to CBOR_TAG_INVALID16. See
672 * GetNext_TaggedItem() and MapTagNumber(). */
673 memset(pMe->auMappedTags, 0xff, sizeof(pMe->auMappedTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700674}
675
676
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800677#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
678
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700679/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800680 * Public function, see header file
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700681 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700682void
683QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
684 QCBORStringAllocate pfAllocateFunction,
685 void *pAllocateContext,
686 bool bAllStrings)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700687{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800688 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
689 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
690 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700691}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800692#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700693
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800694
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800695
696
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800697/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800698 * Deprecated public function, see header file
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800699 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700700void
701QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pMe,
702 const QCBORTagListIn *pTagList)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700703{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800704 /* This does nothing now. It is retained for backwards compatibility */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700705 (void)pMe;
706 (void)pTagList;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700707}
708
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700709
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800710
711
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700712/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800713 * Decoding items is done in six layers, one calling the next one
714 * down. If a layer has no work to do for a particular item, it
715 * returns quickly.
716 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700717 * 1. QCBORDecode_Private_GetNextTagContent - The top layer processes
718 * tagged data items, turning them into the local C representation.
719 * For the most simple it is just associating a QCBOR_TYPE with the
720 * data. For the complex ones that an aggregate of data items, there
721 * is some further decoding and some limited recursion.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800722 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700723 * 2. QCBORDecode_Private_GetNextMapOrArray - This manages the
724 * beginnings and ends of maps and arrays. It tracks descending into
725 * and ascending out of maps/arrays. It processes breaks that
726 * terminate indefinite-length maps and arrays.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800727 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700728 * 3. QCBORDecode_Private_GetNextMapEntry - This handles the combining
729 * of two items, the label and the data, that make up a map entry. It
730 * only does work on maps. It combines the label and data items into
731 * one labeled item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800732 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700733 * 4. QCBORDecode_Private_GetNextTagNumber - This decodes type 6 tag
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800734 * numbers. It turns the tag numbers into bit flags associated with
735 * the data item. No actual decoding of the contents of the tag is
736 * performed here.
737 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700738 * 5. QCBORDecode_Private_GetNextFullString - This assembles the
739 * sub-items that make up an indefinite-length string into one string
740 * item. It uses the string allocator to create contiguous space for
741 * the item. It processes all breaks that are part of
742 * indefinite-length strings.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800743 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700744 * 6. QCBOR_Private_DecodeAtomicDataItem - This decodes the atomic
745 * data items in CBOR. Each atomic data item has a "major type", an
746 * integer "argument" and optionally some content. For text and byte
747 * strings, the content is the bytes that make up the string. These
748 * are the smallest data items that are considered to be well-formed.
749 * The content may also be other data items in the case of aggregate
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800750 * types. They are not handled in this layer.
751 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700752 * This uses about 350 bytes of stack. This number comes from
753 * instrumenting (printf address of stack variables) the code on x86
754 * compiled for size optimization.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700755 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800756
757
758/*
759 * Note about use of int and unsigned variables.
760 *
761 * See http://www.unix.org/whitepapers/64bit.html for reasons int is
762 * used carefully here, and in particular why it isn't used in the
763 * public interface. Also see
764 * https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers
765 *
766 * Int is used for values that need less than 16-bits and would be
767 * subject to integer promotion and result in complaining from static
768 * analyzers.
769 */
770
771
772/**
773 * @brief Decode the CBOR head, the type and argument.
774 *
775 * @param[in] pUInBuf The input buffer to read from.
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700776 * @param[in] bRequirePreferred Require preferred serialization for argument.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800777 * @param[out] pnMajorType The decoded major type.
778 * @param[out] puArgument The decoded argument.
779 * @param[out] pnAdditionalInfo The decoded Lower 5 bits of initial byte.
780 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -0700781 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved features
782 * @retval QCBOR_ERR_HIT_END Unexpected end of input
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800783 *
784 * This decodes the CBOR "head" that every CBOR data item has. See
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700785 * longer description in QCBOREncode_EncodeHead().
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800786 *
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700787 * This does the network to host byte order conversion. The conversion
788 * here also provides the conversion for floats in addition to that
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800789 * for lengths, tags and integer values.
790 *
791 * The int type is preferred to uint8_t for some variables as this
792 * avoids integer promotions, can reduce code size and makes static
793 * analyzers happier.
794 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700795static QCBORError
796QCBOR_Private_DecodeHead(UsefulInputBuf *pUInBuf,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700797#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
798 bool bRequirePreferred,
799#endif
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700800 int *pnMajorType,
801 uint64_t *puArgument,
802 int *pnAdditionalInfo)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700803{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800804 QCBORError uReturn;
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700805 uint64_t uArgument;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800806
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700807 /* Get and break down initial byte that every CBOR data item has */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800808 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800809 const int nTmpMajorType = nInitialByte >> 5;
810 const int nAdditionalInfo = nInitialByte & 0x1f;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800811
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800812 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800813 /* Need to get 1,2,4 or 8 additional argument bytes. Map
814 * LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length.
815 */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800816 static const uint8_t aIterate[] = {1,2,4,8};
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800817
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800818 /* Loop getting all the bytes in the argument */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800819 uArgument = 0;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800820 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700821 /* This shift-and-add gives the endian conversion. */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800822 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
823 }
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700824
825#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
826 /* If requested, check that argument is in preferred form */
827 if(bRequirePreferred) {
828 uint64_t uMinArgument;
829
830 if(nAdditionalInfo == LEN_IS_ONE_BYTE) {
831 if(uArgument < 24) {
832 uReturn = QCBOR_ERR_PREFERRED_CONFORMANCE;
833 goto Done;
834 }
835 } else {
836 if(nTmpMajorType != CBOR_MAJOR_TYPE_SIMPLE) {
837 /* Check only if not a floating-point number */
838 int nArgLen = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE - 1];
839 uMinArgument = UINT64_MAX >> ((int)sizeof(uint64_t) - nArgLen) * 8;
840 if(uArgument <= uMinArgument) {
841 uReturn = QCBOR_ERR_PREFERRED_CONFORMANCE;
842 goto Done;
843 }
844 }
845 }
846 }
847#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
848
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800849 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800850 /* The reserved and thus-far unused additional info values */
851 uReturn = QCBOR_ERR_UNSUPPORTED;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800852 goto Done;
853 } else {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700854#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
855 if(bRequirePreferred && nAdditionalInfo == LEN_IS_INDEFINITE) {
856 uReturn = QCBOR_ERR_PREFERRED_CONFORMANCE;
857 goto Done;
858 }
859#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
860
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800861 /* Less than 24, additional info is argument or 31, an
862 * indefinite-length. No more bytes to get.
863 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800864 uArgument = (uint64_t)nAdditionalInfo;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700865 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800866
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700867 if(UsefulInputBuf_GetError(pUInBuf)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800868 uReturn = QCBOR_ERR_HIT_END;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700869 goto Done;
870 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800871
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800872 /* All successful if arrived here. */
873 uReturn = QCBOR_SUCCESS;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800874 *pnMajorType = nTmpMajorType;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800875 *puArgument = uArgument;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800876 *pnAdditionalInfo = nAdditionalInfo;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800877
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700878Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800879 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700880}
881
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800882
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800883/**
884 * @brief Decode integer types, major types 0 and 1.
885 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700886 * @param[in] nMajorType The CBOR major type (0 or 1).
887 * @param[in] uArgument The argument from the head.
888 * @param[in] nAdditionalInfo So it can be error-checked.
889 * @param[out] pDecodedItem The filled in decoded item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800890 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700891 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered.
892 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800893 *
894 * Must only be called when major type is 0 or 1.
895 *
896 * CBOR doesn't explicitly specify two's compliment for integers but
897 * all CPUs use it these days and the test vectors in the RFC are
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700898 * so. All integers in encoded CBOR are unsigned and the CBOR major
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800899 * type indicates positive or negative. CBOR can express positive
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700900 * integers up to 2^64 - 1 negative integers down to -2^64. Note that
901 * negative numbers can be one more
902 * away from zero than positive because there is no negative zero.
903 *
904 * The "65-bit negs" are values CBOR can encode that can't fit
905 * into an int64_t or uint64_t. They decoded as a special type
906 * QCBOR_TYPE_65BIT_NEG_INT. Not that this type does NOT
907 * take into account the offset of one for CBOR negative integers.
908 * It must be applied to get the correct value. Applying this offset
909 * would overflow a uint64_t.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700910 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700911static QCBORError
912QCBOR_Private_DecodeInteger(const int nMajorType,
913 const uint64_t uArgument,
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700914 const int nAdditionalInfo,
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700915 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700916{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800917 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800918
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700919 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
920 uReturn = QCBOR_ERR_BAD_INT;
921 goto Done;
922 }
923
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700924 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800925 if (uArgument <= INT64_MAX) {
926 pDecodedItem->val.int64 = (int64_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700927 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800928
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700929 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800930 pDecodedItem->val.uint64 = uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700931 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700932 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800933
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700934 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800935 if(uArgument <= INT64_MAX) {
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700936 /* INT64_MIN is one further away from 0 than INT64_MAX
937 * so the -1 here doesn't overflow. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800938 pDecodedItem->val.int64 = (-(int64_t)uArgument) - 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700939 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800940
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700941 } else {
Laurence Lundblade2d493002024-02-01 11:09:17 -0700942 pDecodedItem->val.uint64 = uArgument;
943 pDecodedItem->uDataType = QCBOR_TYPE_65BIT_NEG_INT;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700944 }
945 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800946
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700947Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800948 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700949}
950
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800951
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700952/**
953 * @brief Decode text and byte strings
954 *
955 * @param[in] pMe Decoder context.
956 * @param[in] bAllocate Whether to allocate and copy string.
957 * @param[in] nMajorType Whether it is a byte or text string.
958 * @param[in] uStrLen The length of the string.
959 * @param[in] nAdditionalInfo Whether it is an indefinite-length string.
960 * @param[out] pDecodedItem The filled-in decoded item.
961 *
962 * @retval QCBOR_ERR_HIT_END Unexpected end of input.
963 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
964 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
965 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator
966 *
967 * This reads @c uStrlen bytes from the input and fills in @c
968 * pDecodedItem. If @c bAllocate is true, then memory for the string
969 * is allocated.
970 */
971static QCBORError
972QCBOR_Private_DecodeString(QCBORDecodeContext *pMe,
973 const bool bAllocate,
974 const int nMajorType,
975 const uint64_t uStrLen,
976 const int nAdditionalInfo,
977 QCBORItem *pDecodedItem)
978{
979 QCBORError uReturn = QCBOR_SUCCESS;
980
981 /* ---- Figure out the major type ---- */
982 #if CBOR_MAJOR_TYPE_BYTE_STRING + 4 != QCBOR_TYPE_BYTE_STRING
983 #error QCBOR_TYPE_BYTE_STRING not lined up with major type
984 #endif
985
986 #if CBOR_MAJOR_TYPE_TEXT_STRING + 4 != QCBOR_TYPE_TEXT_STRING
987 #error QCBOR_TYPE_TEXT_STRING not lined up with major type
988 #endif
989 pDecodedItem->uDataType = (uint8_t)(nMajorType + 4);
990
991 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
992 /* --- Just the head of an indefinite-length string --- */
993 pDecodedItem->val.string = (UsefulBufC){NULL, QCBOR_STRING_LENGTH_INDEFINITE};
994
995 } else {
996 /* --- A definite-length string --- */
997 /* --- (which might be a chunk of an indefinte-length string) --- */
998
999 /* CBOR lengths can be 64 bits, but size_t is not 64 bits on all
1000 * CPUs. This check makes the casts to size_t below safe.
1001 *
1002 * The max is 4 bytes less than the largest sizeof() so this can be
1003 * tested by putting a SIZE_MAX length in the CBOR test input (no
1004 * one will care the limit on strings is 4 bytes shorter).
1005 */
1006 if(uStrLen > SIZE_MAX-4) {
1007 uReturn = QCBOR_ERR_STRING_TOO_LONG;
1008 goto Done;
1009 }
1010
1011 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(&(pMe->InBuf), (size_t)uStrLen);
1012 if(UsefulBuf_IsNULLC(Bytes)) {
1013 /* Failed to get the bytes for this string item */
1014 uReturn = QCBOR_ERR_HIT_END;
1015 goto Done;
1016 }
1017
1018 if(bAllocate) {
1019#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
1020 /* --- Put string in allocated memory --- */
1021
1022 /* Note that this is not where allocation to coalesce
1023 * indefinite-length strings is done. This is for when the
1024 * caller has requested all strings be allocated. Disabling
1025 * indefinite length strings also disables this allocate-all
1026 * option.
1027 */
1028
1029 if(pMe->StringAllocator.pfAllocator == NULL) {
1030 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1031 goto Done;
1032 }
1033 UsefulBuf NewMem = StringAllocator_Allocate(&(pMe->StringAllocator), (size_t)uStrLen);
1034 if(UsefulBuf_IsNULL(NewMem)) {
1035 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1036 goto Done;
1037 }
1038 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
1039 pDecodedItem->uDataAlloc = 1;
1040#else
1041 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1042#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1043 } else {
1044 /* --- Normal case with no string allocator --- */
1045 pDecodedItem->val.string = Bytes;
1046 }
1047 }
1048
1049Done:
1050 return uReturn;
1051}
1052
1053
1054/**
1055 * @brief Decode array or map.
1056 *
1057 * @param[in] uMode Decoder mode.
1058 * @param[in] nMajorType Whether it is a byte or text string.
1059 * @param[in] uItemCount The length of the string.
1060 * @param[in] nAdditionalInfo Whether it is an indefinite-length.
1061 * @param[out] pDecodedItem The filled-in decoded item.
1062 *
1063 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinites disabled.
1064 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map.
1065 *
1066 * Not much to do for arrays and maps. Just the type item count (but a
1067 * little messy because of ifdefs for indefinite-lengths and
1068 * map-as-array decoding).
1069 *
1070 * This also does the bulk of the work for @ref
1071 * QCBOR_DECODE_MODE_MAP_AS_ARRAY, a special mode to handle
1072 * arbitrarily complex map labels. This ifdefs out with
1073 * QCBOR_DISABLE_NON_INTEGER_LABELS.
1074 */
1075static QCBORError
1076QCBOR_Private_DecodeArrayOrMap(const uint8_t uMode,
1077 const int nMajorType,
1078 const uint64_t uItemCount,
1079 const int nAdditionalInfo,
1080 QCBORItem *pDecodedItem)
1081{
1082 QCBORError uReturn;
1083
1084 /* ------ Sort out the data type ------ */
1085 #if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
1086 #error QCBOR_TYPE_ARRAY value not lined up with major type
1087 #endif
1088
1089 #if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
1090 #error QCBOR_TYPE_MAP value not lined up with major type
1091 #endif
1092 pDecodedItem->uDataType = (uint8_t)nMajorType;
1093#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1094 if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
1095 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
1096 }
1097#else
1098 (void)uMode;
1099#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
1100
1101 uReturn = QCBOR_SUCCESS;
1102
1103 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1104 /* ------ Indefinite-length array/map ----- */
1105#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
1106 pDecodedItem->val.uCount = QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH;
1107#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1108 uReturn = QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED;
1109#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1110 } else {
1111
1112#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1113 if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
1114 /* ------ Definite-length map as array ------ */
1115
1116 if(uItemCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
1117 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
1118 } else {
1119 /* cast OK because of check above */
1120 pDecodedItem->val.uCount = (uint16_t)uItemCount*2;
1121 }
1122
1123 } else
1124#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
1125 {
1126 /* ------ Definite-length array/map ------ */
1127 if(uItemCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
1128 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
1129 } else {
1130 /* cast OK because of check above */
1131 pDecodedItem->val.uCount = (uint16_t)uItemCount;
1132 }
1133 }
1134 }
1135
1136 return uReturn;
1137}
1138
1139
1140/**
1141 * @brief Decode a tag number.
1142 *
1143 * @param[in] uTagNumber The length of the string.
1144 * @param[in] nAdditionalInfo So this can be error-checked.
1145 * @param[out] pDecodedItem The filled-in decoded item.
1146 *
1147 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo is LEN_IS_INDEFINITE.
1148 * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined.
1149 *
1150 * Not much to do for tags, but fill in pDecodedItem and check for
1151 * error in nAdditionalInfo.
1152 */
1153static QCBORError
1154QCBOR_Private_DecodeTag(const uint64_t uTagNumber,
1155 const int nAdditionalInfo,
1156 QCBORItem *pDecodedItem)
1157{
1158#ifndef QCBOR_DISABLE_TAGS
1159 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1160 return QCBOR_ERR_BAD_INT;
1161 } else {
1162 pDecodedItem->val.uTagV = uTagNumber;
1163 pDecodedItem->uDataType = QCBOR_TYPE_TAG;
1164 return QCBOR_SUCCESS;
1165 }
1166#else /* QCBOR_DISABLE_TAGS */
1167 (void)nAdditionalInfo;
Laurence Lundblade6c9a8242024-06-12 20:34:52 -07001168 (void)uTagNumber;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001169 (void)pDecodedItem;
1170 return QCBOR_ERR_TAGS_DISABLED;
1171#endif /* QCBOR_DISABLE_TAGS */
1172}
1173
1174
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001175#ifndef USEFULBUF_DISABLE_ALL_FLOAT
1176
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001177#if !defined(QCBOR_DISABLE_DECODE_CONFORMANCE) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
1178
1179static QCBORError
1180QCBORDecode_Private_HalfConformance(const double d, const uint8_t uDecodeMode)
1181{
1182 struct IEEE754_ToInt ToInt;
1183
1184 /* Only need to check for conversion to integer because
1185 * half-precision is always preferred serialization. Don't
1186 * need special checker for half-precision because whole
1187 * numbers always convert perfectly from half to double.
1188 *
1189 * This catches half-precision with NaN payload too.
1190 *
1191 * The only thing allowed here is a double/half-precision that
1192 * can't be converted to anything but a double.
1193 */
1194 if(uDecodeMode >= QCBOR_DECODE_MODE_DCBOR) {
1195 ToInt = IEEE754_DoubleToInt(d);
1196 if(ToInt.type != QCBOR_TYPE_DOUBLE) {
1197 return QCBOR_ERR_DCBOR_CONFORMANCE;
1198 }
1199 }
1200
1201 return QCBOR_SUCCESS;
1202}
1203
1204
1205static QCBORError
1206QCBORDecode_Private_SingleConformance(const float f, const uint8_t uDecodeMode)
1207{
1208 struct IEEE754_ToInt ToInt;
1209 IEEE754_union ToSmaller;
1210
1211 if(uDecodeMode >= QCBOR_DECODE_MODE_DCBOR) {
1212 /* See if it could have been encoded as an integer */
1213 ToInt = IEEE754_SingleToInt(f);
1214 if(ToInt.type == IEEE754_ToInt_IS_INT || ToInt.type == IEEE754_ToInt_IS_UINT) {
1215 return QCBOR_ERR_DCBOR_CONFORMANCE;
1216 }
1217
1218 /* Make sure there is no NaN payload */
1219 if(IEEE754_SingleHasNaNPayload(f)) {
1220 return QCBOR_ERR_DCBOR_CONFORMANCE;
1221 }
1222 }
1223
1224 /* See if it could have been encoded shorter */
1225 if(uDecodeMode >= QCBOR_DECODE_MODE_PREFERRED) {
1226 ToSmaller = IEEE754_SingleToHalf(f, true);
1227 if(ToSmaller.uSize != sizeof(float)) {
1228 return QCBOR_ERR_PREFERRED_CONFORMANCE;
1229 }
1230 }
1231
1232 return QCBOR_SUCCESS;
1233}
1234
1235
1236static QCBORError
1237QCBORDecode_Private_DoubleConformance(const double d, uint8_t uDecodeMode)
1238{
1239 struct IEEE754_ToInt ToInt;
1240 IEEE754_union ToSmaller;
1241
1242 if(uDecodeMode >= QCBOR_DECODE_MODE_DCBOR) {
1243 /* See if it could have been encoded as an integer */
1244 ToInt = IEEE754_DoubleToInt(d);
1245 if(ToInt.type == IEEE754_ToInt_IS_INT || ToInt.type == IEEE754_ToInt_IS_UINT) {
1246 return QCBOR_ERR_DCBOR_CONFORMANCE;
1247 }
1248 /* Make sure there is no NaN payload */
1249 if(IEEE754_DoubleHasNaNPayload(d)) {
1250 return QCBOR_ERR_DCBOR_CONFORMANCE;
1251 }
1252 }
1253
1254 /* See if it could have been encoded shorter */
1255 if(uDecodeMode >= QCBOR_DECODE_MODE_PREFERRED) {
1256 ToSmaller = IEEE754_DoubleToSmaller(d, true, true);
1257 if(ToSmaller.uSize != sizeof(double)) {
1258 return QCBOR_ERR_PREFERRED_CONFORMANCE;
1259 }
1260 }
1261
1262 return QCBOR_SUCCESS;
1263}
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001264#else /* ! QCBOR_DISABLE_DECODE_CONFORMANCE && ! QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001265
1266static QCBORError
1267QCBORDecode_Private_SingleConformance(const float f, uint8_t uDecodeMode)
1268{
1269 (void)f;
1270 if(uDecodeMode >= QCBOR_DECODE_MODE_PREFERRED) {
1271 return QCBOR_ERR_CANT_CHECK_FLOAT_CONFORMANCE;
1272 } else {
1273 return QCBOR_SUCCESS;
1274 }
1275}
1276
1277static QCBORError
1278QCBORDecode_Private_DoubleConformance(const double d, uint8_t uDecodeMode)
1279{
1280 (void)d;
1281 if(uDecodeMode >= QCBOR_DECODE_MODE_PREFERRED) {
1282 return QCBOR_ERR_CANT_CHECK_FLOAT_CONFORMANCE;
1283 } else {
1284 return QCBOR_SUCCESS;
1285 }
1286}
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001287#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE && ! QCBOR_DISABLE_PREFERRED_FLOAT */
1288
1289
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001290/*
1291 * Decode a float
1292 */
1293static QCBORError
1294QCBOR_Private_DecodeFloat(const uint8_t uDecodeMode,
1295 const int nAdditionalInfo,
1296 const uint64_t uArgument,
1297 QCBORItem *pDecodedItem)
1298{
1299 QCBORError uReturn = QCBOR_SUCCESS;
1300 float single;
1301
1302 (void)single; /* Avoid unused error from various #ifndefs */
1303
1304 switch(nAdditionalInfo) {
1305 case HALF_PREC_FLOAT: /* 25 */
1306#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
1307 /* Half-precision is returned as a double. The cast to
1308 * uint16_t is safe because the encoded value was 16 bits. It
1309 * was widened to 64 bits to be passed in here.
1310 */
1311 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uArgument);
1312 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
1313
1314 uReturn = QCBORDecode_Private_HalfConformance(pDecodedItem->val.dfnum, uDecodeMode);
1315 if(uReturn != QCBOR_SUCCESS) {
1316 break;
1317 }
1318#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
1319 uReturn = FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS);
1320 break;
1321
1322 case SINGLE_PREC_FLOAT: /* 26 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001323 /* Single precision is normally returned as a double since
1324 * double is widely supported, there is no loss of precision,
1325 * it makes it easy for the caller in most cases and it can
1326 * be converted back to single with no loss of precision
1327 *
1328 * The cast to uint32_t is safe because the encoded value was
1329 * 32 bits. It was widened to 64 bits to be passed in here.
1330 */
1331 single = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uArgument);
1332 uReturn = QCBORDecode_Private_SingleConformance(single, uDecodeMode);
1333 if(uReturn != QCBOR_SUCCESS) {
1334 break;
1335 }
1336
1337#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1338 /* In the normal case, use HW to convert float to
1339 * double. */
1340 pDecodedItem->val.dfnum = (double)single;
1341 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
1342#else /* QCBOR_DISABLE_FLOAT_HW_USE */
1343 /* Use of float HW is disabled, return as a float. */
1344 pDecodedItem->val.fnum = single;
1345 pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
1346
1347 /* IEEE754_FloatToDouble() could be used here to return as
1348 * a double, but it adds object code and most likely
1349 * anyone disabling FLOAT HW use doesn't care about floats
1350 * and wants to save object code.
1351 */
1352#endif /* ! QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001353 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
1354 break;
1355
1356 case DOUBLE_PREC_FLOAT: /* 27 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001357 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uArgument);
1358 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
1359
1360 uReturn = QCBORDecode_Private_DoubleConformance(pDecodedItem->val.dfnum, uDecodeMode);
1361 if(uReturn != QCBOR_SUCCESS) {
1362 break;
1363 }
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001364 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
1365 break;
1366 }
1367
1368 return uReturn;
1369}
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001370#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */
1371
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001372
1373
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001374/* Make sure #define value line up as DecodeSimple counts on this. */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001375#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
1376#error QCBOR_TYPE_FALSE macro value wrong
1377#endif
1378
1379#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
1380#error QCBOR_TYPE_TRUE macro value wrong
1381#endif
1382
1383#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
1384#error QCBOR_TYPE_NULL macro value wrong
1385#endif
1386
1387#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
1388#error QCBOR_TYPE_UNDEF macro value wrong
1389#endif
1390
Laurence Lundblade0f99d692018-09-26 14:39:28 -07001391#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
1392#error QCBOR_TYPE_BREAK macro value wrong
1393#endif
1394
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001395#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
1396#error QCBOR_TYPE_DOUBLE macro value wrong
1397#endif
1398
1399#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
1400#error QCBOR_TYPE_FLOAT macro value wrong
1401#endif
1402
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001403/**
1404 * @brief Decode major type 7 -- true, false, floating-point, break...
1405 *
1406 * @param[in] nAdditionalInfo The lower five bits from the initial byte.
1407 * @param[in] uArgument The argument from the head.
1408 * @param[out] pDecodedItem The filled in decoded item.
1409 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001410 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1411 * of half-precision disabled
1412 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all float
1413 * decode is disabled.
1414 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of simple
1415 * type in input.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001416 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001417static QCBORError
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001418QCBOR_Private_DecodeType7(const uint8_t uDecodeMode,
1419 const int nAdditionalInfo,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001420 const uint64_t uArgument,
1421 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001422{
1423 QCBORError uReturn = QCBOR_SUCCESS;
1424
1425 /* uAdditionalInfo is 5 bits from the initial byte. Compile time
1426 * checks above make sure uAdditionalInfo values line up with
1427 * uDataType values. DecodeHead() never returns an AdditionalInfo
1428 * > 0x1f so cast is safe.
1429 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001430 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001431
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001432 switch(nAdditionalInfo) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001433 /* No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they
1434 * are caught before this is called.
1435 */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001436
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001437 case HALF_PREC_FLOAT: /* 25 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001438 case SINGLE_PREC_FLOAT: /* 26 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001439 case DOUBLE_PREC_FLOAT: /* 27 */
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001440#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001441 uReturn = QCBOR_Private_DecodeFloat(uDecodeMode, nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001442#else
1443 uReturn = QCBOR_ERR_ALL_FLOAT_DISABLED;
1444#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001445 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001446
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001447 case CBOR_SIMPLEV_FALSE: /* 20 */
1448 case CBOR_SIMPLEV_TRUE: /* 21 */
1449 case CBOR_SIMPLEV_NULL: /* 22 */
1450 case CBOR_SIMPLEV_UNDEF: /* 23 */
1451 case CBOR_SIMPLE_BREAK: /* 31 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001452#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
1453 if(uDecodeMode >= QCBOR_ENCODE_MODE_DCBOR &&
1454 nAdditionalInfo == CBOR_SIMPLEV_UNDEF) {
1455 uReturn = QCBOR_ERR_DCBOR_CONFORMANCE;
1456 goto Done;
1457 }
1458#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001459 break; /* nothing to do */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001460
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001461 case CBOR_SIMPLEV_ONEBYTE: /* 24 */
1462 if(uArgument <= CBOR_SIMPLE_BREAK) {
1463 /* This takes out f8 00 ... f8 1f which should be encoded
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001464 * as e0 … f7 -- preferred serialization check for simple values.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001465 */
1466 uReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001467 goto Done;
1468 }
Laurence Lundblade5e390822019-01-06 12:35:01 -08001469 /* FALLTHROUGH */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001470
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001471 default: /* 0-19 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001472#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
1473 if(uDecodeMode >= QCBOR_ENCODE_MODE_DCBOR &&
1474 (uArgument < CBOR_SIMPLEV_FALSE || uArgument > CBOR_SIMPLEV_NULL)) {
1475 uReturn = QCBOR_ERR_DCBOR_CONFORMANCE;
1476 goto Done;
1477 }
1478#endif /* !QCBOR_DISABLE_DECODE_CONFORMANCE */
1479
1480 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
1481 /* QCBOR_Private_DecodeHead() will make uArgument equal to
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001482 * nAdditionalInfo when nAdditionalInfo is < 24. This cast is
1483 * safe because the 2, 4 and 8 byte lengths of uNumber are in
1484 * the double/float cases above
Laurence Lundbladeee851742020-01-08 08:37:05 -08001485 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001486 pDecodedItem->val.uSimple = (uint8_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001487 break;
1488 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001489
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001490Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001491 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001492}
1493
1494
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001495/**
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001496 * @brief Decode a single primitive data item (decode layer 6).
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001497 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001498 * @param[in] pMe Decoder context.
1499 * @param[in] bAllocateStrings If true, use allocator for strings.
1500 * @param[out] pDecodedItem The filled-in decoded item.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001501 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001502 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1503 * features
1504 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1505 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1506 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1507 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001508 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001509 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1510 * of half-precision disabled
1511 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1512 * float decode is disabled.
1513 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1514 * simple type in input.
1515 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1516 * in input, but indefinite
1517 * lengths disabled.
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001518 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte.
1519 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map.
1520 * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001521 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001522 * This decodes the most primitive/atomic data item. It does no
1523 * combining of data items.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001524 */
1525static QCBORError
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001526QCBOR_Private_DecodeAtomicDataItem(QCBORDecodeContext *pMe,
1527 const bool bAllocateStrings,
1528 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001529{
1530 QCBORError uReturn;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001531 int nMajorType = 0;
1532 uint64_t uArgument = 0;
1533 int nAdditionalInfo = 0;
1534
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001535 memset(pDecodedItem, 0, sizeof(QCBORItem));
1536
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001537 /* Decode the "head" that every CBOR item has into the major type,
1538 * argument and the additional info.
1539 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001540 uReturn = QCBOR_Private_DecodeHead(&(pMe->InBuf),
1541#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
1542 // TODO: make this prettier; will optimizer take out stuff without ifdef?
1543 pMe->uDecodeMode >= QCBOR_DECODE_MODE_PREFERRED,
1544#endif /* !QCBOR_DISABLE_DECODE_CONFORMANCE */
1545 &nMajorType,
1546 &uArgument,
1547 &nAdditionalInfo);
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001548
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001549 if(uReturn != QCBOR_SUCCESS) {
1550 return uReturn;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001551 }
1552
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001553 /* All the functions below get inlined by the optimizer. This code
1554 * is easier to read with them all being similar functions, even if
1555 * some functions don't do much.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001556 */
1557 switch (nMajorType) {
1558 case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
1559 case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001560 return QCBOR_Private_DecodeInteger(nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001561 break;
1562
1563 case CBOR_MAJOR_TYPE_BYTE_STRING: /* Major type 2 */
1564 case CBOR_MAJOR_TYPE_TEXT_STRING: /* Major type 3 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001565 return QCBOR_Private_DecodeString(pMe, bAllocateStrings, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001566 break;
1567
1568 case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */
1569 case CBOR_MAJOR_TYPE_MAP: /* Major type 5 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001570 return QCBOR_Private_DecodeArrayOrMap(pMe->uDecodeMode, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001571 break;
1572
1573 case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001574 return QCBOR_Private_DecodeTag(uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001575 break;
1576
1577 case CBOR_MAJOR_TYPE_SIMPLE:
1578 /* Major type 7: float, double, true, false, null... */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001579 return QCBOR_Private_DecodeType7(pMe->uDecodeMode, nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001580 break;
1581
1582 default:
1583 /* Never happens because DecodeHead() should never return > 7 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001584 return QCBOR_ERR_UNSUPPORTED;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001585 break;
1586 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001587}
1588
1589
1590/**
1591 * @brief Process indefinite-length strings (decode layer 5).
1592 *
1593 * @param[in] pMe Decoder context
1594 * @param[out] pDecodedItem The decoded item that work is done on.
1595 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001596 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1597 * features
1598 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1599 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1600 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1601 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1602 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1603 * of half-precision disabled
1604 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1605 * float decode is disabled.
1606 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1607 * simple type in input.
1608 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1609 * in input, but indefinite
1610 * lengths disabled.
1611 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1612 * but no string allocator.
1613 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1614 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1615 * input, but indefinite-length
1616 * strings are disabled.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001617 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001618 * If @c pDecodedItem is not an indefinite-length string, this does nothing.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001619 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001620 * If it is, this loops getting the subsequent chunk data items that
1621 * make up the string. The string allocator is used to make a
1622 * contiguous buffer for the chunks. When this completes @c
1623 * pDecodedItem contains the put-together string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001624 *
1625 * Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001626 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001627static QCBORError
1628QCBORDecode_Private_GetNextFullString(QCBORDecodeContext *pMe,
1629 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001630{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001631 /* Aproximate stack usage
1632 * 64-bit 32-bit
1633 * local vars 32 16
1634 * 2 UsefulBufs 32 16
1635 * QCBORItem 56 52
1636 * TOTAL 120 74
1637 */
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001638 QCBORError uReturn;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001639
1640 /* A note about string allocation -- Memory for strings is
1641 * allocated either because 1) indefinte-length string chunks are
1642 * being coalecsed or 2) caller has requested all strings be
1643 * allocated. The first case is handed below here. The second case
1644 * is handled in DecodeString if the bAllocate is true. That
1645 * boolean originates here with pMe->bStringAllocateAll immediately
1646 * below. That is, QCBOR_Private_DecodeAtomicDataItem() is called
1647 * in two different contexts here 1) main-line processing which is
1648 * where definite-length strings need to be allocated if
1649 * bStringAllocateAll is true and 2) processing chunks of
1650 * indefinite-lengths strings in in which case there must be no
1651 * allocation.
1652 */
1653
1654
1655 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, pMe->bStringAllocateAll, pDecodedItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001656 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001657 goto Done;
1658 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001659
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001660 /* This is where out-of-place break is detected for the whole
1661 * decoding stack. Break is an error for everything that calls
1662 * QCBORDecode_Private_GetNextFullString(), so the check is
1663 * centralized here.
1664 */
1665 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
1666 uReturn = QCBOR_ERR_BAD_BREAK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001667 goto Done;
1668 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001669
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001670
1671 /* Skip out if not an indefinite-length string */
1672 const uint8_t uStringType = pDecodedItem->uDataType;
1673 if(uStringType != QCBOR_TYPE_BYTE_STRING &&
1674 uStringType != QCBOR_TYPE_TEXT_STRING) {
1675 goto Done;
1676 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001677 if(pDecodedItem->val.string.len != QCBOR_STRING_LENGTH_INDEFINITE) {
1678 goto Done;
1679 }
1680
1681#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001682 /* Can't decode indefinite-length strings without a string allocator */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001683 if(!pMe->StringAllocator.pfAllocator) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001684 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1685 goto Done;
1686 }
1687
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001688 /* Loop getting chunks of the indefinite-length string */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001689 UsefulBufC FullString = NULLUsefulBufC;
1690
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001691 for(;;) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001692 /* Get QCBORItem for next chunk */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001693 QCBORItem StringChunkItem;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001694 /* Pass false to DecodeAtomicDataItem() because the individual
1695 * string chunks in an indefinite-length must not be
1696 * allocated. They are always copied into the allocated
1697 * contiguous buffer allocated here.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001698 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001699 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &StringChunkItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001700 if(uReturn) {
1701 break;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001702 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001703
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001704 /* Is item is the marker for end of the indefinite-length string? */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001705 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001706 /* String is complete */
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001707 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301708 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001709 break;
1710 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001711
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001712 /* All chunks must be of the same type, the type of the item
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001713 * that introduces the indefinite-length string. This also
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001714 * catches errors where the chunk is not a string at all and an
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001715 * indefinite-length string inside an indefinite-length string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001716 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001717 if(StringChunkItem.uDataType != uStringType ||
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001718 StringChunkItem.val.string.len == QCBOR_STRING_LENGTH_INDEFINITE) {
1719 uReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001720 break;
1721 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001722
David Navarro9123e5b2022-03-28 16:04:03 +02001723 if (StringChunkItem.val.string.len > 0) {
1724 /* The first time throurgh FullString.ptr is NULL and this is
1725 * equivalent to StringAllocator_Allocate(). Subsequently it is
1726 * not NULL and a reallocation happens.
1727 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001728 UsefulBuf NewMem = StringAllocator_Reallocate(&(pMe->StringAllocator),
David Navarro9123e5b2022-03-28 16:04:03 +02001729 FullString.ptr,
1730 FullString.len + StringChunkItem.val.string.len);
David Navarro9123e5b2022-03-28 16:04:03 +02001731 if(UsefulBuf_IsNULL(NewMem)) {
1732 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1733 break;
1734 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001735
David Navarro9123e5b2022-03-28 16:04:03 +02001736 /* Copy new string chunk to the end of accumulated string */
1737 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001738 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001739 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001740
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001741 if(uReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
1742 /* Getting the item failed, clean up the allocated memory */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001743 StringAllocator_Free(&(pMe->StringAllocator), FullString.ptr);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001744 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001745#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1746 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1747#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001748
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001749Done:
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001750 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001751}
1752
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001753
Laurence Lundblade37286c02022-09-03 10:05:02 -07001754#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001755/**
1756 * @brief This converts a tag number to a shorter mapped value for storage.
1757 *
1758 * @param[in] pMe The decode context.
1759 * @param[in] uUnMappedTag The tag number to map
1760 * @param[out] puMappedTagNumer The stored tag number.
1761 *
1762 * @return error code.
1763 *
1764 * The main point of mapping tag numbers is make QCBORItem
1765 * smaller. With this mapping storage of 4 tags takes up 8
1766 * bytes. Without, it would take up 32 bytes.
1767 *
1768 * This maps tag numbers greater than QCBOR_LAST_UNMAPPED_TAG.
1769 * QCBOR_LAST_UNMAPPED_TAG is a little smaller than MAX_UINT16.
1770 *
1771 * See also UnMapTagNumber() and @ref QCBORItem.
1772 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001773static QCBORError
1774QCBORDecode_Private_MapTagNumber(QCBORDecodeContext *pMe,
1775 const uint64_t uUnMappedTag,
1776 uint16_t *puMappedTagNumer)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001777{
1778 if(uUnMappedTag > QCBOR_LAST_UNMAPPED_TAG) {
1779 unsigned uTagMapIndex;
1780 /* Is there room in the tag map, or is it in it already? */
1781 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
1782 if(pMe->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID64) {
1783 break;
1784 }
1785 if(pMe->auMappedTags[uTagMapIndex] == uUnMappedTag) {
1786 break;
1787 }
1788 }
1789 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
1790 return QCBOR_ERR_TOO_MANY_TAGS;
1791 }
1792
1793 /* Covers the cases where tag is new and were it is already in the map */
1794 pMe->auMappedTags[uTagMapIndex] = uUnMappedTag;
1795 *puMappedTagNumer = (uint16_t)(uTagMapIndex + QCBOR_LAST_UNMAPPED_TAG + 1);
1796
1797 } else {
1798 *puMappedTagNumer = (uint16_t)uUnMappedTag;
1799 }
1800
1801 return QCBOR_SUCCESS;
1802}
1803
1804
1805/**
1806 * @brief This converts a mapped tag number to the actual tag number.
1807 *
1808 * @param[in] pMe The decode context.
1809 * @param[in] uMappedTagNumber The stored tag number.
1810 *
1811 * @return The actual tag number is returned or
1812 * @ref CBOR_TAG_INVALID64 on error.
1813 *
1814 * This is the reverse of MapTagNumber()
1815 */
1816static uint64_t
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001817QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe,
1818 const uint16_t uMappedTagNumber)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001819{
1820 if(uMappedTagNumber <= QCBOR_LAST_UNMAPPED_TAG) {
1821 return uMappedTagNumber;
1822 } else if(uMappedTagNumber == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07001823 return CBOR_TAG_INVALID64;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001824 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001825 /* This won't be negative because of code below in
1826 * MapTagNumber()
1827 */
1828 const unsigned uIndex = uMappedTagNumber - (QCBOR_LAST_UNMAPPED_TAG + 1);
1829 return pMe->auMappedTags[uIndex];
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001830 }
1831}
Laurence Lundblade37286c02022-09-03 10:05:02 -07001832#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001833
Laurence Lundblade9b334962020-08-27 10:55:53 -07001834
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001835/**
1836 * @brief Aggregate all tags wrapping a data item (decode layer 4).
1837 *
1838 * @param[in] pMe Decoder context
1839 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001840 *
1841 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1842 * features
1843 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1844 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1845 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1846 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1847 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1848 * of half-precision disabled
1849 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1850 * float decode is disabled.
1851 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1852 * simple type in input.
1853 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1854 * in input, but indefinite
1855 * lengths disabled.
1856 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1857 * but no string allocator.
1858 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1859 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1860 * input, but indefinite-length
1861 * strings are disabled.
1862 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001863 *
1864 * This loops getting atomic data items until one is not a tag
1865 * number. Usually this is largely pass-through because most
1866 * item are not tag numbers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001867 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001868static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001869QCBORDecode_Private_GetNextTagNumber(QCBORDecodeContext *pMe,
1870 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001871{
Laurence Lundblade37286c02022-09-03 10:05:02 -07001872#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001873 /* Accummulate the tags from multiple items here and then copy them
1874 * into the last item, the non-tag item.
1875 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001876 uint16_t auItemsTags[QCBOR_MAX_TAGS_PER_ITEM];
1877
1878 /* Initialize to CBOR_TAG_INVALID16 */
1879 #if CBOR_TAG_INVALID16 != 0xffff
1880 /* Be sure the memset does the right thing. */
1881 #err CBOR_TAG_INVALID16 tag not defined as expected
1882 #endif
1883 memset(auItemsTags, 0xff, sizeof(auItemsTags));
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001884
Laurence Lundblade9b334962020-08-27 10:55:53 -07001885 QCBORError uReturn = QCBOR_SUCCESS;
1886
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001887 /* Loop fetching data items until the item fetched is not a tag */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001888 for(;;) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001889 QCBORError uErr = QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07001890 if(uErr != QCBOR_SUCCESS) {
1891 uReturn = uErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001892 goto Done;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001893 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001894
Laurence Lundblade9b334962020-08-27 10:55:53 -07001895 if(pDecodedItem->uDataType != QCBOR_TYPE_TAG) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001896 /* Successful exit from loop; maybe got some tags, maybe not */
1897 memcpy(pDecodedItem->uTags, auItemsTags, sizeof(auItemsTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001898 break;
1899 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001900
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001901 if(auItemsTags[QCBOR_MAX_TAGS_PER_ITEM - 1] != CBOR_TAG_INVALID16) {
1902 /* No room in the tag list */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001903 uReturn = QCBOR_ERR_TOO_MANY_TAGS;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001904 /* Continue on to get all tags wrapping this item even though
1905 * it is erroring out in the end. This allows decoding to
1906 * continue. This is a resource limit error, not a problem
1907 * with being well-formed CBOR.
1908 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001909 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001910 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001911 /* Slide tags over one in the array to make room at index 0.
1912 * Must use memmove because the move source and destination
1913 * overlap.
1914 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001915 memmove(&auItemsTags[1],
1916 auItemsTags,
1917 sizeof(auItemsTags) - sizeof(auItemsTags[0]));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001918
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001919 /* Map the tag */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001920 uint16_t uMappedTagNumber = 0;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001921 uReturn = QCBORDecode_Private_MapTagNumber(pMe, pDecodedItem->val.uTagV, &uMappedTagNumber);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001922 /* Continue even on error so as to consume all tags wrapping
1923 * this data item so decoding can go on. If MapTagNumber()
1924 * errors once it will continue to error.
1925 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001926 auItemsTags[0] = uMappedTagNumber;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001927 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001928
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001929Done:
Laurence Lundblade9b334962020-08-27 10:55:53 -07001930 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001931
Laurence Lundblade37286c02022-09-03 10:05:02 -07001932#else /* QCBOR_DISABLE_TAGS */
1933
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07001934 return QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07001935
1936#endif /* QCBOR_DISABLE_TAGS */
1937}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001938
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001939
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001940/**
1941 * @brief Combine a map entry label and value into one item (decode layer 3).
1942 *
1943 * @param[in] pMe Decoder context
1944 * @param[out] pDecodedItem The decoded item that work is done on.
1945 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001946 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1947 * features
1948 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1949 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1950 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1951 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1952 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1953 * of half-precision disabled
1954 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1955 * float decode is disabled.
1956 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1957 * simple type in input.
1958 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1959 * in input, but indefinite
1960 * lengths disabled.
1961 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1962 * but no string allocator.
1963 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1964 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1965 * input, but indefinite-length
1966 * strings are disabled.
1967 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1968 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1969 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001970 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001971 * If the current nesting level is a map, then this combines pairs of
1972 * items into one data item with a label and value.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001973 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001974 * This is passthrough if the current nesting level is not a map.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001975 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001976 * This also implements maps-as-array mode where a map is treated like
1977 * an array to allow caller to do their own label processing.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001978 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001979static QCBORError
1980QCBORDecode_Private_GetNextMapEntry(QCBORDecodeContext *pMe,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001981 QCBORItem *pDecodedItem,
1982 uint32_t *puLabelEndOffset)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001983{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001984 QCBORItem LabelItem;
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001985 QCBORError uErr, uErr2;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001986
1987 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1988 if(QCBORDecode_IsUnrecoverableError(uErr)) {
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001989 goto Done;
1990 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001991
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001992 if(!DecodeNesting_IsCurrentTypeMap(&(pMe->nesting))) {
1993 /* Not decoding a map. Nothing to do. */
1994 /* When decoding maps-as-arrays, the type will be
1995 * QCBOR_TYPE_MAP_AS_ARRAY and this function will exit
1996 * here. This is now map processing for maps-as-arrays is not
1997 * done. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001998 goto Done;
1999 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08002000
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002001 /* Decoding a map entry, so the item decoded above was the label */
2002 LabelItem = *pDecodedItem;
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002003
2004 if(puLabelEndOffset != NULL) {
2005 /* Cast is OK because lengths are all 32-bit in QCBOR */
2006 *puLabelEndOffset = (uint32_t)UsefulInputBuf_Tell(&(pMe->InBuf));
2007 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08002008
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002009 /* Get the value of the map item */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002010 uErr2 = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
2011 if(QCBORDecode_IsUnrecoverableError(uErr2)) {
2012 uErr = uErr2;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002013 goto Done;
2014 }
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002015 if(uErr2 != QCBOR_SUCCESS) {
2016 /* The recoverable error for the value overrides the recoverable error for the label, if there was an error for the label */
2017 uErr = uErr2;
2018 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002019
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002020 /* Combine the label item and value item into one */
2021 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
2022 pDecodedItem->uLabelType = LabelItem.uDataType;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09002023
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002024#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
2025 /* QCBOR_DECODE_MODE_MAP_STRINGS_ONLY might have been a bad idea. Maybe
2026 * get rid of it in QCBOR 2.0
2027 */
2028 if(pMe->uDecodeMode == QCBOR_DECODE_MODE_MAP_STRINGS_ONLY &&
2029 LabelItem.uDataType != QCBOR_TYPE_TEXT_STRING) {
2030 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
2031 goto Done;
2032 }
2033#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
2034
2035 switch(LabelItem.uDataType) {
2036 case QCBOR_TYPE_INT64:
2037 pDecodedItem->label.int64 = LabelItem.val.int64;
2038 break;
2039
2040#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
2041 case QCBOR_TYPE_UINT64:
2042 pDecodedItem->label.uint64 = LabelItem.val.uint64;
2043 break;
2044
2045 case QCBOR_TYPE_TEXT_STRING:
2046 case QCBOR_TYPE_BYTE_STRING:
2047 pDecodedItem->label.string = LabelItem.val.string;
2048 break;
2049#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
2050
2051 default:
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002052 /* It is possible to skip over labels that are non-aggregate
2053 * types like floats, but not to skip over labels that are
2054 * arrays or maps. We might eventually handle more label
2055 * types like floats as they are not too hard and we now
2056 * have QCBOR_DISABLE_NON_INTEGER_LABELS */
2057 if(!pMe->bAllowAllLabels || QCBORItem_IsMapOrArray(LabelItem)) {
2058 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
2059 goto Done;
2060 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002061 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002062
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002063Done:
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002064 return uErr;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002065}
2066
2067
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002068#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002069/**
2070 * @brief Peek and see if next data item is a break;
2071 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002072 * param[in] pUIB UsefulInputBuf to read from.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002073 * @param[out] pbNextIsBreak Indicate if next was a break or not.
2074 *
2075 * @return Any decoding error.
2076 *
2077 * See if next item is a CBOR break. If it is, it is consumed,
2078 * if not it is not consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07002079*/
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002080static QCBORError
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002081QCBOR_Private_NextIsBreak(QCBORDecodeContext *pMe, bool *pbNextIsBreak)
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002082{
2083 *pbNextIsBreak = false;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002084 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) != 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002085 QCBORItem Peek;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002086 size_t uPeek = UsefulInputBuf_Tell(&(pMe->InBuf));
2087 QCBORError uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &Peek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002088 if(uReturn != QCBOR_SUCCESS) {
2089 return uReturn;
2090 }
2091 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002092 /* It is not a break, rewind so it can be processed normally. */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002093 UsefulInputBuf_Seek(&(pMe->InBuf), uPeek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002094 } else {
2095 *pbNextIsBreak = true;
2096 }
2097 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002098
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002099 return QCBOR_SUCCESS;
2100}
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002101#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002102
2103
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002104/**
2105 * @brief Ascend up nesting levels if all items in them have been consumed.
2106 *
2107 * @param[in] pMe The decode context.
2108 * @param[in] bMarkEnd If true mark end of maps/arrays with count of zero.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002109 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002110 *
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002111 * An item was just consumed, now figure out if it was the
2112 * end of an array/map map that can be closed out. That
2113 * may in turn close out the above array/map...
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002114 *
2115 * When ascending indefinite-length arrays and maps, this will correctly
2116 * consume the break for the level above. This is a problem for the
2117 * implementation of QCBORDecode_GetArray() that must not return
2118 * that break. @c pbBreak is set to true to indicate that one
2119 * byte should be removed.
2120 *
2121 * Improvement: this could reduced further if indef is disabled
2122 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002123static QCBORError
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002124QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd, bool *pbBreak)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002125{
2126 QCBORError uReturn;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002127
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002128 /* Loop ascending nesting levels as long as there is ascending to do */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002129 while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002130 if(pbBreak) {
2131 *pbBreak = false;
2132 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002133
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002134 if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) {
2135 /* Nesting level is bstr-wrapped CBOR */
2136
2137 /* Ascent for bstr-wrapped CBOR is always by explicit call
2138 * so no further ascending can happen.
2139 */
2140 break;
2141
2142 } else if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
2143 /* Level is a definite-length array/map */
2144
2145 /* Decrement the item count the definite-length array/map */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002146 DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(&(pMe->nesting));
2147 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002148 /* Didn't close out array/map, so all work here is done */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002149 break;
2150 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002151 /* All items in a definite-length array were consumed so it
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002152 * is time to ascend one level. This happens below.
2153 */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002154
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002155#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002156 } else {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002157 /* Level is an indefinite-length array/map. */
2158
2159 /* Check for a break which is what ends indefinite-length arrays/maps */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002160 bool bIsBreak = false;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002161 uReturn = QCBOR_Private_NextIsBreak(pMe, &bIsBreak);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002162 if(uReturn != QCBOR_SUCCESS) {
2163 goto Done;
2164 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002165
2166 if(!bIsBreak) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002167 /* Not a break so array/map does not close out. All work is done */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002168 break;
2169 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002170
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002171 /* It was a break in an indefinitelength map / array so
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002172 * it is time to ascend one level.
2173 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002174 if(pbBreak) {
2175 *pbBreak = true;
2176 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002177
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002178#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002179 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002180
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002181
2182 /* All items in the array/map have been consumed. */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002183
Laurence Lundblade93d89472020-10-03 22:30:50 -07002184 /* But ascent in bounded mode is only by explicit call to
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002185 * QCBORDecode_ExitBoundedMode().
2186 */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07002187 if(DecodeNesting_IsCurrentBounded(&(pMe->nesting))) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002188 /* Set the count to zero for definite-length arrays to indicate
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002189 * cursor is at end of bounded array/map */
Laurence Lundbladed0304932020-06-27 10:59:38 -07002190 if(bMarkEnd) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002191 /* Used for definite and indefinite to signal end */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07002192 DecodeNesting_ZeroMapOrArrayCount(&(pMe->nesting));
Laurence Lundbladed0304932020-06-27 10:59:38 -07002193
Laurence Lundblade2c1faf92020-06-26 22:43:56 -07002194 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002195 break;
2196 }
2197
2198 /* Finally, actually ascend one level. */
2199 DecodeNesting_Ascend(&(pMe->nesting));
2200 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002201
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002202 uReturn = QCBOR_SUCCESS;
2203
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002204#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002205Done:
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002206#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
2207
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002208 return uReturn;
2209}
2210
2211
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002212/**
2213 * @brief Ascending & Descending out of nesting levels (decode layer 2).
2214 *
2215 * @param[in] pMe Decoder context
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002216 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002217 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002218
2219 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
2220 * features
2221 * @retval QCBOR_ERR_HIT_END Unexpected end of input
2222 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
2223 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
2224 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
2225 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
2226 * of half-precision disabled
2227 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
2228 * float decode is disabled.
2229 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
2230 * simple type in input.
2231 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
2232 * in input, but indefinite
2233 * lengths disabled.
2234 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
2235 * but no string allocator.
2236 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
2237 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
2238 * input, but indefinite-length
2239 * strings are disabled.
2240 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
2241 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
2242 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
2243 * @retval QCBOR_ERR_NO_MORE_ITEMS Need more items for map or array.
2244 * @retval QCBOR_ERR_BAD_BREAK Indefinite-length break in wrong
2245 * place.
2246 * @retval QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP Nesting deeper than QCBOR
2247 * can handle.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002248 *
2249 * This handles the traversal descending into and asecnding out of
2250 * maps, arrays and bstr-wrapped CBOR. It figures out the ends of
2251 * definite- and indefinte-length maps and arrays by looking at the
2252 * item count or finding CBOR breaks. It detects the ends of the
2253 * top-level sequence and of bstr-wrapped CBOR by byte count.
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002254 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002255static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002256QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002257 bool *pbBreak,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002258 QCBORItem *pDecodedItem,
2259 uint32_t *puLabelEndOffset)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002260{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002261 QCBORError uReturn;
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002262 /* ==== First: figure out if at the end of a traversal ==== */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002263
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002264 /* If out of bytes to consume, it is either the end of the
2265 * top-level sequence of some bstr-wrapped CBOR that was entered.
2266 *
2267 * In the case of bstr-wrapped CBOR, the length of the
2268 * UsefulInputBuf was set to that of the bstr-wrapped CBOR. When
2269 * the bstr-wrapped CBOR is exited, the length is set back to the
2270 * top-level's length or to the next highest bstr-wrapped CBOR.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002271 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002272 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) == 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002273 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002274 goto Done;
2275 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07002276
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002277 /* Check to see if at the end of a bounded definite-length map or
2278 * array. The check for a break ending indefinite-length array is
2279 * later in QCBORDecode_NestLevelAscender().
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002280 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002281 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002282 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002283 goto Done;
2284 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002285
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002286 /* ==== Next: not at the end, so get another item ==== */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002287 uReturn = QCBORDecode_Private_GetNextMapEntry(pMe, pDecodedItem, puLabelEndOffset);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002288 if(QCBORDecode_IsUnrecoverableError(uReturn)) {
2289 /* Error is so bad that traversal is not possible. */
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002290 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002291 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05302292
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002293 /* Record the nesting level for this data item before processing
2294 * any of decrementing and descending.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002295 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002296 pDecodedItem->uNestingLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002297
Laurence Lundblade642282a2020-06-23 12:00:33 -07002298
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002299 /* ==== Next: Process the item for descent, ascent, decrement... ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002300 if(QCBORItem_IsMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002301 /* If the new item is a map or array, descend.
2302 *
2303 * Empty indefinite-length maps and arrays are descended into,
2304 * but then ascended out of in the next chunk of code.
2305 *
2306 * Maps and arrays do count as items in the map/array that
2307 * encloses them so a decrement needs to be done for them too,
2308 * but that is done only when all the items in them have been
2309 * processed, not when they are opened with the exception of an
2310 * empty map or array.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002311 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002312 QCBORError uDescendErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002313 uDescendErr = DecodeNesting_DescendMapOrArray(&(pMe->nesting),
Laurence Lundblade642282a2020-06-23 12:00:33 -07002314 pDecodedItem->uDataType,
2315 pDecodedItem->val.uCount);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002316 if(uDescendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002317 /* This error is probably a traversal error and it overrides
2318 * the non-traversal error.
2319 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002320 uReturn = uDescendErr;
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002321 goto Done;
2322 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002323 }
2324
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002325 if(!QCBORItem_IsMapOrArray(*pDecodedItem) ||
2326 QCBORItem_IsEmptyDefiniteLengthMapOrArray(*pDecodedItem) ||
2327 QCBORItem_IsIndefiniteLengthMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002328 /* The following cases are handled here:
2329 * - A non-aggregate item like an integer or string
2330 * - An empty definite-length map or array
2331 * - An indefinite-length map or array that might be empty or might not.
2332 *
2333 * QCBORDecode_NestLevelAscender() does the work of decrementing the count
2334 * for an definite-length map/array and break detection for an
2335 * indefinite-0length map/array. If the end of the map/array was
2336 * reached, then it ascends nesting levels, possibly all the way
2337 * to the top level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002338 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002339 QCBORError uAscendErr;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002340 uAscendErr = QCBORDecode_Private_NestLevelAscender(pMe, true, pbBreak);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002341 if(uAscendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002342 /* This error is probably a traversal error and it overrides
2343 * the non-traversal error.
2344 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002345 uReturn = uAscendErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002346 goto Done;
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002347 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05302348 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002349
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002350 /* ==== Last: tell the caller the nest level of the next item ==== */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002351 /* Tell the caller what level is next. This tells them what
2352 * maps/arrays were closed out and makes it possible for them to
2353 * reconstruct the tree with just the information returned in a
2354 * QCBORItem.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002355 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002356 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07002357 /* At end of a bounded map/array; uNextNestLevel 0 to indicate this */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002358 pDecodedItem->uNextNestLevel = 0;
2359 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002360 pDecodedItem->uNextNestLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002361 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002362
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002363Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002364 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002365}
2366
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002367
Laurence Lundblade37286c02022-09-03 10:05:02 -07002368#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002369/**
2370 * @brief Shift 0th tag out of the tag list.
2371 *
2372 * pDecodedItem[in,out] The data item to convert.
2373 *
2374 * The 0th tag is discarded. \ref CBOR_TAG_INVALID16 is
2375 * shifted into empty slot at the end of the tag list.
2376 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002377static void
2378QCBOR_Private_ShiftTags(QCBORItem *pDecodedItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002379{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002380 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM-1; i++) {
2381 pDecodedItem->uTags[i] = pDecodedItem->uTags[i+1];
2382 }
2383 pDecodedItem->uTags[QCBOR_MAX_TAGS_PER_ITEM-1] = CBOR_TAG_INVALID16;
Laurence Lundblade9b334962020-08-27 10:55:53 -07002384}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002385#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002386
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002387
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002388/**
2389 * @brief Convert different epoch date formats in to the QCBOR epoch date format
2390 *
2391 * pDecodedItem[in,out] The data item to convert.
2392 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002393 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2394 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2395 * floating-point date disabled.
2396 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2397 * all floating-point disabled.
2398 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2399 * error decoding date.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002400 *
2401 * The epoch date tag defined in QCBOR allows for floating-point
2402 * dates. It even allows a protocol to flop between date formats when
2403 * ever it wants. Floating-point dates aren't that useful as they are
2404 * only needed for dates beyond the age of the earth.
2405 *
2406 * This converts all the date formats into one format of an unsigned
2407 * integer plus a floating-point fraction.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002408 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002409static QCBORError
2410QCBOR_Private_DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002411{
Laurence Lundbladec7114722020-08-13 05:11:40 -07002412 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002413
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002414#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade59289e52019-12-30 13:44:37 -08002415 pDecodedItem->val.epochDate.fSecondsFraction = 0;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002416#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002417
2418 switch (pDecodedItem->uDataType) {
2419
2420 case QCBOR_TYPE_INT64:
2421 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
2422 break;
2423
2424 case QCBOR_TYPE_UINT64:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002425 /* This only happens for CBOR type 0 > INT64_MAX so it is
2426 * always an overflow.
2427 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07002428 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2429 goto Done;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002430 break;
2431
2432 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade9682a532020-06-06 18:33:04 -07002433 case QCBOR_TYPE_FLOAT:
2434#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade59289e52019-12-30 13:44:37 -08002435 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002436 /* Convert working value to double if input was a float */
Laurence Lundblade3ed0bca2020-07-14 22:50:10 -07002437 const double d = pDecodedItem->uDataType == QCBOR_TYPE_DOUBLE ?
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002438 pDecodedItem->val.dfnum :
2439 (double)pDecodedItem->val.fnum;
2440
2441 /* The conversion from float to integer requires overflow
2442 * detection since floats can be much larger than integers.
2443 * This implementation errors out on these large float values
2444 * since they are beyond the age of the earth.
2445 *
2446 * These constants for the overflow check are computed by the
2447 * compiler. They are not computed at run time.
2448 *
2449 * The factor of 0x7ff is added/subtracted to avoid a
2450 * rounding error in the wrong direction when the compiler
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002451 * computes these constants. There is rounding because a
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002452 * 64-bit integer has 63 bits of precision where a double
2453 * only has 53 bits. Without the 0x7ff factor, the compiler
2454 * may round up and produce a double for the bounds check
2455 * that is larger than can be stored in a 64-bit integer. The
2456 * amount of 0x7ff is picked because it has 11 bits set.
2457 *
2458 * Without the 0x7ff there is a ~30 minute range of time
2459 * values 10 billion years in the past and in the future
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002460 * where this code could go wrong. Some compilers
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002461 * generate a warning or error without the 0x7ff.
2462 */
2463 const double dDateMax = (double)(INT64_MAX - 0x7ff);
2464 const double dDateMin = (double)(INT64_MIN + 0x7ff);
2465
2466 if(isnan(d) || d > dDateMax || d < dDateMin) {
Laurence Lundbladec7114722020-08-13 05:11:40 -07002467 uReturn = QCBOR_ERR_DATE_OVERFLOW;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002468 goto Done;
2469 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002470
2471 /* The actual conversion */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002472 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
Laurence Lundblade2feb1e12020-07-15 03:50:45 -07002473 pDecodedItem->val.epochDate.fSecondsFraction =
2474 d - (double)pDecodedItem->val.epochDate.nSeconds;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002475 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002476#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade4b270642020-08-14 12:53:07 -07002477
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002478 uReturn = QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundblade4b270642020-08-14 12:53:07 -07002479 goto Done;
2480
Laurence Lundblade9682a532020-06-06 18:33:04 -07002481#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002482 break;
2483
2484 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002485 /* It's the arrays and maps that are unrecoverable because
2486 * they are not consumed here. Since this is just an error
2487 * condition, no extra code is added here to make the error
2488 * recoverable for non-arrays and maps like strings. */
2489 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002490 goto Done;
2491 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002492
Laurence Lundblade59289e52019-12-30 13:44:37 -08002493 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
2494
2495Done:
Laurence Lundbladec7114722020-08-13 05:11:40 -07002496 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002497}
2498
2499
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002500/**
2501 * @brief Convert the days epoch date.
2502 *
2503 * pDecodedItem[in,out] The data item to convert.
2504 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002505 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2506 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2507 * floating-point date disabled.
2508 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2509 * all floating-point disabled.
2510 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2511 * error decoding date.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002512 *
2513 * This is much simpler than the other epoch date format because
2514 * floating-porint is not allowed. This is mostly a simple type check.
2515 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002516static QCBORError
2517QCBOR_Private_DecodeDaysEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002518{
2519 QCBORError uReturn = QCBOR_SUCCESS;
2520
2521 switch (pDecodedItem->uDataType) {
2522
2523 case QCBOR_TYPE_INT64:
2524 pDecodedItem->val.epochDays = pDecodedItem->val.int64;
2525 break;
2526
2527 case QCBOR_TYPE_UINT64:
2528 /* This only happens for CBOR type 0 > INT64_MAX so it is
2529 * always an overflow.
2530 */
2531 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2532 goto Done;
2533 break;
2534
2535 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002536 /* It's the arrays and maps that are unrecoverable because
2537 * they are not consumed here. Since this is just an error
2538 * condition, no extra code is added here to make the error
2539 * recoverable for non-arrays and maps like strings. */
2540 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002541 goto Done;
2542 break;
2543 }
2544
2545 pDecodedItem->uDataType = QCBOR_TYPE_DAYS_EPOCH;
2546
2547Done:
2548 return uReturn;
2549}
2550
2551
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002552#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade37286c02022-09-03 10:05:02 -07002553
2554/* Forward declaration is necessary for
2555 * QCBORDecode_MantissaAndExponent(). to be able to decode bignum
2556 * tags in the mantissa. If the mantissa is a decimal fraction or big
2557 * float in error, this will result in a recurive call to
2558 * QCBORDecode_MantissaAndExponent(), but the recursion will unwined
2559 * correctly and the correct error is returned.
2560 */
2561static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002562QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2563 QCBORItem *pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002564
2565
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002566/**
2567 * @brief Decode decimal fractions and big floats.
2568 *
2569 * @param[in] pMe The decode context.
2570 * @param[in,out] pDecodedItem On input the array data item that
2571 * holds the mantissa and exponent. On
2572 * output the decoded mantissa and
2573 * exponent.
2574 *
2575 * @returns Decoding errors from getting primitive data items or
2576 * \ref QCBOR_ERR_BAD_EXP_AND_MANTISSA.
2577 *
Laurence Lundblade37286c02022-09-03 10:05:02 -07002578 * When called pDecodedItem must be the array with two members, the
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002579 * exponent and mantissa.
2580 *
2581 * This will fetch and decode the exponent and mantissa and put the
2582 * result back into pDecodedItem.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002583 *
2584 * This does no checking or processing of tag numbers. That is to be
2585 * done by the code that calls this.
2586 *
2587 * This stuffs the type of the mantissa into pDecodedItem with the expectation
2588 * the caller will process it.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002589 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002590static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002591QCBORDecode_Private_ExpMantissa(QCBORDecodeContext *pMe,
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002592 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002593{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002594 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002595
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002596 /* --- Make sure it is an array; track nesting level of members --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002597 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002598 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002599 goto Done;
2600 }
2601
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002602 /* A check for pDecodedItem->val.uCount == 2 would work for
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002603 * definite-length arrays, but not for indefinite. Instead remember
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002604 * the nesting level the two integers must be at, which is one
2605 * deeper than that of the array.
2606 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002607 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
2608
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002609 /* --- Get the exponent --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002610 QCBORItem exponentItem;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002611 uReturn = QCBORDecode_GetNext(pMe, &exponentItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002612 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002613 goto Done;
2614 }
2615 if(exponentItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002616 /* Array is empty or a map/array encountered when expecting an int */
2617 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002618 goto Done;
2619 }
2620 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002621 /* Data arriving as an unsigned int < INT64_MAX has been
2622 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2623 * also means that the only data arriving here of type
2624 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2625 * and thus an error that will get handled in the next else.
2626 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002627 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
2628 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002629 /* Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX */
2630 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002631 goto Done;
2632 }
2633
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002634 /* --- Get the mantissa --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002635 QCBORItem mantissaItem;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002636 uReturn = QCBORDecode_GetNext(pMe, &mantissaItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002637 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002638 goto Done;
2639 }
2640 if(mantissaItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002641 /* Mantissa missing or map/array encountered when expecting number */
2642 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002643 goto Done;
2644 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002645 /* Stuff the mantissa data type into the item to send it up to the
2646 * the next level. */
2647 pDecodedItem->uDataType = mantissaItem.uDataType;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002648 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002649 /* Data arriving as an unsigned int < INT64_MAX has been
2650 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2651 * also means that the only data arriving here of type
2652 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2653 * and thus an error that will get handled in an else below.
2654 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002655 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002656#ifndef QCBOR_DISABLE_TAGS
2657 /* With tags fully disabled a big number mantissa will error out
2658 * in the call to QCBORDecode_GetNextWithTags() because it has
2659 * a tag number.
2660 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07002661 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM ||
2662 mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002663 /* Got a good big num mantissa */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002664 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002665#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002666 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002667 /* Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX */
2668 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002669 goto Done;
2670 }
2671
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002672 /* --- Check that array only has the two numbers --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002673 if(mantissaItem.uNextNestLevel == nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002674 /* Extra items in the decimal fraction / big float */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002675 /* Improvement: this should probably be an unrecoverable error. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002676 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002677 goto Done;
2678 }
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002679 pDecodedItem->uNextNestLevel = mantissaItem.uNextNestLevel;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002680
2681Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002682 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002683}
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002684#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002685
2686
Laurence Lundblade37286c02022-09-03 10:05:02 -07002687#ifndef QCBOR_DISABLE_TAGS
2688
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002689#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002690/**
2691 * @brief Decode the MIME type tag
2692 *
2693 * @param[in,out] pDecodedItem The item to decode.
2694 *
2695 * Handle the text and binary MIME type tags. Slightly too complicated
2696 * f or ProcessTaggedString() because the RFC 7049 MIME type was
2697 * incorreclty text-only.
2698 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002699static QCBORError
2700QCBOR_Private_DecodeMIME(QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002701{
2702 if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) {
2703 pDecodedItem->uDataType = QCBOR_TYPE_MIME;
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07002704 } else if(pDecodedItem->uDataType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002705 pDecodedItem->uDataType = QCBOR_TYPE_BINARY_MIME;
2706 } else {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002707 /* It's the arrays and maps that are unrecoverable because
2708 * they are not consumed here. Since this is just an error
2709 * condition, no extra code is added here to make the error
2710 * recoverable for non-arrays and maps like strings. */
2711 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002712 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002713
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002714 return QCBOR_SUCCESS;
2715}
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002716#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002717
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002718/**
Laurence Lundblade99615302020-11-29 11:19:47 -08002719 * Table of CBOR tags whose content is either a text string or a byte
2720 * string. The table maps the CBOR tag to the QCBOR type. The high-bit
2721 * of uQCBORtype indicates the content should be a byte string rather
2722 * than a text string
2723 */
2724struct StringTagMapEntry {
2725 uint16_t uTagNumber;
2726 uint8_t uQCBORtype;
2727};
2728
2729#define IS_BYTE_STRING_BIT 0x80
2730#define QCBOR_TYPE_MASK ~IS_BYTE_STRING_BIT
2731
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002732static const struct StringTagMapEntry QCBOR_Private_StringTagMap[] = {
Laurence Lundblade99615302020-11-29 11:19:47 -08002733 {CBOR_TAG_DATE_STRING, QCBOR_TYPE_DATE_STRING},
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002734 {CBOR_TAG_DAYS_STRING, QCBOR_TYPE_DAYS_STRING},
Laurence Lundblade99615302020-11-29 11:19:47 -08002735 {CBOR_TAG_POS_BIGNUM, QCBOR_TYPE_POSBIGNUM | IS_BYTE_STRING_BIT},
2736 {CBOR_TAG_NEG_BIGNUM, QCBOR_TYPE_NEGBIGNUM | IS_BYTE_STRING_BIT},
2737 {CBOR_TAG_CBOR, QBCOR_TYPE_WRAPPED_CBOR | IS_BYTE_STRING_BIT},
2738 {CBOR_TAG_URI, QCBOR_TYPE_URI},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002739#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002740 {CBOR_TAG_B64URL, QCBOR_TYPE_BASE64URL},
2741 {CBOR_TAG_B64, QCBOR_TYPE_BASE64},
2742 {CBOR_TAG_REGEX, QCBOR_TYPE_REGEX},
2743 {CBOR_TAG_BIN_UUID, QCBOR_TYPE_UUID | IS_BYTE_STRING_BIT},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002744#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade99615302020-11-29 11:19:47 -08002745 {CBOR_TAG_CBOR_SEQUENCE, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE | IS_BYTE_STRING_BIT},
2746 {CBOR_TAG_INVALID16, QCBOR_TYPE_NONE}
2747};
2748
2749
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002750/**
2751 * @brief Process standard CBOR tags whose content is a string
2752 *
2753 * @param[in] uTag The tag.
2754 * @param[in,out] pDecodedItem The data item.
2755 *
2756 * @returns This returns QCBOR_SUCCESS if the tag was procssed,
2757 * \ref QCBOR_ERR_UNSUPPORTED if the tag was not processed and
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002758 * \ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT if the content type was wrong for the tag.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002759 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002760 * Process the CBOR tags that whose content is a byte string or a text
2761 * string and for which the string is just passed on to the caller.
2762 *
2763 * This maps the CBOR tag to the QCBOR type and checks the content
2764 * type. Nothing more. It may not be the most important
Laurence Lundbladec02e13e2020-12-06 05:45:41 -08002765 * functionality, but it part of implementing as much of RFC 8949 as
Laurence Lundblade99615302020-11-29 11:19:47 -08002766 * possible.
Laurence Lundblade99615302020-11-29 11:19:47 -08002767 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002768static QCBORError
2769QCBOR_Private_ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002770{
Laurence Lundblade99615302020-11-29 11:19:47 -08002771 /* This only works on tags that were not mapped; no need for other yet */
2772 if(uTag > QCBOR_LAST_UNMAPPED_TAG) {
2773 return QCBOR_ERR_UNSUPPORTED;
2774 }
2775
2776 unsigned uIndex;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002777 for(uIndex = 0; QCBOR_Private_StringTagMap[uIndex].uTagNumber != CBOR_TAG_INVALID16; uIndex++) {
2778 if(QCBOR_Private_StringTagMap[uIndex].uTagNumber == uTag) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002779 break;
2780 }
2781 }
2782
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002783 const uint8_t uQCBORType = QCBOR_Private_StringTagMap[uIndex].uQCBORtype;
Laurence Lundblade99615302020-11-29 11:19:47 -08002784 if(uQCBORType == QCBOR_TYPE_NONE) {
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002785 /* repurpose this error to mean not handled here */
Laurence Lundblade99615302020-11-29 11:19:47 -08002786 return QCBOR_ERR_UNSUPPORTED;
2787 }
2788
2789 uint8_t uExpectedType = QCBOR_TYPE_TEXT_STRING;
2790 if(uQCBORType & IS_BYTE_STRING_BIT) {
2791 uExpectedType = QCBOR_TYPE_BYTE_STRING;
2792 }
2793
2794 if(pDecodedItem->uDataType != uExpectedType) {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002795 /* It's the arrays and maps that are unrecoverable because
2796 * they are not consumed here. Since this is just an error
2797 * condition, no extra code is added here to make the error
2798 * recoverable for non-arrays and maps like strings. */
2799 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002800 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002801
Laurence Lundblade99615302020-11-29 11:19:47 -08002802 pDecodedItem->uDataType = (uint8_t)(uQCBORType & QCBOR_TYPE_MASK);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002803 return QCBOR_SUCCESS;
2804}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002805#endif /* QCBOR_DISABLE_TAGS */
2806
2807
2808#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002809/**
2810 * @brief Figures out data type for exponent mantissa tags.
2811 *
2812 * @param[in] uTagToProcess Either @ref CBOR_TAG_DECIMAL_FRACTION or
2813 * @ref CBOR_TAG_BIG_FLOAT.
2814 * @param[in] pDecodedItem Item being decoded.
2815 *
2816 * @returns One of the 6 values between \ref QCBOR_TYPE_DECIMAL_FRACTION
2817 * and @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM.
2818 *
2819 * Does mapping between a CBOR tag number and a QCBOR type. with a
2820 * little bit of logic and arithmatic.
2821 *
2822 * Used in serveral contexts. Does the work where sometimes the data
2823 * item is explicitly tagged and sometimes not.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002824 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002825static uint8_t
2826QCBOR_Private_ExpMantissaDataType(const uint16_t uTagToProcess,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002827 const QCBORItem *pDecodedItem)
Laurence Lundblade37286c02022-09-03 10:05:02 -07002828{
2829 uint8_t uBase = uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ?
2830 QCBOR_TYPE_DECIMAL_FRACTION :
2831 QCBOR_TYPE_BIGFLOAT;
2832 if(pDecodedItem->uDataType != QCBOR_TYPE_INT64) {
2833 uBase = (uint8_t)(uBase + pDecodedItem->uDataType - QCBOR_TYPE_POSBIGNUM + 1);
2834 }
2835 return uBase;
2836}
2837#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002838
2839
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002840/**
2841 * @brief Decode tag content for select tags (decoding layer 1).
2842 *
2843 * @param[in] pMe The decode context.
2844 * @param[out] pDecodedItem The decoded item.
2845 *
2846 * @return Decoding error code.
2847 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002848 * CBOR tag numbers for the item were decoded in GetNext_TaggedItem(),
2849 * but the whole tag was not decoded. Here, the whole tags (tag number
2850 * and tag content) that are supported by QCBOR are decoded. This is a
2851 * quick pass through for items that are not tags.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002852 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002853static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002854QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2855 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002856{
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002857 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002858
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002859 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pDecodedItem, NULL);
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002860 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002861 goto Done;
2862 }
2863
Laurence Lundblade37286c02022-09-03 10:05:02 -07002864#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002865 /* When there are no tag numbers for the item, this exits first
2866 * thing and effectively does nothing.
2867 *
2868 * This loops over all the tag numbers accumulated for this item
2869 * trying to decode and interpret them. This stops at the end of
2870 * the list or at the first tag number that can't be interpreted by
2871 * this code. This is effectively a recursive processing of the
2872 * tags number list that handles nested tags.
2873 */
2874 while(1) {
2875 /* Don't bother to unmap tags via QCBORITem.uTags since this
2876 * code only works on tags less than QCBOR_LAST_UNMAPPED_TAG.
2877 */
2878 const uint16_t uTagToProcess = pDecodedItem->uTags[0];
Laurence Lundblade59289e52019-12-30 13:44:37 -08002879
Laurence Lundblade99615302020-11-29 11:19:47 -08002880 if(uTagToProcess == CBOR_TAG_INVALID16) {
2881 /* Hit the end of the tag list. A successful exit. */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002882 break;
2883
Laurence Lundblade99615302020-11-29 11:19:47 -08002884 } else if(uTagToProcess == CBOR_TAG_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002885 uReturn = QCBOR_Private_DecodeDateEpoch(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002886
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002887 } else if(uTagToProcess == CBOR_TAG_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002888 uReturn = QCBOR_Private_DecodeDaysEpoch(pDecodedItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002889
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002890#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade99615302020-11-29 11:19:47 -08002891 } else if(uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ||
2892 uTagToProcess == CBOR_TAG_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002893 uReturn = QCBORDecode_Private_ExpMantissa(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002894 /* --- Which is it, decimal fraction or a bigfloat? --- */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002895 pDecodedItem->uDataType = QCBOR_Private_ExpMantissaDataType(uTagToProcess, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002896
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002897#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002898#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002899 } else if(uTagToProcess == CBOR_TAG_MIME ||
2900 uTagToProcess == CBOR_TAG_BINARY_MIME) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002901 uReturn = QCBOR_Private_DecodeMIME(pDecodedItem);
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002902#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002903
Laurence Lundblade99615302020-11-29 11:19:47 -08002904 } else {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002905 /* See if it is a passthrough byte/text string tag; process if so */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002906 uReturn = QCBOR_Private_ProcessTaggedString(pDecodedItem->uTags[0], pDecodedItem);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002907
Laurence Lundblade99615302020-11-29 11:19:47 -08002908 if(uReturn == QCBOR_ERR_UNSUPPORTED) {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002909 /* It wasn't a passthrough byte/text string tag so it is
Laurence Lundblade99615302020-11-29 11:19:47 -08002910 * an unknown tag. This is the exit from the loop on the
2911 * first unknown tag. It is a successful exit.
2912 */
2913 uReturn = QCBOR_SUCCESS;
2914 break;
2915 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002916 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002917
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002918 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002919 /* Error exit from the loop */
2920 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002921 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002922
2923 /* A tag was successfully processed, shift it out of the list of
2924 * tags returned. This is the loop increment.
2925 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002926 QCBOR_Private_ShiftTags(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002927 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002928#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002929
2930Done:
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002931 return uReturn;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002932}
2933
2934
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002935/**
2936 * @brief Consume an entire map or array including its contents.
2937 *
2938 * @param[in] pMe The decoder context.
2939 * @param[in] pItemToConsume The array/map whose contents are to be
2940 * consumed.
2941 * @param[out] puNextNestLevel The next nesting level after the item was
2942 * fully consumed.
2943 *
2944 * This may be called when @c pItemToConsume is not an array or
2945 * map. In that case, this is just a pass through for @c puNextNestLevel
2946 * since there is nothing to do.
2947 */
2948static QCBORError
2949QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
2950 const QCBORItem *pItemToConsume,
2951 bool *pbBreak,
2952 uint8_t *puNextNestLevel)
2953{
2954 QCBORError uReturn;
2955 QCBORItem Item;
2956
2957 /* If it is a map or array, this will tell if it is empty. */
2958 const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel);
2959
2960 if(QCBORItem_IsMapOrArray(*pItemToConsume) && !bIsEmpty) {
2961 /* There is only real work to do for non-empty maps and arrays */
2962
2963 /* This works for definite- and indefinite-length maps and
2964 * arrays by using the nesting level
2965 */
2966 do {
2967 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pbBreak, &Item, NULL);
2968 if(QCBORDecode_IsUnrecoverableError(uReturn) ||
2969 uReturn == QCBOR_ERR_NO_MORE_ITEMS) {
2970 goto Done;
2971 }
2972 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
2973
2974 *puNextNestLevel = Item.uNextNestLevel;
2975
2976 uReturn = QCBOR_SUCCESS;
2977
2978 } else {
2979 /* pItemToConsume is not a map or array. Just pass the nesting
2980 * level through. */
2981 *puNextNestLevel = pItemToConsume->uNextNestLevel;
2982
2983 uReturn = QCBOR_SUCCESS;
2984 }
2985
2986Done:
2987 return uReturn;
2988}
2989
2990
2991/*
2992 *
2993 * This consumes the next item. It returns the starting position of
2994 * the label and the length of the label. It also returns the nest
2995 * level of the item consumed.
2996 */
2997static QCBORError
2998QCBORDecode_Private_GetLabelAndConsume(QCBORDecodeContext *pMe,
2999 uint8_t *puNestLevel,
3000 size_t *puLabelStart,
3001 size_t *puLabelLen)
3002{
3003 QCBORError uErr;
3004 QCBORItem Item;
3005 uint8_t uLevel;
3006 uint32_t uLabelOffset;
3007
3008 /* Get the label and consume it should it be complex */
3009 *puLabelStart = UsefulInputBuf_Tell(&(pMe->InBuf));
3010
3011 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, &Item, &uLabelOffset);
3012 if(uErr != QCBOR_SUCCESS) {
3013 goto Done;
3014 }
3015 *puLabelLen = uLabelOffset - *puLabelStart;
3016 *puNestLevel = Item.uNestingLevel;
3017 uErr = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uLevel);
3018
3019Done:
3020 return uErr;
3021}
3022
3023
3024/* Loop over items in a map until the end of the map looking for
3025 * duplicates. This starts at the current position in the map, not at
3026 * the beginning of the map.
3027 *
3028 * This saves and restores the traversal cursor and nest tracking so
3029 * they are the same on exit as they were on entry.
3030 */
3031static QCBORError
3032QCBORDecode_Private_CheckDups(QCBORDecodeContext *pMe,
3033 const uint8_t uNestLevel,
3034 const size_t uCompareLabelStart,
3035 const size_t uCompareLabelLen)
3036{
3037 QCBORError uErr;
3038 size_t uLabelStart;
3039 size_t uLabelLen;
3040 uint8_t uLevel;
3041 int nCompare;
3042
3043 const QCBORDecodeNesting SaveNesting = pMe->nesting;
3044 const UsefulInputBuf Save = pMe->InBuf;
3045
3046 do {
3047 uErr = QCBORDecode_Private_GetLabelAndConsume(pMe, &uLevel, &uLabelStart, &uLabelLen);
3048 if(uErr != QCBOR_SUCCESS) {
3049 if(uErr == QCBOR_ERR_NO_MORE_ITEMS) {
3050 uErr = QCBOR_SUCCESS; /* Successful end */
3051 }
3052 break;
3053 }
3054
3055 if(uLevel != uNestLevel) {
3056 break; /* Successful end of loop */
3057 }
3058
3059 /* This check for dups works for labels that are preferred
3060 * serialization and are not maps. If the labels are not in
3061 * preferred serialization, then the check has to be more
3062 * complicated and is type-specific because it uses the decoded
3063 * value, not the encoded CBOR. It is further complicated for
3064 * maps because the order of items in a map that is a label
3065 * doesn't matter when checking that is is the duplicate of
3066 * another map that is a label. QCBOR so far only turns on this
3067 * dup checking as part of CDE checking which requires preferred
3068 * serialization. See 5.6 in RFC 8949.
3069 */
3070 nCompare = UsefulInputBuf_Compare(&(pMe->InBuf),
3071 uCompareLabelStart, uCompareLabelLen,
3072 uLabelStart, uLabelLen);
3073 if(nCompare == 0) {
3074 uErr = QCBOR_ERR_DUPLICATE_LABEL;
3075 break;
3076 }
3077 } while (1);
3078
3079 pMe->nesting = SaveNesting;
3080 pMe->InBuf = Save;
3081
3082 return uErr;
3083}
3084
3085
3086/* This does sort order and duplicate detection on a map. The and all
3087 * it's members must be in preferred serialization so the comparisons
3088 * work correctly.
3089 */
3090static QCBORError
3091QCBORDecode_Private_CheckMap(QCBORDecodeContext *pMe, const QCBORItem *pMapToCheck)
3092{
3093 QCBORError uErr;
3094 uint8_t uNestLevel;
3095 size_t offset2, offset1, length2, length1;
3096
3097 const QCBORDecodeNesting SaveNesting = pMe->nesting;
3098 const UsefulInputBuf Save = pMe->InBuf;
3099 pMe->bAllowAllLabels = 1;
3100
3101 /* This loop runs over all the items in the map once, comparing
3102 * each adjacent pair for correct ordering. It also calls CheckDup
3103 * on each one which also runs over the remaining items in the map
3104 * checking for duplicates. So duplicate checking runs in n^2.
3105 */
3106
3107 offset2 = SIZE_MAX;
3108 length2 = SIZE_MAX; // To avoid uninitialized warning
3109 while(1) {
3110 uErr = QCBORDecode_Private_GetLabelAndConsume(pMe, &uNestLevel, &offset1, &length1);
3111 if(uErr != QCBOR_SUCCESS) {
3112 if(uErr == QCBOR_ERR_NO_MORE_ITEMS) {
3113 uErr = QCBOR_SUCCESS; /* Successful exit from loop */
3114 }
3115 break;
3116 }
3117
3118 if(uNestLevel < pMapToCheck->uNextNestLevel) {
3119 break; /* Successful exit from loop */
3120 }
3121
3122 if(offset2 != SIZE_MAX) {
3123 /* Check that the labels are ordered. Check is not done the
3124 * first time through the loop when offset2 is unset. Since
3125 * this does comparison of the items in encoded form they
3126 * must be preferred serialization encoded. See RFC 8949
3127 * 4.2.1.
3128 */
3129 if(UsefulInputBuf_Compare(&(pMe->InBuf), offset2, length2, offset1, length1) > 0) {
3130 uErr = QCBOR_ERR_UNSORTED;
3131 break;
3132 }
3133 }
3134
3135 uErr = QCBORDecode_Private_CheckDups(pMe, pMapToCheck->uNextNestLevel, offset1, length1);
3136 if(uErr != QCBOR_SUCCESS) {
3137 break;
3138 }
3139
3140 offset2 = offset1;
3141 length2 = length1;
3142 }
3143
3144 pMe->bAllowAllLabels = 0;
3145 pMe->nesting = SaveNesting;
3146 pMe->InBuf = Save;
3147
3148 return uErr;
3149}
3150
3151
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08003152/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003153 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08003154 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003155QCBORError
3156QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
3157{
3158 QCBORError uErr;
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07003159 uErr = QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem);
3160#ifndef QCBOR_DISABLE_CONFORMANCE
3161 if(uErr == QCBOR_SUCCESS && pMe->uDecodeMode >= QCBOR_ENCODE_MODE_CDE && pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
3162 /* Traverse map checking sort order and for duplicates */
3163 uErr = QCBORDecode_Private_CheckMap(pMe, pDecodedItem);
3164 }
3165#endif /* ! QCBOR_DISABLE_CONFORMANCE */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003166 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08003167 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
3168 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
3169 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003170 return uErr;
Laurence Lundblade59289e52019-12-30 13:44:37 -08003171}
3172
3173
3174/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003175 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08003176 */
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08003177QCBORError
3178QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
3179{
3180 const QCBORDecodeNesting SaveNesting = pMe->nesting;
3181 const UsefulInputBuf Save = pMe->InBuf;
3182
3183 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
3184
3185 pMe->nesting = SaveNesting;
3186 pMe->InBuf = Save;
3187
3188 return uErr;
3189}
3190
3191
3192/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003193 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08003194 */
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003195void
3196QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
3197{
3198 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08003199 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
3200 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003201 return;
3202 }
3203
3204 pMe->uLastError = (uint8_t)QCBORDecode_PeekNext(pMe, pDecodedItem);
3205}
3206
3207
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003208static void
3209QCBORDecode_Private_CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem)
3210{
3211#ifndef QCBOR_DISABLE_TAGS
3212 memcpy(pMe->uLastTags, pItem->uTags, sizeof(pItem->uTags));
3213#else
3214 (void)pMe;
3215 (void)pItem;
3216#endif
3217}
3218
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003219/*
3220 * Public function, see header qcbor/qcbor_decode.h file
3221 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003222void
3223QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07003224{
3225 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08003226 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
3227 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07003228 return;
3229 }
3230
3231 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem);
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003232 QCBORDecode_Private_CopyTags(pMe, pDecodedItem);
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07003233}
3234
3235
3236/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003237 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07003238 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07003239QCBORError
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003240QCBORDecode_GetNextWithTags(QCBORDecodeContext *pMe,
3241 QCBORItem *pDecodedItem,
3242 QCBORTagListOut *pTags)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07003243{
Laurence Lundblade37286c02022-09-03 10:05:02 -07003244#ifndef QCBOR_DISABLE_TAGS
3245
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003246 QCBORError uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07003247
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003248 uReturn = QCBORDecode_GetNext(pMe, pDecodedItem);
3249 if(uReturn != QCBOR_SUCCESS) {
3250 return uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07003251 }
3252
3253 if(pTags != NULL) {
3254 pTags->uNumUsed = 0;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003255 /* Reverse the order because pTags is reverse of QCBORItem.uTags. */
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003256 for(int nTagIndex = QCBOR_MAX_TAGS_PER_ITEM-1; nTagIndex >=0; nTagIndex--) {
3257 if(pDecodedItem->uTags[nTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07003258 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07003259 }
3260 if(pTags->uNumUsed >= pTags->uNumAllocated) {
3261 return QCBOR_ERR_TOO_MANY_TAGS;
3262 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003263 pTags->puTags[pTags->uNumUsed] = QCBORDecode_Private_UnMapTagNumber(pMe,pDecodedItem->uTags[nTagIndex]);
Laurence Lundblade830fbf92020-05-31 17:22:33 -07003264 pTags->uNumUsed++;
3265 }
3266 }
3267
3268 return QCBOR_SUCCESS;
Laurence Lundblade37286c02022-09-03 10:05:02 -07003269
3270#else /* QCBOR_DISABLE_TAGS */
3271 (void)pMe;
3272 (void)pDecodedItem;
3273 (void)pTags;
3274 return QCBOR_ERR_TAGS_DISABLED;
3275#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07003276}
3277
3278
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07003279/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003280 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05303281 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003282bool
3283QCBORDecode_IsTagged(QCBORDecodeContext *pMe,
3284 const QCBORItem *pItem,
3285 uint64_t uTag)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07003286{
Laurence Lundblade37286c02022-09-03 10:05:02 -07003287#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003288 for(unsigned uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) {
3289 if(pItem->uTags[uTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07003290 break;
3291 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003292 if(QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uTagIndex]) == uTag) {
Laurence Lundbladef71e1622020-08-06 18:52:13 -07003293 return true;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07003294 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07003295 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07003296#else /* QCBOR_TAGS_DISABLED */
3297 (void)pMe;
3298 (void)pItem;
3299 (void)uTag;
3300#endif /* QCBOR_TAGS_DISABLED */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003301
Laurence Lundbladef71e1622020-08-06 18:52:13 -07003302 return false;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07003303}
3304
3305
3306/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003307 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07003308 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003309QCBORError
3310QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07003311{
Laurence Lundblade87495732021-02-26 10:05:55 -07003312 if(puConsumed != NULL) {
3313 *puConsumed = pMe->InBuf.cursor;
3314 }
3315
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003316 QCBORError uReturn = pMe->uLastError;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003317
3318 if(uReturn != QCBOR_SUCCESS) {
3319 goto Done;
3320 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003321
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003322 /* Error out if all the maps/arrays are not closed out */
3323 if(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003324 uReturn = QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08003325 goto Done;
3326 }
3327
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003328 /* Error out if not all the bytes are consumed */
3329 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf))) {
Laurence Lundblade085d7952020-07-24 10:26:30 -07003330 uReturn = QCBOR_ERR_EXTRA_BYTES;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08003331 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003332
Laurence Lundblade20b533d2018-10-08 20:44:53 +08003333Done:
Laurence Lundblade87495732021-02-26 10:05:55 -07003334 return uReturn;
3335}
3336
3337
3338/*
3339 * Public function, see header qcbor/qcbor_decode.h file
3340 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003341QCBORError
3342QCBORDecode_Finish(QCBORDecodeContext *pMe)
Laurence Lundblade87495732021-02-26 10:05:55 -07003343{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003344#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003345 /* Call the destructor for the string allocator if there is one.
3346 * Always called, even if there are errors; always have to clean up.
3347 */
3348 StringAllocator_Destruct(&(pMe->StringAllocator));
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003349#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003350
Laurence Lundblade87495732021-02-26 10:05:55 -07003351 return QCBORDecode_PartialFinish(pMe, NULL);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07003352}
3353
3354
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07003355/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003356 * Public function, see header qcbor/qcbor_decode.h file
3357 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003358uint64_t
3359QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
3360 const QCBORItem *pItem,
3361 uint32_t uIndex)
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07003362{
Laurence Lundblade37286c02022-09-03 10:05:02 -07003363#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade88e9db22020-11-02 03:56:33 -08003364 if(pItem->uDataType == QCBOR_TYPE_NONE) {
3365 return CBOR_TAG_INVALID64;
3366 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003367 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
3368 return CBOR_TAG_INVALID64;
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07003369 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003370 return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uIndex]);
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07003371 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07003372#else /* QCBOR_DISABLE_TAGS */
3373 (void)pMe;
3374 (void)pItem;
3375 (void)uIndex;
3376
3377 return CBOR_TAG_INVALID64;
3378#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07003379}
3380
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003381
Laurence Lundblade9b334962020-08-27 10:55:53 -07003382/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003383 * Public function, see header qcbor/qcbor_decode.h file
3384 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003385uint64_t
3386QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe,
3387 uint32_t uIndex)
Laurence Lundblade9b334962020-08-27 10:55:53 -07003388{
Laurence Lundblade37286c02022-09-03 10:05:02 -07003389#ifndef QCBOR_DISABLE_TAGS
3390
Laurence Lundblade88e9db22020-11-02 03:56:33 -08003391 if(pMe->uLastError != QCBOR_SUCCESS) {
3392 return CBOR_TAG_INVALID64;
3393 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003394 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
3395 return CBOR_TAG_INVALID64;
3396 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003397 return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->uLastTags[uIndex]);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003398 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07003399#else /* QCBOR_DISABLE_TAGS */
3400 (void)pMe;
3401 (void)uIndex;
3402
3403 return CBOR_TAG_INVALID64;
3404#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003405}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07003406
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07003407
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003408
3409
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003410#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladef6531662018-12-04 10:42:22 +09003411
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003412/* ===========================================================================
3413 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003414
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003415 This implements a simple sting allocator for indefinite-length
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003416 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
3417 implements the function type QCBORStringAllocate and allows easy
3418 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09003419
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003420 This particular allocator is built-in for convenience. The caller
3421 can implement their own. All of this following code will get
3422 dead-stripped if QCBORDecode_SetMemPool() is not called.
3423
3424 This is a very primitive memory allocator. It does not track
3425 individual allocations, only a high-water mark. A free or
3426 reallocation must be of the last chunk allocated.
3427
3428 The size of the pool and offset to free memory are packed into the
3429 first 8 bytes of the memory pool so we don't have to keep them in
3430 the decode context. Since the address of the pool may not be
3431 aligned, they have to be packed and unpacked as if they were
3432 serialized data of the wire or such.
3433
3434 The sizes packed in are uint32_t to be the same on all CPU types
3435 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08003436 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003437
3438
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003439static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08003440MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003441{
3442 // Use of UsefulInputBuf is overkill, but it is convenient.
3443 UsefulInputBuf UIB;
3444
Laurence Lundbladeee851742020-01-08 08:37:05 -08003445 // Just assume the size here. It was checked during SetUp so
3446 // the assumption is safe.
Laurence Lundblade93d89472020-10-03 22:30:50 -07003447 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem,QCBOR_DECODE_MIN_MEM_POOL_SIZE});
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003448 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
3449 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
3450 return UsefulInputBuf_GetError(&UIB);
3451}
3452
3453
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003454static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08003455MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003456{
3457 // Use of UsefulOutBuf is overkill, but convenient. The
3458 // length check performed here is useful.
3459 UsefulOutBuf UOB;
3460
3461 UsefulOutBuf_Init(&UOB, Pool);
3462 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
3463 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
3464 return UsefulOutBuf_GetError(&UOB);
3465}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003466
3467
3468/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003469 Internal function for an allocation, reallocation free and destuct.
3470
3471 Having only one function rather than one each per mode saves space in
3472 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003473
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003474 Code Reviewers: THIS FUNCTION DOES POINTER MATH
3475 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08003476static UsefulBuf
3477MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003478{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003479 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003480
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003481 uint32_t uPoolSize;
3482 uint32_t uFreeOffset;
3483
3484 if(uNewSize > UINT32_MAX) {
3485 // This allocator is only good up to 4GB. This check should
3486 // optimize out if sizeof(size_t) == sizeof(uint32_t)
3487 goto Done;
3488 }
3489 const uint32_t uNewSize32 = (uint32_t)uNewSize;
3490
3491 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
3492 goto Done;
3493 }
3494
3495 if(uNewSize) {
3496 if(pMem) {
3497 // REALLOCATION MODE
3498 // Calculate pointer to the end of the memory pool. It is
3499 // assumed that pPool + uPoolSize won't wrap around by
3500 // assuming the caller won't pass a pool buffer in that is
3501 // not in legitimate memory space.
3502 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
3503
3504 // Check that the pointer for reallocation is in the range of the
3505 // pool. This also makes sure that pointer math further down
3506 // doesn't wrap under or over.
3507 if(pMem >= pPool && pMem < pPoolEnd) {
3508 // Offset to start of chunk for reallocation. This won't
3509 // wrap under because of check that pMem >= pPool. Cast
3510 // is safe because the pool is always less than UINT32_MAX
3511 // because of check in QCBORDecode_SetMemPool().
3512 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3513
3514 // Check to see if the allocation will fit. uPoolSize -
3515 // uMemOffset will not wrap under because of check that
3516 // pMem is in the range of the uPoolSize by check above.
3517 if(uNewSize <= uPoolSize - uMemOffset) {
3518 ReturnValue.ptr = pMem;
3519 ReturnValue.len = uNewSize;
3520
3521 // Addition won't wrap around over because uNewSize was
3522 // checked to be sure it is less than the pool size.
3523 uFreeOffset = uMemOffset + uNewSize32;
3524 }
3525 }
3526 } else {
3527 // ALLOCATION MODE
3528 // uPoolSize - uFreeOffset will not underflow because this
3529 // pool implementation makes sure uFreeOffset is always
3530 // smaller than uPoolSize through this check here and
3531 // reallocation case.
3532 if(uNewSize <= uPoolSize - uFreeOffset) {
3533 ReturnValue.len = uNewSize;
3534 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08003535 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003536 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003537 }
3538 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003539 if(pMem) {
3540 // FREE MODE
3541 // Cast is safe because of limit on pool size in
3542 // QCBORDecode_SetMemPool()
3543 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3544 } else {
3545 // DESTRUCT MODE
3546 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003547 }
3548 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003549
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003550 UsefulBuf Pool = {pPool, uPoolSize};
3551 MemPool_Pack(Pool, uFreeOffset);
3552
3553Done:
3554 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003555}
3556
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003557
Laurence Lundbladef6531662018-12-04 10:42:22 +09003558/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003559 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09003560 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003561QCBORError
3562QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
3563 UsefulBuf Pool,
3564 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003565{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003566 // The pool size and free mem offset are packed into the beginning
Dave Thaler93c01182022-08-06 15:08:35 -04003567 // of the pool memory. This compile time check makes sure the
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003568 // constant in the header is correct. This check should optimize
3569 // down to nothing.
Dave Thaler93c01182022-08-06 15:08:35 -04003570#ifdef _MSC_VER
3571#pragma warning(push)
3572#pragma warning(disable:4127) // conditional expression is constant
3573#endif
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003574 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003575 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003576 }
Dave Thaler93c01182022-08-06 15:08:35 -04003577#ifdef _MSC_VER
3578#pragma warning(pop)
3579#endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003580
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003581 // The pool size and free offset packed in to the beginning of pool
3582 // memory are only 32-bits. This check will optimize out on 32-bit
3583 // machines.
3584 if(Pool.len > UINT32_MAX) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003585 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003586 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003587
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003588 // This checks that the pool buffer given is big enough.
3589 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003590 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003591 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003592
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003593 QCBORDecode_SetUpAllocator(pMe, MemPool_Function, Pool.ptr, bAllStrings);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003594
Laurence Lundblade30816f22018-11-10 13:40:22 +07003595 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003596}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003597#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003598
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003599
3600
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003601/*
3602 * Public function, see header qcbor/qcbor_decode.h file
3603 */
3604void
3605QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003606{
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003607 QCBORDecode_VGetNext(pMe, pDecodedItem);
3608
3609 if(pMe->uLastError == QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003610 pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL,
Máté Tóth-Pálc6d59682021-05-26 18:55:30 +02003611 &pDecodedItem->uNextNestLevel);
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003612 }
3613}
3614
3615
Laurence Lundblade11654912024-05-09 11:49:24 -07003616/*
3617 * Public function, see header qcbor/qcbor_decode.h file
3618 */
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003619QCBORError
3620QCBORDecode_EndCheck(QCBORDecodeContext *pMe)
Laurence Lundblade11654912024-05-09 11:49:24 -07003621{
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003622 size_t uCursorOffset;
3623 QCBORError uErr;
Laurence Lundblade11654912024-05-09 11:49:24 -07003624
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003625 uErr = QCBORDecode_GetError(pMe);
3626 if(uErr != QCBOR_SUCCESS) {
3627 return uErr;
Laurence Lundblade11654912024-05-09 11:49:24 -07003628 }
3629
3630 uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
3631
3632 if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003633 return QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade11654912024-05-09 11:49:24 -07003634 }
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003635
3636 return QCBOR_SUCCESS;
Laurence Lundblade11654912024-05-09 11:49:24 -07003637}
3638
3639
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003640/**
3641 * @brief Rewind cursor to start as if map or array were just entered.
3642 *
3643 * @param[in] pMe The decoding context
3644 *
3645 * This affects the nesting tracking and the UsefulInputBuf.
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003646 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003647static void
3648QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003649{
3650 /* Reset nesting tracking to the deepest bounded level */
3651 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3652
3653 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3654
3655 /* Reposition traversal cursor to the start of the map/array */
3656 UsefulInputBuf_Seek(&(pMe->InBuf),
3657 DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
3658}
3659
3660
3661/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003662 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003663 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003664void
3665QCBORDecode_Rewind(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003666{
3667 if(pMe->nesting.pCurrentBounded != NULL) {
3668 /* In a bounded map, array or bstr-wrapped CBOR */
3669
3670 if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
3671 /* In bstr-wrapped CBOR. */
3672
3673 /* Reposition traversal cursor to start of wrapping byte string */
3674 UsefulInputBuf_Seek(&(pMe->InBuf),
3675 pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
3676 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3677
3678 } else {
3679 /* In a map or array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003680 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003681 }
3682
3683 } else {
3684 /* Not in anything bounded */
3685
3686 /* Reposition traversal cursor to the start of input CBOR */
3687 UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
3688
3689 /* Reset nesting tracking to beginning of input. */
3690 DecodeNesting_Init(&(pMe->nesting));
3691 }
3692
3693 pMe->uLastError = QCBOR_SUCCESS;
3694}
3695
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003696
Laurence Lundblade9b334962020-08-27 10:55:53 -07003697
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003698
3699
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003700typedef struct {
3701 void *pCBContext;
3702 QCBORItemCallback pfCallback;
3703} MapSearchCallBack;
3704
3705typedef struct {
3706 size_t uStartOffset;
3707 uint16_t uItemCount;
3708} MapSearchInfo;
3709
3710
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003711/**
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003712 * @brief Search a map for a set of items.
3713 *
3714 * @param[in] pMe The decode context to search.
3715 * @param[in,out] pItemArray The items to search for and the items found.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003716 * @param[out] pInfo Several bits of meta-info returned by search.
3717 * @param[in] pCallBack Callback object or @c NULL.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003718 *
3719 * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map.
3720 *
3721 * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label)
3722 * were found for one of the labels being
3723 * search for. This duplicate detection is
3724 * only performed for items in pItemArray,
3725 * not every item in the map.
3726 *
3727 * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was
3728 * wrong for the matchd label.
3729 *
3730 * @retval Also errors returned by QCBORDecode_GetNext().
3731 *
3732 * On input, \c pItemArray contains a list of labels and data types of
3733 * items to be found.
3734 *
3735 * On output, the fully retrieved items are filled in with values and
3736 * such. The label was matched, so it never changes.
3737 *
3738 * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE.
3739 *
3740 * This also finds the ends of maps and arrays when they are exited.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003741 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003742static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003743QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
3744 QCBORItem *pItemArray,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003745 MapSearchInfo *pInfo,
3746 MapSearchCallBack *pCallBack)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003747{
Laurence Lundbladee6f15112020-07-23 18:44:16 -07003748 QCBORError uReturn;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003749 uint64_t uFoundItemBitMap = 0;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07003750
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003751 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003752 uReturn = pMe->uLastError;
3753 goto Done2;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003754 }
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003755
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003756 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) &&
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003757 pItemArray->uLabelType != QCBOR_TYPE_NONE) {
3758 /* QCBOR_TYPE_NONE as first item indicates just looking
3759 for the end of an array, so don't give error. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003760 uReturn = QCBOR_ERR_MAP_NOT_ENTERED;
3761 goto Done2;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003762 }
3763
Laurence Lundblade085d7952020-07-24 10:26:30 -07003764 if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) {
3765 // It is an empty bounded array or map
3766 if(pItemArray->uLabelType == QCBOR_TYPE_NONE) {
3767 // Just trying to find the end of the map or array
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003768 pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003769 uReturn = QCBOR_SUCCESS;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003770 } else {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003771 // Nothing is ever found in an empty array or map. All items
3772 // are marked as not found below.
Laurence Lundblade085d7952020-07-24 10:26:30 -07003773 uReturn = QCBOR_SUCCESS;
3774 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003775 goto Done2;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003776 }
3777
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003778 QCBORDecodeNesting SaveNesting;
Laurence Lundblade11654912024-05-09 11:49:24 -07003779 size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003780 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3781
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003782 /* Reposition to search from the start of the map / array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003783 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundblade1341c592020-04-11 14:19:05 -07003784
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003785 /*
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003786 Loop over all the items in the map or array. Each item
3787 could be a map or array, but label matching is only at
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003788 the main level. This handles definite- and indefinite-
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003789 length maps and arrays. The only reason this is ever
3790 called on arrays is to find their end position.
3791
3792 This will always run over all items in order to do
3793 duplicate detection.
3794
3795 This will exit with failure if it encounters an
3796 unrecoverable error, but continue on for recoverable
3797 errors.
3798
3799 If a recoverable error occurs on a matched item, then
3800 that error code is returned.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003801 */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07003802 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003803 if(pInfo) {
3804 pInfo->uItemCount = 0;
3805 }
Máté Tóth-Pál2f2aa5f2021-05-17 21:35:09 +02003806 uint8_t uNextNestLevel;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003807 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003808 /* Remember offset of the item because sometimes it has to be returned */
Laurence Lundblade1341c592020-04-11 14:19:05 -07003809 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003810
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003811 /* Get the item */
3812 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003813 /* QCBORDecode_Private_GetNextTagContent() rather than GetNext()
3814 * because a label match is performed on recoverable errors to
3815 * be able to return the the error code for the found item. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003816 QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003817 if(QCBORDecode_IsUnrecoverableError(uResult)) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003818 /* The map/array can't be decoded when unrecoverable errors occur */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003819 uReturn = uResult;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003820 goto Done;
3821 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003822 if(uResult == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003823 /* Unexpected end of map or array. */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003824 uReturn = uResult;
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003825 goto Done;
3826 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003827
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003828 /* See if item has one of the labels that are of interest */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003829 bool bMatched = false;
3830 for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003831 if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003832 /* A label match has been found */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003833 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
3834 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003835 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003836 }
Laurence Lundblade63926052021-03-29 16:05:51 -07003837 if(uResult != QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003838 /* The label matches, but the data item is in error.
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003839 * It is OK to have recoverable errors on items that
3840 * are not matched. */
Laurence Lundblade63926052021-03-29 16:05:51 -07003841 uReturn = uResult;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003842 goto Done;
3843 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003844 if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) {
Laurence Lundblade63926052021-03-29 16:05:51 -07003845 /* The data item is not of the type(s) requested */
3846 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003847 goto Done;
3848 }
3849
Laurence Lundblade1341c592020-04-11 14:19:05 -07003850 /* Successful match. Return the item. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003851 pItemArray[nIndex] = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003852 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003853 if(pInfo) {
3854 pInfo->uStartOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003855 }
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003856 bMatched = true;
3857 }
3858 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003859
3860
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003861 if(!bMatched && pCallBack != NULL) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003862 /*
3863 Call the callback on unmatched labels.
3864 (It is tempting to do duplicate detection here, but that would
3865 require dynamic memory allocation because the number of labels
3866 that might be encountered is unbounded.)
3867 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003868 uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item);
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003869 if(uReturn != QCBOR_SUCCESS) {
3870 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003871 }
3872 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003873
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003874 /*
3875 Consume the item whether matched or not. This
3876 does the work of traversing maps and array and
3877 everything in them. In this loop only the
3878 items at the current nesting level are examined
3879 to match the labels.
3880 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003881 uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel);
Laurence Lundbladec7114722020-08-13 05:11:40 -07003882 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003883 goto Done;
3884 }
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003885
3886 if(pInfo) {
3887 pInfo->uItemCount++;
3888 }
3889
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003890 } while (uNextNestLevel >= uMapNestLevel);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003891
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003892 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003893
3894 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003895
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003896 // Check here makes sure that this won't accidentally be
3897 // QCBOR_MAP_OFFSET_CACHE_INVALID which is larger than
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003898 // QCBOR_MAX_DECODE_INPUT_SIZE.
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -08003899 // Cast to uint32_t to possibly address cases where SIZE_MAX < UINT32_MAX
3900 if((uint32_t)uEndOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003901 uReturn = QCBOR_ERR_INPUT_TOO_LARGE;
3902 goto Done;
3903 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003904 /* Cast OK because encoded CBOR is limited to UINT32_MAX */
3905 pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003906
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003907 Done:
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003908 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade11654912024-05-09 11:49:24 -07003909 UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos);
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003910
3911 Done2:
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003912 /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */
Laurence Lundbladec7114722020-08-13 05:11:40 -07003913 for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003914 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003915 pItemArray[i].uDataType = QCBOR_TYPE_NONE;
3916 pItemArray[i].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003917 }
3918 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003919
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003920 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003921}
3922
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003923
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003924/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003925 * Public function, see header qcbor/qcbor_decode.h file
3926 */
3927void
3928QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
3929 int64_t nLabel,
3930 uint8_t uQcborType,
3931 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003932{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003933 if(pMe->uLastError != QCBOR_SUCCESS) {
3934 return;
3935 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003936
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003937 QCBORItem OneItemSeach[2];
3938 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3939 OneItemSeach[0].label.int64 = nLabel;
3940 OneItemSeach[0].uDataType = uQcborType;
3941 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003942
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003943 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003944
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003945 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003946 pItem->uDataType = QCBOR_TYPE_NONE;
3947 pItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003948 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003949 }
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003950
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003951 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003952 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003953 }
3954
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003955 *pItem = OneItemSeach[0];
3956 QCBORDecode_Private_CopyTags(pMe, pItem);
3957
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003958 Done:
3959 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003960}
3961
3962
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003963/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003964 * Public function, see header qcbor/qcbor_decode.h file
3965 */
3966void
3967QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
3968 const char *szLabel,
3969 uint8_t uQcborType,
3970 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003971{
Laurence Lundbladeda095972020-06-06 18:35:33 -07003972 if(pMe->uLastError != QCBOR_SUCCESS) {
3973 return;
3974 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003975
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003976#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003977 QCBORItem OneItemSeach[2];
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003978 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3979 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3980 OneItemSeach[0].uDataType = uQcborType;
3981 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003982
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003983 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
3984
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003985 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003986 pItem->uDataType = QCBOR_TYPE_NONE;
3987 pItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003988 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003989 }
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003990 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003991 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003992 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003993 }
3994
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003995 *pItem = OneItemSeach[0];
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003996 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003997
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003998Done:
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003999#else
4000 (void)pMe;
4001 (void)szLabel;
4002 (void)uQcborType;
4003 (void)pItem;
4004 QCBORError uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
4005#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
4006
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004007 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004008}
4009
4010
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004011
4012/**
4013 * @brief Semi-private. Get pointer, length and item for an array or map.
4014 *
4015 * @param[in] pMe The decode context.
4016 * @param[in] uType CBOR major type, either array/map.
4017 * @param[out] pItem The item for the array/map.
4018 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
4019 *
4020 * The next item to be decoded must be a map or array as specified by \c uType.
4021 *
4022 * \c pItem will be filled in with the label and tags of the array or map
4023 * in addition to \c pEncodedCBOR giving the pointer and length of the
4024 * encoded CBOR.
4025 *
4026 * When this is complete, the traversal cursor is at the end of the array or
4027 * map that was retrieved.
4028 */
4029void
4030QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe,
4031 const uint8_t uType,
4032 QCBORItem *pItem,
4033 UsefulBufC *pEncodedCBOR)
4034{
4035 QCBORError uErr;
4036 uint8_t uNestLevel;
4037 size_t uStartingCursor;
4038 size_t uStartOfReturned;
4039 size_t uEndOfReturned;
4040 size_t uTempSaveCursor;
4041 bool bInMap;
4042 QCBORItem LabelItem;
4043 bool EndedByBreak;
4044
4045 uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
4046 bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting));
4047
4048 /* Could call GetNext here, but don't need to because this
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07004049 * is only interested in arrays and maps. TODO: switch to GetNext()? */
4050 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem, NULL);
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004051 if(uErr != QCBOR_SUCCESS) {
4052 pMe->uLastError = (uint8_t)uErr;
4053 return;
4054 }
4055
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004056 uint8_t uItemDataType = pItem->uDataType;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004057#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004058 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
4059 uItemDataType = QCBOR_TYPE_ARRAY;
4060 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004061#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004062
4063 if(uItemDataType != uType) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004064 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4065 return;
4066 }
4067
4068 if(bInMap) {
4069 /* If the item is in a map, the start of the array/map
4070 * itself, not the label, must be found. Do this by
4071 * rewinding to the starting position and fetching
4072 * just the label data item. QCBORDecode_Private_GetNextTagNumber()
4073 * doesn't do any of the array/map item counting or nesting
4074 * level tracking. Used here it will just fetech the label
4075 * data item.
4076 *
4077 * Have to save the cursor and put it back to the position
4078 * after the full item once the label as been fetched by
4079 * itself.
4080 */
4081 uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
4082 UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor);
4083
4084 /* Item has been fetched once so safe to ignore error */
4085 (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem);
4086
4087 uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
4088 UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor);
4089 } else {
4090 uStartOfReturned = uStartingCursor;
4091 }
4092
4093 /* Consume the entire array/map to find the end */
4094 uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel);
4095 if(uErr != QCBOR_SUCCESS) {
4096 pMe->uLastError = (uint8_t)uErr;
4097 goto Done;
4098 }
4099
4100 /* Fill in returned values */
4101 uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
4102 if(EndedByBreak) {
4103 /* When ascending nesting levels, a break for the level above
4104 * was consumed. That break is not a part of what is consumed here. */
4105 uEndOfReturned--;
4106 }
4107 pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned);
4108 pEncodedCBOR->len = uEndOfReturned - uStartOfReturned;
4109
4110Done:
4111 return;
4112}
4113
4114
4115/**
4116 * @brief Semi-private. Get pointer, length and item count of an array or map.
4117 *
4118 * @param[in] pMe The decode context.
4119 * @param[in] pTarget The label and type of the array or map to retrieve.
4120 * @param[out] pItem The item for the array/map.
4121 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
4122 *
4123 * The next item to be decoded must be a map or array as specified by \c uType.
4124 *
4125 * When this is complete, the traversal cursor is unchanged.
4126 */void
4127QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe,
4128 QCBORItem *pTarget,
4129 QCBORItem *pItem,
4130 UsefulBufC *pEncodedCBOR)
4131{
4132 MapSearchInfo Info;
4133 QCBORDecodeNesting SaveNesting;
4134 size_t uSaveCursor;
4135
4136 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL);
4137 if(pMe->uLastError != QCBOR_SUCCESS) {
4138 return;
4139 }
4140
4141 /* Save the whole position of things so they can be restored.
4142 * so the cursor position is unchanged by this operation, like
4143 * all the other GetXxxxInMap() operations. */
4144 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
4145 uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
4146
4147 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
4148 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
4149 QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR);
4150
4151 UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor);
4152 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
4153}
4154
4155
4156
4157
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004158/**
4159 * @brief Is a QCBOR_TYPE in the type list?
4160 *
4161 * @param[in] uDataType Type to check for.
4162 * @param[in] puTypeList List to check.
4163 *
4164 * @retval QCBOR_SUCCESS If in the list.
4165 * @retval QCBOR_ERR_UNEXPECTED_TYPE Not in the list.
4166 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07004167static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004168QCBOR_Private_CheckTypeList(const int uDataType,
4169 const uint8_t puTypeList[QCBOR_TAGSPEC_NUM_TYPES])
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004170{
4171 for(size_t i = 0; i < QCBOR_TAGSPEC_NUM_TYPES; i++) {
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08004172 if(uDataType == puTypeList[i]) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004173 return QCBOR_SUCCESS;
4174 }
4175 }
4176 return QCBOR_ERR_UNEXPECTED_TYPE;
4177}
4178
Laurence Lundblade67257dc2020-07-27 03:33:37 -07004179
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004180/**
Laurence Lundblade37286c02022-09-03 10:05:02 -07004181 * Match a tag/type specification against the type of the item.
4182 *
4183 * @param[in] TagSpec Specification for matching tags.
4184 * @param[in] pItem The item to check.
4185 *
4186 * @retval QCBOR_SUCCESS \c uDataType is allowed by @c TagSpec
4187 * @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec
4188 *
4189 * This checks the item data type of untagged items as well as of
4190 * tagged items against a specification to see if decoding should
4191 * proceed.
4192 *
4193 * This relies on the automatic tag decoding done by QCBOR that turns
4194 * tag numbers into particular QCBOR_TYPEs so there is no actual
4195 * comparsion of tag numbers, just of QCBOR_TYPEs.
4196 *
4197 * This checks the data item type as possibly representing the tag
4198 * number or as the tag content type.
4199 *
4200 * If QCBOR_DISABLE_TAGS is #defined, this primarily checks the item
4201 * data type against the allowed tag content types. It will also error out
4202 * if the caller tries to require a tag because there is no way that can
4203 * ever be fulfilled.
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004204 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07004205static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004206QCBOR_Private_CheckTagRequirement(const QCBOR_Private_TagSpec TagSpec,
4207 const QCBORItem *pItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07004208{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08004209 const int nItemType = pItem->uDataType; /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004210 const int nTagReq = TagSpec.uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
4211
4212#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08004213 /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade9b334962020-08-27 10:55:53 -07004214 if(!(TagSpec.uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS) &&
4215 pItem->uTags[0] != CBOR_TAG_INVALID16) {
4216 /* There are tags that QCBOR couldn't process on this item and
Laurence Lundblade37286c02022-09-03 10:05:02 -07004217 * the caller has told us there should not be.
4218 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07004219 return QCBOR_ERR_UNEXPECTED_TYPE;
4220 }
4221
Laurence Lundblade9b334962020-08-27 10:55:53 -07004222 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
Laurence Lundblade37286c02022-09-03 10:05:02 -07004223 /* Must match the tag number and only the tag */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004224 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07004225 }
4226
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004227 QCBORError uReturn = QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07004228 if(uReturn == QCBOR_SUCCESS) {
4229 return QCBOR_SUCCESS;
4230 }
4231
4232 if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
4233 /* Must match the content type and only the content type.
Laurence Lundblade37286c02022-09-03 10:05:02 -07004234 * There was no match just above so it is a fail. */
Laurence Lundblade9b334962020-08-27 10:55:53 -07004235 return QCBOR_ERR_UNEXPECTED_TYPE;
4236 }
4237
Laurence Lundblade37286c02022-09-03 10:05:02 -07004238 /* QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG: If here it can match either the tag or the content
4239 * and it hasn't matched the content, so the end
4240 * result is whether it matches the tag. This is
4241 * the tag optional case that the CBOR standard discourages.
4242 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07004243
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004244 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07004245
Laurence Lundblade37286c02022-09-03 10:05:02 -07004246#else /* QCBOR_DISABLE_TAGS */
4247 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
4248 return QCBOR_ERR_UNEXPECTED_TYPE;
4249 }
4250
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07004251 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade37286c02022-09-03 10:05:02 -07004252
4253#endif /* QCBOR_DISABLE_TAGS */
4254}
Laurence Lundblade9b334962020-08-27 10:55:53 -07004255
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004256
4257/**
4258 * @brief Get an item by label to match a tag specification.
4259 *
4260 * @param[in] pMe The decode context.
4261 * @param[in] nLabel The label to search map for.
4262 * @param[in] TagSpec The tag number specification to match.
4263 * @param[out] pItem The item found.
4264 *
4265 * This finds the item with the given label in currently open
4266 * map. Then checks that its tag number and types matches the tag
4267 * specification. If not, an error is set in the decode context.
4268 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004269static void
4270QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
4271 const int64_t nLabel,
4272 const QCBOR_Private_TagSpec TagSpec,
4273 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004274{
4275 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
4276 if(pMe->uLastError != QCBOR_SUCCESS) {
4277 return;
4278 }
4279
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004280 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004281}
4282
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07004283
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004284/**
4285 * @brief Get an item by label to match a tag specification.
4286 *
4287 * @param[in] pMe The decode context.
4288 * @param[in] szLabel The label to search map for.
4289 * @param[in] TagSpec The tag number specification to match.
4290 * @param[out] pItem The item found.
4291 *
4292 * This finds the item with the given label in currently open
4293 * map. Then checks that its tag number and types matches the tag
4294 * specification. If not, an error is set in the decode context.
4295 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004296static void
4297QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
4298 const char *szLabel,
4299 const QCBOR_Private_TagSpec TagSpec,
4300 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004301{
4302 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
4303 if(pMe->uLastError != QCBOR_SUCCESS) {
4304 return;
4305 }
4306
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004307 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004308}
4309
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004310
4311/**
4312 * @brief Semi-private to get an string by label to match a tag specification.
4313 *
4314 * @param[in] pMe The decode context.
4315 * @param[in] nLabel The label to search map for.
4316 * @param[in] TagSpec The tag number specification to match.
4317 * @param[out] pString The string found.
4318 *
4319 * This finds the string with the given label in currently open
4320 * map. Then checks that its tag number and types matches the tag
4321 * specification. If not, an error is set in the decode context.
4322 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004323void
4324QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
4325 const int64_t nLabel,
4326 const QCBOR_Private_TagSpec TagSpec,
4327 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004328{
4329 QCBORItem Item;
4330 QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
4331 if(pMe->uLastError == QCBOR_SUCCESS) {
4332 *pString = Item.val.string;
4333 }
4334}
4335
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004336
4337/**
4338 * @brief Semi-private to get an string by label to match a tag specification.
4339 *
4340 * @param[in] pMe The decode context.
4341 * @param[in] szLabel The label to search map for.
4342 * @param[in] TagSpec The tag number specification to match.
4343 * @param[out] pString The string found.
4344 *
4345 * This finds the string with the given label in currently open
4346 * map. Then checks that its tag number and types matches the tag
4347 * specification. If not, an error is set in the decode context.
4348 */void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004349QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
4350 const char * szLabel,
4351 const QCBOR_Private_TagSpec TagSpec,
4352 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004353{
4354 QCBORItem Item;
4355 QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
4356 if(pMe->uLastError == QCBOR_SUCCESS) {
4357 *pString = Item.val.string;
4358 }
4359}
Laurence Lundblade1341c592020-04-11 14:19:05 -07004360
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004361
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004362/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004363 * Public function, see header qcbor/qcbor_decode.h file
4364 */
4365void
4366QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004367{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004368 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL);
Laurence Lundblade5f53f832020-09-03 12:00:14 -07004369 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004370}
4371
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004372/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004373 * Public function, see header qcbor/qcbor_decode.h file
4374 */
4375void
4376QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe,
4377 QCBORItem *pItemList,
4378 void *pCallbackCtx,
4379 QCBORItemCallback pfCB)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004380{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004381 MapSearchCallBack CallBack;
4382 CallBack.pCBContext = pCallbackCtx;
4383 CallBack.pfCallback = pfCB;
4384
4385 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack);
4386
Laurence Lundblade5f53f832020-09-03 12:00:14 -07004387 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004388}
4389
4390
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004391/**
4392 * @brief Search for a map/array by label and enter it
4393 *
4394 * @param[in] pMe The decode context.
4395 * @param[in] pSearch The map/array to search for.
4396 *
4397 * @c pSearch is expected to contain one item of type map or array
4398 * with the label specified. The current bounded map will be searched for
4399 * this and if found will be entered.
4400 *
4401 * If the label is not found, or the item found is not a map or array,
4402 * the error state is set.
4403 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004404static void
4405QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07004406{
Laurence Lundblade323f8a92020-09-06 19:43:09 -07004407 // The first item in pSearch is the one that is to be
4408 // entered. It should be the only one filled in. Any other
4409 // will be ignored unless it causes an error.
Laurence Lundblade34691b92020-05-18 22:25:25 -07004410 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07004411 return;
4412 }
4413
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004414 MapSearchInfo Info;
4415 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pSearch, &Info, NULL);
Laurence Lundblade34691b92020-05-18 22:25:25 -07004416 if(pMe->uLastError != QCBOR_SUCCESS) {
4417 return;
4418 }
4419
Laurence Lundblade9b334962020-08-27 10:55:53 -07004420 if(pSearch->uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004421 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004422 return;
4423 }
4424
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004425
4426 /* The map or array was found. Now enter it.
4427 *
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004428 * QCBORDecode_EnterBoundedMapOrArray() used here, requires the
4429 * next item for the pre-order traversal cursor to be the map/array
4430 * found by MapSearch(). The next few lines of code force the
4431 * cursor to that.
4432 *
4433 * There is no need to retain the old cursor because
4434 * QCBORDecode_EnterBoundedMapOrArray() will set it to the
4435 * beginning of the map/array being entered.
4436 *
4437 * The cursor is forced by: 1) setting the input buffer position to
4438 * the item offset found by MapSearch(), 2) setting the map/array
4439 * counter to the total in the map/array, 3) setting the nesting
4440 * level. Setting the map/array counter to the total is not
4441 * strictly correct, but this is OK because this cursor only needs
4442 * to be used to get one item and MapSearch() has already found it
4443 * confirming it exists.
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004444 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004445 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004446
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004447 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
4448
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004449 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07004450
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004451 QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004452}
4453
4454
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004455/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004456 * Public function, see header qcbor/qcbor_decode.h file
4457 */
4458void
4459QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004460{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004461 QCBORItem OneItemSeach[2];
4462 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4463 OneItemSeach[0].label.int64 = nLabel;
4464 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4465 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004466
Laurence Lundblade9b334962020-08-27 10:55:53 -07004467 /* The map to enter was found, now finish off entering it. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004468 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004469}
4470
4471
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004472/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004473 * Public function, see header qcbor/qcbor_decode.h file
4474 */
4475void
4476QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004477{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004478#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004479 QCBORItem OneItemSeach[2];
4480 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4481 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4482 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4483 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004484
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004485 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004486#else
4487 (void)szLabel;
4488 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
4489#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004490}
4491
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004492/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004493 * Public function, see header qcbor/qcbor_decode.h file
4494 */
4495void
4496QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07004497{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004498 QCBORItem OneItemSeach[2];
4499 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4500 OneItemSeach[0].label.int64 = nLabel;
4501 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4502 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004503
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004504 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07004505}
4506
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004507/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004508 * Public function, see header qcbor/qcbor_decode.h file
4509 */
4510void
4511QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundblade34691b92020-05-18 22:25:25 -07004512{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004513#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004514 QCBORItem OneItemSeach[2];
4515 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4516 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4517 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4518 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004519
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004520 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004521#else
4522 (void)szLabel;
4523 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
4524#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade1341c592020-04-11 14:19:05 -07004525}
4526
4527
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004528/**
4529 * @brief Semi-private to do the the work for EnterMap() and EnterArray().
4530 *
4531 * @param[in] pMe The decode context
4532 * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY.
4533 * @param[out] pItem The data item for the map or array entered.
4534 *
4535 * The next item in the traversal must be a map or array. This
4536 * consumes that item and does the book keeping to enter the map or
4537 * array.
4538 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004539void
4540QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe,
4541 const uint8_t uType,
4542 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004543{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004544 QCBORError uErr;
4545
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004546 /* Must only be called on maps and arrays. */
Laurence Lundblade34691b92020-05-18 22:25:25 -07004547 if(pMe->uLastError != QCBOR_SUCCESS) {
4548 // Already in error state; do nothing.
4549 return;
4550 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07004551
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004552 /* Get the data item that is the map or array being entered. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004553 QCBORItem Item;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004554 uErr = QCBORDecode_GetNext(pMe, &Item);
4555 if(uErr != QCBOR_SUCCESS) {
4556 goto Done;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07004557 }
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004558
4559 uint8_t uItemDataType = Item.uDataType;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004560
4561#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004562 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) {
4563 uItemDataType = QCBOR_TYPE_ARRAY;
4564 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004565#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
4566
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004567 if(uItemDataType != uType) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004568 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
4569 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004570 }
4571
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004572 QCBORDecode_Private_CopyTags(pMe, &Item);
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004573
4574
Laurence Lundbladef0499502020-08-01 11:55:57 -07004575 const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
Laurence Lundblade085d7952020-07-24 10:26:30 -07004576 if(bIsEmpty) {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004577 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
4578 // Undo decrement done by QCBORDecode_GetNext() so the the
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004579 // the decrement when exiting the map/array works correctly
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004580 pMe->nesting.pCurrent->u.ma.uCountCursor++;
4581 }
Laurence Lundblade93d89472020-10-03 22:30:50 -07004582 // Special case to increment nesting level for zero-length maps
4583 // and arrays entered in bounded mode.
Laurence Lundbladee6f15112020-07-23 18:44:16 -07004584 DecodeNesting_Descend(&(pMe->nesting), uType);
4585 }
4586
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004587 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004588
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004589 uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty,
4590 UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004591
Laurence Lundblade6545d1b2020-10-14 11:13:13 -07004592 if(pItem != NULL) {
4593 *pItem = Item;
4594 }
4595
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004596Done:
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004597 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004598}
4599
Laurence Lundblade02625d42020-06-25 14:41:41 -07004600
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004601/**
4602 * @brief Exit a bounded map, array or bstr (semi-private).
4603 *
4604 * @param[in] pMe Decode context.
4605 * @param[in] uEndOffset The input buffer offset of the end of item exited.
4606 *
4607 * @returns QCBOR_SUCCESS or an error code.
4608 *
4609 * This is the common work for exiting a level that is a bounded map,
4610 * array or bstr wrapped CBOR.
4611 *
4612 * One chunk of work is to set up the pre-order traversal so it is at
4613 * the item just after the bounded map, array or bstr that is being
4614 * exited. This is somewhat complex.
4615 *
4616 * The other work is to level-up the bounded mode to next higest
4617 * bounded mode or the top level if there isn't one.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004618 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004619static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004620QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
4621 const uint32_t uEndOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004622{
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004623 QCBORError uErr;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004624
Laurence Lundblade02625d42020-06-25 14:41:41 -07004625 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004626 * First the pre-order-traversal byte offset is positioned to the
4627 * item just after the bounded mode item that was just consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004628 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004629 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
4630
Laurence Lundblade02625d42020-06-25 14:41:41 -07004631 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004632 * Next, set the current nesting level to one above the bounded
4633 * level that was just exited.
4634 *
4635 * DecodeNesting_CheckBoundedType() is always called before this
4636 * and makes sure pCurrentBounded is valid.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004637 */
4638 DecodeNesting_LevelUpCurrent(&(pMe->nesting));
4639
4640 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004641 * This does the complex work of leveling up the pre-order
4642 * traversal when the end of a map or array or another bounded
4643 * level is reached. It may do nothing, or ascend all the way to
4644 * the top level.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004645 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004646 uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004647 if(uErr != QCBOR_SUCCESS) {
4648 goto Done;
4649 }
4650
Laurence Lundblade02625d42020-06-25 14:41:41 -07004651 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004652 * This makes the next highest bounded level the current bounded
4653 * level. If there is no next highest level, then no bounded mode
4654 * is in effect.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004655 */
4656 DecodeNesting_LevelUpBounded(&(pMe->nesting));
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004657
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004658 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004659
4660Done:
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004661 return uErr;
4662}
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004663
Laurence Lundblade02625d42020-06-25 14:41:41 -07004664
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004665/**
4666 * @brief Get started exiting a map or array (semi-private)
4667 *
4668 * @param[in] pMe The decode context
4669 * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP
4670 *
4671 * This does some work for map and array exiting (but not
4672 * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel()
4673 * is called to do the rest.
4674 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004675void
4676QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe,
4677 const uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004678{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004679 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07004680 /* Already in error state; do nothing. */
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004681 return;
4682 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004683
Laurence Lundblade02625d42020-06-25 14:41:41 -07004684 QCBORError uErr;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004685
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004686 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004687 uErr = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004688 goto Done;
4689 }
4690
Laurence Lundblade02625d42020-06-25 14:41:41 -07004691 /*
4692 Have to set the offset to the end of the map/array
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004693 that is being exited. If there is no cached value,
Laurence Lundblade02625d42020-06-25 14:41:41 -07004694 from previous map search, then do a dummy search.
4695 */
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004696 if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004697 QCBORItem Dummy;
4698 Dummy.uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004699 uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL);
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004700 if(uErr != QCBOR_SUCCESS) {
4701 goto Done;
4702 }
4703 }
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004704
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004705 uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004706
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004707Done:
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004708 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004709}
4710
4711
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004712/**
4713 * @brief The main work of entering some byte-string wrapped CBOR.
4714 *
4715 * @param[in] pMe The decode context.
4716 * @param[in] pItem The byte string item.
4717 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX
4718 * @param[out] pBstr Pointer and length of byte string entered.
4719 *
4720 * This is called once the byte string item has been decoded to do all
4721 * the book keeping work for descending a nesting level into the
4722 * nested CBOR.
4723 *
4724 * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement.
4725 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004726static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004727QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe,
4728 const QCBORItem *pItem,
4729 const uint8_t uTagRequirement,
4730 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004731{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004732 if(pBstr) {
4733 *pBstr = NULLUsefulBufC;
4734 }
4735
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004736 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004737 /* Already in error state; do nothing. */
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004738 return pMe->uLastError;
4739 }
4740
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004741 QCBORError uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004742
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004743 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004744 {
4745 uTagRequirement,
4746 {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE},
4747 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4748 };
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004749
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004750 uError = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004751 if(uError != QCBOR_SUCCESS) {
4752 goto Done;
4753 }
4754
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004755 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004756 /* Reverse the decrement done by GetNext() for the bstr so the
4757 * increment in QCBORDecode_NestLevelAscender() called by
4758 * ExitBoundedLevel() will work right.
4759 */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004760 DecodeNesting_ReverseDecrement(&(pMe->nesting));
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07004761 }
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004762
4763 if(pBstr) {
4764 *pBstr = pItem->val.string;
4765 }
4766
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004767 /* This saves the current length of the UsefulInputBuf and then
4768 * narrows the UsefulInputBuf to start and length of the wrapped
4769 * CBOR that is being entered.
4770 *
4771 * Most of these calls are simple inline accessors so this doesn't
4772 * amount to much code.
4773 */
4774
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004775 const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004776 /* This check makes the cast of uPreviousLength to uint32_t below safe. */
4777 if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004778 uError = QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladef76a2622020-08-06 19:51:03 -07004779 goto Done;
4780 }
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004781
4782 const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
4783 pItem->val.string.ptr);
4784 /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
4785 if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
4786 /* This should never happen because pItem->val.string.ptr should
4787 * always be valid since it was just returned.
4788 */
4789 uError = QCBOR_ERR_INPUT_TOO_LARGE;
4790 goto Done;
4791 }
4792
4793 const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
4794
4795 UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004796 UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004797
Laurence Lundblade02625d42020-06-25 14:41:41 -07004798 uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004799 (uint32_t)uPreviousLength,
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004800 (uint32_t)uStartOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004801Done:
4802 return uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004803}
4804
4805
Laurence Lundblade02625d42020-06-25 14:41:41 -07004806/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004807 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004808 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004809void
4810QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe,
4811 const uint8_t uTagRequirement,
4812 UsefulBufC *pBstr)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004813{
4814 if(pMe->uLastError != QCBOR_SUCCESS) {
4815 // Already in error state; do nothing.
4816 return;
4817 }
4818
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004819 /* Get the data item that is the byte string being entered */
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004820 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004821 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4822 if(pMe->uLastError != QCBOR_SUCCESS) {
4823 return;
4824 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004825
Laurence Lundblade31fddb72024-05-13 13:03:35 -07004826 if(Item.uDataAlloc) {
4827 pMe->uLastError = QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
4828 return;
4829 }
4830
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004831 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4832 &Item,
4833 uTagRequirement,
4834 pBstr);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004835}
4836
4837
Laurence Lundblade02625d42020-06-25 14:41:41 -07004838/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004839 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004840 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004841void
4842QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe,
4843 const int64_t nLabel,
4844 const uint8_t uTagRequirement,
4845 UsefulBufC *pBstr)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004846{
4847 QCBORItem Item;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004848 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004849
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004850 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4851 &Item,
4852 uTagRequirement,
4853 pBstr);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004854}
4855
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004856
Laurence Lundblade02625d42020-06-25 14:41:41 -07004857/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004858 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004859 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004860void
4861QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe,
4862 const char *szLabel,
4863 const uint8_t uTagRequirement,
4864 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004865{
4866 QCBORItem Item;
4867 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4868
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004869 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4870 &Item,
4871 uTagRequirement,
4872 pBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004873}
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004874
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004875
Laurence Lundblade02625d42020-06-25 14:41:41 -07004876/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004877 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004878 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004879void
4880QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004881{
Laurence Lundblade02625d42020-06-25 14:41:41 -07004882 if(pMe->uLastError != QCBOR_SUCCESS) {
4883 // Already in error state; do nothing.
4884 return;
4885 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004886
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004887 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004888 pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade02625d42020-06-25 14:41:41 -07004889 return;
4890 }
4891
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004892 const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
4893
Laurence Lundblade02625d42020-06-25 14:41:41 -07004894 /*
4895 Reset the length of the UsefulInputBuf to what it was before
4896 the bstr wrapped CBOR was entered.
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004897 */
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004898 UsefulInputBuf_SetBufferLength(&(pMe->InBuf),
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004899 DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004900
4901
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004902 QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004903 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004904}
4905
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004906
Laurence Lundbladee6430642020-03-14 21:15:44 -07004907
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004908/**
4909 * @brief Process simple type true and false, a boolean
4910 *
4911 * @param[in] pMe The decode context.
4912 * @param[in] pItem The item with either true or false.
4913 * @param[out] pBool The boolean value output.
4914 *
4915 * Sets the internal error if the item isn't a true or a false. Also
4916 * records any tag numbers as the tag numbers of the last item.
4917 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004918static void
4919QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe,
4920 const QCBORItem *pItem,
4921 bool *pBool)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004922{
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004923 if(pMe->uLastError != QCBOR_SUCCESS) {
4924 /* Already in error state, do nothing */
4925 return;
4926 }
4927
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004928 switch(pItem->uDataType) {
4929 case QCBOR_TYPE_TRUE:
4930 *pBool = true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004931 break;
4932
4933 case QCBOR_TYPE_FALSE:
4934 *pBool = false;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004935 break;
4936
4937 default:
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004938 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004939 break;
4940 }
4941}
Laurence Lundbladee6430642020-03-14 21:15:44 -07004942
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004943
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004944/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004945 * Public function, see header qcbor/qcbor_decode.h file
4946 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004947void
4948QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004949{
Laurence Lundbladec4537442020-04-14 18:53:22 -07004950 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07004951 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004952 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004953}
4954
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004955
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004956/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004957 * Public function, see header qcbor/qcbor_decode.h file
4958 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004959void
4960QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe,
4961 const int64_t nLabel,
4962 bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004963{
4964 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004965 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004966 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004967}
4968
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004969
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004970/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004971 * Public function, see header qcbor/qcbor_decode.h file
4972 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004973void
4974QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe,
4975 const char *szLabel,
4976 bool *pValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004977{
4978 QCBORItem Item;
4979 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004980 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004981}
4982
4983
Laurence Lundblade3888f002024-06-12 21:20:56 -07004984/**
4985 * @brief Process simple values.
4986 *
4987 * @param[in] pMe The decode context.
4988 * @param[in] pItem The item with the simple value.
4989 * @param[out] puSimple The simple value output.
4990 *
4991 * Sets the internal error if the item isn't a true or a false. Also
4992 * records any tag numbers as the tag numbers of the last item.
4993 */
4994static void
4995QCBORDecode_Private_ProcessSimple(QCBORDecodeContext *pMe,
4996 const QCBORItem *pItem,
4997 uint8_t *puSimple)
4998{
4999 if(pMe->uLastError != QCBOR_SUCCESS) {
5000 return;
5001 }
5002
5003 /* It's kind of lame to remap true...undef back to simple values, but
5004 * this function isn't used much and to not do it would require
5005 * changing GetNext() behavior in an incompatible way.
5006 */
5007 switch(pItem->uDataType) {
5008 case QCBOR_TYPE_UKNOWN_SIMPLE:
5009 *puSimple = pItem->val.uSimple;
5010 break;
5011
5012 case QCBOR_TYPE_TRUE:
5013 *puSimple = CBOR_SIMPLEV_TRUE;
5014 break;
5015
5016 case QCBOR_TYPE_FALSE:
5017 *puSimple = CBOR_SIMPLEV_FALSE;
5018 break;
5019
5020 case QCBOR_TYPE_NULL:
5021 *puSimple = CBOR_SIMPLEV_NULL;
5022 break;
5023
5024 case QCBOR_TYPE_UNDEF:
5025 *puSimple = CBOR_SIMPLEV_UNDEF;
5026 break;
5027
5028 default:
5029 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
5030 return;
5031 }
Laurence Lundblade3888f002024-06-12 21:20:56 -07005032}
5033
5034/*
5035 * Public function, see header qcbor/qcbor_decode.h file
5036 */
5037void
5038QCBORDecode_GetSimple(QCBORDecodeContext *pMe, uint8_t *puSimple)
5039{
5040 QCBORItem Item;
Laurence Lundblade3888f002024-06-12 21:20:56 -07005041 QCBORDecode_VGetNext(pMe, &Item);
5042 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimple);
5043}
5044
5045/*
5046 * Public function, see header qcbor/qcbor_decode.h file
5047 */
5048void
5049QCBORDecode_GetSimpleInMapN(QCBORDecodeContext *pMe,
5050 int64_t nLabel,
5051 uint8_t *puSimpleValue)
5052{
5053 QCBORItem Item;
5054 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3888f002024-06-12 21:20:56 -07005055 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
5056}
5057
5058/*
5059 * Public function, see header qcbor/qcbor_decode.h file
5060 */
5061void
5062QCBORDecode_GetSimpleInMapSZ(QCBORDecodeContext *pMe,
5063 const char *szLabel,
5064 uint8_t *puSimpleValue)
5065{
5066 QCBORItem Item;
5067 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3888f002024-06-12 21:20:56 -07005068 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
5069}
5070
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005071
Laurence Lundbladec7114722020-08-13 05:11:40 -07005072
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005073/**
5074 * @brief Common processing for an epoch date.
5075 *
5076 * @param[in] pMe The decode context.
5077 * @param[in] pItem The item with the date.
5078 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
5079 * @param[out] pnTime The returned date.
5080 *
5081 * Common processing for the date tag. Mostly make sure the tag
5082 * content is correct and copy forward any further other tag numbers.
5083 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005084static void
5085QCBORDecode_Private_ProcessEpochDate(QCBORDecodeContext *pMe,
5086 QCBORItem *pItem,
5087 const uint8_t uTagRequirement,
5088 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07005089{
5090 if(pMe->uLastError != QCBOR_SUCCESS) {
5091 // Already in error state, do nothing
5092 return;
5093 }
5094
5095 QCBORError uErr;
5096
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005097 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladec7114722020-08-13 05:11:40 -07005098 {
5099 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07005100 {QCBOR_TYPE_DATE_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
5101 {QCBOR_TYPE_INT64, QCBOR_TYPE_DOUBLE, QCBOR_TYPE_FLOAT, QCBOR_TYPE_UINT64}
Laurence Lundbladec7114722020-08-13 05:11:40 -07005102 };
5103
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005104 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07005105 if(uErr != QCBOR_SUCCESS) {
5106 goto Done;
5107 }
5108
5109 if(pItem->uDataType != QCBOR_TYPE_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005110 uErr = QCBOR_Private_DecodeDateEpoch(pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07005111 if(uErr != QCBOR_SUCCESS) {
5112 goto Done;
5113 }
5114 }
5115
5116 *pnTime = pItem->val.epochDate.nSeconds;
5117
5118Done:
5119 pMe->uLastError = (uint8_t)uErr;
5120}
5121
5122
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005123
5124/*
5125 * Public function, see header qcbor/qcbor_spiffy_decode.h file
5126 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005127void
5128QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
5129 uint8_t uTagRequirement,
5130 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07005131{
Laurence Lundbladec7114722020-08-13 05:11:40 -07005132 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07005133 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005134 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07005135}
5136
5137
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005138/*
5139 * Public function, see header qcbor/qcbor_spiffy_decode.h file
5140 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07005141void
5142QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
5143 int64_t nLabel,
5144 uint8_t uTagRequirement,
5145 int64_t *pnTime)
5146{
5147 QCBORItem Item;
5148 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005149 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07005150}
5151
5152
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005153/*
5154 * Public function, see header qcbor/qcbor_spiffy_decode.h file
5155 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07005156void
5157QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
5158 const char *szLabel,
5159 uint8_t uTagRequirement,
5160 int64_t *pnTime)
5161{
5162 QCBORItem Item;
5163 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005164 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07005165}
5166
5167
5168
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005169/**
5170 * @brief Common processing for an epoch date.
5171 *
5172 * @param[in] pMe The decode context.
5173 * @param[in] pItem The item with the date.
5174 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
5175 * @param[out] pnDays The returned day count.
5176 *
5177 * Common processing for the RFC 8943 day-count tag. Mostly make sure
5178 * the tag content is correct and copy forward any further other tag
5179 * numbers.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005180 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005181static void
5182QCBORDecode_Private_ProcessEpochDays(QCBORDecodeContext *pMe,
5183 QCBORItem *pItem,
5184 uint8_t uTagRequirement,
5185 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005186{
5187 if(pMe->uLastError != QCBOR_SUCCESS) {
5188 /* Already in error state, do nothing */
5189 return;
5190 }
5191
5192 QCBORError uErr;
5193
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005194 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005195 {
5196 uTagRequirement,
5197 {QCBOR_TYPE_DAYS_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
5198 {QCBOR_TYPE_INT64, QCBOR_TYPE_UINT64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
5199 };
5200
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005201 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005202 if(uErr != QCBOR_SUCCESS) {
5203 goto Done;
5204 }
5205
5206 if(pItem->uDataType != QCBOR_TYPE_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005207 uErr = QCBOR_Private_DecodeDaysEpoch(pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005208 if(uErr != QCBOR_SUCCESS) {
5209 goto Done;
5210 }
5211 }
5212
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005213 *pnDays = pItem->val.epochDays;
5214
5215Done:
5216 pMe->uLastError = (uint8_t)uErr;
5217}
5218
5219
5220/*
5221 * Public function, see header qcbor/qcbor_decode.h
5222 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005223void
5224QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe,
5225 uint8_t uTagRequirement,
5226 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005227{
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005228 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07005229 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005230 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005231}
5232
5233
5234/*
5235 * Public function, see header qcbor/qcbor_decode.h
5236 */
5237void
5238QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe,
5239 int64_t nLabel,
5240 uint8_t uTagRequirement,
5241 int64_t *pnDays)
5242{
5243 QCBORItem Item;
5244 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005245 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005246}
5247
5248
5249/*
5250 * Public function, see header qcbor/qcbor_decode.h
5251 */
5252void
5253QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe,
5254 const char *szLabel,
5255 uint8_t uTagRequirement,
5256 int64_t *pnDays)
5257{
5258 QCBORItem Item;
5259 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005260 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005261}
5262
5263
5264
Laurence Lundblade37286c02022-09-03 10:05:02 -07005265/*
5266 * @brief Get a string that matches the type/tag specification.
5267 */
5268void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005269QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
5270 const QCBOR_Private_TagSpec TagSpec,
5271 UsefulBufC *pBstr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005272{
Laurence Lundbladec4537442020-04-14 18:53:22 -07005273 QCBORItem Item;
5274
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07005275 QCBORDecode_VGetNext(pMe, &Item);
5276 if(pMe->uLastError) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005277 return;
5278 }
5279
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005280 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005281
5282 if(pMe->uLastError == QCBOR_SUCCESS) {
5283 *pBstr = Item.val.string;
Laurence Lundbladeab40c6f2020-08-28 11:24:58 -07005284 } else {
5285 *pBstr = NULLUsefulBufC;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005286 }
5287}
5288
Laurence Lundbladec4537442020-04-14 18:53:22 -07005289
5290
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005291
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005292/**
5293 * @brief Common processing for a big number tag.
5294 *
5295 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
5296 * @param[in] pItem The item with the date.
5297 * @param[out] pValue The returned big number
5298 * @param[out] pbIsNegative The returned sign of the big number.
5299 *
5300 * Common processing for the big number tag. Mostly make sure
5301 * the tag content is correct and copy forward any further other tag
5302 * numbers.
5303 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07005304static QCBORError
Laurence Lundblade14ce2282024-07-24 22:13:35 -07005305QCBOR_Private_ProcessBigNum(const uint8_t uTagRequirement,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005306 const QCBORItem *pItem,
5307 UsefulBufC *pValue,
5308 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005309{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005310 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005311 {
5312 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07005313 {QCBOR_TYPE_POSBIGNUM, QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
5314 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005315 };
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005316
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005317 QCBORError uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005318 if(uErr != QCBOR_SUCCESS) {
5319 return uErr;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005320 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005321
5322 *pValue = pItem->val.string;
5323
5324 if(pItem->uDataType == QCBOR_TYPE_POSBIGNUM) {
5325 *pbIsNegative = false;
5326 } else if(pItem->uDataType == QCBOR_TYPE_NEGBIGNUM) {
5327 *pbIsNegative = true;
5328 }
5329
5330 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005331}
5332
5333
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005334/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005335 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005336 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005337void
5338QCBORDecode_GetBignum(QCBORDecodeContext *pMe,
5339 const uint8_t uTagRequirement,
5340 UsefulBufC *pValue,
5341 bool *pbIsNegative)
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005342{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005343 QCBORItem Item;
Laurence Lundblade14ce2282024-07-24 22:13:35 -07005344
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07005345 QCBORDecode_VGetNext(pMe, &Item);
5346 if(pMe->uLastError) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005347 return;
5348 }
5349
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005350 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
5351 &Item,
5352 pValue,
5353 pbIsNegative);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005354}
5355
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005356
Laurence Lundblade4e2da002020-06-13 23:08:31 -07005357/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005358 * Public function, see header qcbor/qcbor_spiffy_decode.h
5359 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005360void
5361QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe,
5362 const int64_t nLabel,
5363 const uint8_t uTagRequirement,
5364 UsefulBufC *pValue,
5365 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005366{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005367 QCBORItem Item;
5368 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005369 if(pMe->uLastError != QCBOR_SUCCESS) {
5370 return;
5371 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005372
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005373 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
5374 &Item,
5375 pValue,
5376 pbIsNegative);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005377}
5378
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005379
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005380/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005381 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005382 */
5383void
5384QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe,
5385 const char *szLabel,
5386 const uint8_t uTagRequirement,
5387 UsefulBufC *pValue,
5388 bool *pbIsNegative)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005389{
5390 QCBORItem Item;
5391 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005392 if(pMe->uLastError != QCBOR_SUCCESS) {
5393 return;
5394 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005395
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005396 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
5397 &Item,
5398 pValue,
5399 pbIsNegative);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005400}
5401
5402
5403
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005404/**
5405 * @brief Common processing for MIME tag (semi-private).
5406 *
5407 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
5408 * @param[in] pItem The item with the date.
5409 * @param[out] pMessage The returned MIME message.
5410 * @param[out] pbIsTag257 If true, binary MIME, if not, text MIME.
5411 *
5412 * Common processing for the MIME tag. Mostly make sure the tag
5413 * content is correct and copy forward any further other tag
5414 * numbers. See QCBORDecode_GetMIMEMessage().
5415 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07005416QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005417QCBORDecode_Private_GetMIME(const uint8_t uTagRequirement,
Laurence Lundblade37286c02022-09-03 10:05:02 -07005418 const QCBORItem *pItem,
5419 UsefulBufC *pMessage,
5420 bool *pbIsTag257)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005421{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005422 const QCBOR_Private_TagSpec TagSpecText =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005423 {
5424 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07005425 {QCBOR_TYPE_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
5426 {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005427 };
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005428 const QCBOR_Private_TagSpec TagSpecBinary =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005429 {
5430 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07005431 {QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
5432 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005433 };
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005434
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005435 QCBORError uReturn;
Laurence Lundblade9b334962020-08-27 10:55:53 -07005436
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005437 if(QCBOR_Private_CheckTagRequirement(TagSpecText, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005438 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07005439 if(pbIsTag257 != NULL) {
5440 *pbIsTag257 = false;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005441 }
5442 uReturn = QCBOR_SUCCESS;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005443 } else if(QCBOR_Private_CheckTagRequirement(TagSpecBinary, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005444 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07005445 if(pbIsTag257 != NULL) {
5446 *pbIsTag257 = true;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005447 }
5448 uReturn = QCBOR_SUCCESS;
5449
5450 } else {
5451 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
5452 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07005453
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005454 return uReturn;
5455}
5456
Laurence Lundblade93d89472020-10-03 22:30:50 -07005457// Improvement: add methods for wrapped CBOR, a simple alternate
5458// to EnterBstrWrapped
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005459
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005460
5461
5462
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005463#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundbladee6430642020-03-14 21:15:44 -07005464
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005465/**
5466 * @brief Prototype for conversion of exponent and mantissa to unsigned integer.
5467 *
5468 * @param[in] uMantissa The mantissa.
5469 * @param[in] nExponent The exponent.
5470 * @param[out] puResult The resulting integer.
5471 *
5472 * Concrete implementations of this are for exponent base 10 and 2 supporting
5473 * decimal fractions and big floats.
5474 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005475typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005476
5477
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005478/**
5479 * @brief Base 10 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5480 *
5481 * @param[in] uMantissa The unsigned integer mantissa.
5482 * @param[in] nExponent The signed integer exponent.
5483 * @param[out] puResult Place to return the unsigned integer result.
5484 *
5485 * This computes: mantissa * 10 ^^ exponent as for a decimal fraction. The output is a 64-bit
5486 * unsigned integer.
5487 *
5488 * There are many inputs for which the result will not fit in the
5489 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5490 * be returned.
5491 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005492static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005493QCBOR_Private_Exponentitate10(const uint64_t uMantissa,
5494 int64_t nExponent,
5495 uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005496{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005497 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005498
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005499 if(uResult != 0) {
5500 /* This loop will run a maximum of 19 times because
5501 * UINT64_MAX < 10 ^^ 19. More than that will cause
5502 * exit with the overflow error
5503 */
5504 for(; nExponent > 0; nExponent--) {
5505 if(uResult > UINT64_MAX / 10) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005506 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005507 }
5508 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005509 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005510
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005511 for(; nExponent < 0; nExponent++) {
5512 uResult = uResult / 10;
5513 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005514 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005515 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005516 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005517 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005518 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07005519
5520 *puResult = uResult;
5521
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005522 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005523}
5524
5525
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005526/**
5527 * @brief Base 2 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5528 *
5529 * @param[in] uMantissa The unsigned integer mantissa.
5530 * @param[in] nExponent The signed integer exponent.
5531 * @param[out] puResult Place to return the unsigned integer result.
5532 *
5533 * This computes: mantissa * 2 ^^ exponent as for a big float. The
5534 * output is a 64-bit unsigned integer.
5535 *
5536 * There are many inputs for which the result will not fit in the
5537 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5538 * be returned.
5539 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005540static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005541QCBOR_Private_Exponentitate2(const uint64_t uMantissa,
5542 int64_t nExponent,
5543 uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005544{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005545 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005546
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005547 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005548
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005549 /* This loop will run a maximum of 64 times because INT64_MAX <
5550 * 2^31. More than that will cause exit with the overflow error
Laurence Lundbladee6430642020-03-14 21:15:44 -07005551 */
5552 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005553 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005554 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005555 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005556 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005557 nExponent--;
5558 }
5559
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005560 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005561 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005562 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005563 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005564 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005565 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005566 }
5567
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005568 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005569
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005570 return QCBOR_SUCCESS;
5571}
5572
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005573
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005574/**
5575 * @brief Exponentiate a signed mantissa and signed exponent to produce a signed result.
5576 *
5577 * @param[in] nMantissa Signed integer mantissa.
5578 * @param[in] nExponent Signed integer exponent.
5579 * @param[out] pnResult Place to put the signed integer result.
5580 * @param[in] pfExp Exponentiation function.
5581 *
5582 * @returns Error code
5583 *
5584 * \c pfExp performs exponentiation on and unsigned mantissa and
5585 * produces an unsigned result. This converts the mantissa from signed
5586 * and converts the result to signed. The exponentiation function is
5587 * either for base 2 or base 10 (and could be other if needed).
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005588 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005589static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005590QCBOR_Private_ExponentiateNN(const int64_t nMantissa,
5591 const int64_t nExponent,
5592 int64_t *pnResult,
5593 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005594{
5595 uint64_t uResult;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005596 uint64_t uMantissa;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005597
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005598 /* Take the absolute value and put it into an unsigned. */
5599 if(nMantissa >= 0) {
5600 /* Positive case is straightforward */
5601 uMantissa = (uint64_t)nMantissa;
5602 } else if(nMantissa != INT64_MIN) {
5603 /* The common negative case. See next. */
5604 uMantissa = (uint64_t)-nMantissa;
5605 } else {
5606 /* int64_t and uint64_t are always two's complement per the
5607 * C standard (and since QCBOR uses these it only works with
5608 * two's complement, which is pretty much universal these
5609 * days). The range of a negative two's complement integer is
5610 * one more that than a positive, so the simple code above might
5611 * not work all the time because you can't simply negate the
5612 * value INT64_MIN because it can't be represented in an
5613 * int64_t. -INT64_MIN can however be represented in a
5614 * uint64_t. Some compilers seem to recognize this case for the
5615 * above code and put the correct value in uMantissa, however
5616 * they are not required to do this by the C standard. This next
5617 * line does however work for all compilers.
5618 *
5619 * This does assume two's complement where -INT64_MIN ==
5620 * INT64_MAX + 1 (which wouldn't be true for one's complement or
5621 * sign and magnitude (but we know we're using two's complement
5622 * because int64_t requires it)).
5623 *
5624 * See these, particularly the detailed commentary:
5625 * https://stackoverflow.com/questions/54915742/does-c99-mandate-a-int64-t-type-be-available-always
5626 * https://stackoverflow.com/questions/37301078/is-negating-int-min-undefined-behaviour
5627 */
5628 uMantissa = (uint64_t)INT64_MAX+1;
5629 }
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005630
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005631 /* Call the exponentiator passed for either base 2 or base 10.
5632 * Here is where most of the overflow errors are caught. */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005633 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
5634 if(uReturn) {
5635 return uReturn;
5636 }
5637
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005638 /* Convert back to the sign of the original mantissa */
5639 if(nMantissa >= 0) {
5640 if(uResult > INT64_MAX) {
5641 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5642 }
5643 *pnResult = (int64_t)uResult;
5644 } else {
5645 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
5646 * of INT64_MIN. This assumes two's compliment representation
5647 * where INT64_MIN is one increment farther from 0 than
5648 * INT64_MAX. Trying to write -INT64_MIN doesn't work to get
5649 * this because the compiler makes it an int64_t which can't
5650 * represent -INT64_MIN. Also see above.
5651 */
5652 if(uResult > (uint64_t)INT64_MAX+1) {
5653 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5654 }
5655 *pnResult = -(int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005656 }
5657
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005658 return QCBOR_SUCCESS;
5659}
5660
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005661
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005662/**
5663 * @brief Exponentiate an unsigned mantissa and signed exponent to produce an unsigned result.
5664 *
5665 * @param[in] nMantissa Signed integer mantissa.
5666 * @param[in] nExponent Signed integer exponent.
5667 * @param[out] puResult Place to put the signed integer result.
5668 * @param[in] pfExp Exponentiation function.
5669 *
5670 * @returns Error code
5671 *
5672 * \c pfExp performs exponentiation on and unsigned mantissa and
5673 * produces an unsigned result. This errors out if the mantissa
5674 * is negative because the output is unsigned.
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005675 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005676static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005677QCBOR_Private_ExponentitateNU(const int64_t nMantissa,
5678 const int64_t nExponent,
5679 uint64_t *puResult,
5680 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005681{
5682 if(nMantissa < 0) {
5683 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5684 }
5685
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005686 /* Cast to unsigned is OK because of check for negative.
5687 * Cast to unsigned is OK because UINT64_MAX > INT64_MAX.
5688 * Exponentiation is straight forward
5689 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005690 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
5691}
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005692
5693
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005694/**
5695 * @brief Exponentiate an usnigned mantissa and unsigned exponent to produce an unsigned result.
5696 *
5697 * @param[in] uMantissa Unsigned integer mantissa.
5698 * @param[in] nExponent Unsigned integer exponent.
5699 * @param[out] puResult Place to put the unsigned integer result.
5700 * @param[in] pfExp Exponentiation function.
5701 *
5702 * @returns Error code
5703 *
5704 * \c pfExp performs exponentiation on and unsigned mantissa and
5705 * produces an unsigned result so this is just a wrapper that does
5706 * nothing (and is likely inlined).
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005707 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005708static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005709QCBOR_Private_ExponentitateUU(const uint64_t uMantissa,
5710 const int64_t nExponent,
5711 uint64_t *puResult,
5712 fExponentiator pfExp)
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005713{
5714 return (*pfExp)(uMantissa, nExponent, puResult);
5715}
5716
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005717#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005718
5719
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005720
5721
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005722/**
5723 * @brief Convert a CBOR big number to a uint64_t.
5724 *
5725 * @param[in] BigNum Bytes of the big number to convert.
5726 * @param[in] uMax Maximum value allowed for the result.
5727 * @param[out] pResult Place to put the unsigned integer result.
5728 *
5729 * @returns Error code
5730 *
5731 * Many values will overflow because a big num can represent a much
5732 * larger range than uint64_t.
5733 */
5734static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005735QCBOR_Private_ConvertBigNumToUnsigned(const UsefulBufC BigNum,
5736 const uint64_t uMax,
5737 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005738{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005739 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005740
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005741 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005742 const uint8_t *pByte = BigNum.ptr;
5743 size_t uLen = BigNum.len;
5744 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07005745 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005746 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005747 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07005748 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005749 }
5750
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005751 *pResult = uResult;
5752 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005753}
5754
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005755
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005756/**
5757 * @brief Convert a CBOR postive big number to a uint64_t.
5758 *
5759 * @param[in] BigNum Bytes of the big number to convert.
5760 * @param[out] pResult Place to put the unsigned integer result.
5761 *
5762 * @returns Error code
5763 *
5764 * Many values will overflow because a big num can represent a much
5765 * larger range than uint64_t.
5766 */
5767static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005768QCBOR_Private_ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum,
5769 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005770{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005771 return QCBOR_Private_ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005772}
5773
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005774
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005775/**
5776 * @brief Convert a CBOR positive big number to an int64_t.
5777 *
5778 * @param[in] BigNum Bytes of the big number to convert.
5779 * @param[out] pResult Place to put the signed integer result.
5780 *
5781 * @returns Error code
5782 *
5783 * Many values will overflow because a big num can represent a much
5784 * larger range than int64_t.
5785 */
5786static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005787QCBOR_Private_ConvertPositiveBigNumToSigned(const UsefulBufC BigNum,
5788 int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005789{
5790 uint64_t uResult;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005791 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5792 INT64_MAX,
5793 &uResult);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005794 if(uError) {
5795 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005796 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005797 /* Cast is safe because ConvertBigNumToUnsigned limits to INT64_MAX */
Laurence Lundbladee6430642020-03-14 21:15:44 -07005798 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005799 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005800}
5801
5802
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005803/**
5804 * @brief Convert a CBOR negative big number to an int64_t.
5805 *
5806 * @param[in] BigNum Bytes of the big number to convert.
5807 * @param[out] pnResult Place to put the signed integer result.
5808 *
5809 * @returns Error code
5810 *
5811 * Many values will overflow because a big num can represent a much
5812 * larger range than int64_t.
5813 */
5814static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005815QCBOR_Private_ConvertNegativeBigNumToSigned(const UsefulBufC BigNum,
5816 int64_t *pnResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005817{
5818 uint64_t uResult;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005819 /* The negative integer furthest from zero for a C int64_t is
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005820 * INT64_MIN which is expressed as -INT64_MAX - 1. The value of a
5821 * negative number in CBOR is computed as -n - 1 where n is the
5822 * encoded integer, where n is what is in the variable BigNum. When
5823 * converting BigNum to a uint64_t, the maximum value is thus
5824 * INT64_MAX, so that when it -n - 1 is applied to it the result
5825 * will never be further from 0 than INT64_MIN.
5826 *
5827 * -n - 1 <= INT64_MIN.
5828 * -n - 1 <= -INT64_MAX - 1
5829 * n <= INT64_MAX.
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005830 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005831 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5832 INT64_MAX,
5833 &uResult);
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005834 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005835 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005836 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005837
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005838 /* Now apply -n - 1. The cast is safe because
5839 * ConvertBigNumToUnsigned() is limited to INT64_MAX which does fit
5840 * is the largest positive integer that an int64_t can
5841 * represent. */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005842 *pnResult = -(int64_t)uResult - 1;
5843
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005844 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005845}
5846
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005847
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005848
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005849
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005850/**
5851 * @brief Convert integers and floats to an int64_t.
5852 *
5853 * @param[in] pItem The item to convert.
5854 * @param[in] uConvertTypes Bit mask list of conversion options.
5855 * @param[out] pnValue The resulting converted value.
5856 *
5857 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5858 * in uConvertTypes.
5859 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5860 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5861 * or too small.
5862 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005863static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005864QCBOR_Private_ConvertInt64(const QCBORItem *pItem,
5865 const uint32_t uConvertTypes,
5866 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005867{
5868 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005869 case QCBOR_TYPE_FLOAT:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005870 case QCBOR_TYPE_DOUBLE:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005871#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005872 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005873 /* https://pubs.opengroup.org/onlinepubs/009695399/functions/llround.html
5874 http://www.cplusplus.com/reference/cmath/llround/
5875 */
5876 // Not interested in FE_INEXACT
5877 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005878 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5879 *pnValue = llround(pItem->val.dfnum);
5880 } else {
5881 *pnValue = lroundf(pItem->val.fnum);
5882 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005883 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5884 // llround() shouldn't result in divide by zero, but catch
5885 // it here in case it unexpectedly does. Don't try to
5886 // distinguish between the various exceptions because it seems
5887 // they vary by CPU, compiler and OS.
5888 return QCBOR_ERR_FLOAT_EXCEPTION;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005889 }
5890 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005891 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005892 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005893#else
5894 return QCBOR_ERR_HW_FLOAT_DISABLED;
5895#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005896 break;
5897
5898 case QCBOR_TYPE_INT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005899 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005900 *pnValue = pItem->val.int64;
5901 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005902 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005903 }
5904 break;
5905
5906 case QCBOR_TYPE_UINT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005907 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005908 if(pItem->val.uint64 < INT64_MAX) {
5909 *pnValue = pItem->val.int64;
5910 } else {
5911 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5912 }
5913 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005914 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005915 }
5916 break;
5917
Laurence Lundblade2d493002024-02-01 11:09:17 -07005918 case QCBOR_TYPE_65BIT_NEG_INT:
5919 /* This type occurs if the value won't fit into int64_t
5920 * so this is always an error. */
5921 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5922 break;
5923
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005924 default:
5925 return QCBOR_ERR_UNEXPECTED_TYPE;
5926 }
5927 return QCBOR_SUCCESS;
5928}
5929
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005930
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005931/**
5932 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5933 *
5934 * @param[in] pMe The decode context.
5935 * @param[in] uConvertTypes Bit mask list of conversion options.
5936 * @param[out] pnValue Result of the conversion.
5937 * @param[in,out] pItem Temporary space to store Item, returned item.
5938 *
5939 * See QCBORDecode_GetInt64Convert().
5940 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005941void
5942QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pMe,
5943 uint32_t uConvertTypes,
5944 int64_t *pnValue,
5945 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005946{
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07005947 QCBORDecode_VGetNext(pMe, pItem);
5948 if(pMe->uLastError) {
Laurence Lundbladee6430642020-03-14 21:15:44 -07005949 return;
5950 }
5951
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005952 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005953 uConvertTypes,
5954 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005955}
5956
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005957/**
5958 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5959 *
5960 * @param[in] pMe The decode context.
5961 * @param[in] nLabel Label to find in map.
5962 * @param[in] uConvertTypes Bit mask list of conversion options.
5963 * @param[out] pnValue Result of the conversion.
5964 * @param[in,out] pItem Temporary space to store Item, returned item.
5965 *
5966 * See QCBORDecode_GetInt64ConvertInMapN().
5967 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005968void
5969QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pMe,
5970 int64_t nLabel,
5971 uint32_t uConvertTypes,
5972 int64_t *pnValue,
5973 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005974{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005975 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005976 if(pMe->uLastError != QCBOR_SUCCESS) {
5977 return;
5978 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005979
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005980 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5981 uConvertTypes,
5982 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005983}
5984
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005985/**
5986 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5987 *
5988 * @param[in] pMe The decode context.
5989 * @param[in] szLabel Label to find in map.
5990 * @param[in] uConvertTypes Bit mask list of conversion options.
5991 * @param[out] pnValue Result of the conversion.
5992 * @param[in,out] pItem Temporary space to store Item, returned item.
5993 *
5994 * See QCBORDecode_GetInt64ConvertInMapSZ().
5995 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005996void
5997QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5998 const char * szLabel,
5999 uint32_t uConvertTypes,
6000 int64_t *pnValue,
6001 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006002{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006003 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006004 if(pMe->uLastError != QCBOR_SUCCESS) {
6005 return;
6006 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006007
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006008 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
6009 uConvertTypes,
6010 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006011}
6012
6013
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006014/**
6015 * @brief Convert many number types to an int64_t.
6016 *
6017 * @param[in] pItem The item to convert.
6018 * @param[in] uConvertTypes Bit mask list of conversion options.
6019 * @param[out] pnValue The resulting converted value.
6020 *
6021 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6022 * in uConvertTypes.
6023 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6024 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6025 * or too small.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006026 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006027static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006028QCBOR_Private_Int64ConvertAll(const QCBORItem *pItem,
6029 const uint32_t uConvertTypes,
6030 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006031{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006032 switch(pItem->uDataType) {
6033
6034 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006035 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006036 return QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006037 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006038 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07006039 }
6040 break;
6041
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006042 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006043 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006044 return QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006045 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006046 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07006047 }
6048 break;
6049
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006050#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006051 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006052 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006053 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006054 pItem->val.expAndMantissa.nExponent,
6055 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006056 &QCBOR_Private_Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006057 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006058 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006059 }
6060 break;
6061
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006062 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006063 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006064 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006065 pItem->val.expAndMantissa.nExponent,
6066 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006067 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006068 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006069 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006070 }
6071 break;
6072
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006073 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006074 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006075 int64_t nMantissa;
6076 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006077 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006078 if(uErr) {
6079 return uErr;
6080 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006081 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006082 pItem->val.expAndMantissa.nExponent,
6083 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006084 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006085 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006086 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006087 }
6088 break;
6089
6090 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006091 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006092 int64_t nMantissa;
6093 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006094 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006095 if(uErr) {
6096 return uErr;
6097 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006098 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006099 pItem->val.expAndMantissa.nExponent,
6100 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006101 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006102 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006103 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006104 }
6105 break;
6106
6107 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006108 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006109 int64_t nMantissa;
6110 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006111 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006112 if(uErr) {
6113 return uErr;
6114 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006115 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006116 pItem->val.expAndMantissa.nExponent,
6117 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006118 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006119 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006120 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006121 }
6122 break;
6123
6124 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006125 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006126 int64_t nMantissa;
6127 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006128 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006129 if(uErr) {
6130 return uErr;
6131 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006132 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006133 pItem->val.expAndMantissa.nExponent,
6134 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006135 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006136 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006137 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07006138 }
6139 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006140#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006141
Laurence Lundbladee6430642020-03-14 21:15:44 -07006142
Laurence Lundbladec4537442020-04-14 18:53:22 -07006143 default:
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006144 return QCBOR_ERR_UNEXPECTED_TYPE; }
Laurence Lundbladec4537442020-04-14 18:53:22 -07006145}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006146
6147
Laurence Lundbladec4537442020-04-14 18:53:22 -07006148/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006149 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006150 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006151void
6152QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe,
6153 const uint32_t uConvertTypes,
6154 int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07006155{
6156 QCBORItem Item;
6157
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006158 QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07006159
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006160 if(pMe->uLastError == QCBOR_SUCCESS) {
6161 // The above conversion succeeded
6162 return;
6163 }
6164
Laurence Lundbladef6c86662020-05-12 02:08:00 -07006165 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006166 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07006167 return;
6168 }
6169
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006170 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
6171 uConvertTypes,
6172 pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006173}
6174
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006175
6176/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006177 * Public function, see header qcbor/qcbor_decode.h file
6178 */
6179void
6180QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
6181 const int64_t nLabel,
6182 const uint32_t uConvertTypes,
6183 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006184{
6185 QCBORItem Item;
6186
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006187 QCBORDecode_Private_GetInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006188 nLabel,
6189 uConvertTypes,
6190 pnValue,
6191 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006192
6193 if(pMe->uLastError == QCBOR_SUCCESS) {
6194 // The above conversion succeeded
6195 return;
6196 }
6197
6198 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6199 // The above conversion failed in a way that code below can't correct
6200 return;
6201 }
6202
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006203 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
6204 uConvertTypes,
6205 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006206}
6207
6208
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006209/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006210 * Public function, see header qcbor/qcbor_decode.h file
6211 */
6212void
6213QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
6214 const char *szLabel,
6215 const uint32_t uConvertTypes,
6216 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006217{
6218 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006219 QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006220 szLabel,
6221 uConvertTypes,
6222 pnValue,
6223 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006224
6225 if(pMe->uLastError == QCBOR_SUCCESS) {
6226 // The above conversion succeeded
6227 return;
6228 }
6229
6230 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6231 // The above conversion failed in a way that code below can't correct
6232 return;
6233 }
6234
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006235 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
6236 uConvertTypes,
6237 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006238}
6239
6240
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006241/**
6242 * @brief Convert many number types to an uint64_t.
6243 *
6244 * @param[in] pItem The item to convert.
6245 * @param[in] uConvertTypes Bit mask list of conversion options.
6246 * @param[out] puValue The resulting converted value.
6247 *
6248 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6249 * in uConvertTypes.
6250 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6251 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6252 * or too small.
6253 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006254static QCBORError
6255QCBOR_Private_ConvertUInt64(const QCBORItem *pItem,
6256 const uint32_t uConvertTypes,
6257 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006258{
6259 switch(pItem->uDataType) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006260 case QCBOR_TYPE_DOUBLE:
6261 case QCBOR_TYPE_FLOAT:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006262#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006263 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006264 // Can't use llround here because it will not convert values
6265 // greater than INT64_MAX and less than UINT64_MAX that
6266 // need to be converted so it is more complicated.
6267 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
6268 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
6269 if(isnan(pItem->val.dfnum)) {
6270 return QCBOR_ERR_FLOAT_EXCEPTION;
6271 } else if(pItem->val.dfnum < 0) {
6272 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6273 } else {
6274 double dRounded = round(pItem->val.dfnum);
6275 // See discussion in DecodeDateEpoch() for
6276 // explanation of - 0x7ff
6277 if(dRounded > (double)(UINT64_MAX- 0x7ff)) {
6278 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
6279 }
6280 *puValue = (uint64_t)dRounded;
6281 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006282 } else {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006283 if(isnan(pItem->val.fnum)) {
6284 return QCBOR_ERR_FLOAT_EXCEPTION;
6285 } else if(pItem->val.fnum < 0) {
6286 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6287 } else {
6288 float fRounded = roundf(pItem->val.fnum);
6289 // See discussion in DecodeDateEpoch() for
6290 // explanation of - 0x7ff
6291 if(fRounded > (float)(UINT64_MAX- 0x7ff)) {
6292 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
6293 }
6294 *puValue = (uint64_t)fRounded;
6295 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006296 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006297 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
6298 // round() and roundf() shouldn't result in exceptions here, but
6299 // catch them to be robust and thorough. Don't try to
6300 // distinguish between the various exceptions because it seems
6301 // they vary by CPU, compiler and OS.
6302 return QCBOR_ERR_FLOAT_EXCEPTION;
6303 }
6304
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006305 } else {
6306 return QCBOR_ERR_UNEXPECTED_TYPE;
6307 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006308#else
6309 return QCBOR_ERR_HW_FLOAT_DISABLED;
6310#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006311 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006312
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006313 case QCBOR_TYPE_INT64:
6314 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
6315 if(pItem->val.int64 >= 0) {
6316 *puValue = (uint64_t)pItem->val.int64;
6317 } else {
6318 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6319 }
6320 } else {
6321 return QCBOR_ERR_UNEXPECTED_TYPE;
6322 }
6323 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006324
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006325 case QCBOR_TYPE_UINT64:
6326 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade2d493002024-02-01 11:09:17 -07006327 *puValue = pItem->val.uint64;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006328 } else {
6329 return QCBOR_ERR_UNEXPECTED_TYPE;
6330 }
6331 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006332
Laurence Lundblade2d493002024-02-01 11:09:17 -07006333 case QCBOR_TYPE_65BIT_NEG_INT:
6334 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6335
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006336 default:
6337 return QCBOR_ERR_UNEXPECTED_TYPE;
6338 }
6339
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006340 return QCBOR_SUCCESS;
6341}
Laurence Lundbladec4537442020-04-14 18:53:22 -07006342
6343
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006344/**
6345 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
6346 *
6347 * @param[in] pMe The decode context.
6348 * @param[in] uConvertTypes Bit mask list of conversion options.
6349 * @param[out] puValue Result of the conversion.
6350 * @param[in,out] pItem Temporary space to store Item, returned item.
6351 *
6352 * See QCBORDecode_GetUInt64Convert().
6353 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006354void
6355QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pMe,
6356 const uint32_t uConvertTypes,
6357 uint64_t *puValue,
6358 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07006359{
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07006360 QCBORDecode_VGetNext(pMe, pItem);
6361 if(pMe->uLastError) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006362 return;
6363 }
6364
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07006365 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006366 uConvertTypes,
6367 puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07006368}
6369
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006370
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006371/**
6372 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
6373 *
6374 * @param[in] pMe The decode context.
6375 * @param[in] nLabel Label to find in map.
6376 * @param[in] uConvertTypes Bit mask list of conversion options.
6377 * @param[out] puValue Result of the conversion.
6378 * @param[in,out] pItem Temporary space to store Item, returned item.
6379 *
6380 * See QCBORDecode_GetUInt64ConvertInMapN().
6381 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006382void
6383QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe,
6384 const int64_t nLabel,
6385 const uint32_t uConvertTypes,
6386 uint64_t *puValue,
6387 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006388{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006389 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006390 if(pMe->uLastError != QCBOR_SUCCESS) {
6391 return;
6392 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006393
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006394 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
6395 uConvertTypes,
6396 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006397}
6398
6399
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006400/**
6401 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
6402 *
6403 * @param[in] pMe The decode context.
6404 * @param[in] szLabel Label to find in map.
6405 * @param[in] uConvertTypes Bit mask list of conversion options.
6406 * @param[out] puValue Result of the conversion.
6407 * @param[in,out] pItem Temporary space to store Item, returned item.
6408 *
6409 * See QCBORDecode_GetUInt64ConvertInMapSZ().
6410 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006411void
6412QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
6413 const char *szLabel,
6414 const uint32_t uConvertTypes,
6415 uint64_t *puValue,
6416 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006417{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006418 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006419 if(pMe->uLastError != QCBOR_SUCCESS) {
6420 return;
6421 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006422
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006423 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
6424 uConvertTypes,
6425 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006426}
6427
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006428
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006429/**
6430 * @brief Convert many number types to an unt64_t.
6431 *
6432 * @param[in] pItem The item to convert.
6433 * @param[in] uConvertTypes Bit mask list of conversion options.
6434 * @param[out] puValue The resulting converted value.
6435 *
6436 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6437 * in uConvertTypes.
6438 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6439 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6440 * or too small.
6441 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006442static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006443QCBOR_Private_UInt64ConvertAll(const QCBORItem *pItem,
6444 const uint32_t uConvertTypes,
6445 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006446{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08006447 switch(pItem->uDataType) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006448
6449 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006450 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006451 return QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006452 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006453 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006454 }
6455 break;
6456
6457 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006458 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006459 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6460 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006461 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006462 }
6463 break;
6464
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006465#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006466
6467 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006468 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006469 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006470 pItem->val.expAndMantissa.nExponent,
6471 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006472 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006473 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006474 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006475 }
6476 break;
6477
6478 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006479 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006480 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006481 pItem->val.expAndMantissa.nExponent,
6482 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006483 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006484 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006485 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006486 }
6487 break;
6488
6489 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006490 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006491 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006492 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006493 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006494 if(uErr != QCBOR_SUCCESS) {
6495 return uErr;
6496 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006497 return QCBOR_Private_ExponentitateUU(uMantissa,
6498 pItem->val.expAndMantissa.nExponent,
6499 puValue,
6500 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006501 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006502 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006503 }
6504 break;
6505
6506 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006507 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006508 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6509 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006510 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006511 }
6512 break;
6513
6514 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006515 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006516 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006517 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006518 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum,
6519 &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006520 if(uErr != QCBOR_SUCCESS) {
6521 return uErr;
6522 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006523 return QCBOR_Private_ExponentitateUU(uMantissa,
6524 pItem->val.expAndMantissa.nExponent,
6525 puValue,
6526 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006527 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006528 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006529 }
6530 break;
6531
6532 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006533 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006534 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6535 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006536 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006537 }
6538 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006539#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006540 default:
6541 return QCBOR_ERR_UNEXPECTED_TYPE;
6542 }
6543}
6544
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006545
Laurence Lundblade4e2da002020-06-13 23:08:31 -07006546/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006547 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006548 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006549void
6550QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe,
6551 const uint32_t uConvertTypes,
6552 uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006553{
6554 QCBORItem Item;
6555
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006556 QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006557
Laurence Lundbladef6c86662020-05-12 02:08:00 -07006558 if(pMe->uLastError == QCBOR_SUCCESS) {
6559 // The above conversion succeeded
6560 return;
6561 }
6562
6563 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6564 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07006565 return;
6566 }
6567
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006568 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6569 uConvertTypes,
6570 puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006571}
6572
Laurence Lundbladec4537442020-04-14 18:53:22 -07006573
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006574/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006575 * Public function, see header qcbor/qcbor_decode.h file
6576 */
6577void
6578QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
6579 const int64_t nLabel,
6580 const uint32_t uConvertTypes,
6581 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006582{
6583 QCBORItem Item;
6584
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006585 QCBORDecode_Private_GetUInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006586 nLabel,
6587 uConvertTypes,
6588 puValue,
6589 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006590
6591 if(pMe->uLastError == QCBOR_SUCCESS) {
6592 // The above conversion succeeded
6593 return;
6594 }
6595
6596 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6597 // The above conversion failed in a way that code below can't correct
6598 return;
6599 }
6600
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006601 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6602 uConvertTypes,
6603 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006604}
6605
6606
6607/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006608 * Public function, see header qcbor/qcbor_decode.h file
6609 */
6610void
6611QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
6612 const char *szLabel,
6613 const uint32_t uConvertTypes,
6614 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006615{
6616 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006617 QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006618 szLabel,
6619 uConvertTypes,
6620 puValue,
6621 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006622
6623 if(pMe->uLastError == QCBOR_SUCCESS) {
6624 // The above conversion succeeded
6625 return;
6626 }
6627
6628 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6629 // The above conversion failed in a way that code below can't correct
6630 return;
6631 }
6632
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006633 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6634 uConvertTypes,
6635 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006636}
6637
6638
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006639
6640
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006641#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006642/**
6643 * @brief Basic conversions to a double.
6644 *
6645 * @param[in] pItem The item to convert
6646 * @param[in] uConvertTypes Bit flags indicating source types for conversion
6647 * @param[out] pdValue The value converted to a double
6648 *
6649 * This does the conversions that don't need much object code,
6650 * the conversions from int, uint and float to double.
6651 *
6652 * See QCBOR_Private_DoubleConvertAll() for the full set
6653 * of conversions.
6654 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006655static QCBORError
6656QCBOR_Private_ConvertDouble(const QCBORItem *pItem,
6657 const uint32_t uConvertTypes,
6658 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006659{
6660 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006661 case QCBOR_TYPE_FLOAT:
6662#ifndef QCBOR_DISABLE_FLOAT_HW_USE
6663 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6664 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006665 // Simple cast does the job.
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006666 *pdValue = (double)pItem->val.fnum;
6667 } else {
6668 return QCBOR_ERR_UNEXPECTED_TYPE;
6669 }
6670 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006671#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006672 return QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006673#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006674 break;
6675
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006676 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006677 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6678 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006679 *pdValue = pItem->val.dfnum;
6680 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006681 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006682 }
6683 }
6684 break;
6685
6686 case QCBOR_TYPE_INT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006687#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006688 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006689 // A simple cast seems to do the job with no worry of exceptions.
6690 // There will be precision loss for some values.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006691 *pdValue = (double)pItem->val.int64;
6692
6693 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006694 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006695 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006696#else
6697 return QCBOR_ERR_HW_FLOAT_DISABLED;
6698#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006699 break;
6700
6701 case QCBOR_TYPE_UINT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006702#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006703 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006704 // A simple cast seems to do the job with no worry of exceptions.
6705 // There will be precision loss for some values.
6706 *pdValue = (double)pItem->val.uint64;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006707 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006708 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006709 }
6710 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006711#else
6712 return QCBOR_ERR_HW_FLOAT_DISABLED;
6713#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006714
Laurence Lundblade2d493002024-02-01 11:09:17 -07006715 case QCBOR_TYPE_65BIT_NEG_INT:
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -08006716#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade14ce2282024-07-24 22:13:35 -07006717 // TODO: don't use float HW. We have the function to do it.
Laurence Lundblade2d493002024-02-01 11:09:17 -07006718 *pdValue = -(double)pItem->val.uint64 - 1;
6719 break;
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -08006720#else
6721 return QCBOR_ERR_HW_FLOAT_DISABLED;
6722#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade2d493002024-02-01 11:09:17 -07006723
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006724 default:
6725 return QCBOR_ERR_UNEXPECTED_TYPE;
6726 }
6727
6728 return QCBOR_SUCCESS;
6729}
6730
6731
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006732/**
6733 * @brief Almost-public method to decode a number and convert to double (semi-private).
6734 *
6735 * @param[in] pMe The decode context.
6736 * @param[in] uConvertTypes Bit mask list of conversion options
6737 * @param[out] pdValue The output of the conversion.
6738 * @param[in,out] pItem Temporary space to store Item, returned item.
6739 *
6740 * See QCBORDecode_GetDoubleConvert().
6741 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006742void
6743QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pMe,
6744 const uint32_t uConvertTypes,
6745 double *pdValue,
6746 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07006747{
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07006748 QCBORDecode_VGetNext(pMe, pItem);
6749 if(pMe->uLastError) {
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006750 return;
6751 }
6752
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006753 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006754 uConvertTypes,
6755 pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006756}
Laurence Lundbladec4537442020-04-14 18:53:22 -07006757
Laurence Lundbladec4537442020-04-14 18:53:22 -07006758
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006759/**
6760 * @brief Almost-public method to decode a number and convert to double (semi-private).
6761 *
6762 * @param[in] pMe The decode context.
6763 * @param[in] nLabel Label to find in map.
6764 * @param[in] uConvertTypes Bit mask list of conversion options
6765 * @param[out] pdValue The output of the conversion.
6766 * @param[in,out] pItem Temporary space to store Item, returned item.
6767 *
6768 * See QCBORDecode_GetDoubleConvertInMapN().
6769 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006770void
6771QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pMe,
6772 const int64_t nLabel,
6773 const uint32_t uConvertTypes,
6774 double *pdValue,
6775 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006776{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006777 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006778 if(pMe->uLastError != QCBOR_SUCCESS) {
6779 return;
6780 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006781
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006782 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6783 uConvertTypes,
6784 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006785}
6786
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006787
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006788/**
6789 * @brief Almost-public method to decode a number and convert to double (semi-private).
6790 *
6791 * @param[in] pMe The decode context.
6792 * @param[in] szLabel Label to find in map.
6793 * @param[in] uConvertTypes Bit mask list of conversion options
6794 * @param[out] pdValue The output of the conversion.
6795 * @param[in,out] pItem Temporary space to store Item, returned item.
6796 *
6797 * See QCBORDecode_GetDoubleConvertInMapSZ().
6798 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006799void
6800QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe,
6801 const char *szLabel,
6802 const uint32_t uConvertTypes,
6803 double *pdValue,
6804 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006805{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006806 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006807 if(pMe->uLastError != QCBOR_SUCCESS) {
6808 return;
6809 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006810
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006811 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6812 uConvertTypes,
6813 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006814}
6815
6816
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006817#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006818/**
6819 * @brief Convert a big number to double-precision float.
6820 *
6821 * @param[in] BigNum The big number to convert
6822 *
6823 * @returns The double value.
6824 *
6825 * This will always succeed. It will lose precision for larger
6826 * numbers. If the big number is too large to fit (more than
6827 * 1.7976931348623157E+308) infinity will be returned. NaN is never
6828 * returned.
6829 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006830static double
6831QCBOR_Private_ConvertBigNumToDouble(const UsefulBufC BigNum)
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006832{
6833 double dResult;
6834
6835 dResult = 0.0;
6836 const uint8_t *pByte = BigNum.ptr;
6837 size_t uLen = BigNum.len;
6838 /* This will overflow and become the float value INFINITY if the number
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006839 * is too large to fit. */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006840 while(uLen--) {
6841 dResult = (dResult * 256.0) + (double)*pByte++;
6842 }
6843
6844 return dResult;
6845}
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006846#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6847
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006848
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006849
6850
6851/**
6852 * @brief Convert many number types to a double.
6853 *
6854 * @param[in] pItem The item to convert.
6855 * @param[in] uConvertTypes Bit mask list of conversion options.
6856 * @param[out] pdValue The resulting converted value.
6857 *
6858 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6859 * in uConvertTypes.
6860 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6861 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6862 * or too small.
6863 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006864static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006865QCBOR_Private_DoubleConvertAll(const QCBORItem *pItem,
6866 const uint32_t uConvertTypes,
6867 double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006868{
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006869#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07006870 /*
Laurence Lundblade16a207a2021-09-18 17:22:46 -07006871 * What Every Computer Scientist Should Know About Floating-Point Arithmetic
6872 * https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
6873 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006874 switch(pItem->uDataType) {
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006875
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006876#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006877 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006878 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006879 // Underflow gives 0, overflow gives infinity
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006880 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6881 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
6882 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006883 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006884 }
6885 break;
6886
6887 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006888 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006889 // Underflow gives 0, overflow gives infinity
6890 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6891 exp2((double)pItem->val.expAndMantissa.nExponent);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006892 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006893 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006894 }
6895 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006896#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006897
6898 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006899 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006900 *pdValue = QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006901 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006902 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006903 }
6904 break;
6905
6906 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006907 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006908 *pdValue = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006909 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006910 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006911 }
6912 break;
6913
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006914#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006915 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006916 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006917 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006918 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6919 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006920 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006921 }
6922 break;
6923
6924 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006925 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006926 double dMantissa = -QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006927 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6928 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006929 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006930 }
6931 break;
6932
6933 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006934 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006935 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006936 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6937 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006938 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006939 }
6940 break;
6941
6942 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006943 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006944 double dMantissa = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006945 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6946 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006947 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006948 }
6949 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006950#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006951
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006952 default:
6953 return QCBOR_ERR_UNEXPECTED_TYPE;
6954 }
6955
6956 return QCBOR_SUCCESS;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006957
6958#else
6959 (void)pItem;
6960 (void)uConvertTypes;
6961 (void)pdValue;
6962 return QCBOR_ERR_HW_FLOAT_DISABLED;
6963#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6964
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006965}
6966
6967
6968/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006969 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006970 */
6971void
6972QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe,
6973 const uint32_t uConvertTypes,
6974 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006975{
6976
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006977 QCBORItem Item;
6978
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006979 QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006980
6981 if(pMe->uLastError == QCBOR_SUCCESS) {
6982 // The above conversion succeeded
6983 return;
6984 }
6985
6986 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6987 // The above conversion failed in a way that code below can't correct
6988 return;
6989 }
6990
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006991 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6992 uConvertTypes,
6993 pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006994}
6995
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006996
6997/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006998 * Public function, see header qcbor/qcbor_decode.h file
6999 */
7000void
7001QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe,
7002 const int64_t nLabel,
7003 const uint32_t uConvertTypes,
7004 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07007005{
7006 QCBORItem Item;
7007
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007008 QCBORDecode_Private_GetDoubleConvertInMapN(pMe,
7009 nLabel,
7010 uConvertTypes,
7011 pdValue,
7012 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07007013
7014 if(pMe->uLastError == QCBOR_SUCCESS) {
7015 // The above conversion succeeded
7016 return;
7017 }
7018
7019 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
7020 // The above conversion failed in a way that code below can't correct
7021 return;
7022 }
7023
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007024 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
7025 uConvertTypes,
7026 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07007027}
7028
7029
7030/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007031 * Public function, see header qcbor/qcbor_decode.h file
7032 */
7033void
7034QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe,
7035 const char *szLabel,
7036 const uint32_t uConvertTypes,
7037 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07007038{
7039 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007040 QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe,
7041 szLabel,
7042 uConvertTypes,
7043 pdValue,
7044 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07007045
7046 if(pMe->uLastError == QCBOR_SUCCESS) {
7047 // The above conversion succeeded
7048 return;
7049 }
7050
7051 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
7052 // The above conversion failed in a way that code below can't correct
7053 return;
7054 }
7055
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007056 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
7057 uConvertTypes,
7058 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07007059}
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02007060#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007061
7062
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007063
7064
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07007065#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007066/**
7067 * @brief Convert an integer to a big number
7068 *
7069 * @param[in] uInt The integer to convert.
7070 * @param[in] Buffer The buffer to output the big number to.
7071 *
7072 * @returns The big number or NULLUsefulBufC is the buffer is to small.
7073 *
7074 * This always succeeds unless the buffer is too small.
7075 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007076static UsefulBufC
7077QCBOR_Private_ConvertIntToBigNum(uint64_t uInt, const UsefulBuf Buffer)
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07007078{
7079 while((uInt & 0xff00000000000000UL) == 0) {
7080 uInt = uInt << 8;
7081 };
7082
7083 UsefulOutBuf UOB;
7084
7085 UsefulOutBuf_Init(&UOB, Buffer);
7086
7087 while(uInt) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07007088 UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff00000000000000UL) >> 56));
7089 uInt = uInt << 8;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07007090 }
7091
7092 return UsefulOutBuf_OutUBuf(&UOB);
7093}
7094
7095
Laurence Lundblade37286c02022-09-03 10:05:02 -07007096/**
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07007097 * @brief Check and/or complete exponent and mantissa item.
Laurence Lundblade37286c02022-09-03 10:05:02 -07007098 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07007099 * @param[in] pMe The decoder context.
7100 * @param[in] TagSpec Expected type(s).
7101 * @param[in,out] pItem See below.
Laurence Lundblade37286c02022-09-03 10:05:02 -07007102 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07007103 * This is for decimal fractions and big floats, both of which are an
7104 * exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07007105 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07007106 * If the item item had a tag number indicating it was a
7107 * decimal fraction or big float, then the input @c pItem will
7108 * have been decoded as exponent and mantissa. If there was
7109 * no tag number, the caller is asking this be decoded as a
7110 * big float or decimal fraction and @c pItem just has the
7111 * first item in an exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07007112 *
7113 * On output, the item is always a fully decoded decimal fraction or
7114 * big float.
7115 *
7116 * This errors out if the input type does not meet the TagSpec.
7117 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07007118static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007119QCBOR_Private_ExpMantissaTypeHandler(QCBORDecodeContext *pMe,
7120 const QCBOR_Private_TagSpec TagSpec,
7121 QCBORItem *pItem)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007122{
7123 QCBORError uErr;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007124
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07007125 /* pItem could either be a decoded exponent and mantissa or
7126 * the opening array of an undecoded exponent and mantissa. This
Laurence Lundblade37286c02022-09-03 10:05:02 -07007127 * check will succeed on either, but doesn't say which it was.
7128 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007129 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07007130 if(uErr != QCBOR_SUCCESS) {
7131 goto Done;
7132 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007133
Laurence Lundblade37286c02022-09-03 10:05:02 -07007134 if(pItem->uDataType == QCBOR_TYPE_ARRAY) {
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07007135 /* The item is an array, which means is is an undecoded exponent
7136 * and mantissa. This call consumes the items in the array and
7137 * results in a decoded exponent and mantissa in pItem. This is
Laurence Lundblade37286c02022-09-03 10:05:02 -07007138 * the case where there was no tag.
7139 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007140 uErr = QCBORDecode_Private_ExpMantissa(pMe, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007141 if(uErr != QCBOR_SUCCESS) {
7142 goto Done;
7143 }
7144
Laurence Lundblade37286c02022-09-03 10:05:02 -07007145 /* The above decode didn't determine whether it is a decimal
7146 * fraction or big num. Which of these two depends on what the
7147 * caller wants it decoded as since there is no tag, so fish the
7148 * type out of the TagSpec. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007149 pItem->uDataType = QCBOR_Private_ExpMantissaDataType(TagSpec.uTaggedTypes[0], pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07007150
7151 /* No need to check the type again. All that we need to know was
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07007152 * that it decoded correctly as a exponent and mantissa. The
Laurence Lundblade37286c02022-09-03 10:05:02 -07007153 * QCBOR type is set out by what was requested.
7154 */
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007155 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07007156
7157 /* If the item was not an array and the check passed, then
7158 * it is a fully decoded big float or decimal fraction and
7159 * matches what is requested.
7160 */
7161
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007162Done:
7163 return uErr;
7164}
7165
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007166
Laurence Lundblade37286c02022-09-03 10:05:02 -07007167/* Some notes from the work to disable tags.
7168 *
7169 * The API for big floats and decimal fractions seems good.
7170 * If there's any issue with it it's that the code size to
7171 * implement is a bit large because of the conversion
7172 * to/from int and bignum that is required. There is no API
7173 * that doesn't do the conversion so dead stripping will never
7174 * leave that code out.
7175 *
7176 * The implementation itself seems correct, but not as clean
7177 * and neat as it could be. It could probably be smaller too.
7178 *
7179 * The implementation has three main parts / functions
7180 * - The decoding of the array of two
7181 * - All the tag and type checking for the various API functions
7182 * - Conversion to/from bignum and int
7183 *
7184 * The type checking seems like it wastes the most code for
7185 * what it needs to do.
7186 *
7187 * The inlining for the conversion is probably making the
7188 * overall code base larger.
7189 *
7190 * The tests cases could be organized a lot better and be
7191 * more thorough.
7192 *
7193 * Seems also like there could be more common code in the
7194 * first tier part of the public API. Some functions only
7195 * vary by a TagSpec.
7196 */
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007197
7198/**
7199 * @brief Common processor for exponent and mantissa.
7200 *
7201 * @param[in] pMe The decode context.
7202 * @param[in] TagSpec The expected/allowed tags.
7203 * @param[in] pItem The data item to process.
7204 * @param[out] pnMantissa The returned mantissa as an int64_t.
7205 * @param[out] pnExponent The returned exponent as an int64_t.
7206 *
7207 * This handles exponent and mantissa for base 2 and 10. This
7208 * is limited to a mantissa that is an int64_t. See also
7209 * QCBORDecode_Private_ProcessExpMantissaBig().
7210 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007211static void
7212QCBOR_Private_ProcessExpMantissa(QCBORDecodeContext *pMe,
7213 const QCBOR_Private_TagSpec TagSpec,
7214 QCBORItem *pItem,
7215 int64_t *pnMantissa,
7216 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007217{
7218 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007219
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07007220 if(pMe->uLastError) {
7221 return;
7222 }
7223
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007224 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007225 if(uErr != QCBOR_SUCCESS) {
7226 goto Done;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007227 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007228
Laurence Lundblade9b334962020-08-27 10:55:53 -07007229 switch (pItem->uDataType) {
7230
7231 case QCBOR_TYPE_DECIMAL_FRACTION:
7232 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade9b334962020-08-27 10:55:53 -07007233 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade37286c02022-09-03 10:05:02 -07007234 *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
Laurence Lundblade9b334962020-08-27 10:55:53 -07007235 break;
7236
Laurence Lundblade37286c02022-09-03 10:05:02 -07007237#ifndef QCBOR_DISABLE_TAGS
7238 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundblade9b334962020-08-27 10:55:53 -07007239 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
7240 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
7241 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007242 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07007243 break;
7244
7245 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
7246 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
7247 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007248 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07007249 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07007250#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07007251
7252 default:
7253 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
7254 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007255
7256 Done:
7257 pMe->uLastError = (uint8_t)uErr;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007258}
7259
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007260
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007261/**
7262 * @brief Decode exponent and mantissa into a big number.
7263 *
7264 * @param[in] pMe The decode context.
7265 * @param[in] TagSpec The expected/allowed tags.
7266 * @param[in] pItem Item to decode and convert.
7267 * @param[in] BufferForMantissa Buffer to output mantissa into.
7268 * @param[out] pMantissa The output mantissa.
7269 * @param[out] pbIsNegative The sign of the output.
7270 * @param[out] pnExponent The mantissa of the output.
7271 *
7272 * This is the common processing of a decimal fraction or a big float
7273 * into a big number. This will decode and consume all the CBOR items
7274 * that make up the decimal fraction or big float.
7275 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007276static void
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007277QCBORDecode_Private_ProcessExpMantissaBig(QCBORDecodeContext *pMe,
7278 const QCBOR_Private_TagSpec TagSpec,
7279 QCBORItem *pItem,
7280 const UsefulBuf BufferForMantissa,
7281 UsefulBufC *pMantissa,
7282 bool *pbIsNegative,
7283 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007284{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007285 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007286
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07007287 if(pMe->uLastError != QCBOR_SUCCESS) {
7288 return;
7289 }
7290
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007291 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007292 if(uErr != QCBOR_SUCCESS) {
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007293 goto Done;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007294 }
7295
7296 uint64_t uMantissa;
7297
7298 switch (pItem->uDataType) {
7299
7300 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007301 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07007302 /* See comments in ExponentiateNN() on handling INT64_MIN */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007303 if(pItem->val.expAndMantissa.Mantissa.nInt >= 0) {
7304 uMantissa = (uint64_t)pItem->val.expAndMantissa.Mantissa.nInt;
7305 *pbIsNegative = false;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07007306 } else if(pItem->val.expAndMantissa.Mantissa.nInt != INT64_MIN) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007307 uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt;
7308 *pbIsNegative = true;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07007309 } else {
7310 uMantissa = (uint64_t)INT64_MAX+1;
7311 *pbIsNegative = true;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007312 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007313 *pMantissa = QCBOR_Private_ConvertIntToBigNum(uMantissa,
7314 BufferForMantissa);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007315 *pnExponent = pItem->val.expAndMantissa.nExponent;
7316 break;
7317
Laurence Lundblade37286c02022-09-03 10:05:02 -07007318#ifndef QCBOR_DISABLE_TAGS
7319 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007320 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007321 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007322 *pnExponent = pItem->val.expAndMantissa.nExponent;
7323 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
7324 *pbIsNegative = false;
7325 break;
7326
7327 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007328 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007329 *pnExponent = pItem->val.expAndMantissa.nExponent;
7330 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
7331 *pbIsNegative = true;
7332 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07007333#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007334
7335 default:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007336 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007337 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007338
7339Done:
7340 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007341}
7342
7343
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007344/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007345 * Public function, see header qcbor/qcbor_decode.h file
7346 */
7347void
7348QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe,
7349 const uint8_t uTagRequirement,
7350 int64_t *pnMantissa,
7351 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007352{
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007353 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07007354 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007355
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007356 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007357 {
7358 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007359 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7360 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7361 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007362 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007363
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007364 QCBOR_Private_ProcessExpMantissa(pMe,
7365 TagSpec,
7366 &Item,
7367 pnMantissa,
7368 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007369}
7370
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007371
7372/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007373 * Public function, see header qcbor/qcbor_decode.h file
7374 */
7375void
7376QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe,
7377 const int64_t nLabel,
7378 const uint8_t uTagRequirement,
7379 int64_t *pnMantissa,
7380 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007381{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007382 QCBORItem Item;
7383 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7384
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007385 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007386 {
7387 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007388 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7389 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7390 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007391 };
7392
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007393 QCBOR_Private_ProcessExpMantissa(pMe,
7394 TagSpec,
7395 &Item,
7396 pnMantissa,
7397 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007398}
7399
7400
7401/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007402 * Public function, see header qcbor/qcbor_decode.h file
7403 */
7404void
7405QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
7406 const char *szLabel,
7407 const uint8_t uTagRequirement,
7408 int64_t *pnMantissa,
7409 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007410{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007411 QCBORItem Item;
7412 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7413
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007414 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007415 {
7416 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007417 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7418 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7419 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007420 };
Laurence Lundblade9b334962020-08-27 10:55:53 -07007421
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007422 QCBOR_Private_ProcessExpMantissa(pMe,
7423 TagSpec,
7424 &Item,
7425 pnMantissa,
7426 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007427}
7428
7429
7430/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007431 * Public function, see header qcbor/qcbor_decode.h file
7432 */
7433void
7434QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe,
7435 const uint8_t uTagRequirement,
7436 const UsefulBuf MantissaBuffer,
7437 UsefulBufC *pMantissa,
7438 bool *pbMantissaIsNegative,
7439 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007440{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007441 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07007442 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007443
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007444 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007445 {
7446 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007447 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7448 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7449 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007450 };
7451
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007452 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7453 TagSpec,
7454 &Item,
7455 MantissaBuffer,
7456 pMantissa,
7457 pbMantissaIsNegative,
7458 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007459}
7460
7461
7462/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007463 * Public function, see header qcbor/qcbor_decode.h file
7464 */
7465void
7466QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe,
7467 const int64_t nLabel,
7468 const uint8_t uTagRequirement,
7469 const UsefulBuf BufferForMantissa,
7470 UsefulBufC *pMantissa,
7471 bool *pbIsNegative,
7472 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007473{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007474
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007475 QCBORItem Item;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007476 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007477
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007478 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007479 {
7480 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007481 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7482 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7483 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007484 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007485
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007486 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7487 TagSpec,
7488 &Item,
7489 BufferForMantissa,
7490 pMantissa,
7491 pbIsNegative,
7492 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007493}
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007494
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007495
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007496/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007497 * Public function, see header qcbor/qcbor_decode.h file
7498 */
7499void
7500QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe,
7501 const char *szLabel,
7502 const uint8_t uTagRequirement,
7503 const UsefulBuf BufferForMantissa,
7504 UsefulBufC *pMantissa,
7505 bool *pbIsNegative,
7506 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007507{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007508 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007509 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007510
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007511 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007512 {
7513 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007514 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7515 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7516 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007517 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007518
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007519 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7520 TagSpec,
7521 &Item,
7522 BufferForMantissa,
7523 pMantissa,
7524 pbIsNegative,
7525 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007526}
7527
7528
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007529/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007530 * Public function, see header qcbor/qcbor_decode.h file
7531 */
7532void
7533QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe,
7534 const uint8_t uTagRequirement,
7535 int64_t *pnMantissa,
7536 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007537{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007538 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07007539 QCBORDecode_VGetNext(pMe, &Item);
7540
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007541 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007542 {
7543 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007544 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7545 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7546 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007547 };
7548
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007549 QCBOR_Private_ProcessExpMantissa(pMe,
7550 TagSpec,
7551 &Item,
7552 pnMantissa,
7553 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007554}
7555
7556
7557/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007558 * Public function, see header qcbor/qcbor_decode.h file
7559 */
7560void
7561QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe,
7562 const int64_t nLabel,
7563 const uint8_t uTagRequirement,
7564 int64_t *pnMantissa,
7565 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007566{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007567 QCBORItem Item;
7568 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007569
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007570 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007571 {
7572 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007573 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7574 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7575 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007576 };
7577
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007578 QCBOR_Private_ProcessExpMantissa(pMe,
7579 TagSpec,
7580 &Item,
7581 pnMantissa,
7582 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007583}
7584
7585
7586/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007587 * Public function, see header qcbor/qcbor_decode.h file
7588 */
7589void
7590QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe,
7591 const char *szLabel,
7592 const uint8_t uTagRequirement,
7593 int64_t *pnMantissa,
7594 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007595{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007596 QCBORItem Item;
7597 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007598
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007599 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007600 {
7601 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007602 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7603 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7604 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007605 };
7606
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007607 QCBOR_Private_ProcessExpMantissa(pMe,
7608 TagSpec,
7609 &Item,
7610 pnMantissa,
7611 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007612}
7613
7614
7615/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007616 * Public function, see header qcbor/qcbor_decode.h file
7617 */
7618void
7619QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe,
7620 const uint8_t uTagRequirement,
7621 const UsefulBuf MantissaBuffer,
7622 UsefulBufC *pMantissa,
7623 bool *pbMantissaIsNegative,
7624 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007625{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007626 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07007627 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007628
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007629 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007630 {
7631 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007632 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7633 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7634 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007635 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007636
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007637 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7638 TagSpec,
7639 &Item,
7640 MantissaBuffer,
7641 pMantissa,
7642 pbMantissaIsNegative,
7643 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007644}
7645
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007646
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007647/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007648 * Public function, see header qcbor/qcbor_decode.h file
7649 */
7650void
7651QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe,
7652 const int64_t nLabel,
7653 const uint8_t uTagRequirement,
7654 const UsefulBuf BufferForMantissa,
7655 UsefulBufC *pMantissa,
7656 bool *pbIsNegative,
7657 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007658{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007659 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007660 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007661
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007662 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007663 {
7664 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007665 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7666 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7667 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007668 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007669
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007670 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7671 TagSpec,
7672 &Item,
7673 BufferForMantissa,
7674 pMantissa,
7675 pbIsNegative,
7676 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007677}
7678
7679
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007680/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007681 * Public function, see header qcbor/qcbor_decode.h file
7682 */
7683void
7684QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe,
7685 const char *szLabel,
7686 const uint8_t uTagRequirement,
7687 const UsefulBuf BufferForMantissa,
7688 UsefulBufC *pMantissa,
7689 bool *pbIsNegative,
7690 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007691{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007692 QCBORItem Item;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007693 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007694
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007695 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007696 {
7697 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007698 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7699 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7700 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007701 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007702
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007703 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7704 TagSpec,
7705 &Item,
7706 BufferForMantissa,
7707 pMantissa,
7708 pbIsNegative,
7709 pnExponent);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007710}
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007711
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07007712#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007713
7714
7715#if !defined(USEFULBUF_DISABLE_ALL_FLOAT) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
7716/*
7717 * Public function, see header qcbor/qcbor_spiffy_decode.h file
7718 */
7719void
7720QCBORDecode_GetNumberConvertPrecisely(QCBORDecodeContext *pMe,
7721 QCBORItem *pNumber)
7722{
7723 QCBORItem Item;
7724 struct IEEE754_ToInt ToInt;
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007725 double dNum;
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007726 QCBORError uError;
7727
7728 if(pMe->uLastError != QCBOR_SUCCESS) {
7729 return;
7730 }
7731
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007732 // TODO:VGetNext?
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007733 uError = QCBORDecode_GetNext(pMe, &Item);
7734 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007735 *pNumber = Item;
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007736 pMe->uLastError = (uint8_t)uError;
7737 return;
7738 }
7739
7740 switch(Item.uDataType) {
7741 case QCBOR_TYPE_INT64:
7742 case QCBOR_TYPE_UINT64:
7743 *pNumber = Item;
7744 break;
7745
7746 case QCBOR_TYPE_DOUBLE:
7747 ToInt = IEEE754_DoubleToInt(Item.val.dfnum);
7748 if(ToInt.type == IEEE754_ToInt_IS_INT) {
7749 pNumber->uDataType = QCBOR_TYPE_INT64;
7750 pNumber->val.int64 = ToInt.integer.is_signed;
7751 } else if(ToInt.type == IEEE754_ToInt_IS_UINT) {
7752 if(ToInt.integer.un_signed <= INT64_MAX) {
7753 /* Do the same as base QCBOR integer decoding */
7754 pNumber->uDataType = QCBOR_TYPE_INT64;
7755 pNumber->val.int64 = (int64_t)ToInt.integer.un_signed;
7756 } else {
7757 pNumber->uDataType = QCBOR_TYPE_UINT64;
7758 pNumber->val.uint64 = ToInt.integer.un_signed;
7759 }
7760 } else {
7761 *pNumber = Item;
7762 }
7763 break;
7764
7765 case QCBOR_TYPE_FLOAT:
7766 ToInt = IEEE754_SingleToInt(Item.val.fnum);
7767 if(ToInt.type == IEEE754_ToInt_IS_INT) {
7768 pNumber->uDataType = QCBOR_TYPE_INT64;
7769 pNumber->val.int64 = ToInt.integer.is_signed;
7770 } else if(ToInt.type == IEEE754_ToInt_IS_UINT) {
7771 if(ToInt.integer.un_signed <= INT64_MAX) {
7772 /* Do the same as base QCBOR integer decoding */
7773 pNumber->uDataType = QCBOR_TYPE_INT64;
7774 pNumber->val.int64 = (int64_t)ToInt.integer.un_signed;
7775 } else {
7776 pNumber->uDataType = QCBOR_TYPE_UINT64;
7777 pNumber->val.uint64 = ToInt.integer.un_signed;
7778 }
7779 } else {
7780 *pNumber = Item;
7781 }
7782 break;
7783
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007784 case QCBOR_TYPE_65BIT_NEG_INT:
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007785 if(Item.val.uint64 == UINT64_MAX) {
7786 /* The value -18446744073709551616 is encoded as an
7787 * unsigned 18446744073709551615. It's a whole number that
7788 * needs to be returned as a double. It can't be handled
7789 * by IEEE754_UintToDouble because 18446744073709551616
7790 * doesn't fit into a uint64_t. You can't get it by adding
7791 * 1 to 18446744073709551615.
7792 */
7793 pNumber->val.dfnum = -18446744073709551616.0;
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007794 pNumber->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007795 } else {
7796 dNum = IEEE754_UintToDouble(Item.val.uint64 + 1, 1);
7797 if(dNum == IEEE754_UINT_TO_DOUBLE_OOB) {
7798 *pNumber = Item;
7799 } else {
7800 pNumber->val.dfnum = dNum;
7801 pNumber->uDataType = QCBOR_TYPE_DOUBLE;
7802 }
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007803 }
7804 break;
7805
7806 default:
7807 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
7808 pNumber->uDataType = QCBOR_TYPE_NONE;
7809 break;
7810 }
7811}
7812
7813#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT && ! QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007814
7815
7816static UsefulBufC
7817QCBORDecode_IntToBigNum(uint64_t uNum,
7818 const UsefulBuf BigNumBuf)
7819{
7820 UsefulOutBuf OB;
7821
7822 /* With a UsefulOutBuf, there's no pointer math here. */
7823 UsefulOutBuf_Init(&OB, BigNumBuf);
7824
7825 /* Must copy one byte even if zero. The loop, mask and shift
7826 * algorithm provides endian conversion.
7827 */
7828 do {
7829 UsefulOutBuf_InsertByte(&OB, uNum & 0xff, 0);
7830 uNum >>= 8;
7831 } while(uNum);
7832
7833 return UsefulOutBuf_OutUBuf(&OB);
7834}
7835
7836
7837static UsefulBufC
7838QCBORDecode_Private_RemoveLeadingZeros(UsefulBufC String)
7839{
7840 while(String.len > 1) {
7841 if(*(const uint8_t *)String.ptr) {
7842 break;
7843 }
7844 String.len--;
7845 String.ptr = (const uint8_t *)String.ptr + 1;
7846 }
7847
7848 return String;
7849}
7850
7851
7852/* Add one to the big number and put the result in a new UsefulBufC
7853 * from storage in UsefulBuf.
7854 *
7855 * Leading zeros must be removed before calling this.
7856 *
7857 * Code Reviewers: THIS FUNCTION DOES POINTER MATH
7858 */
7859static UsefulBufC
7860QCBORDecode_BigNumCopyPlusOne(UsefulBufC BigNum,
7861 UsefulBuf BigNumBuf)
7862{
7863 uint8_t uCarry;
7864 uint8_t uSourceValue;
7865 const uint8_t *pSource;
7866 uint8_t *pDest;
7867 ptrdiff_t uDestBytesLeft;
7868
7869 /* Start adding at the LSB */
7870 pSource = &((const uint8_t *)BigNum.ptr)[BigNum.len-1];
7871 pDest = &((uint8_t *)BigNumBuf.ptr)[BigNumBuf.len-1];
7872
7873 uCarry = 1; /* Gets set back to zero if add the next line doesn't wrap */
7874 *pDest = *pSource + 1;
7875 while(1) {
7876 /* Wrap around from 0xff to 0 is a defined operation for
7877 unsigned addition in C. */
7878 if(*pDest != 0) {
7879 /* The add operation didn't wrap so no more carry. This
7880 * funciton only adds one, so when there is no more carry,
7881 * carrying is over to the end.
7882 */
7883 uCarry = 0;
7884 }
7885
7886 uDestBytesLeft = pDest - (uint8_t *)BigNumBuf.ptr;
7887 if(pSource <= (const uint8_t *)BigNum.ptr && uCarry == 0) {
7888 break; /* Successful exit */
7889 }
7890 if(pSource > (const uint8_t *)BigNum.ptr) {
7891 uSourceValue = *--pSource;
7892 } else {
7893 /* All source bytes processed, but not the last carry */
7894 uSourceValue = 0;
7895 }
7896
7897 pDest--;
7898 if(uDestBytesLeft < 0) {
7899 return NULLUsefulBufC; /* Not enough space in destination buffer */
7900 }
7901
7902 *pDest = uSourceValue + uCarry;
7903 }
7904
7905 return (UsefulBufC){pDest, BigNumBuf.len - (size_t)uDestBytesLeft};
7906}
7907
7908
7909/* This returns 1 when uNum is 0 */
7910static size_t
7911QCBORDecode_Private_CountNonZeroBytes(uint64_t uNum)
7912{
7913 size_t uCount = 0;
7914 do {
7915 uCount++;
7916 uNum >>= 8;
7917 } while(uNum);
7918
7919 return uCount;
7920}
7921
7922
7923/*
7924 * Public function, see header qcbor/qcbor_decode.h
7925 */
7926QCBORError
7927QCBORDecode_BignumPreferred(const QCBORItem Item,
7928 UsefulBuf BigNumBuf,
7929 UsefulBufC *pBigNum,
7930 bool *pbIsNegative)
7931{
7932 QCBORError uResult;
7933 size_t uLen;
7934 UsefulBufC BigNum;
7935 int uType;
7936
7937 uType = Item.uDataType;
7938 if(uType == QCBOR_TYPE_BYTE_STRING) {
7939 uType = *pbIsNegative ? QCBOR_TYPE_POSBIGNUM : QCBOR_TYPE_NEGBIGNUM;
7940 }
7941
7942 static const uint8_t Zero[] = {0x00};
7943 BigNum = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(Zero);
7944 if((uType == QCBOR_TYPE_POSBIGNUM || uType == QCBOR_TYPE_NEGBIGNUM) &&
7945 Item.val.bigNum.len) {
7946 BigNum = QCBORDecode_Private_RemoveLeadingZeros(Item.val.bigNum);
7947 }
7948
7949 /* Compute required length so it can be returned if buffer is too small */
7950 switch(uType) {
7951 case QCBOR_TYPE_INT64:
7952 uLen = QCBORDecode_Private_CountNonZeroBytes((uint64_t)(Item.val.int64 < 0 ? -Item.val.int64 : Item.val.int64));
7953 break;
7954
7955 case QCBOR_TYPE_UINT64:
7956 uLen = QCBORDecode_Private_CountNonZeroBytes(Item.val.uint64);
7957 break;
7958
7959 case QCBOR_TYPE_65BIT_NEG_INT:
7960 uLen = Item.val.uint64 == UINT64_MAX ? 9 : QCBORDecode_Private_CountNonZeroBytes(Item.val.uint64);
7961 break;
7962
7963 case QCBOR_TYPE_POSBIGNUM:
7964 uLen = BigNum.len;
7965 break;
7966
7967 case QCBOR_TYPE_NEGBIGNUM:
7968 uLen = BigNum.len;
7969 if(UsefulBuf_IsValue(BigNum, 0xff) == SIZE_MAX) {
7970 uLen++;
7971 }
7972 break;
7973
7974 default:
7975 uLen = 0;
7976 }
7977
7978 *pBigNum = (UsefulBufC){NULL, uLen};
7979
7980 if(BigNumBuf.len < uLen || uLen == 0 || BigNumBuf.ptr == NULL) {
7981 return BigNumBuf.ptr == NULL ? QCBOR_SUCCESS : QCBOR_ERR_BUFFER_TOO_SMALL;
7982 /* Buffer is too short or type is wrong */
7983 }
7984
7985 uResult = QCBOR_SUCCESS;
7986
7987 if(uType == QCBOR_TYPE_POSBIGNUM) {
7988 *pBigNum = UsefulBuf_Copy(BigNumBuf, BigNum);
7989 *pbIsNegative = false;
7990 } else if(uType == QCBOR_TYPE_UINT64) {
7991 *pBigNum = QCBORDecode_IntToBigNum(Item.val.uint64, BigNumBuf);
7992 *pbIsNegative = false;
7993 } else if(uType == QCBOR_TYPE_INT64) {
7994 *pbIsNegative = Item.val.int64 < 0;
7995 *pBigNum = QCBORDecode_IntToBigNum((uint64_t)(*pbIsNegative ? -Item.val.int64 : Item.val.int64), BigNumBuf);
7996 } else if(uType == QCBOR_TYPE_65BIT_NEG_INT) {
7997 *pbIsNegative = true;
7998 if(Item.val.uint64 == UINT64_MAX) {
7999 /* The one value that can't be done with a computation
8000 * because it would overflow a uint64_t*/
8001 static const uint8_t TwoToThe64[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
8002 *pBigNum = UsefulBuf_Copy(BigNumBuf, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(TwoToThe64));
8003 } else {
8004 *pBigNum = QCBORDecode_IntToBigNum(Item.val.uint64 + 1, BigNumBuf);
8005 }
8006 } else if(uType == QCBOR_TYPE_NEGBIGNUM) {
8007 /* The messy one. Take the stuff in the buffer and copy it to
8008 * the new buffer, adding one to it. This might be one byte
8009 * bigger than the original because of the carry from adding
8010 * one.*/
8011 *pbIsNegative = true;
8012 *pBigNum = QCBORDecode_BigNumCopyPlusOne(BigNum, BigNumBuf);
8013
8014 } else {
8015 uResult = QCBOR_ERR_UNEXPECTED_TYPE;
8016 }
8017
8018 return uResult;
8019}
8020
8021
8022static QCBORError
8023QCBOR_Private_ProcessPreferredBigNum(const uint8_t uTagRequirement,
8024 const QCBORItem *pItem,
8025 UsefulBuf BigNumBuf,
8026 UsefulBufC *pValue,
8027 bool *pbIsNegative)
8028{
8029 if(pItem->uDataType != QCBOR_TYPE_INT64 &&
8030 pItem->uDataType != QCBOR_TYPE_UINT64 &&
8031 pItem->uDataType != QCBOR_TYPE_65BIT_NEG_INT) {
8032
8033 /* The integer types are always OK. If it's not an integer type drop
8034 * in to the tag type checking system. */
8035 const QCBOR_Private_TagSpec TagSpec =
8036 {
8037 uTagRequirement,
8038 {QCBOR_TYPE_POSBIGNUM, QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
8039 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
8040 };
8041
8042 QCBORError uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
8043 if(uErr != QCBOR_SUCCESS) {
8044 return uErr;
8045 }
8046 }
8047
8048 return QCBORDecode_BignumPreferred(*pItem, BigNumBuf, pValue, pbIsNegative);
8049}
8050
8051
8052/*
8053 * Public function, see header qcbor/qcbor_decode.h
8054 */
8055void
8056QCBORDecode_GetBigNumPreferred(QCBORDecodeContext *pMe,
8057 const uint8_t uTagRequirement,
8058 UsefulBuf BigNumBuf,
8059 UsefulBufC *pValue,
8060 bool *pbIsNegative)
8061{
8062 QCBORItem Item;
8063
8064 if(pMe->uLastError != QCBOR_SUCCESS) {
8065 /* Already in error state, do nothing */
8066 return;
8067 }
8068
8069 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
8070 if(uError != QCBOR_SUCCESS) {
8071 pMe->uLastError = (uint8_t)uError;
8072 return;
8073 }
8074
8075 QCBOR_Private_ProcessPreferredBigNum(uTagRequirement, &Item, BigNumBuf, pValue, pbIsNegative);
8076}
8077
8078
8079/*
8080 * Public function, see header qcbor/qcbor_decode.h
8081 */
8082void
8083QCBORDecode_GetPreferredBignumInMapN(QCBORDecodeContext *pMe,
8084 const int64_t nLabel,
8085 const uint8_t uTagRequirement,
8086 UsefulBuf BigNumBuf,
8087 UsefulBufC *pValue,
8088 bool *pbIsNegative)
8089{
8090 QCBORItem Item;
8091 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
8092 if(pMe->uLastError != QCBOR_SUCCESS) {
8093 return;
8094 }
8095
8096 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessPreferredBigNum(uTagRequirement,
8097 &Item,
8098 BigNumBuf,
8099 pValue,
8100 pbIsNegative);
8101}
8102
8103/*
8104 * Public function, see header qcbor/qcbor_decode.h
8105 */
8106void
8107QCBORDecode_GetPreferredBignumInMapSZ(QCBORDecodeContext *pMe,
8108 const char * szLabel,
8109 const uint8_t uTagRequirement,
8110 UsefulBuf BigNumBuf,
8111 UsefulBufC *pValue,
8112 bool *pbIsNegative)
8113{
8114 QCBORItem Item;
8115 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
8116 if(pMe->uLastError != QCBOR_SUCCESS) {
8117 return;
8118 }
8119
8120 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessPreferredBigNum(uTagRequirement,
8121 &Item,
8122 BigNumBuf,
8123 pValue,
8124 pbIsNegative);
8125}
8126
8127