blob: 05363f008e768f57daeca228b023b78090326e90 [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
898 * so. All integers in the CBOR structure are positive and the major
899 * type indicates positive or negative. CBOR can express positive
900 * integers up to 2^x - 1 where x is the number of bits and negative
901 * integers down to 2^x. Note that negative numbers can be one more
902 * away from zero than positive. Stdint, as far as I can tell, uses
903 * two's compliment to represent negative integers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700904 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700905static QCBORError
906QCBOR_Private_DecodeInteger(const int nMajorType,
907 const uint64_t uArgument,
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700908 const int nAdditionalInfo,
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700909 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700910{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800911 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800912
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700913 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
914 uReturn = QCBOR_ERR_BAD_INT;
915 goto Done;
916 }
917
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700918 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800919 if (uArgument <= INT64_MAX) {
920 pDecodedItem->val.int64 = (int64_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700921 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800922
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700923 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800924 pDecodedItem->val.uint64 = uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700925 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700926 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800927
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700928 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800929 if(uArgument <= INT64_MAX) {
930 /* CBOR's representation of negative numbers lines up with
931 * the two-compliment representation. A negative integer has
932 * one more in range than a positive integer. INT64_MIN is
933 * equal to (-INT64_MAX) - 1.
934 */
935 pDecodedItem->val.int64 = (-(int64_t)uArgument) - 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700936 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800937
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700938 } else {
Laurence Lundblade2d493002024-02-01 11:09:17 -0700939 pDecodedItem->val.uint64 = uArgument;
940 pDecodedItem->uDataType = QCBOR_TYPE_65BIT_NEG_INT;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700941 }
942 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800943
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700944Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800945 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700946}
947
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800948
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700949/**
950 * @brief Decode text and byte strings
951 *
952 * @param[in] pMe Decoder context.
953 * @param[in] bAllocate Whether to allocate and copy string.
954 * @param[in] nMajorType Whether it is a byte or text string.
955 * @param[in] uStrLen The length of the string.
956 * @param[in] nAdditionalInfo Whether it is an indefinite-length string.
957 * @param[out] pDecodedItem The filled-in decoded item.
958 *
959 * @retval QCBOR_ERR_HIT_END Unexpected end of input.
960 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
961 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
962 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator
963 *
964 * This reads @c uStrlen bytes from the input and fills in @c
965 * pDecodedItem. If @c bAllocate is true, then memory for the string
966 * is allocated.
967 */
968static QCBORError
969QCBOR_Private_DecodeString(QCBORDecodeContext *pMe,
970 const bool bAllocate,
971 const int nMajorType,
972 const uint64_t uStrLen,
973 const int nAdditionalInfo,
974 QCBORItem *pDecodedItem)
975{
976 QCBORError uReturn = QCBOR_SUCCESS;
977
978 /* ---- Figure out the major type ---- */
979 #if CBOR_MAJOR_TYPE_BYTE_STRING + 4 != QCBOR_TYPE_BYTE_STRING
980 #error QCBOR_TYPE_BYTE_STRING not lined up with major type
981 #endif
982
983 #if CBOR_MAJOR_TYPE_TEXT_STRING + 4 != QCBOR_TYPE_TEXT_STRING
984 #error QCBOR_TYPE_TEXT_STRING not lined up with major type
985 #endif
986 pDecodedItem->uDataType = (uint8_t)(nMajorType + 4);
987
988 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
989 /* --- Just the head of an indefinite-length string --- */
990 pDecodedItem->val.string = (UsefulBufC){NULL, QCBOR_STRING_LENGTH_INDEFINITE};
991
992 } else {
993 /* --- A definite-length string --- */
994 /* --- (which might be a chunk of an indefinte-length string) --- */
995
996 /* CBOR lengths can be 64 bits, but size_t is not 64 bits on all
997 * CPUs. This check makes the casts to size_t below safe.
998 *
999 * The max is 4 bytes less than the largest sizeof() so this can be
1000 * tested by putting a SIZE_MAX length in the CBOR test input (no
1001 * one will care the limit on strings is 4 bytes shorter).
1002 */
1003 if(uStrLen > SIZE_MAX-4) {
1004 uReturn = QCBOR_ERR_STRING_TOO_LONG;
1005 goto Done;
1006 }
1007
1008 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(&(pMe->InBuf), (size_t)uStrLen);
1009 if(UsefulBuf_IsNULLC(Bytes)) {
1010 /* Failed to get the bytes for this string item */
1011 uReturn = QCBOR_ERR_HIT_END;
1012 goto Done;
1013 }
1014
1015 if(bAllocate) {
1016#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
1017 /* --- Put string in allocated memory --- */
1018
1019 /* Note that this is not where allocation to coalesce
1020 * indefinite-length strings is done. This is for when the
1021 * caller has requested all strings be allocated. Disabling
1022 * indefinite length strings also disables this allocate-all
1023 * option.
1024 */
1025
1026 if(pMe->StringAllocator.pfAllocator == NULL) {
1027 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1028 goto Done;
1029 }
1030 UsefulBuf NewMem = StringAllocator_Allocate(&(pMe->StringAllocator), (size_t)uStrLen);
1031 if(UsefulBuf_IsNULL(NewMem)) {
1032 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1033 goto Done;
1034 }
1035 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
1036 pDecodedItem->uDataAlloc = 1;
1037#else
1038 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1039#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1040 } else {
1041 /* --- Normal case with no string allocator --- */
1042 pDecodedItem->val.string = Bytes;
1043 }
1044 }
1045
1046Done:
1047 return uReturn;
1048}
1049
1050
1051/**
1052 * @brief Decode array or map.
1053 *
1054 * @param[in] uMode Decoder mode.
1055 * @param[in] nMajorType Whether it is a byte or text string.
1056 * @param[in] uItemCount The length of the string.
1057 * @param[in] nAdditionalInfo Whether it is an indefinite-length.
1058 * @param[out] pDecodedItem The filled-in decoded item.
1059 *
1060 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinites disabled.
1061 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map.
1062 *
1063 * Not much to do for arrays and maps. Just the type item count (but a
1064 * little messy because of ifdefs for indefinite-lengths and
1065 * map-as-array decoding).
1066 *
1067 * This also does the bulk of the work for @ref
1068 * QCBOR_DECODE_MODE_MAP_AS_ARRAY, a special mode to handle
1069 * arbitrarily complex map labels. This ifdefs out with
1070 * QCBOR_DISABLE_NON_INTEGER_LABELS.
1071 */
1072static QCBORError
1073QCBOR_Private_DecodeArrayOrMap(const uint8_t uMode,
1074 const int nMajorType,
1075 const uint64_t uItemCount,
1076 const int nAdditionalInfo,
1077 QCBORItem *pDecodedItem)
1078{
1079 QCBORError uReturn;
1080
1081 /* ------ Sort out the data type ------ */
1082 #if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
1083 #error QCBOR_TYPE_ARRAY value not lined up with major type
1084 #endif
1085
1086 #if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
1087 #error QCBOR_TYPE_MAP value not lined up with major type
1088 #endif
1089 pDecodedItem->uDataType = (uint8_t)nMajorType;
1090#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1091 if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
1092 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
1093 }
1094#else
1095 (void)uMode;
1096#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
1097
1098 uReturn = QCBOR_SUCCESS;
1099
1100 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1101 /* ------ Indefinite-length array/map ----- */
1102#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
1103 pDecodedItem->val.uCount = QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH;
1104#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1105 uReturn = QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED;
1106#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1107 } else {
1108
1109#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1110 if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
1111 /* ------ Definite-length map as array ------ */
1112
1113 if(uItemCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
1114 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
1115 } else {
1116 /* cast OK because of check above */
1117 pDecodedItem->val.uCount = (uint16_t)uItemCount*2;
1118 }
1119
1120 } else
1121#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
1122 {
1123 /* ------ Definite-length array/map ------ */
1124 if(uItemCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
1125 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
1126 } else {
1127 /* cast OK because of check above */
1128 pDecodedItem->val.uCount = (uint16_t)uItemCount;
1129 }
1130 }
1131 }
1132
1133 return uReturn;
1134}
1135
1136
1137/**
1138 * @brief Decode a tag number.
1139 *
1140 * @param[in] uTagNumber The length of the string.
1141 * @param[in] nAdditionalInfo So this can be error-checked.
1142 * @param[out] pDecodedItem The filled-in decoded item.
1143 *
1144 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo is LEN_IS_INDEFINITE.
1145 * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined.
1146 *
1147 * Not much to do for tags, but fill in pDecodedItem and check for
1148 * error in nAdditionalInfo.
1149 */
1150static QCBORError
1151QCBOR_Private_DecodeTag(const uint64_t uTagNumber,
1152 const int nAdditionalInfo,
1153 QCBORItem *pDecodedItem)
1154{
1155#ifndef QCBOR_DISABLE_TAGS
1156 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1157 return QCBOR_ERR_BAD_INT;
1158 } else {
1159 pDecodedItem->val.uTagV = uTagNumber;
1160 pDecodedItem->uDataType = QCBOR_TYPE_TAG;
1161 return QCBOR_SUCCESS;
1162 }
1163#else /* QCBOR_DISABLE_TAGS */
1164 (void)nAdditionalInfo;
Laurence Lundblade6c9a8242024-06-12 20:34:52 -07001165 (void)uTagNumber;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001166 (void)pDecodedItem;
1167 return QCBOR_ERR_TAGS_DISABLED;
1168#endif /* QCBOR_DISABLE_TAGS */
1169}
1170
1171
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001172#if !defined(QCBOR_DISABLE_DECODE_CONFORMANCE) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
1173
1174static QCBORError
1175QCBORDecode_Private_HalfConformance(const double d, const uint8_t uDecodeMode)
1176{
1177 struct IEEE754_ToInt ToInt;
1178
1179 /* Only need to check for conversion to integer because
1180 * half-precision is always preferred serialization. Don't
1181 * need special checker for half-precision because whole
1182 * numbers always convert perfectly from half to double.
1183 *
1184 * This catches half-precision with NaN payload too.
1185 *
1186 * The only thing allowed here is a double/half-precision that
1187 * can't be converted to anything but a double.
1188 */
1189 if(uDecodeMode >= QCBOR_DECODE_MODE_DCBOR) {
1190 ToInt = IEEE754_DoubleToInt(d);
1191 if(ToInt.type != QCBOR_TYPE_DOUBLE) {
1192 return QCBOR_ERR_DCBOR_CONFORMANCE;
1193 }
1194 }
1195
1196 return QCBOR_SUCCESS;
1197}
1198
1199
1200static QCBORError
1201QCBORDecode_Private_SingleConformance(const float f, const uint8_t uDecodeMode)
1202{
1203 struct IEEE754_ToInt ToInt;
1204 IEEE754_union ToSmaller;
1205
1206 if(uDecodeMode >= QCBOR_DECODE_MODE_DCBOR) {
1207 /* See if it could have been encoded as an integer */
1208 ToInt = IEEE754_SingleToInt(f);
1209 if(ToInt.type == IEEE754_ToInt_IS_INT || ToInt.type == IEEE754_ToInt_IS_UINT) {
1210 return QCBOR_ERR_DCBOR_CONFORMANCE;
1211 }
1212
1213 /* Make sure there is no NaN payload */
1214 if(IEEE754_SingleHasNaNPayload(f)) {
1215 return QCBOR_ERR_DCBOR_CONFORMANCE;
1216 }
1217 }
1218
1219 /* See if it could have been encoded shorter */
1220 if(uDecodeMode >= QCBOR_DECODE_MODE_PREFERRED) {
1221 ToSmaller = IEEE754_SingleToHalf(f, true);
1222 if(ToSmaller.uSize != sizeof(float)) {
1223 return QCBOR_ERR_PREFERRED_CONFORMANCE;
1224 }
1225 }
1226
1227 return QCBOR_SUCCESS;
1228}
1229
1230
1231static QCBORError
1232QCBORDecode_Private_DoubleConformance(const double d, uint8_t uDecodeMode)
1233{
1234 struct IEEE754_ToInt ToInt;
1235 IEEE754_union ToSmaller;
1236
1237 if(uDecodeMode >= QCBOR_DECODE_MODE_DCBOR) {
1238 /* See if it could have been encoded as an integer */
1239 ToInt = IEEE754_DoubleToInt(d);
1240 if(ToInt.type == IEEE754_ToInt_IS_INT || ToInt.type == IEEE754_ToInt_IS_UINT) {
1241 return QCBOR_ERR_DCBOR_CONFORMANCE;
1242 }
1243 /* Make sure there is no NaN payload */
1244 if(IEEE754_DoubleHasNaNPayload(d)) {
1245 return QCBOR_ERR_DCBOR_CONFORMANCE;
1246 }
1247 }
1248
1249 /* See if it could have been encoded shorter */
1250 if(uDecodeMode >= QCBOR_DECODE_MODE_PREFERRED) {
1251 ToSmaller = IEEE754_DoubleToSmaller(d, true, true);
1252 if(ToSmaller.uSize != sizeof(double)) {
1253 return QCBOR_ERR_PREFERRED_CONFORMANCE;
1254 }
1255 }
1256
1257 return QCBOR_SUCCESS;
1258}
1259#else /* ! QCBOR_DISABLE_PREFERRED_FLOAT && ! QCBOR_DISABLE_PREFERRED_FLOAT */
1260#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1261
1262static QCBORError
1263QCBORDecode_Private_SingleConformance(const float f, uint8_t uDecodeMode)
1264{
1265 (void)f;
1266 if(uDecodeMode >= QCBOR_DECODE_MODE_PREFERRED) {
1267 return QCBOR_ERR_CANT_CHECK_FLOAT_CONFORMANCE;
1268 } else {
1269 return QCBOR_SUCCESS;
1270 }
1271}
1272
1273static QCBORError
1274QCBORDecode_Private_DoubleConformance(const double d, uint8_t uDecodeMode)
1275{
1276 (void)d;
1277 if(uDecodeMode >= QCBOR_DECODE_MODE_PREFERRED) {
1278 return QCBOR_ERR_CANT_CHECK_FLOAT_CONFORMANCE;
1279 } else {
1280 return QCBOR_SUCCESS;
1281 }
1282}
1283#endif /* ! QCBOR_DISABLE_FLOAT_HW_USE */
1284#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE && ! QCBOR_DISABLE_PREFERRED_FLOAT */
1285
1286
1287
1288/*
1289 * Decode a float
1290 */
1291static QCBORError
1292QCBOR_Private_DecodeFloat(const uint8_t uDecodeMode,
1293 const int nAdditionalInfo,
1294 const uint64_t uArgument,
1295 QCBORItem *pDecodedItem)
1296{
1297 QCBORError uReturn = QCBOR_SUCCESS;
1298 float single;
1299
1300 (void)single; /* Avoid unused error from various #ifndefs */
1301
1302 switch(nAdditionalInfo) {
1303 case HALF_PREC_FLOAT: /* 25 */
1304#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
1305 /* Half-precision is returned as a double. The cast to
1306 * uint16_t is safe because the encoded value was 16 bits. It
1307 * was widened to 64 bits to be passed in here.
1308 */
1309 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uArgument);
1310 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
1311
1312 uReturn = QCBORDecode_Private_HalfConformance(pDecodedItem->val.dfnum, uDecodeMode);
1313 if(uReturn != QCBOR_SUCCESS) {
1314 break;
1315 }
1316#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
1317 uReturn = FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS);
1318 break;
1319
1320 case SINGLE_PREC_FLOAT: /* 26 */
1321#ifndef USEFULBUF_DISABLE_ALL_FLOAT
1322 /* Single precision is normally returned as a double since
1323 * double is widely supported, there is no loss of precision,
1324 * it makes it easy for the caller in most cases and it can
1325 * be converted back to single with no loss of precision
1326 *
1327 * The cast to uint32_t is safe because the encoded value was
1328 * 32 bits. It was widened to 64 bits to be passed in here.
1329 */
1330 single = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uArgument);
1331 uReturn = QCBORDecode_Private_SingleConformance(single, uDecodeMode);
1332 if(uReturn != QCBOR_SUCCESS) {
1333 break;
1334 }
1335
1336#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1337 /* In the normal case, use HW to convert float to
1338 * double. */
1339 pDecodedItem->val.dfnum = (double)single;
1340 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
1341#else /* QCBOR_DISABLE_FLOAT_HW_USE */
1342 /* Use of float HW is disabled, return as a float. */
1343 pDecodedItem->val.fnum = single;
1344 pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
1345
1346 /* IEEE754_FloatToDouble() could be used here to return as
1347 * a double, but it adds object code and most likely
1348 * anyone disabling FLOAT HW use doesn't care about floats
1349 * and wants to save object code.
1350 */
1351#endif /* ! QCBOR_DISABLE_FLOAT_HW_USE */
1352#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */
1353 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
1354 break;
1355
1356 case DOUBLE_PREC_FLOAT: /* 27 */
1357#ifndef USEFULBUF_DISABLE_ALL_FLOAT
1358 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uArgument);
1359 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
1360
1361 uReturn = QCBORDecode_Private_DoubleConformance(pDecodedItem->val.dfnum, uDecodeMode);
1362 if(uReturn != QCBOR_SUCCESS) {
1363 break;
1364 }
1365#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */
1366 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
1367 break;
1368 }
1369
1370 return uReturn;
1371}
1372
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 Lundblade9b2ae8a2024-07-12 11:00:20 -07001440 uReturn = QCBOR_Private_DecodeFloat(uDecodeMode, nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001441 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001442
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001443 case CBOR_SIMPLEV_FALSE: /* 20 */
1444 case CBOR_SIMPLEV_TRUE: /* 21 */
1445 case CBOR_SIMPLEV_NULL: /* 22 */
1446 case CBOR_SIMPLEV_UNDEF: /* 23 */
1447 case CBOR_SIMPLE_BREAK: /* 31 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001448#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
1449 if(uDecodeMode >= QCBOR_ENCODE_MODE_DCBOR &&
1450 nAdditionalInfo == CBOR_SIMPLEV_UNDEF) {
1451 uReturn = QCBOR_ERR_DCBOR_CONFORMANCE;
1452 goto Done;
1453 }
1454#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001455 break; /* nothing to do */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001456
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001457 case CBOR_SIMPLEV_ONEBYTE: /* 24 */
1458 if(uArgument <= CBOR_SIMPLE_BREAK) {
1459 /* This takes out f8 00 ... f8 1f which should be encoded
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001460 * as e0 … f7 -- preferred serialization check for simple values.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001461 */
1462 uReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001463 goto Done;
1464 }
Laurence Lundblade5e390822019-01-06 12:35:01 -08001465 /* FALLTHROUGH */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001466
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001467 default: /* 0-19 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001468#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
1469 if(uDecodeMode >= QCBOR_ENCODE_MODE_DCBOR &&
1470 (uArgument < CBOR_SIMPLEV_FALSE || uArgument > CBOR_SIMPLEV_NULL)) {
1471 uReturn = QCBOR_ERR_DCBOR_CONFORMANCE;
1472 goto Done;
1473 }
1474#endif /* !QCBOR_DISABLE_DECODE_CONFORMANCE */
1475
1476 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
1477 /* QCBOR_Private_DecodeHead() will make uArgument equal to
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001478 * nAdditionalInfo when nAdditionalInfo is < 24. This cast is
1479 * safe because the 2, 4 and 8 byte lengths of uNumber are in
1480 * the double/float cases above
Laurence Lundbladeee851742020-01-08 08:37:05 -08001481 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001482 pDecodedItem->val.uSimple = (uint8_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001483 break;
1484 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001485
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001486Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001487 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001488}
1489
1490
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001491/**
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001492 * @brief Decode a single primitive data item (decode layer 6).
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001493 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001494 * @param[in] pMe Decoder context.
1495 * @param[in] bAllocateStrings If true, use allocator for strings.
1496 * @param[out] pDecodedItem The filled-in decoded item.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001497 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001498 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1499 * features
1500 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1501 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1502 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1503 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001504 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001505 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1506 * of half-precision disabled
1507 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1508 * float decode is disabled.
1509 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1510 * simple type in input.
1511 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1512 * in input, but indefinite
1513 * lengths disabled.
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001514 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte.
1515 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map.
1516 * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001517 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001518 * This decodes the most primitive/atomic data item. It does no
1519 * combining of data items.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001520 */
1521static QCBORError
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001522QCBOR_Private_DecodeAtomicDataItem(QCBORDecodeContext *pMe,
1523 const bool bAllocateStrings,
1524 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001525{
1526 QCBORError uReturn;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001527 int nMajorType = 0;
1528 uint64_t uArgument = 0;
1529 int nAdditionalInfo = 0;
1530
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001531 /* Decode the "head" that every CBOR item has into the major type,
1532 * argument and the additional info.
1533 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001534 uReturn = QCBOR_Private_DecodeHead(&(pMe->InBuf),
1535#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
1536 // TODO: make this prettier; will optimizer take out stuff without ifdef?
1537 pMe->uDecodeMode >= QCBOR_DECODE_MODE_PREFERRED,
1538#endif /* !QCBOR_DISABLE_DECODE_CONFORMANCE */
1539 &nMajorType,
1540 &uArgument,
1541 &nAdditionalInfo);
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001542 if(uReturn != QCBOR_SUCCESS) {
1543 return uReturn;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001544 }
1545
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001546 memset(pDecodedItem, 0, sizeof(QCBORItem));
1547
1548 /* All the functions below get inlined by the optimizer. This code
1549 * is easier to read with them all being similar functions, even if
1550 * some functions don't do much.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001551 */
1552 switch (nMajorType) {
1553 case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
1554 case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001555 return QCBOR_Private_DecodeInteger(nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001556 break;
1557
1558 case CBOR_MAJOR_TYPE_BYTE_STRING: /* Major type 2 */
1559 case CBOR_MAJOR_TYPE_TEXT_STRING: /* Major type 3 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001560 return QCBOR_Private_DecodeString(pMe, bAllocateStrings, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001561 break;
1562
1563 case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */
1564 case CBOR_MAJOR_TYPE_MAP: /* Major type 5 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001565 return QCBOR_Private_DecodeArrayOrMap(pMe->uDecodeMode, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001566 break;
1567
1568 case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001569 return QCBOR_Private_DecodeTag(uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001570 break;
1571
1572 case CBOR_MAJOR_TYPE_SIMPLE:
1573 /* Major type 7: float, double, true, false, null... */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001574 return QCBOR_Private_DecodeType7(pMe->uDecodeMode, nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001575 break;
1576
1577 default:
1578 /* Never happens because DecodeHead() should never return > 7 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001579 return QCBOR_ERR_UNSUPPORTED;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001580 break;
1581 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001582}
1583
1584
1585/**
1586 * @brief Process indefinite-length strings (decode layer 5).
1587 *
1588 * @param[in] pMe Decoder context
1589 * @param[out] pDecodedItem The decoded item that work is done on.
1590 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001591 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1592 * features
1593 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1594 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1595 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1596 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1597 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1598 * of half-precision disabled
1599 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1600 * float decode is disabled.
1601 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1602 * simple type in input.
1603 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1604 * in input, but indefinite
1605 * lengths disabled.
1606 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1607 * but no string allocator.
1608 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1609 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1610 * input, but indefinite-length
1611 * strings are disabled.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001612 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001613 * If @c pDecodedItem is not an indefinite-length string, this does nothing.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001614 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001615 * If it is, this loops getting the subsequent chunk data items that
1616 * make up the string. The string allocator is used to make a
1617 * contiguous buffer for the chunks. When this completes @c
1618 * pDecodedItem contains the put-together string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001619 *
1620 * Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001621 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001622static QCBORError
1623QCBORDecode_Private_GetNextFullString(QCBORDecodeContext *pMe,
1624 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001625{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001626 /* Aproximate stack usage
1627 * 64-bit 32-bit
1628 * local vars 32 16
1629 * 2 UsefulBufs 32 16
1630 * QCBORItem 56 52
1631 * TOTAL 120 74
1632 */
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001633 QCBORError uReturn;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001634
1635 /* A note about string allocation -- Memory for strings is
1636 * allocated either because 1) indefinte-length string chunks are
1637 * being coalecsed or 2) caller has requested all strings be
1638 * allocated. The first case is handed below here. The second case
1639 * is handled in DecodeString if the bAllocate is true. That
1640 * boolean originates here with pMe->bStringAllocateAll immediately
1641 * below. That is, QCBOR_Private_DecodeAtomicDataItem() is called
1642 * in two different contexts here 1) main-line processing which is
1643 * where definite-length strings need to be allocated if
1644 * bStringAllocateAll is true and 2) processing chunks of
1645 * indefinite-lengths strings in in which case there must be no
1646 * allocation.
1647 */
1648
1649
1650 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, pMe->bStringAllocateAll, pDecodedItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001651 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001652 goto Done;
1653 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001654
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001655 /* This is where out-of-place break is detected for the whole
1656 * decoding stack. Break is an error for everything that calls
1657 * QCBORDecode_Private_GetNextFullString(), so the check is
1658 * centralized here.
1659 */
1660 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
1661 uReturn = QCBOR_ERR_BAD_BREAK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001662 goto Done;
1663 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001664
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001665
1666 /* Skip out if not an indefinite-length string */
1667 const uint8_t uStringType = pDecodedItem->uDataType;
1668 if(uStringType != QCBOR_TYPE_BYTE_STRING &&
1669 uStringType != QCBOR_TYPE_TEXT_STRING) {
1670 goto Done;
1671 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001672 if(pDecodedItem->val.string.len != QCBOR_STRING_LENGTH_INDEFINITE) {
1673 goto Done;
1674 }
1675
1676#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001677 /* Can't decode indefinite-length strings without a string allocator */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001678 if(!pMe->StringAllocator.pfAllocator) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001679 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1680 goto Done;
1681 }
1682
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001683 /* Loop getting chunks of the indefinite-length string */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001684 UsefulBufC FullString = NULLUsefulBufC;
1685
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001686 for(;;) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001687 /* Get QCBORItem for next chunk */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001688 QCBORItem StringChunkItem;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001689 /* Pass false to DecodeAtomicDataItem() because the individual
1690 * string chunks in an indefinite-length must not be
1691 * allocated. They are always copied into the allocated
1692 * contiguous buffer allocated here.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001693 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001694 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &StringChunkItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001695 if(uReturn) {
1696 break;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001697 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001698
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001699 /* Is item is the marker for end of the indefinite-length string? */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001700 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001701 /* String is complete */
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001702 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301703 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001704 break;
1705 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001706
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001707 /* All chunks must be of the same type, the type of the item
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001708 * that introduces the indefinite-length string. This also
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001709 * catches errors where the chunk is not a string at all and an
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001710 * indefinite-length string inside an indefinite-length string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001711 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001712 if(StringChunkItem.uDataType != uStringType ||
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001713 StringChunkItem.val.string.len == QCBOR_STRING_LENGTH_INDEFINITE) {
1714 uReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001715 break;
1716 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001717
David Navarro9123e5b2022-03-28 16:04:03 +02001718 if (StringChunkItem.val.string.len > 0) {
1719 /* The first time throurgh FullString.ptr is NULL and this is
1720 * equivalent to StringAllocator_Allocate(). Subsequently it is
1721 * not NULL and a reallocation happens.
1722 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001723 UsefulBuf NewMem = StringAllocator_Reallocate(&(pMe->StringAllocator),
David Navarro9123e5b2022-03-28 16:04:03 +02001724 FullString.ptr,
1725 FullString.len + StringChunkItem.val.string.len);
David Navarro9123e5b2022-03-28 16:04:03 +02001726 if(UsefulBuf_IsNULL(NewMem)) {
1727 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1728 break;
1729 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001730
David Navarro9123e5b2022-03-28 16:04:03 +02001731 /* Copy new string chunk to the end of accumulated string */
1732 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001733 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001734 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001735
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001736 if(uReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
1737 /* Getting the item failed, clean up the allocated memory */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001738 StringAllocator_Free(&(pMe->StringAllocator), FullString.ptr);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001739 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001740#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1741 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1742#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001743
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001744Done:
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001745 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001746}
1747
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001748
Laurence Lundblade37286c02022-09-03 10:05:02 -07001749#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001750/**
1751 * @brief This converts a tag number to a shorter mapped value for storage.
1752 *
1753 * @param[in] pMe The decode context.
1754 * @param[in] uUnMappedTag The tag number to map
1755 * @param[out] puMappedTagNumer The stored tag number.
1756 *
1757 * @return error code.
1758 *
1759 * The main point of mapping tag numbers is make QCBORItem
1760 * smaller. With this mapping storage of 4 tags takes up 8
1761 * bytes. Without, it would take up 32 bytes.
1762 *
1763 * This maps tag numbers greater than QCBOR_LAST_UNMAPPED_TAG.
1764 * QCBOR_LAST_UNMAPPED_TAG is a little smaller than MAX_UINT16.
1765 *
1766 * See also UnMapTagNumber() and @ref QCBORItem.
1767 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001768static QCBORError
1769QCBORDecode_Private_MapTagNumber(QCBORDecodeContext *pMe,
1770 const uint64_t uUnMappedTag,
1771 uint16_t *puMappedTagNumer)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001772{
1773 if(uUnMappedTag > QCBOR_LAST_UNMAPPED_TAG) {
1774 unsigned uTagMapIndex;
1775 /* Is there room in the tag map, or is it in it already? */
1776 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
1777 if(pMe->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID64) {
1778 break;
1779 }
1780 if(pMe->auMappedTags[uTagMapIndex] == uUnMappedTag) {
1781 break;
1782 }
1783 }
1784 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
1785 return QCBOR_ERR_TOO_MANY_TAGS;
1786 }
1787
1788 /* Covers the cases where tag is new and were it is already in the map */
1789 pMe->auMappedTags[uTagMapIndex] = uUnMappedTag;
1790 *puMappedTagNumer = (uint16_t)(uTagMapIndex + QCBOR_LAST_UNMAPPED_TAG + 1);
1791
1792 } else {
1793 *puMappedTagNumer = (uint16_t)uUnMappedTag;
1794 }
1795
1796 return QCBOR_SUCCESS;
1797}
1798
1799
1800/**
1801 * @brief This converts a mapped tag number to the actual tag number.
1802 *
1803 * @param[in] pMe The decode context.
1804 * @param[in] uMappedTagNumber The stored tag number.
1805 *
1806 * @return The actual tag number is returned or
1807 * @ref CBOR_TAG_INVALID64 on error.
1808 *
1809 * This is the reverse of MapTagNumber()
1810 */
1811static uint64_t
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001812QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe,
1813 const uint16_t uMappedTagNumber)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001814{
1815 if(uMappedTagNumber <= QCBOR_LAST_UNMAPPED_TAG) {
1816 return uMappedTagNumber;
1817 } else if(uMappedTagNumber == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07001818 return CBOR_TAG_INVALID64;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001819 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001820 /* This won't be negative because of code below in
1821 * MapTagNumber()
1822 */
1823 const unsigned uIndex = uMappedTagNumber - (QCBOR_LAST_UNMAPPED_TAG + 1);
1824 return pMe->auMappedTags[uIndex];
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001825 }
1826}
Laurence Lundblade37286c02022-09-03 10:05:02 -07001827#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001828
Laurence Lundblade9b334962020-08-27 10:55:53 -07001829
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001830/**
1831 * @brief Aggregate all tags wrapping a data item (decode layer 4).
1832 *
1833 * @param[in] pMe Decoder context
1834 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001835 *
1836 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1837 * features
1838 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1839 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1840 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1841 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1842 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1843 * of half-precision disabled
1844 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1845 * float decode is disabled.
1846 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1847 * simple type in input.
1848 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1849 * in input, but indefinite
1850 * lengths disabled.
1851 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1852 * but no string allocator.
1853 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1854 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1855 * input, but indefinite-length
1856 * strings are disabled.
1857 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001858 *
1859 * This loops getting atomic data items until one is not a tag
1860 * number. Usually this is largely pass-through because most
1861 * item are not tag numbers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001862 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001863static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001864QCBORDecode_Private_GetNextTagNumber(QCBORDecodeContext *pMe,
1865 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001866{
Laurence Lundblade37286c02022-09-03 10:05:02 -07001867#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001868 /* Accummulate the tags from multiple items here and then copy them
1869 * into the last item, the non-tag item.
1870 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001871 uint16_t auItemsTags[QCBOR_MAX_TAGS_PER_ITEM];
1872
1873 /* Initialize to CBOR_TAG_INVALID16 */
1874 #if CBOR_TAG_INVALID16 != 0xffff
1875 /* Be sure the memset does the right thing. */
1876 #err CBOR_TAG_INVALID16 tag not defined as expected
1877 #endif
1878 memset(auItemsTags, 0xff, sizeof(auItemsTags));
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001879
Laurence Lundblade9b334962020-08-27 10:55:53 -07001880 QCBORError uReturn = QCBOR_SUCCESS;
1881
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001882 /* Loop fetching data items until the item fetched is not a tag */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001883 for(;;) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001884 QCBORError uErr = QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07001885 if(uErr != QCBOR_SUCCESS) {
1886 uReturn = uErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001887 goto Done;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001888 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001889
Laurence Lundblade9b334962020-08-27 10:55:53 -07001890 if(pDecodedItem->uDataType != QCBOR_TYPE_TAG) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001891 /* Successful exit from loop; maybe got some tags, maybe not */
1892 memcpy(pDecodedItem->uTags, auItemsTags, sizeof(auItemsTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001893 break;
1894 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001895
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001896 if(auItemsTags[QCBOR_MAX_TAGS_PER_ITEM - 1] != CBOR_TAG_INVALID16) {
1897 /* No room in the tag list */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001898 uReturn = QCBOR_ERR_TOO_MANY_TAGS;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001899 /* Continue on to get all tags wrapping this item even though
1900 * it is erroring out in the end. This allows decoding to
1901 * continue. This is a resource limit error, not a problem
1902 * with being well-formed CBOR.
1903 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001904 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001905 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001906 /* Slide tags over one in the array to make room at index 0.
1907 * Must use memmove because the move source and destination
1908 * overlap.
1909 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001910 memmove(&auItemsTags[1],
1911 auItemsTags,
1912 sizeof(auItemsTags) - sizeof(auItemsTags[0]));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001913
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001914 /* Map the tag */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001915 uint16_t uMappedTagNumber = 0;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001916 uReturn = QCBORDecode_Private_MapTagNumber(pMe, pDecodedItem->val.uTagV, &uMappedTagNumber);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001917 /* Continue even on error so as to consume all tags wrapping
1918 * this data item so decoding can go on. If MapTagNumber()
1919 * errors once it will continue to error.
1920 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001921 auItemsTags[0] = uMappedTagNumber;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001922 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001923
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001924Done:
Laurence Lundblade9b334962020-08-27 10:55:53 -07001925 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001926
Laurence Lundblade37286c02022-09-03 10:05:02 -07001927#else /* QCBOR_DISABLE_TAGS */
1928
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07001929 return QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07001930
1931#endif /* QCBOR_DISABLE_TAGS */
1932}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001933
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001934
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001935/**
1936 * @brief Combine a map entry label and value into one item (decode layer 3).
1937 *
1938 * @param[in] pMe Decoder context
1939 * @param[out] pDecodedItem The decoded item that work is done on.
1940 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001941 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1942 * features
1943 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1944 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1945 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1946 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1947 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1948 * of half-precision disabled
1949 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1950 * float decode is disabled.
1951 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1952 * simple type in input.
1953 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1954 * in input, but indefinite
1955 * lengths disabled.
1956 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1957 * but no string allocator.
1958 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1959 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1960 * input, but indefinite-length
1961 * strings are disabled.
1962 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1963 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1964 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001965 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001966 * If the current nesting level is a map, then this combines pairs of
1967 * items into one data item with a label and value.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001968 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001969 * This is passthrough if the current nesting level is not a map.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001970 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001971 * This also implements maps-as-array mode where a map is treated like
1972 * an array to allow caller to do their own label processing.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001973 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001974static QCBORError
1975QCBORDecode_Private_GetNextMapEntry(QCBORDecodeContext *pMe,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001976 QCBORItem *pDecodedItem,
1977 uint32_t *puLabelEndOffset)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001978{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001979 QCBORItem LabelItem;
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001980 QCBORError uErr, uErr2;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001981
1982 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1983 if(QCBORDecode_IsUnrecoverableError(uErr)) {
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001984 goto Done;
1985 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001986
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001987 if(!DecodeNesting_IsCurrentTypeMap(&(pMe->nesting))) {
1988 /* Not decoding a map. Nothing to do. */
1989 /* When decoding maps-as-arrays, the type will be
1990 * QCBOR_TYPE_MAP_AS_ARRAY and this function will exit
1991 * here. This is now map processing for maps-as-arrays is not
1992 * done. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001993 goto Done;
1994 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001995
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001996 /* Decoding a map entry, so the item decoded above was the label */
1997 LabelItem = *pDecodedItem;
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001998
1999 if(puLabelEndOffset != NULL) {
2000 /* Cast is OK because lengths are all 32-bit in QCBOR */
2001 *puLabelEndOffset = (uint32_t)UsefulInputBuf_Tell(&(pMe->InBuf));
2002 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08002003
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002004 /* Get the value of the map item */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002005 uErr2 = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
2006 if(QCBORDecode_IsUnrecoverableError(uErr2)) {
2007 uErr = uErr2;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002008 goto Done;
2009 }
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002010 if(uErr2 != QCBOR_SUCCESS) {
2011 /* The recoverable error for the value overrides the recoverable error for the label, if there was an error for the label */
2012 uErr = uErr2;
2013 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002014
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002015 /* Combine the label item and value item into one */
2016 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
2017 pDecodedItem->uLabelType = LabelItem.uDataType;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09002018
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002019#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
2020 /* QCBOR_DECODE_MODE_MAP_STRINGS_ONLY might have been a bad idea. Maybe
2021 * get rid of it in QCBOR 2.0
2022 */
2023 if(pMe->uDecodeMode == QCBOR_DECODE_MODE_MAP_STRINGS_ONLY &&
2024 LabelItem.uDataType != QCBOR_TYPE_TEXT_STRING) {
2025 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
2026 goto Done;
2027 }
2028#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
2029
2030 switch(LabelItem.uDataType) {
2031 case QCBOR_TYPE_INT64:
2032 pDecodedItem->label.int64 = LabelItem.val.int64;
2033 break;
2034
2035#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
2036 case QCBOR_TYPE_UINT64:
2037 pDecodedItem->label.uint64 = LabelItem.val.uint64;
2038 break;
2039
2040 case QCBOR_TYPE_TEXT_STRING:
2041 case QCBOR_TYPE_BYTE_STRING:
2042 pDecodedItem->label.string = LabelItem.val.string;
2043 break;
2044#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
2045
2046 default:
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002047 /* It is possible to skip over labels that are non-aggregate
2048 * types like floats, but not to skip over labels that are
2049 * arrays or maps. We might eventually handle more label
2050 * types like floats as they are not too hard and we now
2051 * have QCBOR_DISABLE_NON_INTEGER_LABELS */
2052 if(!pMe->bAllowAllLabels || QCBORItem_IsMapOrArray(LabelItem)) {
2053 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
2054 goto Done;
2055 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002056 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002057
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002058Done:
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002059 return uErr;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002060}
2061
2062
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002063#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002064/**
2065 * @brief Peek and see if next data item is a break;
2066 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002067 * param[in] pUIB UsefulInputBuf to read from.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002068 * @param[out] pbNextIsBreak Indicate if next was a break or not.
2069 *
2070 * @return Any decoding error.
2071 *
2072 * See if next item is a CBOR break. If it is, it is consumed,
2073 * if not it is not consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07002074*/
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002075static QCBORError
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002076QCBOR_Private_NextIsBreak(QCBORDecodeContext *pMe, bool *pbNextIsBreak)
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002077{
2078 *pbNextIsBreak = false;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002079 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) != 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002080 QCBORItem Peek;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002081 size_t uPeek = UsefulInputBuf_Tell(&(pMe->InBuf));
2082 QCBORError uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &Peek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002083 if(uReturn != QCBOR_SUCCESS) {
2084 return uReturn;
2085 }
2086 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002087 /* It is not a break, rewind so it can be processed normally. */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002088 UsefulInputBuf_Seek(&(pMe->InBuf), uPeek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002089 } else {
2090 *pbNextIsBreak = true;
2091 }
2092 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002093
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002094 return QCBOR_SUCCESS;
2095}
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002096#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002097
2098
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002099/**
2100 * @brief Ascend up nesting levels if all items in them have been consumed.
2101 *
2102 * @param[in] pMe The decode context.
2103 * @param[in] bMarkEnd If true mark end of maps/arrays with count of zero.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002104 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002105 *
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002106 * An item was just consumed, now figure out if it was the
2107 * end of an array/map map that can be closed out. That
2108 * may in turn close out the above array/map...
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002109 *
2110 * When ascending indefinite-length arrays and maps, this will correctly
2111 * consume the break for the level above. This is a problem for the
2112 * implementation of QCBORDecode_GetArray() that must not return
2113 * that break. @c pbBreak is set to true to indicate that one
2114 * byte should be removed.
2115 *
2116 * Improvement: this could reduced further if indef is disabled
2117 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002118static QCBORError
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002119QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd, bool *pbBreak)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002120{
2121 QCBORError uReturn;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002122
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002123 /* Loop ascending nesting levels as long as there is ascending to do */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002124 while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002125 if(pbBreak) {
2126 *pbBreak = false;
2127 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002128
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002129 if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) {
2130 /* Nesting level is bstr-wrapped CBOR */
2131
2132 /* Ascent for bstr-wrapped CBOR is always by explicit call
2133 * so no further ascending can happen.
2134 */
2135 break;
2136
2137 } else if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
2138 /* Level is a definite-length array/map */
2139
2140 /* Decrement the item count the definite-length array/map */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002141 DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(&(pMe->nesting));
2142 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002143 /* Didn't close out array/map, so all work here is done */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002144 break;
2145 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002146 /* All items in a definite-length array were consumed so it
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002147 * is time to ascend one level. This happens below.
2148 */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002149
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002150#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002151 } else {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002152 /* Level is an indefinite-length array/map. */
2153
2154 /* Check for a break which is what ends indefinite-length arrays/maps */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002155 bool bIsBreak = false;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002156 uReturn = QCBOR_Private_NextIsBreak(pMe, &bIsBreak);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002157 if(uReturn != QCBOR_SUCCESS) {
2158 goto Done;
2159 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002160
2161 if(!bIsBreak) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002162 /* Not a break so array/map does not close out. All work is done */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002163 break;
2164 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002165
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002166 /* It was a break in an indefinitelength map / array so
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002167 * it is time to ascend one level.
2168 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002169 if(pbBreak) {
2170 *pbBreak = true;
2171 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002172
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002173#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002174 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002175
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002176
2177 /* All items in the array/map have been consumed. */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002178
Laurence Lundblade93d89472020-10-03 22:30:50 -07002179 /* But ascent in bounded mode is only by explicit call to
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002180 * QCBORDecode_ExitBoundedMode().
2181 */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07002182 if(DecodeNesting_IsCurrentBounded(&(pMe->nesting))) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002183 /* Set the count to zero for definite-length arrays to indicate
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002184 * cursor is at end of bounded array/map */
Laurence Lundbladed0304932020-06-27 10:59:38 -07002185 if(bMarkEnd) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002186 /* Used for definite and indefinite to signal end */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07002187 DecodeNesting_ZeroMapOrArrayCount(&(pMe->nesting));
Laurence Lundbladed0304932020-06-27 10:59:38 -07002188
Laurence Lundblade2c1faf92020-06-26 22:43:56 -07002189 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002190 break;
2191 }
2192
2193 /* Finally, actually ascend one level. */
2194 DecodeNesting_Ascend(&(pMe->nesting));
2195 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002196
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002197 uReturn = QCBOR_SUCCESS;
2198
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002199#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002200Done:
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002201#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
2202
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002203 return uReturn;
2204}
2205
2206
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002207/**
2208 * @brief Ascending & Descending out of nesting levels (decode layer 2).
2209 *
2210 * @param[in] pMe Decoder context
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002211 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002212 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002213
2214 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
2215 * features
2216 * @retval QCBOR_ERR_HIT_END Unexpected end of input
2217 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
2218 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
2219 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
2220 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
2221 * of half-precision disabled
2222 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
2223 * float decode is disabled.
2224 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
2225 * simple type in input.
2226 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
2227 * in input, but indefinite
2228 * lengths disabled.
2229 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
2230 * but no string allocator.
2231 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
2232 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
2233 * input, but indefinite-length
2234 * strings are disabled.
2235 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
2236 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
2237 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
2238 * @retval QCBOR_ERR_NO_MORE_ITEMS Need more items for map or array.
2239 * @retval QCBOR_ERR_BAD_BREAK Indefinite-length break in wrong
2240 * place.
2241 * @retval QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP Nesting deeper than QCBOR
2242 * can handle.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002243 *
2244 * This handles the traversal descending into and asecnding out of
2245 * maps, arrays and bstr-wrapped CBOR. It figures out the ends of
2246 * definite- and indefinte-length maps and arrays by looking at the
2247 * item count or finding CBOR breaks. It detects the ends of the
2248 * top-level sequence and of bstr-wrapped CBOR by byte count.
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002249 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002250static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002251QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002252 bool *pbBreak,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002253 QCBORItem *pDecodedItem,
2254 uint32_t *puLabelEndOffset)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002255{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002256 QCBORError uReturn;
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002257 /* ==== First: figure out if at the end of a traversal ==== */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002258
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002259 /* If out of bytes to consume, it is either the end of the
2260 * top-level sequence of some bstr-wrapped CBOR that was entered.
2261 *
2262 * In the case of bstr-wrapped CBOR, the length of the
2263 * UsefulInputBuf was set to that of the bstr-wrapped CBOR. When
2264 * the bstr-wrapped CBOR is exited, the length is set back to the
2265 * top-level's length or to the next highest bstr-wrapped CBOR.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002266 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002267 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) == 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002268 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002269 goto Done;
2270 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07002271
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002272 /* Check to see if at the end of a bounded definite-length map or
2273 * array. The check for a break ending indefinite-length array is
2274 * later in QCBORDecode_NestLevelAscender().
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002275 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002276 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002277 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002278 goto Done;
2279 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002280
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002281 /* ==== Next: not at the end, so get another item ==== */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002282 uReturn = QCBORDecode_Private_GetNextMapEntry(pMe, pDecodedItem, puLabelEndOffset);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002283 if(QCBORDecode_IsUnrecoverableError(uReturn)) {
2284 /* Error is so bad that traversal is not possible. */
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002285 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002286 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05302287
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002288 /* Record the nesting level for this data item before processing
2289 * any of decrementing and descending.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002290 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002291 pDecodedItem->uNestingLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002292
Laurence Lundblade642282a2020-06-23 12:00:33 -07002293
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002294 /* ==== Next: Process the item for descent, ascent, decrement... ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002295 if(QCBORItem_IsMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002296 /* If the new item is a map or array, descend.
2297 *
2298 * Empty indefinite-length maps and arrays are descended into,
2299 * but then ascended out of in the next chunk of code.
2300 *
2301 * Maps and arrays do count as items in the map/array that
2302 * encloses them so a decrement needs to be done for them too,
2303 * but that is done only when all the items in them have been
2304 * processed, not when they are opened with the exception of an
2305 * empty map or array.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002306 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002307 QCBORError uDescendErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002308 uDescendErr = DecodeNesting_DescendMapOrArray(&(pMe->nesting),
Laurence Lundblade642282a2020-06-23 12:00:33 -07002309 pDecodedItem->uDataType,
2310 pDecodedItem->val.uCount);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002311 if(uDescendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002312 /* This error is probably a traversal error and it overrides
2313 * the non-traversal error.
2314 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002315 uReturn = uDescendErr;
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002316 goto Done;
2317 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002318 }
2319
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002320 if(!QCBORItem_IsMapOrArray(*pDecodedItem) ||
2321 QCBORItem_IsEmptyDefiniteLengthMapOrArray(*pDecodedItem) ||
2322 QCBORItem_IsIndefiniteLengthMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002323 /* The following cases are handled here:
2324 * - A non-aggregate item like an integer or string
2325 * - An empty definite-length map or array
2326 * - An indefinite-length map or array that might be empty or might not.
2327 *
2328 * QCBORDecode_NestLevelAscender() does the work of decrementing the count
2329 * for an definite-length map/array and break detection for an
2330 * indefinite-0length map/array. If the end of the map/array was
2331 * reached, then it ascends nesting levels, possibly all the way
2332 * to the top level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002333 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002334 QCBORError uAscendErr;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002335 uAscendErr = QCBORDecode_Private_NestLevelAscender(pMe, true, pbBreak);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002336 if(uAscendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002337 /* This error is probably a traversal error and it overrides
2338 * the non-traversal error.
2339 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002340 uReturn = uAscendErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002341 goto Done;
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002342 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05302343 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002344
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002345 /* ==== Last: tell the caller the nest level of the next item ==== */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002346 /* Tell the caller what level is next. This tells them what
2347 * maps/arrays were closed out and makes it possible for them to
2348 * reconstruct the tree with just the information returned in a
2349 * QCBORItem.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002350 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002351 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07002352 /* At end of a bounded map/array; uNextNestLevel 0 to indicate this */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002353 pDecodedItem->uNextNestLevel = 0;
2354 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002355 pDecodedItem->uNextNestLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002356 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002357
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002358Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002359 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002360}
2361
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002362
Laurence Lundblade37286c02022-09-03 10:05:02 -07002363#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002364/**
2365 * @brief Shift 0th tag out of the tag list.
2366 *
2367 * pDecodedItem[in,out] The data item to convert.
2368 *
2369 * The 0th tag is discarded. \ref CBOR_TAG_INVALID16 is
2370 * shifted into empty slot at the end of the tag list.
2371 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002372static void
2373QCBOR_Private_ShiftTags(QCBORItem *pDecodedItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002374{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002375 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM-1; i++) {
2376 pDecodedItem->uTags[i] = pDecodedItem->uTags[i+1];
2377 }
2378 pDecodedItem->uTags[QCBOR_MAX_TAGS_PER_ITEM-1] = CBOR_TAG_INVALID16;
Laurence Lundblade9b334962020-08-27 10:55:53 -07002379}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002380#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002381
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002382
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002383/**
2384 * @brief Convert different epoch date formats in to the QCBOR epoch date format
2385 *
2386 * pDecodedItem[in,out] The data item to convert.
2387 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002388 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2389 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2390 * floating-point date disabled.
2391 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2392 * all floating-point disabled.
2393 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2394 * error decoding date.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002395 *
2396 * The epoch date tag defined in QCBOR allows for floating-point
2397 * dates. It even allows a protocol to flop between date formats when
2398 * ever it wants. Floating-point dates aren't that useful as they are
2399 * only needed for dates beyond the age of the earth.
2400 *
2401 * This converts all the date formats into one format of an unsigned
2402 * integer plus a floating-point fraction.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002403 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002404static QCBORError
2405QCBOR_Private_DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002406{
Laurence Lundbladec7114722020-08-13 05:11:40 -07002407 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002408
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002409#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade59289e52019-12-30 13:44:37 -08002410 pDecodedItem->val.epochDate.fSecondsFraction = 0;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002411#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002412
2413 switch (pDecodedItem->uDataType) {
2414
2415 case QCBOR_TYPE_INT64:
2416 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
2417 break;
2418
2419 case QCBOR_TYPE_UINT64:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002420 /* This only happens for CBOR type 0 > INT64_MAX so it is
2421 * always an overflow.
2422 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07002423 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2424 goto Done;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002425 break;
2426
2427 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade9682a532020-06-06 18:33:04 -07002428 case QCBOR_TYPE_FLOAT:
2429#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade59289e52019-12-30 13:44:37 -08002430 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002431 /* Convert working value to double if input was a float */
Laurence Lundblade3ed0bca2020-07-14 22:50:10 -07002432 const double d = pDecodedItem->uDataType == QCBOR_TYPE_DOUBLE ?
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002433 pDecodedItem->val.dfnum :
2434 (double)pDecodedItem->val.fnum;
2435
2436 /* The conversion from float to integer requires overflow
2437 * detection since floats can be much larger than integers.
2438 * This implementation errors out on these large float values
2439 * since they are beyond the age of the earth.
2440 *
2441 * These constants for the overflow check are computed by the
2442 * compiler. They are not computed at run time.
2443 *
2444 * The factor of 0x7ff is added/subtracted to avoid a
2445 * rounding error in the wrong direction when the compiler
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002446 * computes these constants. There is rounding because a
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002447 * 64-bit integer has 63 bits of precision where a double
2448 * only has 53 bits. Without the 0x7ff factor, the compiler
2449 * may round up and produce a double for the bounds check
2450 * that is larger than can be stored in a 64-bit integer. The
2451 * amount of 0x7ff is picked because it has 11 bits set.
2452 *
2453 * Without the 0x7ff there is a ~30 minute range of time
2454 * values 10 billion years in the past and in the future
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002455 * where this code could go wrong. Some compilers
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002456 * generate a warning or error without the 0x7ff.
2457 */
2458 const double dDateMax = (double)(INT64_MAX - 0x7ff);
2459 const double dDateMin = (double)(INT64_MIN + 0x7ff);
2460
2461 if(isnan(d) || d > dDateMax || d < dDateMin) {
Laurence Lundbladec7114722020-08-13 05:11:40 -07002462 uReturn = QCBOR_ERR_DATE_OVERFLOW;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002463 goto Done;
2464 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002465
2466 /* The actual conversion */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002467 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
Laurence Lundblade2feb1e12020-07-15 03:50:45 -07002468 pDecodedItem->val.epochDate.fSecondsFraction =
2469 d - (double)pDecodedItem->val.epochDate.nSeconds;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002470 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002471#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade4b270642020-08-14 12:53:07 -07002472
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002473 uReturn = QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundblade4b270642020-08-14 12:53:07 -07002474 goto Done;
2475
Laurence Lundblade9682a532020-06-06 18:33:04 -07002476#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002477 break;
2478
2479 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002480 /* It's the arrays and maps that are unrecoverable because
2481 * they are not consumed here. Since this is just an error
2482 * condition, no extra code is added here to make the error
2483 * recoverable for non-arrays and maps like strings. */
2484 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002485 goto Done;
2486 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002487
Laurence Lundblade59289e52019-12-30 13:44:37 -08002488 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
2489
2490Done:
Laurence Lundbladec7114722020-08-13 05:11:40 -07002491 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002492}
2493
2494
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002495/**
2496 * @brief Convert the days epoch date.
2497 *
2498 * pDecodedItem[in,out] The data item to convert.
2499 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002500 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2501 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2502 * floating-point date disabled.
2503 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2504 * all floating-point disabled.
2505 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2506 * error decoding date.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002507 *
2508 * This is much simpler than the other epoch date format because
2509 * floating-porint is not allowed. This is mostly a simple type check.
2510 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002511static QCBORError
2512QCBOR_Private_DecodeDaysEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002513{
2514 QCBORError uReturn = QCBOR_SUCCESS;
2515
2516 switch (pDecodedItem->uDataType) {
2517
2518 case QCBOR_TYPE_INT64:
2519 pDecodedItem->val.epochDays = pDecodedItem->val.int64;
2520 break;
2521
2522 case QCBOR_TYPE_UINT64:
2523 /* This only happens for CBOR type 0 > INT64_MAX so it is
2524 * always an overflow.
2525 */
2526 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2527 goto Done;
2528 break;
2529
2530 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002531 /* It's the arrays and maps that are unrecoverable because
2532 * they are not consumed here. Since this is just an error
2533 * condition, no extra code is added here to make the error
2534 * recoverable for non-arrays and maps like strings. */
2535 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002536 goto Done;
2537 break;
2538 }
2539
2540 pDecodedItem->uDataType = QCBOR_TYPE_DAYS_EPOCH;
2541
2542Done:
2543 return uReturn;
2544}
2545
2546
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002547#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade37286c02022-09-03 10:05:02 -07002548
2549/* Forward declaration is necessary for
2550 * QCBORDecode_MantissaAndExponent(). to be able to decode bignum
2551 * tags in the mantissa. If the mantissa is a decimal fraction or big
2552 * float in error, this will result in a recurive call to
2553 * QCBORDecode_MantissaAndExponent(), but the recursion will unwined
2554 * correctly and the correct error is returned.
2555 */
2556static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002557QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2558 QCBORItem *pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002559
2560
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002561/**
2562 * @brief Decode decimal fractions and big floats.
2563 *
2564 * @param[in] pMe The decode context.
2565 * @param[in,out] pDecodedItem On input the array data item that
2566 * holds the mantissa and exponent. On
2567 * output the decoded mantissa and
2568 * exponent.
2569 *
2570 * @returns Decoding errors from getting primitive data items or
2571 * \ref QCBOR_ERR_BAD_EXP_AND_MANTISSA.
2572 *
Laurence Lundblade37286c02022-09-03 10:05:02 -07002573 * When called pDecodedItem must be the array with two members, the
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002574 * exponent and mantissa.
2575 *
2576 * This will fetch and decode the exponent and mantissa and put the
2577 * result back into pDecodedItem.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002578 *
2579 * This does no checking or processing of tag numbers. That is to be
2580 * done by the code that calls this.
2581 *
2582 * This stuffs the type of the mantissa into pDecodedItem with the expectation
2583 * the caller will process it.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002584 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002585static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002586QCBORDecode_Private_ExpMantissa(QCBORDecodeContext *pMe,
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002587 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002588{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002589 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002590
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002591 /* --- Make sure it is an array; track nesting level of members --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002592 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002593 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002594 goto Done;
2595 }
2596
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002597 /* A check for pDecodedItem->val.uCount == 2 would work for
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002598 * definite-length arrays, but not for indefinite. Instead remember
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002599 * the nesting level the two integers must be at, which is one
2600 * deeper than that of the array.
2601 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002602 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
2603
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002604 /* --- Get the exponent --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002605 QCBORItem exponentItem;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002606 uReturn = QCBORDecode_GetNext(pMe, &exponentItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002607 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002608 goto Done;
2609 }
2610 if(exponentItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002611 /* Array is empty or a map/array encountered when expecting an int */
2612 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002613 goto Done;
2614 }
2615 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002616 /* Data arriving as an unsigned int < INT64_MAX has been
2617 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2618 * also means that the only data arriving here of type
2619 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2620 * and thus an error that will get handled in the next else.
2621 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002622 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
2623 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002624 /* Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX */
2625 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002626 goto Done;
2627 }
2628
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002629 /* --- Get the mantissa --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002630 QCBORItem mantissaItem;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002631 uReturn = QCBORDecode_GetNext(pMe, &mantissaItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002632 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002633 goto Done;
2634 }
2635 if(mantissaItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002636 /* Mantissa missing or map/array encountered when expecting number */
2637 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002638 goto Done;
2639 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002640 /* Stuff the mantissa data type into the item to send it up to the
2641 * the next level. */
2642 pDecodedItem->uDataType = mantissaItem.uDataType;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002643 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002644 /* Data arriving as an unsigned int < INT64_MAX has been
2645 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2646 * also means that the only data arriving here of type
2647 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2648 * and thus an error that will get handled in an else below.
2649 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002650 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002651#ifndef QCBOR_DISABLE_TAGS
2652 /* With tags fully disabled a big number mantissa will error out
2653 * in the call to QCBORDecode_GetNextWithTags() because it has
2654 * a tag number.
2655 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07002656 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM ||
2657 mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002658 /* Got a good big num mantissa */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002659 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002660#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002661 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002662 /* Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX */
2663 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002664 goto Done;
2665 }
2666
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002667 /* --- Check that array only has the two numbers --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002668 if(mantissaItem.uNextNestLevel == nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002669 /* Extra items in the decimal fraction / big float */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002670 /* Improvement: this should probably be an unrecoverable error. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002671 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002672 goto Done;
2673 }
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002674 pDecodedItem->uNextNestLevel = mantissaItem.uNextNestLevel;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002675
2676Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002677 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002678}
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002679#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002680
2681
Laurence Lundblade37286c02022-09-03 10:05:02 -07002682#ifndef QCBOR_DISABLE_TAGS
2683
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002684#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002685/**
2686 * @brief Decode the MIME type tag
2687 *
2688 * @param[in,out] pDecodedItem The item to decode.
2689 *
2690 * Handle the text and binary MIME type tags. Slightly too complicated
2691 * f or ProcessTaggedString() because the RFC 7049 MIME type was
2692 * incorreclty text-only.
2693 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002694static QCBORError
2695QCBOR_Private_DecodeMIME(QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002696{
2697 if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) {
2698 pDecodedItem->uDataType = QCBOR_TYPE_MIME;
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07002699 } else if(pDecodedItem->uDataType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002700 pDecodedItem->uDataType = QCBOR_TYPE_BINARY_MIME;
2701 } else {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002702 /* It's the arrays and maps that are unrecoverable because
2703 * they are not consumed here. Since this is just an error
2704 * condition, no extra code is added here to make the error
2705 * recoverable for non-arrays and maps like strings. */
2706 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002707 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002708
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002709 return QCBOR_SUCCESS;
2710}
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002711#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002712
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002713/**
Laurence Lundblade99615302020-11-29 11:19:47 -08002714 * Table of CBOR tags whose content is either a text string or a byte
2715 * string. The table maps the CBOR tag to the QCBOR type. The high-bit
2716 * of uQCBORtype indicates the content should be a byte string rather
2717 * than a text string
2718 */
2719struct StringTagMapEntry {
2720 uint16_t uTagNumber;
2721 uint8_t uQCBORtype;
2722};
2723
2724#define IS_BYTE_STRING_BIT 0x80
2725#define QCBOR_TYPE_MASK ~IS_BYTE_STRING_BIT
2726
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002727static const struct StringTagMapEntry QCBOR_Private_StringTagMap[] = {
Laurence Lundblade99615302020-11-29 11:19:47 -08002728 {CBOR_TAG_DATE_STRING, QCBOR_TYPE_DATE_STRING},
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002729 {CBOR_TAG_DAYS_STRING, QCBOR_TYPE_DAYS_STRING},
Laurence Lundblade99615302020-11-29 11:19:47 -08002730 {CBOR_TAG_POS_BIGNUM, QCBOR_TYPE_POSBIGNUM | IS_BYTE_STRING_BIT},
2731 {CBOR_TAG_NEG_BIGNUM, QCBOR_TYPE_NEGBIGNUM | IS_BYTE_STRING_BIT},
2732 {CBOR_TAG_CBOR, QBCOR_TYPE_WRAPPED_CBOR | IS_BYTE_STRING_BIT},
2733 {CBOR_TAG_URI, QCBOR_TYPE_URI},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002734#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002735 {CBOR_TAG_B64URL, QCBOR_TYPE_BASE64URL},
2736 {CBOR_TAG_B64, QCBOR_TYPE_BASE64},
2737 {CBOR_TAG_REGEX, QCBOR_TYPE_REGEX},
2738 {CBOR_TAG_BIN_UUID, QCBOR_TYPE_UUID | IS_BYTE_STRING_BIT},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002739#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade99615302020-11-29 11:19:47 -08002740 {CBOR_TAG_CBOR_SEQUENCE, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE | IS_BYTE_STRING_BIT},
2741 {CBOR_TAG_INVALID16, QCBOR_TYPE_NONE}
2742};
2743
2744
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002745/**
2746 * @brief Process standard CBOR tags whose content is a string
2747 *
2748 * @param[in] uTag The tag.
2749 * @param[in,out] pDecodedItem The data item.
2750 *
2751 * @returns This returns QCBOR_SUCCESS if the tag was procssed,
2752 * \ref QCBOR_ERR_UNSUPPORTED if the tag was not processed and
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002753 * \ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT if the content type was wrong for the tag.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002754 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002755 * Process the CBOR tags that whose content is a byte string or a text
2756 * string and for which the string is just passed on to the caller.
2757 *
2758 * This maps the CBOR tag to the QCBOR type and checks the content
2759 * type. Nothing more. It may not be the most important
Laurence Lundbladec02e13e2020-12-06 05:45:41 -08002760 * functionality, but it part of implementing as much of RFC 8949 as
Laurence Lundblade99615302020-11-29 11:19:47 -08002761 * possible.
Laurence Lundblade99615302020-11-29 11:19:47 -08002762 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002763static QCBORError
2764QCBOR_Private_ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002765{
Laurence Lundblade99615302020-11-29 11:19:47 -08002766 /* This only works on tags that were not mapped; no need for other yet */
2767 if(uTag > QCBOR_LAST_UNMAPPED_TAG) {
2768 return QCBOR_ERR_UNSUPPORTED;
2769 }
2770
2771 unsigned uIndex;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002772 for(uIndex = 0; QCBOR_Private_StringTagMap[uIndex].uTagNumber != CBOR_TAG_INVALID16; uIndex++) {
2773 if(QCBOR_Private_StringTagMap[uIndex].uTagNumber == uTag) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002774 break;
2775 }
2776 }
2777
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002778 const uint8_t uQCBORType = QCBOR_Private_StringTagMap[uIndex].uQCBORtype;
Laurence Lundblade99615302020-11-29 11:19:47 -08002779 if(uQCBORType == QCBOR_TYPE_NONE) {
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002780 /* repurpose this error to mean not handled here */
Laurence Lundblade99615302020-11-29 11:19:47 -08002781 return QCBOR_ERR_UNSUPPORTED;
2782 }
2783
2784 uint8_t uExpectedType = QCBOR_TYPE_TEXT_STRING;
2785 if(uQCBORType & IS_BYTE_STRING_BIT) {
2786 uExpectedType = QCBOR_TYPE_BYTE_STRING;
2787 }
2788
2789 if(pDecodedItem->uDataType != uExpectedType) {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002790 /* It's the arrays and maps that are unrecoverable because
2791 * they are not consumed here. Since this is just an error
2792 * condition, no extra code is added here to make the error
2793 * recoverable for non-arrays and maps like strings. */
2794 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002795 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002796
Laurence Lundblade99615302020-11-29 11:19:47 -08002797 pDecodedItem->uDataType = (uint8_t)(uQCBORType & QCBOR_TYPE_MASK);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002798 return QCBOR_SUCCESS;
2799}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002800#endif /* QCBOR_DISABLE_TAGS */
2801
2802
2803#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002804/**
2805 * @brief Figures out data type for exponent mantissa tags.
2806 *
2807 * @param[in] uTagToProcess Either @ref CBOR_TAG_DECIMAL_FRACTION or
2808 * @ref CBOR_TAG_BIG_FLOAT.
2809 * @param[in] pDecodedItem Item being decoded.
2810 *
2811 * @returns One of the 6 values between \ref QCBOR_TYPE_DECIMAL_FRACTION
2812 * and @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM.
2813 *
2814 * Does mapping between a CBOR tag number and a QCBOR type. with a
2815 * little bit of logic and arithmatic.
2816 *
2817 * Used in serveral contexts. Does the work where sometimes the data
2818 * item is explicitly tagged and sometimes not.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002819 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002820static uint8_t
2821QCBOR_Private_ExpMantissaDataType(const uint16_t uTagToProcess,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002822 const QCBORItem *pDecodedItem)
Laurence Lundblade37286c02022-09-03 10:05:02 -07002823{
2824 uint8_t uBase = uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ?
2825 QCBOR_TYPE_DECIMAL_FRACTION :
2826 QCBOR_TYPE_BIGFLOAT;
2827 if(pDecodedItem->uDataType != QCBOR_TYPE_INT64) {
2828 uBase = (uint8_t)(uBase + pDecodedItem->uDataType - QCBOR_TYPE_POSBIGNUM + 1);
2829 }
2830 return uBase;
2831}
2832#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002833
2834
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002835/**
2836 * @brief Decode tag content for select tags (decoding layer 1).
2837 *
2838 * @param[in] pMe The decode context.
2839 * @param[out] pDecodedItem The decoded item.
2840 *
2841 * @return Decoding error code.
2842 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002843 * CBOR tag numbers for the item were decoded in GetNext_TaggedItem(),
2844 * but the whole tag was not decoded. Here, the whole tags (tag number
2845 * and tag content) that are supported by QCBOR are decoded. This is a
2846 * quick pass through for items that are not tags.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002847 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002848static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002849QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2850 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002851{
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002852 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002853
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002854 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pDecodedItem, NULL);
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002855 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002856 goto Done;
2857 }
2858
Laurence Lundblade37286c02022-09-03 10:05:02 -07002859#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002860 /* When there are no tag numbers for the item, this exits first
2861 * thing and effectively does nothing.
2862 *
2863 * This loops over all the tag numbers accumulated for this item
2864 * trying to decode and interpret them. This stops at the end of
2865 * the list or at the first tag number that can't be interpreted by
2866 * this code. This is effectively a recursive processing of the
2867 * tags number list that handles nested tags.
2868 */
2869 while(1) {
2870 /* Don't bother to unmap tags via QCBORITem.uTags since this
2871 * code only works on tags less than QCBOR_LAST_UNMAPPED_TAG.
2872 */
2873 const uint16_t uTagToProcess = pDecodedItem->uTags[0];
Laurence Lundblade59289e52019-12-30 13:44:37 -08002874
Laurence Lundblade99615302020-11-29 11:19:47 -08002875 if(uTagToProcess == CBOR_TAG_INVALID16) {
2876 /* Hit the end of the tag list. A successful exit. */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002877 break;
2878
Laurence Lundblade99615302020-11-29 11:19:47 -08002879 } else if(uTagToProcess == CBOR_TAG_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002880 uReturn = QCBOR_Private_DecodeDateEpoch(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002881
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002882 } else if(uTagToProcess == CBOR_TAG_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002883 uReturn = QCBOR_Private_DecodeDaysEpoch(pDecodedItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002884
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002885#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade99615302020-11-29 11:19:47 -08002886 } else if(uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ||
2887 uTagToProcess == CBOR_TAG_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002888 uReturn = QCBORDecode_Private_ExpMantissa(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002889 /* --- Which is it, decimal fraction or a bigfloat? --- */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002890 pDecodedItem->uDataType = QCBOR_Private_ExpMantissaDataType(uTagToProcess, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002891
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002892#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002893#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002894 } else if(uTagToProcess == CBOR_TAG_MIME ||
2895 uTagToProcess == CBOR_TAG_BINARY_MIME) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002896 uReturn = QCBOR_Private_DecodeMIME(pDecodedItem);
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002897#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002898
Laurence Lundblade99615302020-11-29 11:19:47 -08002899 } else {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002900 /* See if it is a passthrough byte/text string tag; process if so */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002901 uReturn = QCBOR_Private_ProcessTaggedString(pDecodedItem->uTags[0], pDecodedItem);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002902
Laurence Lundblade99615302020-11-29 11:19:47 -08002903 if(uReturn == QCBOR_ERR_UNSUPPORTED) {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002904 /* It wasn't a passthrough byte/text string tag so it is
Laurence Lundblade99615302020-11-29 11:19:47 -08002905 * an unknown tag. This is the exit from the loop on the
2906 * first unknown tag. It is a successful exit.
2907 */
2908 uReturn = QCBOR_SUCCESS;
2909 break;
2910 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002911 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002912
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002913 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002914 /* Error exit from the loop */
2915 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002916 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002917
2918 /* A tag was successfully processed, shift it out of the list of
2919 * tags returned. This is the loop increment.
2920 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002921 QCBOR_Private_ShiftTags(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002922 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002923#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002924
2925Done:
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002926 return uReturn;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002927}
2928
2929
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002930/**
2931 * @brief Consume an entire map or array including its contents.
2932 *
2933 * @param[in] pMe The decoder context.
2934 * @param[in] pItemToConsume The array/map whose contents are to be
2935 * consumed.
2936 * @param[out] puNextNestLevel The next nesting level after the item was
2937 * fully consumed.
2938 *
2939 * This may be called when @c pItemToConsume is not an array or
2940 * map. In that case, this is just a pass through for @c puNextNestLevel
2941 * since there is nothing to do.
2942 */
2943static QCBORError
2944QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
2945 const QCBORItem *pItemToConsume,
2946 bool *pbBreak,
2947 uint8_t *puNextNestLevel)
2948{
2949 QCBORError uReturn;
2950 QCBORItem Item;
2951
2952 /* If it is a map or array, this will tell if it is empty. */
2953 const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel);
2954
2955 if(QCBORItem_IsMapOrArray(*pItemToConsume) && !bIsEmpty) {
2956 /* There is only real work to do for non-empty maps and arrays */
2957
2958 /* This works for definite- and indefinite-length maps and
2959 * arrays by using the nesting level
2960 */
2961 do {
2962 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pbBreak, &Item, NULL);
2963 if(QCBORDecode_IsUnrecoverableError(uReturn) ||
2964 uReturn == QCBOR_ERR_NO_MORE_ITEMS) {
2965 goto Done;
2966 }
2967 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
2968
2969 *puNextNestLevel = Item.uNextNestLevel;
2970
2971 uReturn = QCBOR_SUCCESS;
2972
2973 } else {
2974 /* pItemToConsume is not a map or array. Just pass the nesting
2975 * level through. */
2976 *puNextNestLevel = pItemToConsume->uNextNestLevel;
2977
2978 uReturn = QCBOR_SUCCESS;
2979 }
2980
2981Done:
2982 return uReturn;
2983}
2984
2985
2986/*
2987 *
2988 * This consumes the next item. It returns the starting position of
2989 * the label and the length of the label. It also returns the nest
2990 * level of the item consumed.
2991 */
2992static QCBORError
2993QCBORDecode_Private_GetLabelAndConsume(QCBORDecodeContext *pMe,
2994 uint8_t *puNestLevel,
2995 size_t *puLabelStart,
2996 size_t *puLabelLen)
2997{
2998 QCBORError uErr;
2999 QCBORItem Item;
3000 uint8_t uLevel;
3001 uint32_t uLabelOffset;
3002
3003 /* Get the label and consume it should it be complex */
3004 *puLabelStart = UsefulInputBuf_Tell(&(pMe->InBuf));
3005
3006 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, &Item, &uLabelOffset);
3007 if(uErr != QCBOR_SUCCESS) {
3008 goto Done;
3009 }
3010 *puLabelLen = uLabelOffset - *puLabelStart;
3011 *puNestLevel = Item.uNestingLevel;
3012 uErr = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uLevel);
3013
3014Done:
3015 return uErr;
3016}
3017
3018
3019/* Loop over items in a map until the end of the map looking for
3020 * duplicates. This starts at the current position in the map, not at
3021 * the beginning of the map.
3022 *
3023 * This saves and restores the traversal cursor and nest tracking so
3024 * they are the same on exit as they were on entry.
3025 */
3026static QCBORError
3027QCBORDecode_Private_CheckDups(QCBORDecodeContext *pMe,
3028 const uint8_t uNestLevel,
3029 const size_t uCompareLabelStart,
3030 const size_t uCompareLabelLen)
3031{
3032 QCBORError uErr;
3033 size_t uLabelStart;
3034 size_t uLabelLen;
3035 uint8_t uLevel;
3036 int nCompare;
3037
3038 const QCBORDecodeNesting SaveNesting = pMe->nesting;
3039 const UsefulInputBuf Save = pMe->InBuf;
3040
3041 do {
3042 uErr = QCBORDecode_Private_GetLabelAndConsume(pMe, &uLevel, &uLabelStart, &uLabelLen);
3043 if(uErr != QCBOR_SUCCESS) {
3044 if(uErr == QCBOR_ERR_NO_MORE_ITEMS) {
3045 uErr = QCBOR_SUCCESS; /* Successful end */
3046 }
3047 break;
3048 }
3049
3050 if(uLevel != uNestLevel) {
3051 break; /* Successful end of loop */
3052 }
3053
3054 /* This check for dups works for labels that are preferred
3055 * serialization and are not maps. If the labels are not in
3056 * preferred serialization, then the check has to be more
3057 * complicated and is type-specific because it uses the decoded
3058 * value, not the encoded CBOR. It is further complicated for
3059 * maps because the order of items in a map that is a label
3060 * doesn't matter when checking that is is the duplicate of
3061 * another map that is a label. QCBOR so far only turns on this
3062 * dup checking as part of CDE checking which requires preferred
3063 * serialization. See 5.6 in RFC 8949.
3064 */
3065 nCompare = UsefulInputBuf_Compare(&(pMe->InBuf),
3066 uCompareLabelStart, uCompareLabelLen,
3067 uLabelStart, uLabelLen);
3068 if(nCompare == 0) {
3069 uErr = QCBOR_ERR_DUPLICATE_LABEL;
3070 break;
3071 }
3072 } while (1);
3073
3074 pMe->nesting = SaveNesting;
3075 pMe->InBuf = Save;
3076
3077 return uErr;
3078}
3079
3080
3081/* This does sort order and duplicate detection on a map. The and all
3082 * it's members must be in preferred serialization so the comparisons
3083 * work correctly.
3084 */
3085static QCBORError
3086QCBORDecode_Private_CheckMap(QCBORDecodeContext *pMe, const QCBORItem *pMapToCheck)
3087{
3088 QCBORError uErr;
3089 uint8_t uNestLevel;
3090 size_t offset2, offset1, length2, length1;
3091
3092 const QCBORDecodeNesting SaveNesting = pMe->nesting;
3093 const UsefulInputBuf Save = pMe->InBuf;
3094 pMe->bAllowAllLabels = 1;
3095
3096 /* This loop runs over all the items in the map once, comparing
3097 * each adjacent pair for correct ordering. It also calls CheckDup
3098 * on each one which also runs over the remaining items in the map
3099 * checking for duplicates. So duplicate checking runs in n^2.
3100 */
3101
3102 offset2 = SIZE_MAX;
3103 length2 = SIZE_MAX; // To avoid uninitialized warning
3104 while(1) {
3105 uErr = QCBORDecode_Private_GetLabelAndConsume(pMe, &uNestLevel, &offset1, &length1);
3106 if(uErr != QCBOR_SUCCESS) {
3107 if(uErr == QCBOR_ERR_NO_MORE_ITEMS) {
3108 uErr = QCBOR_SUCCESS; /* Successful exit from loop */
3109 }
3110 break;
3111 }
3112
3113 if(uNestLevel < pMapToCheck->uNextNestLevel) {
3114 break; /* Successful exit from loop */
3115 }
3116
3117 if(offset2 != SIZE_MAX) {
3118 /* Check that the labels are ordered. Check is not done the
3119 * first time through the loop when offset2 is unset. Since
3120 * this does comparison of the items in encoded form they
3121 * must be preferred serialization encoded. See RFC 8949
3122 * 4.2.1.
3123 */
3124 if(UsefulInputBuf_Compare(&(pMe->InBuf), offset2, length2, offset1, length1) > 0) {
3125 uErr = QCBOR_ERR_UNSORTED;
3126 break;
3127 }
3128 }
3129
3130 uErr = QCBORDecode_Private_CheckDups(pMe, pMapToCheck->uNextNestLevel, offset1, length1);
3131 if(uErr != QCBOR_SUCCESS) {
3132 break;
3133 }
3134
3135 offset2 = offset1;
3136 length2 = length1;
3137 }
3138
3139 pMe->bAllowAllLabels = 0;
3140 pMe->nesting = SaveNesting;
3141 pMe->InBuf = Save;
3142
3143 return uErr;
3144}
3145
3146
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08003147/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003148 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08003149 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003150QCBORError
3151QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
3152{
3153 QCBORError uErr;
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07003154 uErr = QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem);
3155#ifndef QCBOR_DISABLE_CONFORMANCE
3156 if(uErr == QCBOR_SUCCESS && pMe->uDecodeMode >= QCBOR_ENCODE_MODE_CDE && pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
3157 /* Traverse map checking sort order and for duplicates */
3158 uErr = QCBORDecode_Private_CheckMap(pMe, pDecodedItem);
3159 }
3160#endif /* ! QCBOR_DISABLE_CONFORMANCE */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003161 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08003162 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
3163 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
3164 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003165 return uErr;
Laurence Lundblade59289e52019-12-30 13:44:37 -08003166}
3167
3168
3169/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003170 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08003171 */
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08003172QCBORError
3173QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
3174{
3175 const QCBORDecodeNesting SaveNesting = pMe->nesting;
3176 const UsefulInputBuf Save = pMe->InBuf;
3177
3178 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
3179
3180 pMe->nesting = SaveNesting;
3181 pMe->InBuf = Save;
3182
3183 return uErr;
3184}
3185
3186
3187/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003188 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08003189 */
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003190void
3191QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
3192{
3193 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08003194 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
3195 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003196 return;
3197 }
3198
3199 pMe->uLastError = (uint8_t)QCBORDecode_PeekNext(pMe, pDecodedItem);
3200}
3201
3202
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003203static void
3204QCBORDecode_Private_CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem)
3205{
3206#ifndef QCBOR_DISABLE_TAGS
3207 memcpy(pMe->uLastTags, pItem->uTags, sizeof(pItem->uTags));
3208#else
3209 (void)pMe;
3210 (void)pItem;
3211#endif
3212}
3213
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003214/*
3215 * Public function, see header qcbor/qcbor_decode.h file
3216 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003217void
3218QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07003219{
3220 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08003221 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
3222 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07003223 return;
3224 }
3225
3226 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem);
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003227 QCBORDecode_Private_CopyTags(pMe, pDecodedItem);
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07003228}
3229
3230
3231/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003232 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07003233 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07003234QCBORError
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003235QCBORDecode_GetNextWithTags(QCBORDecodeContext *pMe,
3236 QCBORItem *pDecodedItem,
3237 QCBORTagListOut *pTags)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07003238{
Laurence Lundblade37286c02022-09-03 10:05:02 -07003239#ifndef QCBOR_DISABLE_TAGS
3240
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003241 QCBORError uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07003242
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003243 uReturn = QCBORDecode_GetNext(pMe, pDecodedItem);
3244 if(uReturn != QCBOR_SUCCESS) {
3245 return uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07003246 }
3247
3248 if(pTags != NULL) {
3249 pTags->uNumUsed = 0;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003250 /* Reverse the order because pTags is reverse of QCBORItem.uTags. */
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003251 for(int nTagIndex = QCBOR_MAX_TAGS_PER_ITEM-1; nTagIndex >=0; nTagIndex--) {
3252 if(pDecodedItem->uTags[nTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07003253 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07003254 }
3255 if(pTags->uNumUsed >= pTags->uNumAllocated) {
3256 return QCBOR_ERR_TOO_MANY_TAGS;
3257 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003258 pTags->puTags[pTags->uNumUsed] = QCBORDecode_Private_UnMapTagNumber(pMe,pDecodedItem->uTags[nTagIndex]);
Laurence Lundblade830fbf92020-05-31 17:22:33 -07003259 pTags->uNumUsed++;
3260 }
3261 }
3262
3263 return QCBOR_SUCCESS;
Laurence Lundblade37286c02022-09-03 10:05:02 -07003264
3265#else /* QCBOR_DISABLE_TAGS */
3266 (void)pMe;
3267 (void)pDecodedItem;
3268 (void)pTags;
3269 return QCBOR_ERR_TAGS_DISABLED;
3270#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07003271}
3272
3273
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07003274/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003275 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05303276 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003277bool
3278QCBORDecode_IsTagged(QCBORDecodeContext *pMe,
3279 const QCBORItem *pItem,
3280 uint64_t uTag)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07003281{
Laurence Lundblade37286c02022-09-03 10:05:02 -07003282#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003283 for(unsigned uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) {
3284 if(pItem->uTags[uTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07003285 break;
3286 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003287 if(QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uTagIndex]) == uTag) {
Laurence Lundbladef71e1622020-08-06 18:52:13 -07003288 return true;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07003289 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07003290 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07003291#else /* QCBOR_TAGS_DISABLED */
3292 (void)pMe;
3293 (void)pItem;
3294 (void)uTag;
3295#endif /* QCBOR_TAGS_DISABLED */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003296
Laurence Lundbladef71e1622020-08-06 18:52:13 -07003297 return false;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07003298}
3299
3300
3301/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003302 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07003303 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003304QCBORError
3305QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07003306{
Laurence Lundblade87495732021-02-26 10:05:55 -07003307 if(puConsumed != NULL) {
3308 *puConsumed = pMe->InBuf.cursor;
3309 }
3310
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003311 QCBORError uReturn = pMe->uLastError;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003312
3313 if(uReturn != QCBOR_SUCCESS) {
3314 goto Done;
3315 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003316
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003317 /* Error out if all the maps/arrays are not closed out */
3318 if(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003319 uReturn = QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08003320 goto Done;
3321 }
3322
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003323 /* Error out if not all the bytes are consumed */
3324 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf))) {
Laurence Lundblade085d7952020-07-24 10:26:30 -07003325 uReturn = QCBOR_ERR_EXTRA_BYTES;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08003326 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003327
Laurence Lundblade20b533d2018-10-08 20:44:53 +08003328Done:
Laurence Lundblade87495732021-02-26 10:05:55 -07003329 return uReturn;
3330}
3331
3332
3333/*
3334 * Public function, see header qcbor/qcbor_decode.h file
3335 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003336QCBORError
3337QCBORDecode_Finish(QCBORDecodeContext *pMe)
Laurence Lundblade87495732021-02-26 10:05:55 -07003338{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003339#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003340 /* Call the destructor for the string allocator if there is one.
3341 * Always called, even if there are errors; always have to clean up.
3342 */
3343 StringAllocator_Destruct(&(pMe->StringAllocator));
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003344#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003345
Laurence Lundblade87495732021-02-26 10:05:55 -07003346 return QCBORDecode_PartialFinish(pMe, NULL);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07003347}
3348
3349
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07003350/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003351 * Public function, see header qcbor/qcbor_decode.h file
3352 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003353uint64_t
3354QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
3355 const QCBORItem *pItem,
3356 uint32_t uIndex)
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07003357{
Laurence Lundblade37286c02022-09-03 10:05:02 -07003358#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade88e9db22020-11-02 03:56:33 -08003359 if(pItem->uDataType == QCBOR_TYPE_NONE) {
3360 return CBOR_TAG_INVALID64;
3361 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003362 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
3363 return CBOR_TAG_INVALID64;
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07003364 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003365 return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uIndex]);
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07003366 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07003367#else /* QCBOR_DISABLE_TAGS */
3368 (void)pMe;
3369 (void)pItem;
3370 (void)uIndex;
3371
3372 return CBOR_TAG_INVALID64;
3373#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07003374}
3375
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003376
Laurence Lundblade9b334962020-08-27 10:55:53 -07003377/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003378 * Public function, see header qcbor/qcbor_decode.h file
3379 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003380uint64_t
3381QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe,
3382 uint32_t uIndex)
Laurence Lundblade9b334962020-08-27 10:55:53 -07003383{
Laurence Lundblade37286c02022-09-03 10:05:02 -07003384#ifndef QCBOR_DISABLE_TAGS
3385
Laurence Lundblade88e9db22020-11-02 03:56:33 -08003386 if(pMe->uLastError != QCBOR_SUCCESS) {
3387 return CBOR_TAG_INVALID64;
3388 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003389 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
3390 return CBOR_TAG_INVALID64;
3391 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003392 return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->uLastTags[uIndex]);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003393 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07003394#else /* QCBOR_DISABLE_TAGS */
3395 (void)pMe;
3396 (void)uIndex;
3397
3398 return CBOR_TAG_INVALID64;
3399#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003400}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07003401
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07003402
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003403
3404
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003405#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladef6531662018-12-04 10:42:22 +09003406
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003407/* ===========================================================================
3408 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003409
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003410 This implements a simple sting allocator for indefinite-length
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003411 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
3412 implements the function type QCBORStringAllocate and allows easy
3413 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09003414
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003415 This particular allocator is built-in for convenience. The caller
3416 can implement their own. All of this following code will get
3417 dead-stripped if QCBORDecode_SetMemPool() is not called.
3418
3419 This is a very primitive memory allocator. It does not track
3420 individual allocations, only a high-water mark. A free or
3421 reallocation must be of the last chunk allocated.
3422
3423 The size of the pool and offset to free memory are packed into the
3424 first 8 bytes of the memory pool so we don't have to keep them in
3425 the decode context. Since the address of the pool may not be
3426 aligned, they have to be packed and unpacked as if they were
3427 serialized data of the wire or such.
3428
3429 The sizes packed in are uint32_t to be the same on all CPU types
3430 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08003431 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003432
3433
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003434static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08003435MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003436{
3437 // Use of UsefulInputBuf is overkill, but it is convenient.
3438 UsefulInputBuf UIB;
3439
Laurence Lundbladeee851742020-01-08 08:37:05 -08003440 // Just assume the size here. It was checked during SetUp so
3441 // the assumption is safe.
Laurence Lundblade93d89472020-10-03 22:30:50 -07003442 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem,QCBOR_DECODE_MIN_MEM_POOL_SIZE});
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003443 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
3444 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
3445 return UsefulInputBuf_GetError(&UIB);
3446}
3447
3448
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003449static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08003450MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003451{
3452 // Use of UsefulOutBuf is overkill, but convenient. The
3453 // length check performed here is useful.
3454 UsefulOutBuf UOB;
3455
3456 UsefulOutBuf_Init(&UOB, Pool);
3457 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
3458 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
3459 return UsefulOutBuf_GetError(&UOB);
3460}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003461
3462
3463/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003464 Internal function for an allocation, reallocation free and destuct.
3465
3466 Having only one function rather than one each per mode saves space in
3467 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003468
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003469 Code Reviewers: THIS FUNCTION DOES POINTER MATH
3470 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08003471static UsefulBuf
3472MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003473{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003474 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003475
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003476 uint32_t uPoolSize;
3477 uint32_t uFreeOffset;
3478
3479 if(uNewSize > UINT32_MAX) {
3480 // This allocator is only good up to 4GB. This check should
3481 // optimize out if sizeof(size_t) == sizeof(uint32_t)
3482 goto Done;
3483 }
3484 const uint32_t uNewSize32 = (uint32_t)uNewSize;
3485
3486 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
3487 goto Done;
3488 }
3489
3490 if(uNewSize) {
3491 if(pMem) {
3492 // REALLOCATION MODE
3493 // Calculate pointer to the end of the memory pool. It is
3494 // assumed that pPool + uPoolSize won't wrap around by
3495 // assuming the caller won't pass a pool buffer in that is
3496 // not in legitimate memory space.
3497 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
3498
3499 // Check that the pointer for reallocation is in the range of the
3500 // pool. This also makes sure that pointer math further down
3501 // doesn't wrap under or over.
3502 if(pMem >= pPool && pMem < pPoolEnd) {
3503 // Offset to start of chunk for reallocation. This won't
3504 // wrap under because of check that pMem >= pPool. Cast
3505 // is safe because the pool is always less than UINT32_MAX
3506 // because of check in QCBORDecode_SetMemPool().
3507 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3508
3509 // Check to see if the allocation will fit. uPoolSize -
3510 // uMemOffset will not wrap under because of check that
3511 // pMem is in the range of the uPoolSize by check above.
3512 if(uNewSize <= uPoolSize - uMemOffset) {
3513 ReturnValue.ptr = pMem;
3514 ReturnValue.len = uNewSize;
3515
3516 // Addition won't wrap around over because uNewSize was
3517 // checked to be sure it is less than the pool size.
3518 uFreeOffset = uMemOffset + uNewSize32;
3519 }
3520 }
3521 } else {
3522 // ALLOCATION MODE
3523 // uPoolSize - uFreeOffset will not underflow because this
3524 // pool implementation makes sure uFreeOffset is always
3525 // smaller than uPoolSize through this check here and
3526 // reallocation case.
3527 if(uNewSize <= uPoolSize - uFreeOffset) {
3528 ReturnValue.len = uNewSize;
3529 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08003530 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003531 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003532 }
3533 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003534 if(pMem) {
3535 // FREE MODE
3536 // Cast is safe because of limit on pool size in
3537 // QCBORDecode_SetMemPool()
3538 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3539 } else {
3540 // DESTRUCT MODE
3541 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003542 }
3543 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003544
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003545 UsefulBuf Pool = {pPool, uPoolSize};
3546 MemPool_Pack(Pool, uFreeOffset);
3547
3548Done:
3549 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003550}
3551
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003552
Laurence Lundbladef6531662018-12-04 10:42:22 +09003553/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003554 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09003555 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003556QCBORError
3557QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
3558 UsefulBuf Pool,
3559 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003560{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003561 // The pool size and free mem offset are packed into the beginning
Dave Thaler93c01182022-08-06 15:08:35 -04003562 // of the pool memory. This compile time check makes sure the
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003563 // constant in the header is correct. This check should optimize
3564 // down to nothing.
Dave Thaler93c01182022-08-06 15:08:35 -04003565#ifdef _MSC_VER
3566#pragma warning(push)
3567#pragma warning(disable:4127) // conditional expression is constant
3568#endif
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003569 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003570 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003571 }
Dave Thaler93c01182022-08-06 15:08:35 -04003572#ifdef _MSC_VER
3573#pragma warning(pop)
3574#endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003575
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003576 // The pool size and free offset packed in to the beginning of pool
3577 // memory are only 32-bits. This check will optimize out on 32-bit
3578 // machines.
3579 if(Pool.len > UINT32_MAX) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003580 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003581 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003582
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003583 // This checks that the pool buffer given is big enough.
3584 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
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 Lundblade3427dee2021-06-20 11:11:24 -07003588 QCBORDecode_SetUpAllocator(pMe, MemPool_Function, Pool.ptr, bAllStrings);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003589
Laurence Lundblade30816f22018-11-10 13:40:22 +07003590 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003591}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003592#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003593
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003594
3595
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003596/*
3597 * Public function, see header qcbor/qcbor_decode.h file
3598 */
3599void
3600QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003601{
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003602 QCBORDecode_VGetNext(pMe, pDecodedItem);
3603
3604 if(pMe->uLastError == QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003605 pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL,
Máté Tóth-Pálc6d59682021-05-26 18:55:30 +02003606 &pDecodedItem->uNextNestLevel);
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003607 }
3608}
3609
3610
Laurence Lundblade11654912024-05-09 11:49:24 -07003611/*
3612 * Public function, see header qcbor/qcbor_decode.h file
3613 */
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003614QCBORError
3615QCBORDecode_EndCheck(QCBORDecodeContext *pMe)
Laurence Lundblade11654912024-05-09 11:49:24 -07003616{
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003617 size_t uCursorOffset;
3618 QCBORError uErr;
Laurence Lundblade11654912024-05-09 11:49:24 -07003619
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003620 uErr = QCBORDecode_GetError(pMe);
3621 if(uErr != QCBOR_SUCCESS) {
3622 return uErr;
Laurence Lundblade11654912024-05-09 11:49:24 -07003623 }
3624
3625 uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
3626
3627 if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003628 return QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade11654912024-05-09 11:49:24 -07003629 }
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003630
3631 return QCBOR_SUCCESS;
Laurence Lundblade11654912024-05-09 11:49:24 -07003632}
3633
3634
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003635/**
3636 * @brief Rewind cursor to start as if map or array were just entered.
3637 *
3638 * @param[in] pMe The decoding context
3639 *
3640 * This affects the nesting tracking and the UsefulInputBuf.
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003641 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003642static void
3643QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003644{
3645 /* Reset nesting tracking to the deepest bounded level */
3646 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3647
3648 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3649
3650 /* Reposition traversal cursor to the start of the map/array */
3651 UsefulInputBuf_Seek(&(pMe->InBuf),
3652 DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
3653}
3654
3655
3656/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003657 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003658 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003659void
3660QCBORDecode_Rewind(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003661{
3662 if(pMe->nesting.pCurrentBounded != NULL) {
3663 /* In a bounded map, array or bstr-wrapped CBOR */
3664
3665 if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
3666 /* In bstr-wrapped CBOR. */
3667
3668 /* Reposition traversal cursor to start of wrapping byte string */
3669 UsefulInputBuf_Seek(&(pMe->InBuf),
3670 pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
3671 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3672
3673 } else {
3674 /* In a map or array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003675 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003676 }
3677
3678 } else {
3679 /* Not in anything bounded */
3680
3681 /* Reposition traversal cursor to the start of input CBOR */
3682 UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
3683
3684 /* Reset nesting tracking to beginning of input. */
3685 DecodeNesting_Init(&(pMe->nesting));
3686 }
3687
3688 pMe->uLastError = QCBOR_SUCCESS;
3689}
3690
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003691
Laurence Lundblade9b334962020-08-27 10:55:53 -07003692
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003693
3694
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003695typedef struct {
3696 void *pCBContext;
3697 QCBORItemCallback pfCallback;
3698} MapSearchCallBack;
3699
3700typedef struct {
3701 size_t uStartOffset;
3702 uint16_t uItemCount;
3703} MapSearchInfo;
3704
3705
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003706/**
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003707 * @brief Search a map for a set of items.
3708 *
3709 * @param[in] pMe The decode context to search.
3710 * @param[in,out] pItemArray The items to search for and the items found.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003711 * @param[out] pInfo Several bits of meta-info returned by search.
3712 * @param[in] pCallBack Callback object or @c NULL.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003713 *
3714 * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map.
3715 *
3716 * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label)
3717 * were found for one of the labels being
3718 * search for. This duplicate detection is
3719 * only performed for items in pItemArray,
3720 * not every item in the map.
3721 *
3722 * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was
3723 * wrong for the matchd label.
3724 *
3725 * @retval Also errors returned by QCBORDecode_GetNext().
3726 *
3727 * On input, \c pItemArray contains a list of labels and data types of
3728 * items to be found.
3729 *
3730 * On output, the fully retrieved items are filled in with values and
3731 * such. The label was matched, so it never changes.
3732 *
3733 * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE.
3734 *
3735 * This also finds the ends of maps and arrays when they are exited.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003736 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003737static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003738QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
3739 QCBORItem *pItemArray,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003740 MapSearchInfo *pInfo,
3741 MapSearchCallBack *pCallBack)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003742{
Laurence Lundbladee6f15112020-07-23 18:44:16 -07003743 QCBORError uReturn;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003744 uint64_t uFoundItemBitMap = 0;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07003745
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003746 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003747 uReturn = pMe->uLastError;
3748 goto Done2;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003749 }
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003750
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003751 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) &&
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003752 pItemArray->uLabelType != QCBOR_TYPE_NONE) {
3753 /* QCBOR_TYPE_NONE as first item indicates just looking
3754 for the end of an array, so don't give error. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003755 uReturn = QCBOR_ERR_MAP_NOT_ENTERED;
3756 goto Done2;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003757 }
3758
Laurence Lundblade085d7952020-07-24 10:26:30 -07003759 if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) {
3760 // It is an empty bounded array or map
3761 if(pItemArray->uLabelType == QCBOR_TYPE_NONE) {
3762 // Just trying to find the end of the map or array
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003763 pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003764 uReturn = QCBOR_SUCCESS;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003765 } else {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003766 // Nothing is ever found in an empty array or map. All items
3767 // are marked as not found below.
Laurence Lundblade085d7952020-07-24 10:26:30 -07003768 uReturn = QCBOR_SUCCESS;
3769 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003770 goto Done2;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003771 }
3772
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003773 QCBORDecodeNesting SaveNesting;
Laurence Lundblade11654912024-05-09 11:49:24 -07003774 size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003775 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3776
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003777 /* Reposition to search from the start of the map / array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003778 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundblade1341c592020-04-11 14:19:05 -07003779
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003780 /*
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003781 Loop over all the items in the map or array. Each item
3782 could be a map or array, but label matching is only at
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003783 the main level. This handles definite- and indefinite-
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003784 length maps and arrays. The only reason this is ever
3785 called on arrays is to find their end position.
3786
3787 This will always run over all items in order to do
3788 duplicate detection.
3789
3790 This will exit with failure if it encounters an
3791 unrecoverable error, but continue on for recoverable
3792 errors.
3793
3794 If a recoverable error occurs on a matched item, then
3795 that error code is returned.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003796 */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07003797 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003798 if(pInfo) {
3799 pInfo->uItemCount = 0;
3800 }
Máté Tóth-Pál2f2aa5f2021-05-17 21:35:09 +02003801 uint8_t uNextNestLevel;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003802 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003803 /* Remember offset of the item because sometimes it has to be returned */
Laurence Lundblade1341c592020-04-11 14:19:05 -07003804 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003805
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003806 /* Get the item */
3807 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003808 /* QCBORDecode_Private_GetNextTagContent() rather than GetNext()
3809 * because a label match is performed on recoverable errors to
3810 * be able to return the the error code for the found item. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003811 QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003812 if(QCBORDecode_IsUnrecoverableError(uResult)) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003813 /* The map/array can't be decoded when unrecoverable errors occur */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003814 uReturn = uResult;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003815 goto Done;
3816 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003817 if(uResult == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003818 /* Unexpected end of map or array. */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003819 uReturn = uResult;
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003820 goto Done;
3821 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003822
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003823 /* See if item has one of the labels that are of interest */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003824 bool bMatched = false;
3825 for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003826 if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003827 /* A label match has been found */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003828 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
3829 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003830 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003831 }
Laurence Lundblade63926052021-03-29 16:05:51 -07003832 if(uResult != QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003833 /* The label matches, but the data item is in error.
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003834 * It is OK to have recoverable errors on items that
3835 * are not matched. */
Laurence Lundblade63926052021-03-29 16:05:51 -07003836 uReturn = uResult;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003837 goto Done;
3838 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003839 if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) {
Laurence Lundblade63926052021-03-29 16:05:51 -07003840 /* The data item is not of the type(s) requested */
3841 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003842 goto Done;
3843 }
3844
Laurence Lundblade1341c592020-04-11 14:19:05 -07003845 /* Successful match. Return the item. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003846 pItemArray[nIndex] = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003847 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003848 if(pInfo) {
3849 pInfo->uStartOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003850 }
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003851 bMatched = true;
3852 }
3853 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003854
3855
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003856 if(!bMatched && pCallBack != NULL) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003857 /*
3858 Call the callback on unmatched labels.
3859 (It is tempting to do duplicate detection here, but that would
3860 require dynamic memory allocation because the number of labels
3861 that might be encountered is unbounded.)
3862 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003863 uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item);
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003864 if(uReturn != QCBOR_SUCCESS) {
3865 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003866 }
3867 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003868
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003869 /*
3870 Consume the item whether matched or not. This
3871 does the work of traversing maps and array and
3872 everything in them. In this loop only the
3873 items at the current nesting level are examined
3874 to match the labels.
3875 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003876 uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel);
Laurence Lundbladec7114722020-08-13 05:11:40 -07003877 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003878 goto Done;
3879 }
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003880
3881 if(pInfo) {
3882 pInfo->uItemCount++;
3883 }
3884
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003885 } while (uNextNestLevel >= uMapNestLevel);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003886
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003887 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003888
3889 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003890
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003891 // Check here makes sure that this won't accidentally be
3892 // QCBOR_MAP_OFFSET_CACHE_INVALID which is larger than
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003893 // QCBOR_MAX_DECODE_INPUT_SIZE.
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -08003894 // Cast to uint32_t to possibly address cases where SIZE_MAX < UINT32_MAX
3895 if((uint32_t)uEndOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003896 uReturn = QCBOR_ERR_INPUT_TOO_LARGE;
3897 goto Done;
3898 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003899 /* Cast OK because encoded CBOR is limited to UINT32_MAX */
3900 pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003901
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003902 Done:
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003903 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade11654912024-05-09 11:49:24 -07003904 UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos);
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003905
3906 Done2:
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003907 /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */
Laurence Lundbladec7114722020-08-13 05:11:40 -07003908 for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003909 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003910 pItemArray[i].uDataType = QCBOR_TYPE_NONE;
3911 pItemArray[i].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003912 }
3913 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003914
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003915 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003916}
3917
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003918
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003919/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003920 * Public function, see header qcbor/qcbor_decode.h file
3921 */
3922void
3923QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
3924 int64_t nLabel,
3925 uint8_t uQcborType,
3926 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003927{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003928 if(pMe->uLastError != QCBOR_SUCCESS) {
3929 return;
3930 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003931
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003932 QCBORItem OneItemSeach[2];
3933 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3934 OneItemSeach[0].label.int64 = nLabel;
3935 OneItemSeach[0].uDataType = uQcborType;
3936 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003937
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003938 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003939
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003940 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003941 pItem->uDataType = QCBOR_TYPE_NONE;
3942 pItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003943 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003944 }
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003945
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003946 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003947 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003948 }
3949
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003950 *pItem = OneItemSeach[0];
3951 QCBORDecode_Private_CopyTags(pMe, pItem);
3952
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003953 Done:
3954 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003955}
3956
3957
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003958/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003959 * Public function, see header qcbor/qcbor_decode.h file
3960 */
3961void
3962QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
3963 const char *szLabel,
3964 uint8_t uQcborType,
3965 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003966{
Laurence Lundbladeda095972020-06-06 18:35:33 -07003967 if(pMe->uLastError != QCBOR_SUCCESS) {
3968 return;
3969 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003970
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003971#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003972 QCBORItem OneItemSeach[2];
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003973 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3974 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3975 OneItemSeach[0].uDataType = uQcborType;
3976 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003977
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003978 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
3979
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003980 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003981 pItem->uDataType = QCBOR_TYPE_NONE;
3982 pItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003983 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003984 }
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003985 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003986 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003987 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003988 }
3989
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003990 *pItem = OneItemSeach[0];
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003991 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003992
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003993Done:
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003994#else
3995 (void)pMe;
3996 (void)szLabel;
3997 (void)uQcborType;
3998 (void)pItem;
3999 QCBORError uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
4000#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
4001
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004002 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004003}
4004
4005
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004006
4007/**
4008 * @brief Semi-private. Get pointer, length and item for an array or map.
4009 *
4010 * @param[in] pMe The decode context.
4011 * @param[in] uType CBOR major type, either array/map.
4012 * @param[out] pItem The item for the array/map.
4013 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
4014 *
4015 * The next item to be decoded must be a map or array as specified by \c uType.
4016 *
4017 * \c pItem will be filled in with the label and tags of the array or map
4018 * in addition to \c pEncodedCBOR giving the pointer and length of the
4019 * encoded CBOR.
4020 *
4021 * When this is complete, the traversal cursor is at the end of the array or
4022 * map that was retrieved.
4023 */
4024void
4025QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe,
4026 const uint8_t uType,
4027 QCBORItem *pItem,
4028 UsefulBufC *pEncodedCBOR)
4029{
4030 QCBORError uErr;
4031 uint8_t uNestLevel;
4032 size_t uStartingCursor;
4033 size_t uStartOfReturned;
4034 size_t uEndOfReturned;
4035 size_t uTempSaveCursor;
4036 bool bInMap;
4037 QCBORItem LabelItem;
4038 bool EndedByBreak;
4039
4040 uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
4041 bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting));
4042
4043 /* Could call GetNext here, but don't need to because this
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07004044 * is only interested in arrays and maps. TODO: switch to GetNext()? */
4045 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem, NULL);
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004046 if(uErr != QCBOR_SUCCESS) {
4047 pMe->uLastError = (uint8_t)uErr;
4048 return;
4049 }
4050
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004051 uint8_t uItemDataType = pItem->uDataType;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004052#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004053 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
4054 uItemDataType = QCBOR_TYPE_ARRAY;
4055 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004056#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004057
4058 if(uItemDataType != uType) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004059 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4060 return;
4061 }
4062
4063 if(bInMap) {
4064 /* If the item is in a map, the start of the array/map
4065 * itself, not the label, must be found. Do this by
4066 * rewinding to the starting position and fetching
4067 * just the label data item. QCBORDecode_Private_GetNextTagNumber()
4068 * doesn't do any of the array/map item counting or nesting
4069 * level tracking. Used here it will just fetech the label
4070 * data item.
4071 *
4072 * Have to save the cursor and put it back to the position
4073 * after the full item once the label as been fetched by
4074 * itself.
4075 */
4076 uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
4077 UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor);
4078
4079 /* Item has been fetched once so safe to ignore error */
4080 (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem);
4081
4082 uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
4083 UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor);
4084 } else {
4085 uStartOfReturned = uStartingCursor;
4086 }
4087
4088 /* Consume the entire array/map to find the end */
4089 uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel);
4090 if(uErr != QCBOR_SUCCESS) {
4091 pMe->uLastError = (uint8_t)uErr;
4092 goto Done;
4093 }
4094
4095 /* Fill in returned values */
4096 uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
4097 if(EndedByBreak) {
4098 /* When ascending nesting levels, a break for the level above
4099 * was consumed. That break is not a part of what is consumed here. */
4100 uEndOfReturned--;
4101 }
4102 pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned);
4103 pEncodedCBOR->len = uEndOfReturned - uStartOfReturned;
4104
4105Done:
4106 return;
4107}
4108
4109
4110/**
4111 * @brief Semi-private. Get pointer, length and item count of an array or map.
4112 *
4113 * @param[in] pMe The decode context.
4114 * @param[in] pTarget The label and type of the array or map to retrieve.
4115 * @param[out] pItem The item for the array/map.
4116 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
4117 *
4118 * The next item to be decoded must be a map or array as specified by \c uType.
4119 *
4120 * When this is complete, the traversal cursor is unchanged.
4121 */void
4122QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe,
4123 QCBORItem *pTarget,
4124 QCBORItem *pItem,
4125 UsefulBufC *pEncodedCBOR)
4126{
4127 MapSearchInfo Info;
4128 QCBORDecodeNesting SaveNesting;
4129 size_t uSaveCursor;
4130
4131 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL);
4132 if(pMe->uLastError != QCBOR_SUCCESS) {
4133 return;
4134 }
4135
4136 /* Save the whole position of things so they can be restored.
4137 * so the cursor position is unchanged by this operation, like
4138 * all the other GetXxxxInMap() operations. */
4139 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
4140 uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
4141
4142 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
4143 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
4144 QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR);
4145
4146 UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor);
4147 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
4148}
4149
4150
4151
4152
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004153/**
4154 * @brief Is a QCBOR_TYPE in the type list?
4155 *
4156 * @param[in] uDataType Type to check for.
4157 * @param[in] puTypeList List to check.
4158 *
4159 * @retval QCBOR_SUCCESS If in the list.
4160 * @retval QCBOR_ERR_UNEXPECTED_TYPE Not in the list.
4161 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07004162static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004163QCBOR_Private_CheckTypeList(const int uDataType,
4164 const uint8_t puTypeList[QCBOR_TAGSPEC_NUM_TYPES])
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004165{
4166 for(size_t i = 0; i < QCBOR_TAGSPEC_NUM_TYPES; i++) {
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08004167 if(uDataType == puTypeList[i]) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004168 return QCBOR_SUCCESS;
4169 }
4170 }
4171 return QCBOR_ERR_UNEXPECTED_TYPE;
4172}
4173
Laurence Lundblade67257dc2020-07-27 03:33:37 -07004174
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004175/**
Laurence Lundblade37286c02022-09-03 10:05:02 -07004176 * Match a tag/type specification against the type of the item.
4177 *
4178 * @param[in] TagSpec Specification for matching tags.
4179 * @param[in] pItem The item to check.
4180 *
4181 * @retval QCBOR_SUCCESS \c uDataType is allowed by @c TagSpec
4182 * @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec
4183 *
4184 * This checks the item data type of untagged items as well as of
4185 * tagged items against a specification to see if decoding should
4186 * proceed.
4187 *
4188 * This relies on the automatic tag decoding done by QCBOR that turns
4189 * tag numbers into particular QCBOR_TYPEs so there is no actual
4190 * comparsion of tag numbers, just of QCBOR_TYPEs.
4191 *
4192 * This checks the data item type as possibly representing the tag
4193 * number or as the tag content type.
4194 *
4195 * If QCBOR_DISABLE_TAGS is #defined, this primarily checks the item
4196 * data type against the allowed tag content types. It will also error out
4197 * if the caller tries to require a tag because there is no way that can
4198 * ever be fulfilled.
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004199 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07004200static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004201QCBOR_Private_CheckTagRequirement(const QCBOR_Private_TagSpec TagSpec,
4202 const QCBORItem *pItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07004203{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08004204 const int nItemType = pItem->uDataType; /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004205 const int nTagReq = TagSpec.uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
4206
4207#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08004208 /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade9b334962020-08-27 10:55:53 -07004209 if(!(TagSpec.uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS) &&
4210 pItem->uTags[0] != CBOR_TAG_INVALID16) {
4211 /* There are tags that QCBOR couldn't process on this item and
Laurence Lundblade37286c02022-09-03 10:05:02 -07004212 * the caller has told us there should not be.
4213 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07004214 return QCBOR_ERR_UNEXPECTED_TYPE;
4215 }
4216
Laurence Lundblade9b334962020-08-27 10:55:53 -07004217 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
Laurence Lundblade37286c02022-09-03 10:05:02 -07004218 /* Must match the tag number and only the tag */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004219 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07004220 }
4221
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004222 QCBORError uReturn = QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07004223 if(uReturn == QCBOR_SUCCESS) {
4224 return QCBOR_SUCCESS;
4225 }
4226
4227 if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
4228 /* Must match the content type and only the content type.
Laurence Lundblade37286c02022-09-03 10:05:02 -07004229 * There was no match just above so it is a fail. */
Laurence Lundblade9b334962020-08-27 10:55:53 -07004230 return QCBOR_ERR_UNEXPECTED_TYPE;
4231 }
4232
Laurence Lundblade37286c02022-09-03 10:05:02 -07004233 /* QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG: If here it can match either the tag or the content
4234 * and it hasn't matched the content, so the end
4235 * result is whether it matches the tag. This is
4236 * the tag optional case that the CBOR standard discourages.
4237 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07004238
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004239 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07004240
Laurence Lundblade37286c02022-09-03 10:05:02 -07004241#else /* QCBOR_DISABLE_TAGS */
4242 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
4243 return QCBOR_ERR_UNEXPECTED_TYPE;
4244 }
4245
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07004246 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade37286c02022-09-03 10:05:02 -07004247
4248#endif /* QCBOR_DISABLE_TAGS */
4249}
Laurence Lundblade9b334962020-08-27 10:55:53 -07004250
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004251
4252/**
4253 * @brief Get an item by label to match a tag specification.
4254 *
4255 * @param[in] pMe The decode context.
4256 * @param[in] nLabel The label to search map for.
4257 * @param[in] TagSpec The tag number specification to match.
4258 * @param[out] pItem The item found.
4259 *
4260 * This finds the item with the given label in currently open
4261 * map. Then checks that its tag number and types matches the tag
4262 * specification. If not, an error is set in the decode context.
4263 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004264static void
4265QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
4266 const int64_t nLabel,
4267 const QCBOR_Private_TagSpec TagSpec,
4268 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004269{
4270 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
4271 if(pMe->uLastError != QCBOR_SUCCESS) {
4272 return;
4273 }
4274
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004275 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004276}
4277
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07004278
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004279/**
4280 * @brief Get an item by label to match a tag specification.
4281 *
4282 * @param[in] pMe The decode context.
4283 * @param[in] szLabel The label to search map for.
4284 * @param[in] TagSpec The tag number specification to match.
4285 * @param[out] pItem The item found.
4286 *
4287 * This finds the item with the given label in currently open
4288 * map. Then checks that its tag number and types matches the tag
4289 * specification. If not, an error is set in the decode context.
4290 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004291static void
4292QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
4293 const char *szLabel,
4294 const QCBOR_Private_TagSpec TagSpec,
4295 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004296{
4297 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
4298 if(pMe->uLastError != QCBOR_SUCCESS) {
4299 return;
4300 }
4301
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004302 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004303}
4304
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004305
4306/**
4307 * @brief Semi-private to get an string by label to match a tag specification.
4308 *
4309 * @param[in] pMe The decode context.
4310 * @param[in] nLabel The label to search map for.
4311 * @param[in] TagSpec The tag number specification to match.
4312 * @param[out] pString The string found.
4313 *
4314 * This finds the string with the given label in currently open
4315 * map. Then checks that its tag number and types matches the tag
4316 * specification. If not, an error is set in the decode context.
4317 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004318void
4319QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
4320 const int64_t nLabel,
4321 const QCBOR_Private_TagSpec TagSpec,
4322 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004323{
4324 QCBORItem Item;
4325 QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
4326 if(pMe->uLastError == QCBOR_SUCCESS) {
4327 *pString = Item.val.string;
4328 }
4329}
4330
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004331
4332/**
4333 * @brief Semi-private to get an string by label to match a tag specification.
4334 *
4335 * @param[in] pMe The decode context.
4336 * @param[in] szLabel The label to search map for.
4337 * @param[in] TagSpec The tag number specification to match.
4338 * @param[out] pString The string found.
4339 *
4340 * This finds the string with the given label in currently open
4341 * map. Then checks that its tag number and types matches the tag
4342 * specification. If not, an error is set in the decode context.
4343 */void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004344QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
4345 const char * szLabel,
4346 const QCBOR_Private_TagSpec TagSpec,
4347 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004348{
4349 QCBORItem Item;
4350 QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
4351 if(pMe->uLastError == QCBOR_SUCCESS) {
4352 *pString = Item.val.string;
4353 }
4354}
Laurence Lundblade1341c592020-04-11 14:19:05 -07004355
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004356
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004357/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004358 * Public function, see header qcbor/qcbor_decode.h file
4359 */
4360void
4361QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004362{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004363 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL);
Laurence Lundblade5f53f832020-09-03 12:00:14 -07004364 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004365}
4366
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004367/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004368 * Public function, see header qcbor/qcbor_decode.h file
4369 */
4370void
4371QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe,
4372 QCBORItem *pItemList,
4373 void *pCallbackCtx,
4374 QCBORItemCallback pfCB)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004375{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004376 MapSearchCallBack CallBack;
4377 CallBack.pCBContext = pCallbackCtx;
4378 CallBack.pfCallback = pfCB;
4379
4380 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack);
4381
Laurence Lundblade5f53f832020-09-03 12:00:14 -07004382 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004383}
4384
4385
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004386/**
4387 * @brief Search for a map/array by label and enter it
4388 *
4389 * @param[in] pMe The decode context.
4390 * @param[in] pSearch The map/array to search for.
4391 *
4392 * @c pSearch is expected to contain one item of type map or array
4393 * with the label specified. The current bounded map will be searched for
4394 * this and if found will be entered.
4395 *
4396 * If the label is not found, or the item found is not a map or array,
4397 * the error state is set.
4398 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004399static void
4400QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07004401{
Laurence Lundblade323f8a92020-09-06 19:43:09 -07004402 // The first item in pSearch is the one that is to be
4403 // entered. It should be the only one filled in. Any other
4404 // will be ignored unless it causes an error.
Laurence Lundblade34691b92020-05-18 22:25:25 -07004405 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07004406 return;
4407 }
4408
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004409 MapSearchInfo Info;
4410 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pSearch, &Info, NULL);
Laurence Lundblade34691b92020-05-18 22:25:25 -07004411 if(pMe->uLastError != QCBOR_SUCCESS) {
4412 return;
4413 }
4414
Laurence Lundblade9b334962020-08-27 10:55:53 -07004415 if(pSearch->uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004416 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004417 return;
4418 }
4419
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004420
4421 /* The map or array was found. Now enter it.
4422 *
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004423 * QCBORDecode_EnterBoundedMapOrArray() used here, requires the
4424 * next item for the pre-order traversal cursor to be the map/array
4425 * found by MapSearch(). The next few lines of code force the
4426 * cursor to that.
4427 *
4428 * There is no need to retain the old cursor because
4429 * QCBORDecode_EnterBoundedMapOrArray() will set it to the
4430 * beginning of the map/array being entered.
4431 *
4432 * The cursor is forced by: 1) setting the input buffer position to
4433 * the item offset found by MapSearch(), 2) setting the map/array
4434 * counter to the total in the map/array, 3) setting the nesting
4435 * level. Setting the map/array counter to the total is not
4436 * strictly correct, but this is OK because this cursor only needs
4437 * to be used to get one item and MapSearch() has already found it
4438 * confirming it exists.
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004439 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004440 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004441
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004442 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
4443
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004444 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07004445
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004446 QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004447}
4448
4449
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004450/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004451 * Public function, see header qcbor/qcbor_decode.h file
4452 */
4453void
4454QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004455{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004456 QCBORItem OneItemSeach[2];
4457 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4458 OneItemSeach[0].label.int64 = nLabel;
4459 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4460 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004461
Laurence Lundblade9b334962020-08-27 10:55:53 -07004462 /* The map to enter was found, now finish off entering it. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004463 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004464}
4465
4466
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004467/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004468 * Public function, see header qcbor/qcbor_decode.h file
4469 */
4470void
4471QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004472{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004473#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004474 QCBORItem OneItemSeach[2];
4475 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4476 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4477 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4478 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004479
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004480 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004481#else
4482 (void)szLabel;
4483 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
4484#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004485}
4486
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004487/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004488 * Public function, see header qcbor/qcbor_decode.h file
4489 */
4490void
4491QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07004492{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004493 QCBORItem OneItemSeach[2];
4494 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4495 OneItemSeach[0].label.int64 = nLabel;
4496 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4497 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004498
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004499 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07004500}
4501
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004502/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004503 * Public function, see header qcbor/qcbor_decode.h file
4504 */
4505void
4506QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundblade34691b92020-05-18 22:25:25 -07004507{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004508#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004509 QCBORItem OneItemSeach[2];
4510 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4511 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4512 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4513 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004514
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004515 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004516#else
4517 (void)szLabel;
4518 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
4519#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade1341c592020-04-11 14:19:05 -07004520}
4521
4522
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004523/**
4524 * @brief Semi-private to do the the work for EnterMap() and EnterArray().
4525 *
4526 * @param[in] pMe The decode context
4527 * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY.
4528 * @param[out] pItem The data item for the map or array entered.
4529 *
4530 * The next item in the traversal must be a map or array. This
4531 * consumes that item and does the book keeping to enter the map or
4532 * array.
4533 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004534void
4535QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe,
4536 const uint8_t uType,
4537 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004538{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004539 QCBORError uErr;
4540
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004541 /* Must only be called on maps and arrays. */
Laurence Lundblade34691b92020-05-18 22:25:25 -07004542 if(pMe->uLastError != QCBOR_SUCCESS) {
4543 // Already in error state; do nothing.
4544 return;
4545 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07004546
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004547 /* Get the data item that is the map or array being entered. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004548 QCBORItem Item;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004549 uErr = QCBORDecode_GetNext(pMe, &Item);
4550 if(uErr != QCBOR_SUCCESS) {
4551 goto Done;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07004552 }
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004553
4554 uint8_t uItemDataType = Item.uDataType;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004555
4556#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004557 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) {
4558 uItemDataType = QCBOR_TYPE_ARRAY;
4559 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004560#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
4561
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004562 if(uItemDataType != uType) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004563 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
4564 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004565 }
4566
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004567 QCBORDecode_Private_CopyTags(pMe, &Item);
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004568
4569
Laurence Lundbladef0499502020-08-01 11:55:57 -07004570 const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
Laurence Lundblade085d7952020-07-24 10:26:30 -07004571 if(bIsEmpty) {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004572 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
4573 // Undo decrement done by QCBORDecode_GetNext() so the the
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004574 // the decrement when exiting the map/array works correctly
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004575 pMe->nesting.pCurrent->u.ma.uCountCursor++;
4576 }
Laurence Lundblade93d89472020-10-03 22:30:50 -07004577 // Special case to increment nesting level for zero-length maps
4578 // and arrays entered in bounded mode.
Laurence Lundbladee6f15112020-07-23 18:44:16 -07004579 DecodeNesting_Descend(&(pMe->nesting), uType);
4580 }
4581
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004582 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004583
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004584 uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty,
4585 UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004586
Laurence Lundblade6545d1b2020-10-14 11:13:13 -07004587 if(pItem != NULL) {
4588 *pItem = Item;
4589 }
4590
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004591Done:
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004592 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004593}
4594
Laurence Lundblade02625d42020-06-25 14:41:41 -07004595
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004596/**
4597 * @brief Exit a bounded map, array or bstr (semi-private).
4598 *
4599 * @param[in] pMe Decode context.
4600 * @param[in] uEndOffset The input buffer offset of the end of item exited.
4601 *
4602 * @returns QCBOR_SUCCESS or an error code.
4603 *
4604 * This is the common work for exiting a level that is a bounded map,
4605 * array or bstr wrapped CBOR.
4606 *
4607 * One chunk of work is to set up the pre-order traversal so it is at
4608 * the item just after the bounded map, array or bstr that is being
4609 * exited. This is somewhat complex.
4610 *
4611 * The other work is to level-up the bounded mode to next higest
4612 * bounded mode or the top level if there isn't one.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004613 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004614static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004615QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
4616 const uint32_t uEndOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004617{
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004618 QCBORError uErr;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004619
Laurence Lundblade02625d42020-06-25 14:41:41 -07004620 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004621 * First the pre-order-traversal byte offset is positioned to the
4622 * item just after the bounded mode item that was just consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004623 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004624 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
4625
Laurence Lundblade02625d42020-06-25 14:41:41 -07004626 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004627 * Next, set the current nesting level to one above the bounded
4628 * level that was just exited.
4629 *
4630 * DecodeNesting_CheckBoundedType() is always called before this
4631 * and makes sure pCurrentBounded is valid.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004632 */
4633 DecodeNesting_LevelUpCurrent(&(pMe->nesting));
4634
4635 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004636 * This does the complex work of leveling up the pre-order
4637 * traversal when the end of a map or array or another bounded
4638 * level is reached. It may do nothing, or ascend all the way to
4639 * the top level.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004640 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004641 uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004642 if(uErr != QCBOR_SUCCESS) {
4643 goto Done;
4644 }
4645
Laurence Lundblade02625d42020-06-25 14:41:41 -07004646 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004647 * This makes the next highest bounded level the current bounded
4648 * level. If there is no next highest level, then no bounded mode
4649 * is in effect.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004650 */
4651 DecodeNesting_LevelUpBounded(&(pMe->nesting));
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004652
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004653 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004654
4655Done:
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004656 return uErr;
4657}
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004658
Laurence Lundblade02625d42020-06-25 14:41:41 -07004659
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004660/**
4661 * @brief Get started exiting a map or array (semi-private)
4662 *
4663 * @param[in] pMe The decode context
4664 * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP
4665 *
4666 * This does some work for map and array exiting (but not
4667 * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel()
4668 * is called to do the rest.
4669 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004670void
4671QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe,
4672 const uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004673{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004674 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07004675 /* Already in error state; do nothing. */
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004676 return;
4677 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004678
Laurence Lundblade02625d42020-06-25 14:41:41 -07004679 QCBORError uErr;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004680
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004681 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004682 uErr = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004683 goto Done;
4684 }
4685
Laurence Lundblade02625d42020-06-25 14:41:41 -07004686 /*
4687 Have to set the offset to the end of the map/array
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004688 that is being exited. If there is no cached value,
Laurence Lundblade02625d42020-06-25 14:41:41 -07004689 from previous map search, then do a dummy search.
4690 */
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004691 if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004692 QCBORItem Dummy;
4693 Dummy.uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004694 uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL);
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004695 if(uErr != QCBOR_SUCCESS) {
4696 goto Done;
4697 }
4698 }
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004699
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004700 uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004701
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004702Done:
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004703 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004704}
4705
4706
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004707/**
4708 * @brief The main work of entering some byte-string wrapped CBOR.
4709 *
4710 * @param[in] pMe The decode context.
4711 * @param[in] pItem The byte string item.
4712 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX
4713 * @param[out] pBstr Pointer and length of byte string entered.
4714 *
4715 * This is called once the byte string item has been decoded to do all
4716 * the book keeping work for descending a nesting level into the
4717 * nested CBOR.
4718 *
4719 * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement.
4720 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004721static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004722QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe,
4723 const QCBORItem *pItem,
4724 const uint8_t uTagRequirement,
4725 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004726{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004727 if(pBstr) {
4728 *pBstr = NULLUsefulBufC;
4729 }
4730
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004731 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004732 /* Already in error state; do nothing. */
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004733 return pMe->uLastError;
4734 }
4735
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004736 QCBORError uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004737
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004738 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004739 {
4740 uTagRequirement,
4741 {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE},
4742 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4743 };
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004744
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004745 uError = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004746 if(uError != QCBOR_SUCCESS) {
4747 goto Done;
4748 }
4749
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004750 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004751 /* Reverse the decrement done by GetNext() for the bstr so the
4752 * increment in QCBORDecode_NestLevelAscender() called by
4753 * ExitBoundedLevel() will work right.
4754 */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004755 DecodeNesting_ReverseDecrement(&(pMe->nesting));
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07004756 }
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004757
4758 if(pBstr) {
4759 *pBstr = pItem->val.string;
4760 }
4761
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004762 /* This saves the current length of the UsefulInputBuf and then
4763 * narrows the UsefulInputBuf to start and length of the wrapped
4764 * CBOR that is being entered.
4765 *
4766 * Most of these calls are simple inline accessors so this doesn't
4767 * amount to much code.
4768 */
4769
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004770 const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004771 /* This check makes the cast of uPreviousLength to uint32_t below safe. */
4772 if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004773 uError = QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladef76a2622020-08-06 19:51:03 -07004774 goto Done;
4775 }
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004776
4777 const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
4778 pItem->val.string.ptr);
4779 /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
4780 if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
4781 /* This should never happen because pItem->val.string.ptr should
4782 * always be valid since it was just returned.
4783 */
4784 uError = QCBOR_ERR_INPUT_TOO_LARGE;
4785 goto Done;
4786 }
4787
4788 const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
4789
4790 UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004791 UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004792
Laurence Lundblade02625d42020-06-25 14:41:41 -07004793 uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004794 (uint32_t)uPreviousLength,
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004795 (uint32_t)uStartOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004796Done:
4797 return uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004798}
4799
4800
Laurence Lundblade02625d42020-06-25 14:41:41 -07004801/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004802 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004803 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004804void
4805QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe,
4806 const uint8_t uTagRequirement,
4807 UsefulBufC *pBstr)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004808{
4809 if(pMe->uLastError != QCBOR_SUCCESS) {
4810 // Already in error state; do nothing.
4811 return;
4812 }
4813
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004814 /* Get the data item that is the byte string being entered */
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004815 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004816 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4817 if(pMe->uLastError != QCBOR_SUCCESS) {
4818 return;
4819 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004820
Laurence Lundblade31fddb72024-05-13 13:03:35 -07004821 if(Item.uDataAlloc) {
4822 pMe->uLastError = QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
4823 return;
4824 }
4825
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004826 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4827 &Item,
4828 uTagRequirement,
4829 pBstr);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004830}
4831
4832
Laurence Lundblade02625d42020-06-25 14:41:41 -07004833/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004834 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004835 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004836void
4837QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe,
4838 const int64_t nLabel,
4839 const uint8_t uTagRequirement,
4840 UsefulBufC *pBstr)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004841{
4842 QCBORItem Item;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004843 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004844
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004845 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4846 &Item,
4847 uTagRequirement,
4848 pBstr);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004849}
4850
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004851
Laurence Lundblade02625d42020-06-25 14:41:41 -07004852/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004853 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004854 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004855void
4856QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe,
4857 const char *szLabel,
4858 const uint8_t uTagRequirement,
4859 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004860{
4861 QCBORItem Item;
4862 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4863
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004864 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4865 &Item,
4866 uTagRequirement,
4867 pBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004868}
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004869
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004870
Laurence Lundblade02625d42020-06-25 14:41:41 -07004871/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004872 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004873 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004874void
4875QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004876{
Laurence Lundblade02625d42020-06-25 14:41:41 -07004877 if(pMe->uLastError != QCBOR_SUCCESS) {
4878 // Already in error state; do nothing.
4879 return;
4880 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004881
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004882 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004883 pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade02625d42020-06-25 14:41:41 -07004884 return;
4885 }
4886
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004887 const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
4888
Laurence Lundblade02625d42020-06-25 14:41:41 -07004889 /*
4890 Reset the length of the UsefulInputBuf to what it was before
4891 the bstr wrapped CBOR was entered.
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004892 */
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004893 UsefulInputBuf_SetBufferLength(&(pMe->InBuf),
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004894 DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004895
4896
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004897 QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004898 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004899}
4900
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004901
Laurence Lundbladee6430642020-03-14 21:15:44 -07004902
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004903/**
4904 * @brief Process simple type true and false, a boolean
4905 *
4906 * @param[in] pMe The decode context.
4907 * @param[in] pItem The item with either true or false.
4908 * @param[out] pBool The boolean value output.
4909 *
4910 * Sets the internal error if the item isn't a true or a false. Also
4911 * records any tag numbers as the tag numbers of the last item.
4912 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004913static void
4914QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe,
4915 const QCBORItem *pItem,
4916 bool *pBool)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004917{
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004918 if(pMe->uLastError != QCBOR_SUCCESS) {
4919 /* Already in error state, do nothing */
4920 return;
4921 }
4922
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004923 switch(pItem->uDataType) {
4924 case QCBOR_TYPE_TRUE:
4925 *pBool = true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004926 break;
4927
4928 case QCBOR_TYPE_FALSE:
4929 *pBool = false;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004930 break;
4931
4932 default:
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004933 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004934 break;
4935 }
4936}
Laurence Lundbladee6430642020-03-14 21:15:44 -07004937
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004938
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004939/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004940 * Public function, see header qcbor/qcbor_decode.h file
4941 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004942void
4943QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004944{
Laurence Lundbladec4537442020-04-14 18:53:22 -07004945 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07004946 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004947 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004948}
4949
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004950
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004951/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004952 * Public function, see header qcbor/qcbor_decode.h file
4953 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004954void
4955QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe,
4956 const int64_t nLabel,
4957 bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004958{
4959 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004960 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004961 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004962}
4963
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004964
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004965/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004966 * Public function, see header qcbor/qcbor_decode.h file
4967 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004968void
4969QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe,
4970 const char *szLabel,
4971 bool *pValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004972{
4973 QCBORItem Item;
4974 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004975 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004976}
4977
4978
Laurence Lundblade3888f002024-06-12 21:20:56 -07004979/**
4980 * @brief Process simple values.
4981 *
4982 * @param[in] pMe The decode context.
4983 * @param[in] pItem The item with the simple value.
4984 * @param[out] puSimple The simple value output.
4985 *
4986 * Sets the internal error if the item isn't a true or a false. Also
4987 * records any tag numbers as the tag numbers of the last item.
4988 */
4989static void
4990QCBORDecode_Private_ProcessSimple(QCBORDecodeContext *pMe,
4991 const QCBORItem *pItem,
4992 uint8_t *puSimple)
4993{
4994 if(pMe->uLastError != QCBOR_SUCCESS) {
4995 return;
4996 }
4997
4998 /* It's kind of lame to remap true...undef back to simple values, but
4999 * this function isn't used much and to not do it would require
5000 * changing GetNext() behavior in an incompatible way.
5001 */
5002 switch(pItem->uDataType) {
5003 case QCBOR_TYPE_UKNOWN_SIMPLE:
5004 *puSimple = pItem->val.uSimple;
5005 break;
5006
5007 case QCBOR_TYPE_TRUE:
5008 *puSimple = CBOR_SIMPLEV_TRUE;
5009 break;
5010
5011 case QCBOR_TYPE_FALSE:
5012 *puSimple = CBOR_SIMPLEV_FALSE;
5013 break;
5014
5015 case QCBOR_TYPE_NULL:
5016 *puSimple = CBOR_SIMPLEV_NULL;
5017 break;
5018
5019 case QCBOR_TYPE_UNDEF:
5020 *puSimple = CBOR_SIMPLEV_UNDEF;
5021 break;
5022
5023 default:
5024 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
5025 return;
5026 }
Laurence Lundblade3888f002024-06-12 21:20:56 -07005027}
5028
5029/*
5030 * Public function, see header qcbor/qcbor_decode.h file
5031 */
5032void
5033QCBORDecode_GetSimple(QCBORDecodeContext *pMe, uint8_t *puSimple)
5034{
5035 QCBORItem Item;
Laurence Lundblade3888f002024-06-12 21:20:56 -07005036 QCBORDecode_VGetNext(pMe, &Item);
5037 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimple);
5038}
5039
5040/*
5041 * Public function, see header qcbor/qcbor_decode.h file
5042 */
5043void
5044QCBORDecode_GetSimpleInMapN(QCBORDecodeContext *pMe,
5045 int64_t nLabel,
5046 uint8_t *puSimpleValue)
5047{
5048 QCBORItem Item;
5049 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3888f002024-06-12 21:20:56 -07005050 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
5051}
5052
5053/*
5054 * Public function, see header qcbor/qcbor_decode.h file
5055 */
5056void
5057QCBORDecode_GetSimpleInMapSZ(QCBORDecodeContext *pMe,
5058 const char *szLabel,
5059 uint8_t *puSimpleValue)
5060{
5061 QCBORItem Item;
5062 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3888f002024-06-12 21:20:56 -07005063 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
5064}
5065
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005066
Laurence Lundbladec7114722020-08-13 05:11:40 -07005067
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005068/**
5069 * @brief Common processing for an epoch date.
5070 *
5071 * @param[in] pMe The decode context.
5072 * @param[in] pItem The item with the date.
5073 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
5074 * @param[out] pnTime The returned date.
5075 *
5076 * Common processing for the date tag. Mostly make sure the tag
5077 * content is correct and copy forward any further other tag numbers.
5078 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005079static void
5080QCBORDecode_Private_ProcessEpochDate(QCBORDecodeContext *pMe,
5081 QCBORItem *pItem,
5082 const uint8_t uTagRequirement,
5083 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07005084{
5085 if(pMe->uLastError != QCBOR_SUCCESS) {
5086 // Already in error state, do nothing
5087 return;
5088 }
5089
5090 QCBORError uErr;
5091
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005092 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladec7114722020-08-13 05:11:40 -07005093 {
5094 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07005095 {QCBOR_TYPE_DATE_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
5096 {QCBOR_TYPE_INT64, QCBOR_TYPE_DOUBLE, QCBOR_TYPE_FLOAT, QCBOR_TYPE_UINT64}
Laurence Lundbladec7114722020-08-13 05:11:40 -07005097 };
5098
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005099 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07005100 if(uErr != QCBOR_SUCCESS) {
5101 goto Done;
5102 }
5103
5104 if(pItem->uDataType != QCBOR_TYPE_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005105 uErr = QCBOR_Private_DecodeDateEpoch(pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07005106 if(uErr != QCBOR_SUCCESS) {
5107 goto Done;
5108 }
5109 }
5110
5111 *pnTime = pItem->val.epochDate.nSeconds;
5112
5113Done:
5114 pMe->uLastError = (uint8_t)uErr;
5115}
5116
5117
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005118
5119/*
5120 * Public function, see header qcbor/qcbor_spiffy_decode.h file
5121 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005122void
5123QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
5124 uint8_t uTagRequirement,
5125 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07005126{
Laurence Lundbladec7114722020-08-13 05:11:40 -07005127 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07005128 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005129 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07005130}
5131
5132
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005133/*
5134 * Public function, see header qcbor/qcbor_spiffy_decode.h file
5135 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07005136void
5137QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
5138 int64_t nLabel,
5139 uint8_t uTagRequirement,
5140 int64_t *pnTime)
5141{
5142 QCBORItem Item;
5143 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005144 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07005145}
5146
5147
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005148/*
5149 * Public function, see header qcbor/qcbor_spiffy_decode.h file
5150 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07005151void
5152QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
5153 const char *szLabel,
5154 uint8_t uTagRequirement,
5155 int64_t *pnTime)
5156{
5157 QCBORItem Item;
5158 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005159 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07005160}
5161
5162
5163
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005164/**
5165 * @brief Common processing for an epoch date.
5166 *
5167 * @param[in] pMe The decode context.
5168 * @param[in] pItem The item with the date.
5169 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
5170 * @param[out] pnDays The returned day count.
5171 *
5172 * Common processing for the RFC 8943 day-count tag. Mostly make sure
5173 * the tag content is correct and copy forward any further other tag
5174 * numbers.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005175 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005176static void
5177QCBORDecode_Private_ProcessEpochDays(QCBORDecodeContext *pMe,
5178 QCBORItem *pItem,
5179 uint8_t uTagRequirement,
5180 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005181{
5182 if(pMe->uLastError != QCBOR_SUCCESS) {
5183 /* Already in error state, do nothing */
5184 return;
5185 }
5186
5187 QCBORError uErr;
5188
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005189 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005190 {
5191 uTagRequirement,
5192 {QCBOR_TYPE_DAYS_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
5193 {QCBOR_TYPE_INT64, QCBOR_TYPE_UINT64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
5194 };
5195
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005196 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005197 if(uErr != QCBOR_SUCCESS) {
5198 goto Done;
5199 }
5200
5201 if(pItem->uDataType != QCBOR_TYPE_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005202 uErr = QCBOR_Private_DecodeDaysEpoch(pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005203 if(uErr != QCBOR_SUCCESS) {
5204 goto Done;
5205 }
5206 }
5207
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005208 *pnDays = pItem->val.epochDays;
5209
5210Done:
5211 pMe->uLastError = (uint8_t)uErr;
5212}
5213
5214
5215/*
5216 * Public function, see header qcbor/qcbor_decode.h
5217 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005218void
5219QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe,
5220 uint8_t uTagRequirement,
5221 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005222{
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005223 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07005224 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005225 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005226}
5227
5228
5229/*
5230 * Public function, see header qcbor/qcbor_decode.h
5231 */
5232void
5233QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe,
5234 int64_t nLabel,
5235 uint8_t uTagRequirement,
5236 int64_t *pnDays)
5237{
5238 QCBORItem Item;
5239 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005240 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005241}
5242
5243
5244/*
5245 * Public function, see header qcbor/qcbor_decode.h
5246 */
5247void
5248QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe,
5249 const char *szLabel,
5250 uint8_t uTagRequirement,
5251 int64_t *pnDays)
5252{
5253 QCBORItem Item;
5254 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005255 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005256}
5257
5258
5259
Laurence Lundblade37286c02022-09-03 10:05:02 -07005260/*
5261 * @brief Get a string that matches the type/tag specification.
5262 */
5263void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005264QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
5265 const QCBOR_Private_TagSpec TagSpec,
5266 UsefulBufC *pBstr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005267{
Laurence Lundbladec4537442020-04-14 18:53:22 -07005268 QCBORItem Item;
5269
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07005270 QCBORDecode_VGetNext(pMe, &Item);
5271 if(pMe->uLastError) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005272 return;
5273 }
5274
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005275 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005276
5277 if(pMe->uLastError == QCBOR_SUCCESS) {
5278 *pBstr = Item.val.string;
Laurence Lundbladeab40c6f2020-08-28 11:24:58 -07005279 } else {
5280 *pBstr = NULLUsefulBufC;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005281 }
5282}
5283
Laurence Lundbladec4537442020-04-14 18:53:22 -07005284
5285
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005286
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005287/**
5288 * @brief Common processing for a big number tag.
5289 *
5290 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
5291 * @param[in] pItem The item with the date.
5292 * @param[out] pValue The returned big number
5293 * @param[out] pbIsNegative The returned sign of the big number.
5294 *
5295 * Common processing for the big number tag. Mostly make sure
5296 * the tag content is correct and copy forward any further other tag
5297 * numbers.
5298 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07005299static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005300QCBOR_Private_ProcessBigNum(const uint8_t uTagRequirement,
5301 const QCBORItem *pItem,
5302 UsefulBufC *pValue,
5303 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005304{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005305 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005306 {
5307 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07005308 {QCBOR_TYPE_POSBIGNUM, QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
5309 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005310 };
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005311
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005312 QCBORError uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005313 if(uErr != QCBOR_SUCCESS) {
5314 return uErr;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005315 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005316
5317 *pValue = pItem->val.string;
5318
5319 if(pItem->uDataType == QCBOR_TYPE_POSBIGNUM) {
5320 *pbIsNegative = false;
5321 } else if(pItem->uDataType == QCBOR_TYPE_NEGBIGNUM) {
5322 *pbIsNegative = true;
5323 }
5324
5325 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005326}
5327
5328
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005329/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005330 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005331 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005332void
5333QCBORDecode_GetBignum(QCBORDecodeContext *pMe,
5334 const uint8_t uTagRequirement,
5335 UsefulBufC *pValue,
5336 bool *pbIsNegative)
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005337{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005338 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07005339 QCBORDecode_VGetNext(pMe, &Item);
5340 if(pMe->uLastError) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005341 return;
5342 }
5343
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005344 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
5345 &Item,
5346 pValue,
5347 pbIsNegative);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005348}
5349
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005350
Laurence Lundblade4e2da002020-06-13 23:08:31 -07005351/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005352 * Public function, see header qcbor/qcbor_spiffy_decode.h
5353 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005354void
5355QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe,
5356 const int64_t nLabel,
5357 const uint8_t uTagRequirement,
5358 UsefulBufC *pValue,
5359 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005360{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005361 QCBORItem Item;
5362 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005363 if(pMe->uLastError != QCBOR_SUCCESS) {
5364 return;
5365 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005366
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005367 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
5368 &Item,
5369 pValue,
5370 pbIsNegative);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005371}
5372
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005373
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005374/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005375 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005376 */
5377void
5378QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe,
5379 const char *szLabel,
5380 const uint8_t uTagRequirement,
5381 UsefulBufC *pValue,
5382 bool *pbIsNegative)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005383{
5384 QCBORItem Item;
5385 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005386 if(pMe->uLastError != QCBOR_SUCCESS) {
5387 return;
5388 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005389
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005390 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
5391 &Item,
5392 pValue,
5393 pbIsNegative);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005394}
5395
5396
5397
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005398/**
5399 * @brief Common processing for MIME tag (semi-private).
5400 *
5401 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
5402 * @param[in] pItem The item with the date.
5403 * @param[out] pMessage The returned MIME message.
5404 * @param[out] pbIsTag257 If true, binary MIME, if not, text MIME.
5405 *
5406 * Common processing for the MIME tag. Mostly make sure the tag
5407 * content is correct and copy forward any further other tag
5408 * numbers. See QCBORDecode_GetMIMEMessage().
5409 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07005410QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005411QCBORDecode_Private_GetMIME(const uint8_t uTagRequirement,
Laurence Lundblade37286c02022-09-03 10:05:02 -07005412 const QCBORItem *pItem,
5413 UsefulBufC *pMessage,
5414 bool *pbIsTag257)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005415{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005416 const QCBOR_Private_TagSpec TagSpecText =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005417 {
5418 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07005419 {QCBOR_TYPE_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
5420 {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005421 };
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005422 const QCBOR_Private_TagSpec TagSpecBinary =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005423 {
5424 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07005425 {QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
5426 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005427 };
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005428
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005429 QCBORError uReturn;
Laurence Lundblade9b334962020-08-27 10:55:53 -07005430
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005431 if(QCBOR_Private_CheckTagRequirement(TagSpecText, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005432 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07005433 if(pbIsTag257 != NULL) {
5434 *pbIsTag257 = false;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005435 }
5436 uReturn = QCBOR_SUCCESS;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005437 } else if(QCBOR_Private_CheckTagRequirement(TagSpecBinary, 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 = true;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005441 }
5442 uReturn = QCBOR_SUCCESS;
5443
5444 } else {
5445 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
5446 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07005447
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005448 return uReturn;
5449}
5450
Laurence Lundblade93d89472020-10-03 22:30:50 -07005451// Improvement: add methods for wrapped CBOR, a simple alternate
5452// to EnterBstrWrapped
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005453
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005454
5455
5456
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005457#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundbladee6430642020-03-14 21:15:44 -07005458
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005459/**
5460 * @brief Prototype for conversion of exponent and mantissa to unsigned integer.
5461 *
5462 * @param[in] uMantissa The mantissa.
5463 * @param[in] nExponent The exponent.
5464 * @param[out] puResult The resulting integer.
5465 *
5466 * Concrete implementations of this are for exponent base 10 and 2 supporting
5467 * decimal fractions and big floats.
5468 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005469typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005470
5471
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005472/**
5473 * @brief Base 10 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5474 *
5475 * @param[in] uMantissa The unsigned integer mantissa.
5476 * @param[in] nExponent The signed integer exponent.
5477 * @param[out] puResult Place to return the unsigned integer result.
5478 *
5479 * This computes: mantissa * 10 ^^ exponent as for a decimal fraction. The output is a 64-bit
5480 * unsigned integer.
5481 *
5482 * There are many inputs for which the result will not fit in the
5483 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5484 * be returned.
5485 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005486static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005487QCBOR_Private_Exponentitate10(const uint64_t uMantissa,
5488 int64_t nExponent,
5489 uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005490{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005491 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005492
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005493 if(uResult != 0) {
5494 /* This loop will run a maximum of 19 times because
5495 * UINT64_MAX < 10 ^^ 19. More than that will cause
5496 * exit with the overflow error
5497 */
5498 for(; nExponent > 0; nExponent--) {
5499 if(uResult > UINT64_MAX / 10) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005500 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005501 }
5502 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005503 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005504
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005505 for(; nExponent < 0; nExponent++) {
5506 uResult = uResult / 10;
5507 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005508 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005509 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005510 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005511 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005512 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07005513
5514 *puResult = uResult;
5515
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005516 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005517}
5518
5519
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005520/**
5521 * @brief Base 2 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5522 *
5523 * @param[in] uMantissa The unsigned integer mantissa.
5524 * @param[in] nExponent The signed integer exponent.
5525 * @param[out] puResult Place to return the unsigned integer result.
5526 *
5527 * This computes: mantissa * 2 ^^ exponent as for a big float. The
5528 * output is a 64-bit unsigned integer.
5529 *
5530 * There are many inputs for which the result will not fit in the
5531 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5532 * be returned.
5533 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005534static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005535QCBOR_Private_Exponentitate2(const uint64_t uMantissa,
5536 int64_t nExponent,
5537 uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005538{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005539 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005540
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005541 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005542
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005543 /* This loop will run a maximum of 64 times because INT64_MAX <
5544 * 2^31. More than that will cause exit with the overflow error
Laurence Lundbladee6430642020-03-14 21:15:44 -07005545 */
5546 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005547 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005548 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005549 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005550 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005551 nExponent--;
5552 }
5553
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005554 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005555 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005556 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005557 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005558 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005559 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005560 }
5561
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005562 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005563
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005564 return QCBOR_SUCCESS;
5565}
5566
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005567
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005568/**
5569 * @brief Exponentiate a signed mantissa and signed exponent to produce a signed result.
5570 *
5571 * @param[in] nMantissa Signed integer mantissa.
5572 * @param[in] nExponent Signed integer exponent.
5573 * @param[out] pnResult Place to put the signed integer result.
5574 * @param[in] pfExp Exponentiation function.
5575 *
5576 * @returns Error code
5577 *
5578 * \c pfExp performs exponentiation on and unsigned mantissa and
5579 * produces an unsigned result. This converts the mantissa from signed
5580 * and converts the result to signed. The exponentiation function is
5581 * either for base 2 or base 10 (and could be other if needed).
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005582 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005583static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005584QCBOR_Private_ExponentiateNN(const int64_t nMantissa,
5585 const int64_t nExponent,
5586 int64_t *pnResult,
5587 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005588{
5589 uint64_t uResult;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005590 uint64_t uMantissa;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005591
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005592 /* Take the absolute value and put it into an unsigned. */
5593 if(nMantissa >= 0) {
5594 /* Positive case is straightforward */
5595 uMantissa = (uint64_t)nMantissa;
5596 } else if(nMantissa != INT64_MIN) {
5597 /* The common negative case. See next. */
5598 uMantissa = (uint64_t)-nMantissa;
5599 } else {
5600 /* int64_t and uint64_t are always two's complement per the
5601 * C standard (and since QCBOR uses these it only works with
5602 * two's complement, which is pretty much universal these
5603 * days). The range of a negative two's complement integer is
5604 * one more that than a positive, so the simple code above might
5605 * not work all the time because you can't simply negate the
5606 * value INT64_MIN because it can't be represented in an
5607 * int64_t. -INT64_MIN can however be represented in a
5608 * uint64_t. Some compilers seem to recognize this case for the
5609 * above code and put the correct value in uMantissa, however
5610 * they are not required to do this by the C standard. This next
5611 * line does however work for all compilers.
5612 *
5613 * This does assume two's complement where -INT64_MIN ==
5614 * INT64_MAX + 1 (which wouldn't be true for one's complement or
5615 * sign and magnitude (but we know we're using two's complement
5616 * because int64_t requires it)).
5617 *
5618 * See these, particularly the detailed commentary:
5619 * https://stackoverflow.com/questions/54915742/does-c99-mandate-a-int64-t-type-be-available-always
5620 * https://stackoverflow.com/questions/37301078/is-negating-int-min-undefined-behaviour
5621 */
5622 uMantissa = (uint64_t)INT64_MAX+1;
5623 }
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005624
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005625 /* Call the exponentiator passed for either base 2 or base 10.
5626 * Here is where most of the overflow errors are caught. */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005627 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
5628 if(uReturn) {
5629 return uReturn;
5630 }
5631
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005632 /* Convert back to the sign of the original mantissa */
5633 if(nMantissa >= 0) {
5634 if(uResult > INT64_MAX) {
5635 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5636 }
5637 *pnResult = (int64_t)uResult;
5638 } else {
5639 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
5640 * of INT64_MIN. This assumes two's compliment representation
5641 * where INT64_MIN is one increment farther from 0 than
5642 * INT64_MAX. Trying to write -INT64_MIN doesn't work to get
5643 * this because the compiler makes it an int64_t which can't
5644 * represent -INT64_MIN. Also see above.
5645 */
5646 if(uResult > (uint64_t)INT64_MAX+1) {
5647 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5648 }
5649 *pnResult = -(int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005650 }
5651
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005652 return QCBOR_SUCCESS;
5653}
5654
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005655
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005656/**
5657 * @brief Exponentiate an unsigned mantissa and signed exponent to produce an unsigned result.
5658 *
5659 * @param[in] nMantissa Signed integer mantissa.
5660 * @param[in] nExponent Signed integer exponent.
5661 * @param[out] puResult Place to put the signed integer result.
5662 * @param[in] pfExp Exponentiation function.
5663 *
5664 * @returns Error code
5665 *
5666 * \c pfExp performs exponentiation on and unsigned mantissa and
5667 * produces an unsigned result. This errors out if the mantissa
5668 * is negative because the output is unsigned.
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005669 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005670static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005671QCBOR_Private_ExponentitateNU(const int64_t nMantissa,
5672 const int64_t nExponent,
5673 uint64_t *puResult,
5674 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005675{
5676 if(nMantissa < 0) {
5677 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5678 }
5679
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005680 /* Cast to unsigned is OK because of check for negative.
5681 * Cast to unsigned is OK because UINT64_MAX > INT64_MAX.
5682 * Exponentiation is straight forward
5683 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005684 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
5685}
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005686
5687
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005688/**
5689 * @brief Exponentiate an usnigned mantissa and unsigned exponent to produce an unsigned result.
5690 *
5691 * @param[in] uMantissa Unsigned integer mantissa.
5692 * @param[in] nExponent Unsigned integer exponent.
5693 * @param[out] puResult Place to put the unsigned integer result.
5694 * @param[in] pfExp Exponentiation function.
5695 *
5696 * @returns Error code
5697 *
5698 * \c pfExp performs exponentiation on and unsigned mantissa and
5699 * produces an unsigned result so this is just a wrapper that does
5700 * nothing (and is likely inlined).
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005701 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005702static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005703QCBOR_Private_ExponentitateUU(const uint64_t uMantissa,
5704 const int64_t nExponent,
5705 uint64_t *puResult,
5706 fExponentiator pfExp)
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005707{
5708 return (*pfExp)(uMantissa, nExponent, puResult);
5709}
5710
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005711#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005712
5713
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005714
5715
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005716/**
5717 * @brief Convert a CBOR big number to a uint64_t.
5718 *
5719 * @param[in] BigNum Bytes of the big number to convert.
5720 * @param[in] uMax Maximum value allowed for the result.
5721 * @param[out] pResult Place to put the unsigned integer result.
5722 *
5723 * @returns Error code
5724 *
5725 * Many values will overflow because a big num can represent a much
5726 * larger range than uint64_t.
5727 */
5728static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005729QCBOR_Private_ConvertBigNumToUnsigned(const UsefulBufC BigNum,
5730 const uint64_t uMax,
5731 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005732{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005733 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005734
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005735 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005736 const uint8_t *pByte = BigNum.ptr;
5737 size_t uLen = BigNum.len;
5738 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07005739 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005740 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005741 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07005742 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005743 }
5744
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005745 *pResult = uResult;
5746 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005747}
5748
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005749
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005750/**
5751 * @brief Convert a CBOR postive big number to a uint64_t.
5752 *
5753 * @param[in] BigNum Bytes of the big number to convert.
5754 * @param[out] pResult Place to put the unsigned integer result.
5755 *
5756 * @returns Error code
5757 *
5758 * Many values will overflow because a big num can represent a much
5759 * larger range than uint64_t.
5760 */
5761static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005762QCBOR_Private_ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum,
5763 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005764{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005765 return QCBOR_Private_ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005766}
5767
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005768
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005769/**
5770 * @brief Convert a CBOR positive big number to an int64_t.
5771 *
5772 * @param[in] BigNum Bytes of the big number to convert.
5773 * @param[out] pResult Place to put the signed integer result.
5774 *
5775 * @returns Error code
5776 *
5777 * Many values will overflow because a big num can represent a much
5778 * larger range than int64_t.
5779 */
5780static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005781QCBOR_Private_ConvertPositiveBigNumToSigned(const UsefulBufC BigNum,
5782 int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005783{
5784 uint64_t uResult;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005785 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5786 INT64_MAX,
5787 &uResult);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005788 if(uError) {
5789 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005790 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005791 /* Cast is safe because ConvertBigNumToUnsigned limits to INT64_MAX */
Laurence Lundbladee6430642020-03-14 21:15:44 -07005792 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005793 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005794}
5795
5796
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005797/**
5798 * @brief Convert a CBOR negative big number to an int64_t.
5799 *
5800 * @param[in] BigNum Bytes of the big number to convert.
5801 * @param[out] pnResult Place to put the signed integer result.
5802 *
5803 * @returns Error code
5804 *
5805 * Many values will overflow because a big num can represent a much
5806 * larger range than int64_t.
5807 */
5808static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005809QCBOR_Private_ConvertNegativeBigNumToSigned(const UsefulBufC BigNum,
5810 int64_t *pnResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005811{
5812 uint64_t uResult;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005813 /* The negative integer furthest from zero for a C int64_t is
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005814 * INT64_MIN which is expressed as -INT64_MAX - 1. The value of a
5815 * negative number in CBOR is computed as -n - 1 where n is the
5816 * encoded integer, where n is what is in the variable BigNum. When
5817 * converting BigNum to a uint64_t, the maximum value is thus
5818 * INT64_MAX, so that when it -n - 1 is applied to it the result
5819 * will never be further from 0 than INT64_MIN.
5820 *
5821 * -n - 1 <= INT64_MIN.
5822 * -n - 1 <= -INT64_MAX - 1
5823 * n <= INT64_MAX.
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005824 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005825 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5826 INT64_MAX,
5827 &uResult);
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005828 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005829 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005830 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005831
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005832 /* Now apply -n - 1. The cast is safe because
5833 * ConvertBigNumToUnsigned() is limited to INT64_MAX which does fit
5834 * is the largest positive integer that an int64_t can
5835 * represent. */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005836 *pnResult = -(int64_t)uResult - 1;
5837
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005838 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005839}
5840
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005841
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005842
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005843
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005844/**
5845 * @brief Convert integers and floats to an int64_t.
5846 *
5847 * @param[in] pItem The item to convert.
5848 * @param[in] uConvertTypes Bit mask list of conversion options.
5849 * @param[out] pnValue The resulting converted value.
5850 *
5851 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5852 * in uConvertTypes.
5853 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5854 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5855 * or too small.
5856 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005857static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005858QCBOR_Private_ConvertInt64(const QCBORItem *pItem,
5859 const uint32_t uConvertTypes,
5860 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005861{
5862 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005863 case QCBOR_TYPE_FLOAT:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005864 case QCBOR_TYPE_DOUBLE:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005865#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005866 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005867 /* https://pubs.opengroup.org/onlinepubs/009695399/functions/llround.html
5868 http://www.cplusplus.com/reference/cmath/llround/
5869 */
5870 // Not interested in FE_INEXACT
5871 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005872 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5873 *pnValue = llround(pItem->val.dfnum);
5874 } else {
5875 *pnValue = lroundf(pItem->val.fnum);
5876 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005877 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5878 // llround() shouldn't result in divide by zero, but catch
5879 // it here in case it unexpectedly does. Don't try to
5880 // distinguish between the various exceptions because it seems
5881 // they vary by CPU, compiler and OS.
5882 return QCBOR_ERR_FLOAT_EXCEPTION;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005883 }
5884 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005885 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005886 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005887#else
5888 return QCBOR_ERR_HW_FLOAT_DISABLED;
5889#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005890 break;
5891
5892 case QCBOR_TYPE_INT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005893 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005894 *pnValue = pItem->val.int64;
5895 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005896 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005897 }
5898 break;
5899
5900 case QCBOR_TYPE_UINT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005901 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005902 if(pItem->val.uint64 < INT64_MAX) {
5903 *pnValue = pItem->val.int64;
5904 } else {
5905 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5906 }
5907 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005908 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005909 }
5910 break;
5911
Laurence Lundblade2d493002024-02-01 11:09:17 -07005912 case QCBOR_TYPE_65BIT_NEG_INT:
5913 /* This type occurs if the value won't fit into int64_t
5914 * so this is always an error. */
5915 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5916 break;
5917
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005918 default:
5919 return QCBOR_ERR_UNEXPECTED_TYPE;
5920 }
5921 return QCBOR_SUCCESS;
5922}
5923
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005924
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005925/**
5926 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5927 *
5928 * @param[in] pMe The decode context.
5929 * @param[in] uConvertTypes Bit mask list of conversion options.
5930 * @param[out] pnValue Result of the conversion.
5931 * @param[in,out] pItem Temporary space to store Item, returned item.
5932 *
5933 * See QCBORDecode_GetInt64Convert().
5934 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005935void
5936QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pMe,
5937 uint32_t uConvertTypes,
5938 int64_t *pnValue,
5939 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005940{
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07005941 QCBORDecode_VGetNext(pMe, pItem);
5942 if(pMe->uLastError) {
Laurence Lundbladee6430642020-03-14 21:15:44 -07005943 return;
5944 }
5945
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005946 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005947 uConvertTypes,
5948 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005949}
5950
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005951/**
5952 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5953 *
5954 * @param[in] pMe The decode context.
5955 * @param[in] nLabel Label to find in map.
5956 * @param[in] uConvertTypes Bit mask list of conversion options.
5957 * @param[out] pnValue Result of the conversion.
5958 * @param[in,out] pItem Temporary space to store Item, returned item.
5959 *
5960 * See QCBORDecode_GetInt64ConvertInMapN().
5961 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005962void
5963QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pMe,
5964 int64_t nLabel,
5965 uint32_t uConvertTypes,
5966 int64_t *pnValue,
5967 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005968{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005969 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005970 if(pMe->uLastError != QCBOR_SUCCESS) {
5971 return;
5972 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005973
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005974 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5975 uConvertTypes,
5976 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005977}
5978
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005979/**
5980 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5981 *
5982 * @param[in] pMe The decode context.
5983 * @param[in] szLabel Label to find in map.
5984 * @param[in] uConvertTypes Bit mask list of conversion options.
5985 * @param[out] pnValue Result of the conversion.
5986 * @param[in,out] pItem Temporary space to store Item, returned item.
5987 *
5988 * See QCBORDecode_GetInt64ConvertInMapSZ().
5989 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005990void
5991QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5992 const char * szLabel,
5993 uint32_t uConvertTypes,
5994 int64_t *pnValue,
5995 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005996{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005997 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005998 if(pMe->uLastError != QCBOR_SUCCESS) {
5999 return;
6000 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006001
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006002 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
6003 uConvertTypes,
6004 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006005}
6006
6007
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006008/**
6009 * @brief Convert many number types to an int64_t.
6010 *
6011 * @param[in] pItem The item to convert.
6012 * @param[in] uConvertTypes Bit mask list of conversion options.
6013 * @param[out] pnValue The resulting converted value.
6014 *
6015 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6016 * in uConvertTypes.
6017 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6018 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6019 * or too small.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006020 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006021static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006022QCBOR_Private_Int64ConvertAll(const QCBORItem *pItem,
6023 const uint32_t uConvertTypes,
6024 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006025{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006026 switch(pItem->uDataType) {
6027
6028 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006029 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006030 return QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006031 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006032 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07006033 }
6034 break;
6035
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006036 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006037 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006038 return QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006039 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006040 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07006041 }
6042 break;
6043
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006044#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006045 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006046 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006047 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006048 pItem->val.expAndMantissa.nExponent,
6049 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006050 &QCBOR_Private_Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006051 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006052 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006053 }
6054 break;
6055
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006056 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006057 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006058 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006059 pItem->val.expAndMantissa.nExponent,
6060 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006061 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006062 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006063 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006064 }
6065 break;
6066
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006067 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006068 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006069 int64_t nMantissa;
6070 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006071 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006072 if(uErr) {
6073 return uErr;
6074 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006075 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006076 pItem->val.expAndMantissa.nExponent,
6077 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006078 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006079 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006080 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006081 }
6082 break;
6083
6084 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006085 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006086 int64_t nMantissa;
6087 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006088 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006089 if(uErr) {
6090 return uErr;
6091 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006092 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006093 pItem->val.expAndMantissa.nExponent,
6094 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006095 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006096 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006097 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006098 }
6099 break;
6100
6101 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006102 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006103 int64_t nMantissa;
6104 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006105 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006106 if(uErr) {
6107 return uErr;
6108 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006109 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006110 pItem->val.expAndMantissa.nExponent,
6111 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006112 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006113 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006114 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006115 }
6116 break;
6117
6118 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006119 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006120 int64_t nMantissa;
6121 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006122 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006123 if(uErr) {
6124 return uErr;
6125 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006126 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006127 pItem->val.expAndMantissa.nExponent,
6128 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006129 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006130 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006131 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07006132 }
6133 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006134#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006135
Laurence Lundbladee6430642020-03-14 21:15:44 -07006136
Laurence Lundbladec4537442020-04-14 18:53:22 -07006137 default:
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006138 return QCBOR_ERR_UNEXPECTED_TYPE; }
Laurence Lundbladec4537442020-04-14 18:53:22 -07006139}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006140
6141
Laurence Lundbladec4537442020-04-14 18:53:22 -07006142/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006143 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006144 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006145void
6146QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe,
6147 const uint32_t uConvertTypes,
6148 int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07006149{
6150 QCBORItem Item;
6151
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006152 QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07006153
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006154 if(pMe->uLastError == QCBOR_SUCCESS) {
6155 // The above conversion succeeded
6156 return;
6157 }
6158
Laurence Lundbladef6c86662020-05-12 02:08:00 -07006159 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006160 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07006161 return;
6162 }
6163
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006164 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
6165 uConvertTypes,
6166 pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006167}
6168
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006169
6170/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006171 * Public function, see header qcbor/qcbor_decode.h file
6172 */
6173void
6174QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
6175 const int64_t nLabel,
6176 const uint32_t uConvertTypes,
6177 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006178{
6179 QCBORItem Item;
6180
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006181 QCBORDecode_Private_GetInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006182 nLabel,
6183 uConvertTypes,
6184 pnValue,
6185 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006186
6187 if(pMe->uLastError == QCBOR_SUCCESS) {
6188 // The above conversion succeeded
6189 return;
6190 }
6191
6192 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6193 // The above conversion failed in a way that code below can't correct
6194 return;
6195 }
6196
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006197 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
6198 uConvertTypes,
6199 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006200}
6201
6202
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006203/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006204 * Public function, see header qcbor/qcbor_decode.h file
6205 */
6206void
6207QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
6208 const char *szLabel,
6209 const uint32_t uConvertTypes,
6210 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006211{
6212 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006213 QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006214 szLabel,
6215 uConvertTypes,
6216 pnValue,
6217 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006218
6219 if(pMe->uLastError == QCBOR_SUCCESS) {
6220 // The above conversion succeeded
6221 return;
6222 }
6223
6224 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6225 // The above conversion failed in a way that code below can't correct
6226 return;
6227 }
6228
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006229 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
6230 uConvertTypes,
6231 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006232}
6233
6234
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006235/**
6236 * @brief Convert many number types to an uint64_t.
6237 *
6238 * @param[in] pItem The item to convert.
6239 * @param[in] uConvertTypes Bit mask list of conversion options.
6240 * @param[out] puValue The resulting converted value.
6241 *
6242 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6243 * in uConvertTypes.
6244 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6245 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6246 * or too small.
6247 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006248static QCBORError
6249QCBOR_Private_ConvertUInt64(const QCBORItem *pItem,
6250 const uint32_t uConvertTypes,
6251 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006252{
6253 switch(pItem->uDataType) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006254 case QCBOR_TYPE_DOUBLE:
6255 case QCBOR_TYPE_FLOAT:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006256#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006257 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006258 // Can't use llround here because it will not convert values
6259 // greater than INT64_MAX and less than UINT64_MAX that
6260 // need to be converted so it is more complicated.
6261 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
6262 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
6263 if(isnan(pItem->val.dfnum)) {
6264 return QCBOR_ERR_FLOAT_EXCEPTION;
6265 } else if(pItem->val.dfnum < 0) {
6266 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6267 } else {
6268 double dRounded = round(pItem->val.dfnum);
6269 // See discussion in DecodeDateEpoch() for
6270 // explanation of - 0x7ff
6271 if(dRounded > (double)(UINT64_MAX- 0x7ff)) {
6272 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
6273 }
6274 *puValue = (uint64_t)dRounded;
6275 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006276 } else {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006277 if(isnan(pItem->val.fnum)) {
6278 return QCBOR_ERR_FLOAT_EXCEPTION;
6279 } else if(pItem->val.fnum < 0) {
6280 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6281 } else {
6282 float fRounded = roundf(pItem->val.fnum);
6283 // See discussion in DecodeDateEpoch() for
6284 // explanation of - 0x7ff
6285 if(fRounded > (float)(UINT64_MAX- 0x7ff)) {
6286 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
6287 }
6288 *puValue = (uint64_t)fRounded;
6289 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006290 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006291 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
6292 // round() and roundf() shouldn't result in exceptions here, but
6293 // catch them to be robust and thorough. Don't try to
6294 // distinguish between the various exceptions because it seems
6295 // they vary by CPU, compiler and OS.
6296 return QCBOR_ERR_FLOAT_EXCEPTION;
6297 }
6298
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006299 } else {
6300 return QCBOR_ERR_UNEXPECTED_TYPE;
6301 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006302#else
6303 return QCBOR_ERR_HW_FLOAT_DISABLED;
6304#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006305 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006306
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006307 case QCBOR_TYPE_INT64:
6308 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
6309 if(pItem->val.int64 >= 0) {
6310 *puValue = (uint64_t)pItem->val.int64;
6311 } else {
6312 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6313 }
6314 } else {
6315 return QCBOR_ERR_UNEXPECTED_TYPE;
6316 }
6317 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006318
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006319 case QCBOR_TYPE_UINT64:
6320 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade2d493002024-02-01 11:09:17 -07006321 *puValue = pItem->val.uint64;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006322 } else {
6323 return QCBOR_ERR_UNEXPECTED_TYPE;
6324 }
6325 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006326
Laurence Lundblade2d493002024-02-01 11:09:17 -07006327 case QCBOR_TYPE_65BIT_NEG_INT:
6328 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6329
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006330 default:
6331 return QCBOR_ERR_UNEXPECTED_TYPE;
6332 }
6333
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006334 return QCBOR_SUCCESS;
6335}
Laurence Lundbladec4537442020-04-14 18:53:22 -07006336
6337
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006338/**
6339 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
6340 *
6341 * @param[in] pMe The decode context.
6342 * @param[in] uConvertTypes Bit mask list of conversion options.
6343 * @param[out] puValue Result of the conversion.
6344 * @param[in,out] pItem Temporary space to store Item, returned item.
6345 *
6346 * See QCBORDecode_GetUInt64Convert().
6347 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006348void
6349QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pMe,
6350 const uint32_t uConvertTypes,
6351 uint64_t *puValue,
6352 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07006353{
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07006354 QCBORDecode_VGetNext(pMe, pItem);
6355 if(pMe->uLastError) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006356 return;
6357 }
6358
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07006359 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006360 uConvertTypes,
6361 puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07006362}
6363
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006364
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006365/**
6366 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
6367 *
6368 * @param[in] pMe The decode context.
6369 * @param[in] nLabel Label to find in map.
6370 * @param[in] uConvertTypes Bit mask list of conversion options.
6371 * @param[out] puValue Result of the conversion.
6372 * @param[in,out] pItem Temporary space to store Item, returned item.
6373 *
6374 * See QCBORDecode_GetUInt64ConvertInMapN().
6375 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006376void
6377QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe,
6378 const int64_t nLabel,
6379 const uint32_t uConvertTypes,
6380 uint64_t *puValue,
6381 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006382{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006383 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006384 if(pMe->uLastError != QCBOR_SUCCESS) {
6385 return;
6386 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006387
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006388 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
6389 uConvertTypes,
6390 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006391}
6392
6393
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006394/**
6395 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
6396 *
6397 * @param[in] pMe The decode context.
6398 * @param[in] szLabel Label to find in map.
6399 * @param[in] uConvertTypes Bit mask list of conversion options.
6400 * @param[out] puValue Result of the conversion.
6401 * @param[in,out] pItem Temporary space to store Item, returned item.
6402 *
6403 * See QCBORDecode_GetUInt64ConvertInMapSZ().
6404 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006405void
6406QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
6407 const char *szLabel,
6408 const uint32_t uConvertTypes,
6409 uint64_t *puValue,
6410 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006411{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006412 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006413 if(pMe->uLastError != QCBOR_SUCCESS) {
6414 return;
6415 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006416
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006417 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
6418 uConvertTypes,
6419 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006420}
6421
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006422
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006423/**
6424 * @brief Convert many number types to an unt64_t.
6425 *
6426 * @param[in] pItem The item to convert.
6427 * @param[in] uConvertTypes Bit mask list of conversion options.
6428 * @param[out] puValue The resulting converted value.
6429 *
6430 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6431 * in uConvertTypes.
6432 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6433 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6434 * or too small.
6435 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006436static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006437QCBOR_Private_UInt64ConvertAll(const QCBORItem *pItem,
6438 const uint32_t uConvertTypes,
6439 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006440{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08006441 switch(pItem->uDataType) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006442
6443 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006444 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006445 return QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006446 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006447 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006448 }
6449 break;
6450
6451 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006452 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006453 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6454 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006455 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006456 }
6457 break;
6458
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006459#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006460
6461 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006462 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006463 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006464 pItem->val.expAndMantissa.nExponent,
6465 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006466 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006467 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006468 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006469 }
6470 break;
6471
6472 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006473 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006474 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006475 pItem->val.expAndMantissa.nExponent,
6476 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006477 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006478 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006479 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006480 }
6481 break;
6482
6483 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006484 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006485 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006486 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006487 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006488 if(uErr != QCBOR_SUCCESS) {
6489 return uErr;
6490 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006491 return QCBOR_Private_ExponentitateUU(uMantissa,
6492 pItem->val.expAndMantissa.nExponent,
6493 puValue,
6494 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006495 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006496 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006497 }
6498 break;
6499
6500 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006501 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006502 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6503 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006504 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006505 }
6506 break;
6507
6508 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006509 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006510 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006511 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006512 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum,
6513 &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006514 if(uErr != QCBOR_SUCCESS) {
6515 return uErr;
6516 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006517 return QCBOR_Private_ExponentitateUU(uMantissa,
6518 pItem->val.expAndMantissa.nExponent,
6519 puValue,
6520 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006521 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006522 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006523 }
6524 break;
6525
6526 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006527 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006528 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6529 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006530 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006531 }
6532 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006533#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006534 default:
6535 return QCBOR_ERR_UNEXPECTED_TYPE;
6536 }
6537}
6538
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006539
Laurence Lundblade4e2da002020-06-13 23:08:31 -07006540/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006541 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006542 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006543void
6544QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe,
6545 const uint32_t uConvertTypes,
6546 uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006547{
6548 QCBORItem Item;
6549
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006550 QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006551
Laurence Lundbladef6c86662020-05-12 02:08:00 -07006552 if(pMe->uLastError == QCBOR_SUCCESS) {
6553 // The above conversion succeeded
6554 return;
6555 }
6556
6557 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6558 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07006559 return;
6560 }
6561
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006562 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6563 uConvertTypes,
6564 puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006565}
6566
Laurence Lundbladec4537442020-04-14 18:53:22 -07006567
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006568/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006569 * Public function, see header qcbor/qcbor_decode.h file
6570 */
6571void
6572QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
6573 const int64_t nLabel,
6574 const uint32_t uConvertTypes,
6575 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006576{
6577 QCBORItem Item;
6578
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006579 QCBORDecode_Private_GetUInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006580 nLabel,
6581 uConvertTypes,
6582 puValue,
6583 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006584
6585 if(pMe->uLastError == QCBOR_SUCCESS) {
6586 // The above conversion succeeded
6587 return;
6588 }
6589
6590 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6591 // The above conversion failed in a way that code below can't correct
6592 return;
6593 }
6594
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006595 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6596 uConvertTypes,
6597 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006598}
6599
6600
6601/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006602 * Public function, see header qcbor/qcbor_decode.h file
6603 */
6604void
6605QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
6606 const char *szLabel,
6607 const uint32_t uConvertTypes,
6608 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006609{
6610 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006611 QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006612 szLabel,
6613 uConvertTypes,
6614 puValue,
6615 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006616
6617 if(pMe->uLastError == QCBOR_SUCCESS) {
6618 // The above conversion succeeded
6619 return;
6620 }
6621
6622 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6623 // The above conversion failed in a way that code below can't correct
6624 return;
6625 }
6626
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006627 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6628 uConvertTypes,
6629 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006630}
6631
6632
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006633
6634
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006635#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006636/**
6637 * @brief Basic conversions to a double.
6638 *
6639 * @param[in] pItem The item to convert
6640 * @param[in] uConvertTypes Bit flags indicating source types for conversion
6641 * @param[out] pdValue The value converted to a double
6642 *
6643 * This does the conversions that don't need much object code,
6644 * the conversions from int, uint and float to double.
6645 *
6646 * See QCBOR_Private_DoubleConvertAll() for the full set
6647 * of conversions.
6648 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006649static QCBORError
6650QCBOR_Private_ConvertDouble(const QCBORItem *pItem,
6651 const uint32_t uConvertTypes,
6652 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006653{
6654 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006655 case QCBOR_TYPE_FLOAT:
6656#ifndef QCBOR_DISABLE_FLOAT_HW_USE
6657 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6658 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006659 // Simple cast does the job.
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006660 *pdValue = (double)pItem->val.fnum;
6661 } else {
6662 return QCBOR_ERR_UNEXPECTED_TYPE;
6663 }
6664 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006665#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006666 return QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006667#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006668 break;
6669
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006670 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006671 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6672 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006673 *pdValue = pItem->val.dfnum;
6674 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006675 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006676 }
6677 }
6678 break;
6679
6680 case QCBOR_TYPE_INT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006681#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006682 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006683 // A simple cast seems to do the job with no worry of exceptions.
6684 // There will be precision loss for some values.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006685 *pdValue = (double)pItem->val.int64;
6686
6687 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006688 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006689 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006690#else
6691 return QCBOR_ERR_HW_FLOAT_DISABLED;
6692#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006693 break;
6694
6695 case QCBOR_TYPE_UINT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006696#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006697 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006698 // A simple cast seems to do the job with no worry of exceptions.
6699 // There will be precision loss for some values.
6700 *pdValue = (double)pItem->val.uint64;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006701 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006702 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006703 }
6704 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006705#else
6706 return QCBOR_ERR_HW_FLOAT_DISABLED;
6707#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006708
Laurence Lundblade2d493002024-02-01 11:09:17 -07006709 case QCBOR_TYPE_65BIT_NEG_INT:
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -08006710#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade2d493002024-02-01 11:09:17 -07006711 *pdValue = -(double)pItem->val.uint64 - 1;
6712 break;
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -08006713#else
6714 return QCBOR_ERR_HW_FLOAT_DISABLED;
6715#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade2d493002024-02-01 11:09:17 -07006716
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006717 default:
6718 return QCBOR_ERR_UNEXPECTED_TYPE;
6719 }
6720
6721 return QCBOR_SUCCESS;
6722}
6723
6724
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006725/**
6726 * @brief Almost-public method to decode a number and convert to double (semi-private).
6727 *
6728 * @param[in] pMe The decode context.
6729 * @param[in] uConvertTypes Bit mask list of conversion options
6730 * @param[out] pdValue The output of the conversion.
6731 * @param[in,out] pItem Temporary space to store Item, returned item.
6732 *
6733 * See QCBORDecode_GetDoubleConvert().
6734 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006735void
6736QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pMe,
6737 const uint32_t uConvertTypes,
6738 double *pdValue,
6739 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07006740{
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07006741 QCBORDecode_VGetNext(pMe, pItem);
6742 if(pMe->uLastError) {
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006743 return;
6744 }
6745
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006746 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006747 uConvertTypes,
6748 pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006749}
Laurence Lundbladec4537442020-04-14 18:53:22 -07006750
Laurence Lundbladec4537442020-04-14 18:53:22 -07006751
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006752/**
6753 * @brief Almost-public method to decode a number and convert to double (semi-private).
6754 *
6755 * @param[in] pMe The decode context.
6756 * @param[in] nLabel Label to find in map.
6757 * @param[in] uConvertTypes Bit mask list of conversion options
6758 * @param[out] pdValue The output of the conversion.
6759 * @param[in,out] pItem Temporary space to store Item, returned item.
6760 *
6761 * See QCBORDecode_GetDoubleConvertInMapN().
6762 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006763void
6764QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pMe,
6765 const int64_t nLabel,
6766 const uint32_t uConvertTypes,
6767 double *pdValue,
6768 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006769{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006770 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006771 if(pMe->uLastError != QCBOR_SUCCESS) {
6772 return;
6773 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006774
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006775 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6776 uConvertTypes,
6777 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006778}
6779
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006780
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006781/**
6782 * @brief Almost-public method to decode a number and convert to double (semi-private).
6783 *
6784 * @param[in] pMe The decode context.
6785 * @param[in] szLabel Label to find in map.
6786 * @param[in] uConvertTypes Bit mask list of conversion options
6787 * @param[out] pdValue The output of the conversion.
6788 * @param[in,out] pItem Temporary space to store Item, returned item.
6789 *
6790 * See QCBORDecode_GetDoubleConvertInMapSZ().
6791 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006792void
6793QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe,
6794 const char *szLabel,
6795 const uint32_t uConvertTypes,
6796 double *pdValue,
6797 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006798{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006799 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006800 if(pMe->uLastError != QCBOR_SUCCESS) {
6801 return;
6802 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006803
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006804 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6805 uConvertTypes,
6806 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006807}
6808
6809
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006810#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006811/**
6812 * @brief Convert a big number to double-precision float.
6813 *
6814 * @param[in] BigNum The big number to convert
6815 *
6816 * @returns The double value.
6817 *
6818 * This will always succeed. It will lose precision for larger
6819 * numbers. If the big number is too large to fit (more than
6820 * 1.7976931348623157E+308) infinity will be returned. NaN is never
6821 * returned.
6822 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006823static double
6824QCBOR_Private_ConvertBigNumToDouble(const UsefulBufC BigNum)
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006825{
6826 double dResult;
6827
6828 dResult = 0.0;
6829 const uint8_t *pByte = BigNum.ptr;
6830 size_t uLen = BigNum.len;
6831 /* This will overflow and become the float value INFINITY if the number
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006832 * is too large to fit. */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006833 while(uLen--) {
6834 dResult = (dResult * 256.0) + (double)*pByte++;
6835 }
6836
6837 return dResult;
6838}
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006839#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6840
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006841
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006842
6843
6844/**
6845 * @brief Convert many number types to a double.
6846 *
6847 * @param[in] pItem The item to convert.
6848 * @param[in] uConvertTypes Bit mask list of conversion options.
6849 * @param[out] pdValue The resulting converted value.
6850 *
6851 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6852 * in uConvertTypes.
6853 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6854 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6855 * or too small.
6856 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006857static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006858QCBOR_Private_DoubleConvertAll(const QCBORItem *pItem,
6859 const uint32_t uConvertTypes,
6860 double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006861{
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006862#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07006863 /*
Laurence Lundblade16a207a2021-09-18 17:22:46 -07006864 * What Every Computer Scientist Should Know About Floating-Point Arithmetic
6865 * https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
6866 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006867 switch(pItem->uDataType) {
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006868
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006869#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006870 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006871 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006872 // Underflow gives 0, overflow gives infinity
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006873 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6874 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
6875 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006876 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006877 }
6878 break;
6879
6880 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006881 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006882 // Underflow gives 0, overflow gives infinity
6883 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6884 exp2((double)pItem->val.expAndMantissa.nExponent);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006885 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006886 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006887 }
6888 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006889#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006890
6891 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006892 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006893 *pdValue = QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006894 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006895 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006896 }
6897 break;
6898
6899 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006900 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006901 *pdValue = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006902 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006903 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006904 }
6905 break;
6906
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006907#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006908 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006909 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006910 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006911 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6912 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006913 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006914 }
6915 break;
6916
6917 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006918 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006919 double dMantissa = -QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006920 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6921 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006922 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006923 }
6924 break;
6925
6926 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006927 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006928 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006929 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6930 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006931 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006932 }
6933 break;
6934
6935 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006936 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006937 double dMantissa = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006938 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6939 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006940 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006941 }
6942 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006943#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006944
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006945 default:
6946 return QCBOR_ERR_UNEXPECTED_TYPE;
6947 }
6948
6949 return QCBOR_SUCCESS;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006950
6951#else
6952 (void)pItem;
6953 (void)uConvertTypes;
6954 (void)pdValue;
6955 return QCBOR_ERR_HW_FLOAT_DISABLED;
6956#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6957
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006958}
6959
6960
6961/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006962 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006963 */
6964void
6965QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe,
6966 const uint32_t uConvertTypes,
6967 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006968{
6969
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006970 QCBORItem Item;
6971
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006972 QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006973
6974 if(pMe->uLastError == QCBOR_SUCCESS) {
6975 // The above conversion succeeded
6976 return;
6977 }
6978
6979 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6980 // The above conversion failed in a way that code below can't correct
6981 return;
6982 }
6983
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006984 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6985 uConvertTypes,
6986 pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006987}
6988
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006989
6990/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006991 * Public function, see header qcbor/qcbor_decode.h file
6992 */
6993void
6994QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe,
6995 const int64_t nLabel,
6996 const uint32_t uConvertTypes,
6997 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006998{
6999 QCBORItem Item;
7000
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007001 QCBORDecode_Private_GetDoubleConvertInMapN(pMe,
7002 nLabel,
7003 uConvertTypes,
7004 pdValue,
7005 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07007006
7007 if(pMe->uLastError == QCBOR_SUCCESS) {
7008 // The above conversion succeeded
7009 return;
7010 }
7011
7012 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
7013 // The above conversion failed in a way that code below can't correct
7014 return;
7015 }
7016
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007017 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
7018 uConvertTypes,
7019 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07007020}
7021
7022
7023/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007024 * Public function, see header qcbor/qcbor_decode.h file
7025 */
7026void
7027QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe,
7028 const char *szLabel,
7029 const uint32_t uConvertTypes,
7030 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07007031{
7032 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007033 QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe,
7034 szLabel,
7035 uConvertTypes,
7036 pdValue,
7037 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07007038
7039 if(pMe->uLastError == QCBOR_SUCCESS) {
7040 // The above conversion succeeded
7041 return;
7042 }
7043
7044 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
7045 // The above conversion failed in a way that code below can't correct
7046 return;
7047 }
7048
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007049 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
7050 uConvertTypes,
7051 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07007052}
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02007053#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007054
7055
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007056
7057
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07007058#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007059/**
7060 * @brief Convert an integer to a big number
7061 *
7062 * @param[in] uInt The integer to convert.
7063 * @param[in] Buffer The buffer to output the big number to.
7064 *
7065 * @returns The big number or NULLUsefulBufC is the buffer is to small.
7066 *
7067 * This always succeeds unless the buffer is too small.
7068 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007069static UsefulBufC
7070QCBOR_Private_ConvertIntToBigNum(uint64_t uInt, const UsefulBuf Buffer)
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07007071{
7072 while((uInt & 0xff00000000000000UL) == 0) {
7073 uInt = uInt << 8;
7074 };
7075
7076 UsefulOutBuf UOB;
7077
7078 UsefulOutBuf_Init(&UOB, Buffer);
7079
7080 while(uInt) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07007081 UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff00000000000000UL) >> 56));
7082 uInt = uInt << 8;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07007083 }
7084
7085 return UsefulOutBuf_OutUBuf(&UOB);
7086}
7087
7088
Laurence Lundblade37286c02022-09-03 10:05:02 -07007089/**
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07007090 * @brief Check and/or complete exponent and mantissa item.
Laurence Lundblade37286c02022-09-03 10:05:02 -07007091 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07007092 * @param[in] pMe The decoder context.
7093 * @param[in] TagSpec Expected type(s).
7094 * @param[in,out] pItem See below.
Laurence Lundblade37286c02022-09-03 10:05:02 -07007095 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07007096 * This is for decimal fractions and big floats, both of which are an
7097 * exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07007098 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07007099 * If the item item had a tag number indicating it was a
7100 * decimal fraction or big float, then the input @c pItem will
7101 * have been decoded as exponent and mantissa. If there was
7102 * no tag number, the caller is asking this be decoded as a
7103 * big float or decimal fraction and @c pItem just has the
7104 * first item in an exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07007105 *
7106 * On output, the item is always a fully decoded decimal fraction or
7107 * big float.
7108 *
7109 * This errors out if the input type does not meet the TagSpec.
7110 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07007111static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007112QCBOR_Private_ExpMantissaTypeHandler(QCBORDecodeContext *pMe,
7113 const QCBOR_Private_TagSpec TagSpec,
7114 QCBORItem *pItem)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007115{
7116 QCBORError uErr;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007117
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07007118 /* pItem could either be a decoded exponent and mantissa or
7119 * the opening array of an undecoded exponent and mantissa. This
Laurence Lundblade37286c02022-09-03 10:05:02 -07007120 * check will succeed on either, but doesn't say which it was.
7121 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007122 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07007123 if(uErr != QCBOR_SUCCESS) {
7124 goto Done;
7125 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007126
Laurence Lundblade37286c02022-09-03 10:05:02 -07007127 if(pItem->uDataType == QCBOR_TYPE_ARRAY) {
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07007128 /* The item is an array, which means is is an undecoded exponent
7129 * and mantissa. This call consumes the items in the array and
7130 * results in a decoded exponent and mantissa in pItem. This is
Laurence Lundblade37286c02022-09-03 10:05:02 -07007131 * the case where there was no tag.
7132 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007133 uErr = QCBORDecode_Private_ExpMantissa(pMe, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007134 if(uErr != QCBOR_SUCCESS) {
7135 goto Done;
7136 }
7137
Laurence Lundblade37286c02022-09-03 10:05:02 -07007138 /* The above decode didn't determine whether it is a decimal
7139 * fraction or big num. Which of these two depends on what the
7140 * caller wants it decoded as since there is no tag, so fish the
7141 * type out of the TagSpec. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007142 pItem->uDataType = QCBOR_Private_ExpMantissaDataType(TagSpec.uTaggedTypes[0], pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07007143
7144 /* No need to check the type again. All that we need to know was
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07007145 * that it decoded correctly as a exponent and mantissa. The
Laurence Lundblade37286c02022-09-03 10:05:02 -07007146 * QCBOR type is set out by what was requested.
7147 */
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007148 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07007149
7150 /* If the item was not an array and the check passed, then
7151 * it is a fully decoded big float or decimal fraction and
7152 * matches what is requested.
7153 */
7154
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007155Done:
7156 return uErr;
7157}
7158
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007159
Laurence Lundblade37286c02022-09-03 10:05:02 -07007160/* Some notes from the work to disable tags.
7161 *
7162 * The API for big floats and decimal fractions seems good.
7163 * If there's any issue with it it's that the code size to
7164 * implement is a bit large because of the conversion
7165 * to/from int and bignum that is required. There is no API
7166 * that doesn't do the conversion so dead stripping will never
7167 * leave that code out.
7168 *
7169 * The implementation itself seems correct, but not as clean
7170 * and neat as it could be. It could probably be smaller too.
7171 *
7172 * The implementation has three main parts / functions
7173 * - The decoding of the array of two
7174 * - All the tag and type checking for the various API functions
7175 * - Conversion to/from bignum and int
7176 *
7177 * The type checking seems like it wastes the most code for
7178 * what it needs to do.
7179 *
7180 * The inlining for the conversion is probably making the
7181 * overall code base larger.
7182 *
7183 * The tests cases could be organized a lot better and be
7184 * more thorough.
7185 *
7186 * Seems also like there could be more common code in the
7187 * first tier part of the public API. Some functions only
7188 * vary by a TagSpec.
7189 */
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007190
7191/**
7192 * @brief Common processor for exponent and mantissa.
7193 *
7194 * @param[in] pMe The decode context.
7195 * @param[in] TagSpec The expected/allowed tags.
7196 * @param[in] pItem The data item to process.
7197 * @param[out] pnMantissa The returned mantissa as an int64_t.
7198 * @param[out] pnExponent The returned exponent as an int64_t.
7199 *
7200 * This handles exponent and mantissa for base 2 and 10. This
7201 * is limited to a mantissa that is an int64_t. See also
7202 * QCBORDecode_Private_ProcessExpMantissaBig().
7203 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007204static void
7205QCBOR_Private_ProcessExpMantissa(QCBORDecodeContext *pMe,
7206 const QCBOR_Private_TagSpec TagSpec,
7207 QCBORItem *pItem,
7208 int64_t *pnMantissa,
7209 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007210{
7211 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007212
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07007213 if(pMe->uLastError) {
7214 return;
7215 }
7216
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007217 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007218 if(uErr != QCBOR_SUCCESS) {
7219 goto Done;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007220 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007221
Laurence Lundblade9b334962020-08-27 10:55:53 -07007222 switch (pItem->uDataType) {
7223
7224 case QCBOR_TYPE_DECIMAL_FRACTION:
7225 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade9b334962020-08-27 10:55:53 -07007226 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade37286c02022-09-03 10:05:02 -07007227 *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
Laurence Lundblade9b334962020-08-27 10:55:53 -07007228 break;
7229
Laurence Lundblade37286c02022-09-03 10:05:02 -07007230#ifndef QCBOR_DISABLE_TAGS
7231 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundblade9b334962020-08-27 10:55:53 -07007232 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
7233 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
7234 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007235 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07007236 break;
7237
7238 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
7239 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
7240 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007241 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07007242 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07007243#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07007244
7245 default:
7246 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
7247 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007248
7249 Done:
7250 pMe->uLastError = (uint8_t)uErr;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007251}
7252
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007253
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007254/**
7255 * @brief Decode exponent and mantissa into a big number.
7256 *
7257 * @param[in] pMe The decode context.
7258 * @param[in] TagSpec The expected/allowed tags.
7259 * @param[in] pItem Item to decode and convert.
7260 * @param[in] BufferForMantissa Buffer to output mantissa into.
7261 * @param[out] pMantissa The output mantissa.
7262 * @param[out] pbIsNegative The sign of the output.
7263 * @param[out] pnExponent The mantissa of the output.
7264 *
7265 * This is the common processing of a decimal fraction or a big float
7266 * into a big number. This will decode and consume all the CBOR items
7267 * that make up the decimal fraction or big float.
7268 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007269static void
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007270QCBORDecode_Private_ProcessExpMantissaBig(QCBORDecodeContext *pMe,
7271 const QCBOR_Private_TagSpec TagSpec,
7272 QCBORItem *pItem,
7273 const UsefulBuf BufferForMantissa,
7274 UsefulBufC *pMantissa,
7275 bool *pbIsNegative,
7276 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007277{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007278 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007279
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07007280 if(pMe->uLastError != QCBOR_SUCCESS) {
7281 return;
7282 }
7283
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007284 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007285 if(uErr != QCBOR_SUCCESS) {
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007286 goto Done;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007287 }
7288
7289 uint64_t uMantissa;
7290
7291 switch (pItem->uDataType) {
7292
7293 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007294 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07007295 /* See comments in ExponentiateNN() on handling INT64_MIN */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007296 if(pItem->val.expAndMantissa.Mantissa.nInt >= 0) {
7297 uMantissa = (uint64_t)pItem->val.expAndMantissa.Mantissa.nInt;
7298 *pbIsNegative = false;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07007299 } else if(pItem->val.expAndMantissa.Mantissa.nInt != INT64_MIN) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007300 uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt;
7301 *pbIsNegative = true;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07007302 } else {
7303 uMantissa = (uint64_t)INT64_MAX+1;
7304 *pbIsNegative = true;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007305 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007306 *pMantissa = QCBOR_Private_ConvertIntToBigNum(uMantissa,
7307 BufferForMantissa);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007308 *pnExponent = pItem->val.expAndMantissa.nExponent;
7309 break;
7310
Laurence Lundblade37286c02022-09-03 10:05:02 -07007311#ifndef QCBOR_DISABLE_TAGS
7312 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007313 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007314 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007315 *pnExponent = pItem->val.expAndMantissa.nExponent;
7316 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
7317 *pbIsNegative = false;
7318 break;
7319
7320 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007321 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007322 *pnExponent = pItem->val.expAndMantissa.nExponent;
7323 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
7324 *pbIsNegative = true;
7325 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07007326#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007327
7328 default:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007329 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007330 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007331
7332Done:
7333 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007334}
7335
7336
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007337/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007338 * Public function, see header qcbor/qcbor_decode.h file
7339 */
7340void
7341QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe,
7342 const uint8_t uTagRequirement,
7343 int64_t *pnMantissa,
7344 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007345{
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007346 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07007347 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007348
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007349 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007350 {
7351 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007352 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7353 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7354 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007355 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007356
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007357 QCBOR_Private_ProcessExpMantissa(pMe,
7358 TagSpec,
7359 &Item,
7360 pnMantissa,
7361 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007362}
7363
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007364
7365/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007366 * Public function, see header qcbor/qcbor_decode.h file
7367 */
7368void
7369QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe,
7370 const int64_t nLabel,
7371 const uint8_t uTagRequirement,
7372 int64_t *pnMantissa,
7373 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007374{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007375 QCBORItem Item;
7376 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7377
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007378 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007379 {
7380 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007381 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7382 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7383 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007384 };
7385
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007386 QCBOR_Private_ProcessExpMantissa(pMe,
7387 TagSpec,
7388 &Item,
7389 pnMantissa,
7390 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007391}
7392
7393
7394/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007395 * Public function, see header qcbor/qcbor_decode.h file
7396 */
7397void
7398QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
7399 const char *szLabel,
7400 const uint8_t uTagRequirement,
7401 int64_t *pnMantissa,
7402 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007403{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007404 QCBORItem Item;
7405 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7406
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007407 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007408 {
7409 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007410 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7411 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7412 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007413 };
Laurence Lundblade9b334962020-08-27 10:55:53 -07007414
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007415 QCBOR_Private_ProcessExpMantissa(pMe,
7416 TagSpec,
7417 &Item,
7418 pnMantissa,
7419 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007420}
7421
7422
7423/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007424 * Public function, see header qcbor/qcbor_decode.h file
7425 */
7426void
7427QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe,
7428 const uint8_t uTagRequirement,
7429 const UsefulBuf MantissaBuffer,
7430 UsefulBufC *pMantissa,
7431 bool *pbMantissaIsNegative,
7432 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007433{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007434 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07007435 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007436
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007437 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007438 {
7439 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007440 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7441 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7442 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007443 };
7444
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007445 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7446 TagSpec,
7447 &Item,
7448 MantissaBuffer,
7449 pMantissa,
7450 pbMantissaIsNegative,
7451 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007452}
7453
7454
7455/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007456 * Public function, see header qcbor/qcbor_decode.h file
7457 */
7458void
7459QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe,
7460 const int64_t nLabel,
7461 const uint8_t uTagRequirement,
7462 const UsefulBuf BufferForMantissa,
7463 UsefulBufC *pMantissa,
7464 bool *pbIsNegative,
7465 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007466{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007467
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007468 QCBORItem Item;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007469 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007470
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007471 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007472 {
7473 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007474 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7475 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7476 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007477 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007478
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007479 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7480 TagSpec,
7481 &Item,
7482 BufferForMantissa,
7483 pMantissa,
7484 pbIsNegative,
7485 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007486}
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007487
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007488
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007489/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007490 * Public function, see header qcbor/qcbor_decode.h file
7491 */
7492void
7493QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe,
7494 const char *szLabel,
7495 const uint8_t uTagRequirement,
7496 const UsefulBuf BufferForMantissa,
7497 UsefulBufC *pMantissa,
7498 bool *pbIsNegative,
7499 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007500{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007501 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007502 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007503
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007504 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007505 {
7506 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007507 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7508 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7509 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007510 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007511
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007512 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7513 TagSpec,
7514 &Item,
7515 BufferForMantissa,
7516 pMantissa,
7517 pbIsNegative,
7518 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007519}
7520
7521
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007522/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007523 * Public function, see header qcbor/qcbor_decode.h file
7524 */
7525void
7526QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe,
7527 const uint8_t uTagRequirement,
7528 int64_t *pnMantissa,
7529 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007530{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007531 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07007532 QCBORDecode_VGetNext(pMe, &Item);
7533
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007534 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007535 {
7536 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007537 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7538 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7539 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007540 };
7541
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007542 QCBOR_Private_ProcessExpMantissa(pMe,
7543 TagSpec,
7544 &Item,
7545 pnMantissa,
7546 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007547}
7548
7549
7550/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007551 * Public function, see header qcbor/qcbor_decode.h file
7552 */
7553void
7554QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe,
7555 const int64_t nLabel,
7556 const uint8_t uTagRequirement,
7557 int64_t *pnMantissa,
7558 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007559{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007560 QCBORItem Item;
7561 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007562
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007563 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007564 {
7565 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007566 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7567 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7568 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007569 };
7570
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007571 QCBOR_Private_ProcessExpMantissa(pMe,
7572 TagSpec,
7573 &Item,
7574 pnMantissa,
7575 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007576}
7577
7578
7579/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007580 * Public function, see header qcbor/qcbor_decode.h file
7581 */
7582void
7583QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe,
7584 const char *szLabel,
7585 const uint8_t uTagRequirement,
7586 int64_t *pnMantissa,
7587 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007588{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007589 QCBORItem Item;
7590 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007591
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007592 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007593 {
7594 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007595 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7596 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7597 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007598 };
7599
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007600 QCBOR_Private_ProcessExpMantissa(pMe,
7601 TagSpec,
7602 &Item,
7603 pnMantissa,
7604 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007605}
7606
7607
7608/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007609 * Public function, see header qcbor/qcbor_decode.h file
7610 */
7611void
7612QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe,
7613 const uint8_t uTagRequirement,
7614 const UsefulBuf MantissaBuffer,
7615 UsefulBufC *pMantissa,
7616 bool *pbMantissaIsNegative,
7617 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007618{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007619 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07007620 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007621
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007622 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007623 {
7624 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007625 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7626 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7627 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007628 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007629
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007630 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7631 TagSpec,
7632 &Item,
7633 MantissaBuffer,
7634 pMantissa,
7635 pbMantissaIsNegative,
7636 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007637}
7638
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007639
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007640/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007641 * Public function, see header qcbor/qcbor_decode.h file
7642 */
7643void
7644QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe,
7645 const int64_t nLabel,
7646 const uint8_t uTagRequirement,
7647 const UsefulBuf BufferForMantissa,
7648 UsefulBufC *pMantissa,
7649 bool *pbIsNegative,
7650 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007651{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007652 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007653 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007654
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007655 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007656 {
7657 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007658 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7659 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7660 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007661 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007662
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007663 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7664 TagSpec,
7665 &Item,
7666 BufferForMantissa,
7667 pMantissa,
7668 pbIsNegative,
7669 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007670}
7671
7672
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007673/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007674 * Public function, see header qcbor/qcbor_decode.h file
7675 */
7676void
7677QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe,
7678 const char *szLabel,
7679 const uint8_t uTagRequirement,
7680 const UsefulBuf BufferForMantissa,
7681 UsefulBufC *pMantissa,
7682 bool *pbIsNegative,
7683 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007684{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007685 QCBORItem Item;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007686 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007687
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007688 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007689 {
7690 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007691 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7692 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7693 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007694 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007695
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007696 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7697 TagSpec,
7698 &Item,
7699 BufferForMantissa,
7700 pMantissa,
7701 pbIsNegative,
7702 pnExponent);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007703}
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007704
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07007705#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007706
7707
7708#if !defined(USEFULBUF_DISABLE_ALL_FLOAT) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
7709/*
7710 * Public function, see header qcbor/qcbor_spiffy_decode.h file
7711 */
7712void
7713QCBORDecode_GetNumberConvertPrecisely(QCBORDecodeContext *pMe,
7714 QCBORItem *pNumber)
7715{
7716 QCBORItem Item;
7717 struct IEEE754_ToInt ToInt;
7718 double d;
7719 QCBORError uError;
7720
7721 if(pMe->uLastError != QCBOR_SUCCESS) {
7722 return;
7723 }
7724
7725 uError = QCBORDecode_GetNext(pMe, &Item);
7726 if(uError != QCBOR_SUCCESS) {
7727 pMe->uLastError = (uint8_t)uError;
7728 return;
7729 }
7730
7731 switch(Item.uDataType) {
7732 case QCBOR_TYPE_INT64:
7733 case QCBOR_TYPE_UINT64:
7734 *pNumber = Item;
7735 break;
7736
7737 case QCBOR_TYPE_DOUBLE:
7738 ToInt = IEEE754_DoubleToInt(Item.val.dfnum);
7739 if(ToInt.type == IEEE754_ToInt_IS_INT) {
7740 pNumber->uDataType = QCBOR_TYPE_INT64;
7741 pNumber->val.int64 = ToInt.integer.is_signed;
7742 } else if(ToInt.type == IEEE754_ToInt_IS_UINT) {
7743 if(ToInt.integer.un_signed <= INT64_MAX) {
7744 /* Do the same as base QCBOR integer decoding */
7745 pNumber->uDataType = QCBOR_TYPE_INT64;
7746 pNumber->val.int64 = (int64_t)ToInt.integer.un_signed;
7747 } else {
7748 pNumber->uDataType = QCBOR_TYPE_UINT64;
7749 pNumber->val.uint64 = ToInt.integer.un_signed;
7750 }
7751 } else {
7752 *pNumber = Item;
7753 }
7754 break;
7755
7756 case QCBOR_TYPE_FLOAT:
7757 ToInt = IEEE754_SingleToInt(Item.val.fnum);
7758 if(ToInt.type == IEEE754_ToInt_IS_INT) {
7759 pNumber->uDataType = QCBOR_TYPE_INT64;
7760 pNumber->val.int64 = ToInt.integer.is_signed;
7761 } else if(ToInt.type == IEEE754_ToInt_IS_UINT) {
7762 if(ToInt.integer.un_signed <= INT64_MAX) {
7763 /* Do the same as base QCBOR integer decoding */
7764 pNumber->uDataType = QCBOR_TYPE_INT64;
7765 pNumber->val.int64 = (int64_t)ToInt.integer.un_signed;
7766 } else {
7767 pNumber->uDataType = QCBOR_TYPE_UINT64;
7768 pNumber->val.uint64 = ToInt.integer.un_signed;
7769 }
7770 } else {
7771 *pNumber = Item;
7772 }
7773 break;
7774
7775
7776 case QCBOR_TYPE_65BIT_NEG_INT:
7777 d = IEEE754_UintToDouble(Item.val.uint64, 1);
7778 if(d == IEEE754_UINT_TO_DOUBLE_OOB) {
7779 *pNumber = Item;
7780 } else {
7781 pNumber->uDataType = QCBOR_TYPE_DOUBLE;
7782 /* -1 is because of CBOR offset of negative numbers */
7783 pNumber->val.dfnum = d - 1;
7784 }
7785 break;
7786
7787 default:
7788 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
7789 pNumber->uDataType = QCBOR_TYPE_NONE;
7790 break;
7791 }
7792}
7793
7794#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT && ! QCBOR_DISABLE_PREFERRED_FLOAT */