blob: 21845f4753de09a0f4faffcd6279f45b6b60f047 [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 Lundbladeb95afec2024-08-26 10:51:28 -0700464 const uint8_t uQCBORType,
465 const uint16_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 Lundbladeb95afec2024-08-26 10:51:28 -0700477 /* Rely on check in QCBOR_Private_DecodeArrayOrMap() for definite-length
478 * arrays and maps that are too long */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700479
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700480 uError = DecodeNesting_Descend(pNesting, uQCBORType);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700481 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700482 goto Done;
483 }
484
Laurence Lundbladeb95afec2024-08-26 10:51:28 -0700485 pNesting->pCurrent->u.ma.uCountCursor = uCount;
486 pNesting->pCurrent->u.ma.uCountTotal = uCount;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700487
488 DecodeNesting_ClearBoundedMode(pNesting);
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700489
490Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700491 return uError;;
492}
493
494
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700495static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700496DecodeNesting_LevelUpCurrent(QCBORDecodeNesting *pNesting)
497{
498 pNesting->pCurrent = pNesting->pCurrentBounded - 1;
499}
500
501
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700502static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700503DecodeNesting_LevelUpBounded(QCBORDecodeNesting *pNesting)
504{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700505 while(pNesting->pCurrentBounded != &(pNesting->pLevels[0])) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700506 pNesting->pCurrentBounded--;
507 if(DecodeNesting_IsCurrentBounded(pNesting)) {
508 break;
509 }
510 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700511}
512
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800513
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700514static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700515DecodeNesting_SetCurrentToBoundedLevel(QCBORDecodeNesting *pNesting)
516{
517 pNesting->pCurrent = pNesting->pCurrentBounded;
518}
519
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700520
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700521static QCBORError
Laurence Lundblade02625d42020-06-25 14:41:41 -0700522DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting,
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700523 uint32_t uEndOffset,
524 uint32_t uStartOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700525{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700526 QCBORError uError;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700527
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700528 uError = DecodeNesting_Descend(pNesting, QCBOR_TYPE_BYTE_STRING);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700529 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700530 goto Done;
531 }
532
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800533 /* Fill in the new byte string level */
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700534 pNesting->pCurrent->u.bs.uSavedEndOffset = uEndOffset;
535 pNesting->pCurrent->u.bs.uBstrStartOffset = uStartOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700536
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800537 /* Bstr wrapped levels are always bounded */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700538 pNesting->pCurrentBounded = pNesting->pCurrent;
539
540Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700541 return uError;;
542}
543
Laurence Lundbladed0304932020-06-27 10:59:38 -0700544
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700545static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700546DecodeNesting_ZeroMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700547{
548 pNesting->pCurrent->u.ma.uCountCursor = 0;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700549}
550
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700551
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700552static void
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800553DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting)
554{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700555 if(pNesting->pCurrent->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
556 pNesting->pCurrentBounded->u.ma.uCountCursor = pNesting->pCurrentBounded->u.ma.uCountTotal;
557 }
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800558}
559
560
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700561static void
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700562DecodeNesting_Init(QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700563{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700564 /* Assumes that *pNesting has been zero'd before this call. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700565 pNesting->pLevels[0].uLevelType = QCBOR_TYPE_BYTE_STRING;
566 pNesting->pCurrent = &(pNesting->pLevels[0]);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700567}
568
569
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700570static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800571DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting,
572 QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700573{
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700574 *pSave = *pNesting;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700575}
576
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700577
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700578static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800579DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting,
580 const QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700581{
582 *pNesting = *pSave;
583}
584
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700585
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700586static uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700587DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700588{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700589 return pMe->pCurrentBounded->u.bs.uSavedEndOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700590}
591
592
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800593
594
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800595#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladeee851742020-01-08 08:37:05 -0800596/*===========================================================================
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800597 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
598
599 The following four functions are pretty wrappers for invocation of
600 the string allocator supplied by the caller.
601
Laurence Lundbladeee851742020-01-08 08:37:05 -0800602 ===========================================================================*/
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800603
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700604static void
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800605StringAllocator_Free(const QCBORInternalAllocator *pMe, const void *pMem)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800606{
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300607 /* This cast to uintptr_t suppresses the "-Wcast-qual" warnings.
608 * This is the one place where the const needs to be cast away so const can
609 * be use in the rest of the code.
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800610 */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300611 (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, 0);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800612}
613
Laurence Lundbladeee851742020-01-08 08:37:05 -0800614// StringAllocator_Reallocate called with pMem NULL is
615// equal to StringAllocator_Allocate()
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700616static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800617StringAllocator_Reallocate(const QCBORInternalAllocator *pMe,
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800618 const void *pMem,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800619 size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800620{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800621 /* See comment in StringAllocator_Free() */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300622 return (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, uSize);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800623}
624
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700625static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800626StringAllocator_Allocate(const QCBORInternalAllocator *pMe, size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800627{
628 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
629}
630
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700631static void
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800632StringAllocator_Destruct(const QCBORInternalAllocator *pMe)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800633{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800634 /* See comment in StringAllocator_Free() */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800635 if(pMe->pfAllocator) {
636 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
637 }
638}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800639#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800640
641
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800642
643
Laurence Lundbladeee851742020-01-08 08:37:05 -0800644/*===========================================================================
645 QCBORDecode -- The main implementation of CBOR decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700646
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800647 See qcbor/qcbor_decode.h for definition of the object
648 used here: QCBORDecodeContext
Laurence Lundbladeee851742020-01-08 08:37:05 -0800649 ===========================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700650/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800651 * Public function, see header file
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700652 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700653void
654QCBORDecode_Init(QCBORDecodeContext *pMe,
655 UsefulBufC EncodedCBOR,
656 QCBORDecodeMode nDecodeMode)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700657{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800658 memset(pMe, 0, sizeof(QCBORDecodeContext));
659 UsefulInputBuf_Init(&(pMe->InBuf), EncodedCBOR);
660 /* Don't bother with error check on decode mode. If a bad value is
661 * passed it will just act as if the default normal mode of 0 was set.
662 */
663 pMe->uDecodeMode = (uint8_t)nDecodeMode;
664 DecodeNesting_Init(&(pMe->nesting));
665
666 /* Inialize me->auMappedTags to CBOR_TAG_INVALID16. See
667 * GetNext_TaggedItem() and MapTagNumber(). */
668 memset(pMe->auMappedTags, 0xff, sizeof(pMe->auMappedTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700669}
670
671
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800672#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
673
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700674/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800675 * Public function, see header file
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700676 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700677void
678QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
679 QCBORStringAllocate pfAllocateFunction,
680 void *pAllocateContext,
681 bool bAllStrings)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700682{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800683 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
684 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
685 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700686}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800687#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700688
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800689
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800690
691
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800692/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800693 * Deprecated public function, see header file
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800694 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700695void
696QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pMe,
697 const QCBORTagListIn *pTagList)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700698{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800699 /* This does nothing now. It is retained for backwards compatibility */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700700 (void)pMe;
701 (void)pTagList;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700702}
703
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700704
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800705
706
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700707/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800708 * Decoding items is done in six layers, one calling the next one
709 * down. If a layer has no work to do for a particular item, it
710 * returns quickly.
711 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700712 * 1. QCBORDecode_Private_GetNextTagContent - The top layer processes
713 * tagged data items, turning them into the local C representation.
714 * For the most simple it is just associating a QCBOR_TYPE with the
715 * data. For the complex ones that an aggregate of data items, there
716 * is some further decoding and some limited recursion.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800717 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700718 * 2. QCBORDecode_Private_GetNextMapOrArray - This manages the
719 * beginnings and ends of maps and arrays. It tracks descending into
720 * and ascending out of maps/arrays. It processes breaks that
721 * terminate indefinite-length maps and arrays.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800722 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700723 * 3. QCBORDecode_Private_GetNextMapEntry - This handles the combining
724 * of two items, the label and the data, that make up a map entry. It
725 * only does work on maps. It combines the label and data items into
726 * one labeled item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800727 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700728 * 4. QCBORDecode_Private_GetNextTagNumber - This decodes type 6 tag
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800729 * numbers. It turns the tag numbers into bit flags associated with
730 * the data item. No actual decoding of the contents of the tag is
731 * performed here.
732 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700733 * 5. QCBORDecode_Private_GetNextFullString - This assembles the
734 * sub-items that make up an indefinite-length string into one string
735 * item. It uses the string allocator to create contiguous space for
736 * the item. It processes all breaks that are part of
737 * indefinite-length strings.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800738 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700739 * 6. QCBOR_Private_DecodeAtomicDataItem - This decodes the atomic
740 * data items in CBOR. Each atomic data item has a "major type", an
741 * integer "argument" and optionally some content. For text and byte
742 * strings, the content is the bytes that make up the string. These
743 * are the smallest data items that are considered to be well-formed.
744 * The content may also be other data items in the case of aggregate
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800745 * types. They are not handled in this layer.
746 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700747 * This uses about 350 bytes of stack. This number comes from
748 * instrumenting (printf address of stack variables) the code on x86
749 * compiled for size optimization.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700750 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800751
752
753/*
754 * Note about use of int and unsigned variables.
755 *
756 * See http://www.unix.org/whitepapers/64bit.html for reasons int is
757 * used carefully here, and in particular why it isn't used in the
758 * public interface. Also see
759 * https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers
760 *
761 * Int is used for values that need less than 16-bits and would be
762 * subject to integer promotion and result in complaining from static
763 * analyzers.
764 */
765
766
767/**
768 * @brief Decode the CBOR head, the type and argument.
769 *
770 * @param[in] pUInBuf The input buffer to read from.
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700771 * @param[in] bRequirePreferred Require preferred serialization for argument.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800772 * @param[out] pnMajorType The decoded major type.
773 * @param[out] puArgument The decoded argument.
774 * @param[out] pnAdditionalInfo The decoded Lower 5 bits of initial byte.
775 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -0700776 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved features
777 * @retval QCBOR_ERR_HIT_END Unexpected end of input
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800778 *
779 * This decodes the CBOR "head" that every CBOR data item has. See
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700780 * longer description in QCBOREncode_EncodeHead().
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800781 *
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700782 * This does the network to host byte order conversion. The conversion
783 * here also provides the conversion for floats in addition to that
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800784 * for lengths, tags and integer values.
785 *
786 * The int type is preferred to uint8_t for some variables as this
787 * avoids integer promotions, can reduce code size and makes static
788 * analyzers happier.
789 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700790static QCBORError
791QCBOR_Private_DecodeHead(UsefulInputBuf *pUInBuf,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700792#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
793 bool bRequirePreferred,
794#endif
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700795 int *pnMajorType,
796 uint64_t *puArgument,
797 int *pnAdditionalInfo)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700798{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800799 QCBORError uReturn;
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700800 uint64_t uArgument;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800801
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700802 /* Get and break down initial byte that every CBOR data item has */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800803 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800804 const int nTmpMajorType = nInitialByte >> 5;
805 const int nAdditionalInfo = nInitialByte & 0x1f;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800806
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800807 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800808 /* Need to get 1,2,4 or 8 additional argument bytes. Map
809 * LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length.
810 */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800811 static const uint8_t aIterate[] = {1,2,4,8};
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800812
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800813 /* Loop getting all the bytes in the argument */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800814 uArgument = 0;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800815 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700816 /* This shift-and-add gives the endian conversion. */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800817 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
818 }
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700819
820#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
821 /* If requested, check that argument is in preferred form */
822 if(bRequirePreferred) {
823 uint64_t uMinArgument;
824
825 if(nAdditionalInfo == LEN_IS_ONE_BYTE) {
826 if(uArgument < 24) {
827 uReturn = QCBOR_ERR_PREFERRED_CONFORMANCE;
828 goto Done;
829 }
830 } else {
831 if(nTmpMajorType != CBOR_MAJOR_TYPE_SIMPLE) {
832 /* Check only if not a floating-point number */
833 int nArgLen = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE - 1];
834 uMinArgument = UINT64_MAX >> ((int)sizeof(uint64_t) - nArgLen) * 8;
835 if(uArgument <= uMinArgument) {
836 uReturn = QCBOR_ERR_PREFERRED_CONFORMANCE;
837 goto Done;
838 }
839 }
840 }
841 }
842#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
843
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800844 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800845 /* The reserved and thus-far unused additional info values */
846 uReturn = QCBOR_ERR_UNSUPPORTED;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800847 goto Done;
848 } else {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700849#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
850 if(bRequirePreferred && nAdditionalInfo == LEN_IS_INDEFINITE) {
851 uReturn = QCBOR_ERR_PREFERRED_CONFORMANCE;
852 goto Done;
853 }
854#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
855
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800856 /* Less than 24, additional info is argument or 31, an
857 * indefinite-length. No more bytes to get.
858 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800859 uArgument = (uint64_t)nAdditionalInfo;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700860 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800861
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700862 if(UsefulInputBuf_GetError(pUInBuf)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800863 uReturn = QCBOR_ERR_HIT_END;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700864 goto Done;
865 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800866
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800867 /* All successful if arrived here. */
868 uReturn = QCBOR_SUCCESS;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800869 *pnMajorType = nTmpMajorType;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800870 *puArgument = uArgument;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800871 *pnAdditionalInfo = nAdditionalInfo;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800872
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700873Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800874 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700875}
876
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800877
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800878/**
879 * @brief Decode integer types, major types 0 and 1.
880 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700881 * @param[in] nMajorType The CBOR major type (0 or 1).
882 * @param[in] uArgument The argument from the head.
883 * @param[in] nAdditionalInfo So it can be error-checked.
884 * @param[out] pDecodedItem The filled in decoded item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800885 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700886 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered.
887 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800888 *
889 * Must only be called when major type is 0 or 1.
890 *
891 * CBOR doesn't explicitly specify two's compliment for integers but
892 * all CPUs use it these days and the test vectors in the RFC are
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700893 * so. All integers in encoded CBOR are unsigned and the CBOR major
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800894 * type indicates positive or negative. CBOR can express positive
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700895 * integers up to 2^64 - 1 negative integers down to -2^64. Note that
896 * negative numbers can be one more
897 * away from zero than positive because there is no negative zero.
898 *
899 * The "65-bit negs" are values CBOR can encode that can't fit
900 * into an int64_t or uint64_t. They decoded as a special type
901 * QCBOR_TYPE_65BIT_NEG_INT. Not that this type does NOT
902 * take into account the offset of one for CBOR negative integers.
903 * It must be applied to get the correct value. Applying this offset
904 * would overflow a uint64_t.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700905 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700906static QCBORError
907QCBOR_Private_DecodeInteger(const int nMajorType,
908 const uint64_t uArgument,
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700909 const int nAdditionalInfo,
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700910 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700911{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800912 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800913
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700914 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
915 uReturn = QCBOR_ERR_BAD_INT;
916 goto Done;
917 }
918
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700919 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800920 if (uArgument <= INT64_MAX) {
921 pDecodedItem->val.int64 = (int64_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700922 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800923
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700924 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800925 pDecodedItem->val.uint64 = uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700926 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700927 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800928
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700929 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800930 if(uArgument <= INT64_MAX) {
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700931 /* INT64_MIN is one further away from 0 than INT64_MAX
932 * so the -1 here doesn't overflow. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800933 pDecodedItem->val.int64 = (-(int64_t)uArgument) - 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700934 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800935
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700936 } else {
Laurence Lundblade2d493002024-02-01 11:09:17 -0700937 pDecodedItem->val.uint64 = uArgument;
938 pDecodedItem->uDataType = QCBOR_TYPE_65BIT_NEG_INT;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700939 }
940 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800941
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700942Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800943 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700944}
945
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800946
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700947/**
948 * @brief Decode text and byte strings
949 *
950 * @param[in] pMe Decoder context.
951 * @param[in] bAllocate Whether to allocate and copy string.
952 * @param[in] nMajorType Whether it is a byte or text string.
953 * @param[in] uStrLen The length of the string.
954 * @param[in] nAdditionalInfo Whether it is an indefinite-length string.
955 * @param[out] pDecodedItem The filled-in decoded item.
956 *
957 * @retval QCBOR_ERR_HIT_END Unexpected end of input.
958 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
959 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
960 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator
961 *
962 * This reads @c uStrlen bytes from the input and fills in @c
963 * pDecodedItem. If @c bAllocate is true, then memory for the string
964 * is allocated.
965 */
966static QCBORError
967QCBOR_Private_DecodeString(QCBORDecodeContext *pMe,
968 const bool bAllocate,
969 const int nMajorType,
970 const uint64_t uStrLen,
971 const int nAdditionalInfo,
972 QCBORItem *pDecodedItem)
973{
974 QCBORError uReturn = QCBOR_SUCCESS;
975
976 /* ---- Figure out the major type ---- */
977 #if CBOR_MAJOR_TYPE_BYTE_STRING + 4 != QCBOR_TYPE_BYTE_STRING
978 #error QCBOR_TYPE_BYTE_STRING not lined up with major type
979 #endif
980
981 #if CBOR_MAJOR_TYPE_TEXT_STRING + 4 != QCBOR_TYPE_TEXT_STRING
982 #error QCBOR_TYPE_TEXT_STRING not lined up with major type
983 #endif
984 pDecodedItem->uDataType = (uint8_t)(nMajorType + 4);
985
986 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
987 /* --- Just the head of an indefinite-length string --- */
988 pDecodedItem->val.string = (UsefulBufC){NULL, QCBOR_STRING_LENGTH_INDEFINITE};
989
990 } else {
991 /* --- A definite-length string --- */
992 /* --- (which might be a chunk of an indefinte-length string) --- */
993
994 /* CBOR lengths can be 64 bits, but size_t is not 64 bits on all
995 * CPUs. This check makes the casts to size_t below safe.
996 *
997 * The max is 4 bytes less than the largest sizeof() so this can be
998 * tested by putting a SIZE_MAX length in the CBOR test input (no
999 * one will care the limit on strings is 4 bytes shorter).
1000 */
1001 if(uStrLen > SIZE_MAX-4) {
1002 uReturn = QCBOR_ERR_STRING_TOO_LONG;
1003 goto Done;
1004 }
1005
1006 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(&(pMe->InBuf), (size_t)uStrLen);
1007 if(UsefulBuf_IsNULLC(Bytes)) {
1008 /* Failed to get the bytes for this string item */
1009 uReturn = QCBOR_ERR_HIT_END;
1010 goto Done;
1011 }
1012
1013 if(bAllocate) {
1014#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
1015 /* --- Put string in allocated memory --- */
1016
1017 /* Note that this is not where allocation to coalesce
1018 * indefinite-length strings is done. This is for when the
1019 * caller has requested all strings be allocated. Disabling
1020 * indefinite length strings also disables this allocate-all
1021 * option.
1022 */
1023
1024 if(pMe->StringAllocator.pfAllocator == NULL) {
1025 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1026 goto Done;
1027 }
1028 UsefulBuf NewMem = StringAllocator_Allocate(&(pMe->StringAllocator), (size_t)uStrLen);
1029 if(UsefulBuf_IsNULL(NewMem)) {
1030 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1031 goto Done;
1032 }
1033 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
1034 pDecodedItem->uDataAlloc = 1;
1035#else
1036 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1037#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1038 } else {
1039 /* --- Normal case with no string allocator --- */
1040 pDecodedItem->val.string = Bytes;
1041 }
1042 }
1043
1044Done:
1045 return uReturn;
1046}
1047
1048
1049/**
1050 * @brief Decode array or map.
1051 *
1052 * @param[in] uMode Decoder mode.
1053 * @param[in] nMajorType Whether it is a byte or text string.
1054 * @param[in] uItemCount The length of the string.
1055 * @param[in] nAdditionalInfo Whether it is an indefinite-length.
1056 * @param[out] pDecodedItem The filled-in decoded item.
1057 *
1058 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinites disabled.
1059 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map.
1060 *
1061 * Not much to do for arrays and maps. Just the type item count (but a
1062 * little messy because of ifdefs for indefinite-lengths and
1063 * map-as-array decoding).
1064 *
1065 * This also does the bulk of the work for @ref
1066 * QCBOR_DECODE_MODE_MAP_AS_ARRAY, a special mode to handle
1067 * arbitrarily complex map labels. This ifdefs out with
1068 * QCBOR_DISABLE_NON_INTEGER_LABELS.
1069 */
1070static QCBORError
1071QCBOR_Private_DecodeArrayOrMap(const uint8_t uMode,
1072 const int nMajorType,
Laurence Lundbladeb95afec2024-08-26 10:51:28 -07001073 uint64_t uItemCount,
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001074 const int nAdditionalInfo,
1075 QCBORItem *pDecodedItem)
1076{
1077 QCBORError uReturn;
1078
1079 /* ------ Sort out the data type ------ */
1080 #if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
1081 #error QCBOR_TYPE_ARRAY value not lined up with major type
1082 #endif
1083
1084 #if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
1085 #error QCBOR_TYPE_MAP value not lined up with major type
1086 #endif
1087 pDecodedItem->uDataType = (uint8_t)nMajorType;
1088#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
1089 if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
1090 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
1091 }
1092#else
1093 (void)uMode;
1094#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
1095
1096 uReturn = QCBOR_SUCCESS;
1097
1098 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1099 /* ------ Indefinite-length array/map ----- */
1100#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
1101 pDecodedItem->val.uCount = QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH;
1102#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1103 uReturn = QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED;
1104#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1105 } else {
Laurence Lundbladeb95afec2024-08-26 10:51:28 -07001106 /* ----- Definite-length array/map ----- */
1107 if(uItemCount > (nMajorType == QCBOR_TYPE_MAP ? QCBOR_MAX_ITEMS_IN_MAP : QCBOR_MAX_ITEMS_IN_ARRAY)) {
1108 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001109
Laurence Lundbladeb95afec2024-08-26 10:51:28 -07001110 } else {
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001111#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb95afec2024-08-26 10:51:28 -07001112 if(uMode == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
1113 /* ------ Map as array ------ */
1114 uItemCount *= 2;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001115 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001116#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundbladeb95afec2024-08-26 10:51:28 -07001117
1118 /* cast OK because of check above */
1119 pDecodedItem->val.uCount = (uint16_t)uItemCount;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001120 }
1121 }
1122
1123 return uReturn;
1124}
1125
1126
1127/**
1128 * @brief Decode a tag number.
1129 *
1130 * @param[in] uTagNumber The length of the string.
1131 * @param[in] nAdditionalInfo So this can be error-checked.
1132 * @param[out] pDecodedItem The filled-in decoded item.
1133 *
1134 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo is LEN_IS_INDEFINITE.
1135 * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined.
1136 *
1137 * Not much to do for tags, but fill in pDecodedItem and check for
1138 * error in nAdditionalInfo.
1139 */
1140static QCBORError
1141QCBOR_Private_DecodeTag(const uint64_t uTagNumber,
1142 const int nAdditionalInfo,
1143 QCBORItem *pDecodedItem)
1144{
1145#ifndef QCBOR_DISABLE_TAGS
1146 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1147 return QCBOR_ERR_BAD_INT;
1148 } else {
1149 pDecodedItem->val.uTagV = uTagNumber;
1150 pDecodedItem->uDataType = QCBOR_TYPE_TAG;
1151 return QCBOR_SUCCESS;
1152 }
1153#else /* QCBOR_DISABLE_TAGS */
1154 (void)nAdditionalInfo;
Laurence Lundblade6c9a8242024-06-12 20:34:52 -07001155 (void)uTagNumber;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001156 (void)pDecodedItem;
1157 return QCBOR_ERR_TAGS_DISABLED;
1158#endif /* QCBOR_DISABLE_TAGS */
1159}
1160
1161
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001162#ifndef USEFULBUF_DISABLE_ALL_FLOAT
1163
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001164#if !defined(QCBOR_DISABLE_DECODE_CONFORMANCE) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
1165
1166static QCBORError
1167QCBORDecode_Private_HalfConformance(const double d, const uint8_t uDecodeMode)
1168{
1169 struct IEEE754_ToInt ToInt;
1170
1171 /* Only need to check for conversion to integer because
1172 * half-precision is always preferred serialization. Don't
1173 * need special checker for half-precision because whole
1174 * numbers always convert perfectly from half to double.
1175 *
1176 * This catches half-precision with NaN payload too.
1177 *
1178 * The only thing allowed here is a double/half-precision that
1179 * can't be converted to anything but a double.
1180 */
1181 if(uDecodeMode >= QCBOR_DECODE_MODE_DCBOR) {
1182 ToInt = IEEE754_DoubleToInt(d);
1183 if(ToInt.type != QCBOR_TYPE_DOUBLE) {
1184 return QCBOR_ERR_DCBOR_CONFORMANCE;
1185 }
1186 }
1187
1188 return QCBOR_SUCCESS;
1189}
1190
1191
1192static QCBORError
1193QCBORDecode_Private_SingleConformance(const float f, const uint8_t uDecodeMode)
1194{
1195 struct IEEE754_ToInt ToInt;
1196 IEEE754_union ToSmaller;
1197
1198 if(uDecodeMode >= QCBOR_DECODE_MODE_DCBOR) {
1199 /* See if it could have been encoded as an integer */
1200 ToInt = IEEE754_SingleToInt(f);
1201 if(ToInt.type == IEEE754_ToInt_IS_INT || ToInt.type == IEEE754_ToInt_IS_UINT) {
1202 return QCBOR_ERR_DCBOR_CONFORMANCE;
1203 }
1204
1205 /* Make sure there is no NaN payload */
1206 if(IEEE754_SingleHasNaNPayload(f)) {
1207 return QCBOR_ERR_DCBOR_CONFORMANCE;
1208 }
1209 }
1210
1211 /* See if it could have been encoded shorter */
1212 if(uDecodeMode >= QCBOR_DECODE_MODE_PREFERRED) {
1213 ToSmaller = IEEE754_SingleToHalf(f, true);
1214 if(ToSmaller.uSize != sizeof(float)) {
1215 return QCBOR_ERR_PREFERRED_CONFORMANCE;
1216 }
1217 }
1218
1219 return QCBOR_SUCCESS;
1220}
1221
1222
1223static QCBORError
1224QCBORDecode_Private_DoubleConformance(const double d, uint8_t uDecodeMode)
1225{
1226 struct IEEE754_ToInt ToInt;
1227 IEEE754_union ToSmaller;
1228
1229 if(uDecodeMode >= QCBOR_DECODE_MODE_DCBOR) {
1230 /* See if it could have been encoded as an integer */
1231 ToInt = IEEE754_DoubleToInt(d);
1232 if(ToInt.type == IEEE754_ToInt_IS_INT || ToInt.type == IEEE754_ToInt_IS_UINT) {
1233 return QCBOR_ERR_DCBOR_CONFORMANCE;
1234 }
1235 /* Make sure there is no NaN payload */
1236 if(IEEE754_DoubleHasNaNPayload(d)) {
1237 return QCBOR_ERR_DCBOR_CONFORMANCE;
1238 }
1239 }
1240
1241 /* See if it could have been encoded shorter */
1242 if(uDecodeMode >= QCBOR_DECODE_MODE_PREFERRED) {
1243 ToSmaller = IEEE754_DoubleToSmaller(d, true, true);
1244 if(ToSmaller.uSize != sizeof(double)) {
1245 return QCBOR_ERR_PREFERRED_CONFORMANCE;
1246 }
1247 }
1248
1249 return QCBOR_SUCCESS;
1250}
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001251#else /* ! QCBOR_DISABLE_DECODE_CONFORMANCE && ! QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001252
1253static QCBORError
1254QCBORDecode_Private_SingleConformance(const float f, uint8_t uDecodeMode)
1255{
1256 (void)f;
1257 if(uDecodeMode >= QCBOR_DECODE_MODE_PREFERRED) {
1258 return QCBOR_ERR_CANT_CHECK_FLOAT_CONFORMANCE;
1259 } else {
1260 return QCBOR_SUCCESS;
1261 }
1262}
1263
1264static QCBORError
1265QCBORDecode_Private_DoubleConformance(const double d, uint8_t uDecodeMode)
1266{
1267 (void)d;
1268 if(uDecodeMode >= QCBOR_DECODE_MODE_PREFERRED) {
1269 return QCBOR_ERR_CANT_CHECK_FLOAT_CONFORMANCE;
1270 } else {
1271 return QCBOR_SUCCESS;
1272 }
1273}
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001274#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE && ! QCBOR_DISABLE_PREFERRED_FLOAT */
1275
1276
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001277/*
1278 * Decode a float
1279 */
1280static QCBORError
1281QCBOR_Private_DecodeFloat(const uint8_t uDecodeMode,
1282 const int nAdditionalInfo,
1283 const uint64_t uArgument,
1284 QCBORItem *pDecodedItem)
1285{
1286 QCBORError uReturn = QCBOR_SUCCESS;
1287 float single;
1288
1289 (void)single; /* Avoid unused error from various #ifndefs */
1290
1291 switch(nAdditionalInfo) {
1292 case HALF_PREC_FLOAT: /* 25 */
1293#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
1294 /* Half-precision is returned as a double. The cast to
1295 * uint16_t is safe because the encoded value was 16 bits. It
1296 * was widened to 64 bits to be passed in here.
1297 */
1298 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uArgument);
1299 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
1300
1301 uReturn = QCBORDecode_Private_HalfConformance(pDecodedItem->val.dfnum, uDecodeMode);
1302 if(uReturn != QCBOR_SUCCESS) {
1303 break;
1304 }
1305#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
1306 uReturn = FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS);
1307 break;
1308
1309 case SINGLE_PREC_FLOAT: /* 26 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001310 /* Single precision is normally returned as a double since
1311 * double is widely supported, there is no loss of precision,
1312 * it makes it easy for the caller in most cases and it can
1313 * be converted back to single with no loss of precision
1314 *
1315 * The cast to uint32_t is safe because the encoded value was
1316 * 32 bits. It was widened to 64 bits to be passed in here.
1317 */
1318 single = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uArgument);
1319 uReturn = QCBORDecode_Private_SingleConformance(single, uDecodeMode);
1320 if(uReturn != QCBOR_SUCCESS) {
1321 break;
1322 }
1323
1324#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1325 /* In the normal case, use HW to convert float to
1326 * double. */
1327 pDecodedItem->val.dfnum = (double)single;
1328 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
1329#else /* QCBOR_DISABLE_FLOAT_HW_USE */
1330 /* Use of float HW is disabled, return as a float. */
1331 pDecodedItem->val.fnum = single;
1332 pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
1333
1334 /* IEEE754_FloatToDouble() could be used here to return as
1335 * a double, but it adds object code and most likely
1336 * anyone disabling FLOAT HW use doesn't care about floats
1337 * and wants to save object code.
1338 */
1339#endif /* ! QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001340 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
1341 break;
1342
1343 case DOUBLE_PREC_FLOAT: /* 27 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001344 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uArgument);
1345 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
1346
1347 uReturn = QCBORDecode_Private_DoubleConformance(pDecodedItem->val.dfnum, uDecodeMode);
1348 if(uReturn != QCBOR_SUCCESS) {
1349 break;
1350 }
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001351 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
1352 break;
1353 }
1354
1355 return uReturn;
1356}
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001357#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */
1358
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001359
1360
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001361/* Make sure #define value line up as DecodeSimple counts on this. */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001362#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
1363#error QCBOR_TYPE_FALSE macro value wrong
1364#endif
1365
1366#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
1367#error QCBOR_TYPE_TRUE macro value wrong
1368#endif
1369
1370#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
1371#error QCBOR_TYPE_NULL macro value wrong
1372#endif
1373
1374#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
1375#error QCBOR_TYPE_UNDEF macro value wrong
1376#endif
1377
Laurence Lundblade0f99d692018-09-26 14:39:28 -07001378#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
1379#error QCBOR_TYPE_BREAK macro value wrong
1380#endif
1381
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001382#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
1383#error QCBOR_TYPE_DOUBLE macro value wrong
1384#endif
1385
1386#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
1387#error QCBOR_TYPE_FLOAT macro value wrong
1388#endif
1389
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001390/**
1391 * @brief Decode major type 7 -- true, false, floating-point, break...
1392 *
1393 * @param[in] nAdditionalInfo The lower five bits from the initial byte.
1394 * @param[in] uArgument The argument from the head.
1395 * @param[out] pDecodedItem The filled in decoded item.
1396 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001397 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1398 * of half-precision disabled
1399 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all float
1400 * decode is disabled.
1401 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of simple
1402 * type in input.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001403 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001404static QCBORError
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001405QCBOR_Private_DecodeType7(const uint8_t uDecodeMode,
1406 const int nAdditionalInfo,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001407 const uint64_t uArgument,
1408 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001409{
1410 QCBORError uReturn = QCBOR_SUCCESS;
1411
1412 /* uAdditionalInfo is 5 bits from the initial byte. Compile time
1413 * checks above make sure uAdditionalInfo values line up with
1414 * uDataType values. DecodeHead() never returns an AdditionalInfo
1415 * > 0x1f so cast is safe.
1416 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001417 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001418
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001419 switch(nAdditionalInfo) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001420 /* No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they
1421 * are caught before this is called.
1422 */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001423
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001424 case HALF_PREC_FLOAT: /* 25 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001425 case SINGLE_PREC_FLOAT: /* 26 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001426 case DOUBLE_PREC_FLOAT: /* 27 */
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001427#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001428 uReturn = QCBOR_Private_DecodeFloat(uDecodeMode, nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001429#else
1430 uReturn = QCBOR_ERR_ALL_FLOAT_DISABLED;
1431#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001432 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001433
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001434 case CBOR_SIMPLEV_FALSE: /* 20 */
1435 case CBOR_SIMPLEV_TRUE: /* 21 */
1436 case CBOR_SIMPLEV_NULL: /* 22 */
1437 case CBOR_SIMPLEV_UNDEF: /* 23 */
1438 case CBOR_SIMPLE_BREAK: /* 31 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001439#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
1440 if(uDecodeMode >= QCBOR_ENCODE_MODE_DCBOR &&
1441 nAdditionalInfo == CBOR_SIMPLEV_UNDEF) {
1442 uReturn = QCBOR_ERR_DCBOR_CONFORMANCE;
1443 goto Done;
1444 }
1445#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001446 break; /* nothing to do */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001447
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001448 case CBOR_SIMPLEV_ONEBYTE: /* 24 */
1449 if(uArgument <= CBOR_SIMPLE_BREAK) {
1450 /* This takes out f8 00 ... f8 1f which should be encoded
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001451 * as e0 … f7 -- preferred serialization check for simple values.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001452 */
1453 uReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001454 goto Done;
1455 }
Laurence Lundblade5e390822019-01-06 12:35:01 -08001456 /* FALLTHROUGH */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001457
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001458 default: /* 0-19 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001459#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
1460 if(uDecodeMode >= QCBOR_ENCODE_MODE_DCBOR &&
1461 (uArgument < CBOR_SIMPLEV_FALSE || uArgument > CBOR_SIMPLEV_NULL)) {
1462 uReturn = QCBOR_ERR_DCBOR_CONFORMANCE;
1463 goto Done;
1464 }
1465#endif /* !QCBOR_DISABLE_DECODE_CONFORMANCE */
1466
1467 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
1468 /* QCBOR_Private_DecodeHead() will make uArgument equal to
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001469 * nAdditionalInfo when nAdditionalInfo is < 24. This cast is
1470 * safe because the 2, 4 and 8 byte lengths of uNumber are in
1471 * the double/float cases above
Laurence Lundbladeee851742020-01-08 08:37:05 -08001472 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001473 pDecodedItem->val.uSimple = (uint8_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001474 break;
1475 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001476
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001477Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001478 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001479}
1480
1481
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001482/**
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001483 * @brief Decode a single primitive data item (decode layer 6).
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001484 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001485 * @param[in] pMe Decoder context.
1486 * @param[in] bAllocateStrings If true, use allocator for strings.
1487 * @param[out] pDecodedItem The filled-in decoded item.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001488 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001489 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1490 * features
1491 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1492 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1493 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1494 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001495 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001496 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1497 * of half-precision disabled
1498 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1499 * float decode is disabled.
1500 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1501 * simple type in input.
1502 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1503 * in input, but indefinite
1504 * lengths disabled.
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001505 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte.
1506 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map.
1507 * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001508 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001509 * This decodes the most primitive/atomic data item. It does no
1510 * combining of data items.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001511 */
1512static QCBORError
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001513QCBOR_Private_DecodeAtomicDataItem(QCBORDecodeContext *pMe,
1514 const bool bAllocateStrings,
1515 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001516{
1517 QCBORError uReturn;
Laurence Lundbladede2e1502024-08-26 11:37:05 -07001518 int nMajorType = 0;
1519 uint64_t uArgument = 0;
1520 int nAdditionalInfo = 0;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001521
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001522 memset(pDecodedItem, 0, sizeof(QCBORItem));
1523
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001524 /* Decode the "head" that every CBOR item has into the major type,
1525 * argument and the additional info.
1526 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001527 uReturn = QCBOR_Private_DecodeHead(&(pMe->InBuf),
1528#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
1529 // TODO: make this prettier; will optimizer take out stuff without ifdef?
1530 pMe->uDecodeMode >= QCBOR_DECODE_MODE_PREFERRED,
1531#endif /* !QCBOR_DISABLE_DECODE_CONFORMANCE */
1532 &nMajorType,
1533 &uArgument,
1534 &nAdditionalInfo);
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001535
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001536 if(uReturn != QCBOR_SUCCESS) {
1537 return uReturn;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001538 }
1539
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001540 /* All the functions below get inlined by the optimizer. This code
1541 * is easier to read with them all being similar functions, even if
1542 * some functions don't do much.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001543 */
1544 switch (nMajorType) {
1545 case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
1546 case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001547 return QCBOR_Private_DecodeInteger(nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001548 break;
1549
1550 case CBOR_MAJOR_TYPE_BYTE_STRING: /* Major type 2 */
1551 case CBOR_MAJOR_TYPE_TEXT_STRING: /* Major type 3 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001552 return QCBOR_Private_DecodeString(pMe, bAllocateStrings, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001553 break;
1554
1555 case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */
1556 case CBOR_MAJOR_TYPE_MAP: /* Major type 5 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001557 return QCBOR_Private_DecodeArrayOrMap(pMe->uDecodeMode, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001558 break;
1559
1560 case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001561 return QCBOR_Private_DecodeTag(uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001562 break;
1563
1564 case CBOR_MAJOR_TYPE_SIMPLE:
1565 /* Major type 7: float, double, true, false, null... */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001566 return QCBOR_Private_DecodeType7(pMe->uDecodeMode, nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001567 break;
1568
1569 default:
1570 /* Never happens because DecodeHead() should never return > 7 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001571 return QCBOR_ERR_UNSUPPORTED;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001572 break;
1573 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001574}
1575
1576
1577/**
1578 * @brief Process indefinite-length strings (decode layer 5).
1579 *
1580 * @param[in] pMe Decoder context
1581 * @param[out] pDecodedItem The decoded item that work is done on.
1582 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001583 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1584 * features
1585 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1586 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1587 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1588 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1589 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1590 * of half-precision disabled
1591 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1592 * float decode is disabled.
1593 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1594 * simple type in input.
1595 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1596 * in input, but indefinite
1597 * lengths disabled.
1598 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1599 * but no string allocator.
1600 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1601 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1602 * input, but indefinite-length
1603 * strings are disabled.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001604 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001605 * If @c pDecodedItem is not an indefinite-length string, this does nothing.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001606 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001607 * If it is, this loops getting the subsequent chunk data items that
1608 * make up the string. The string allocator is used to make a
1609 * contiguous buffer for the chunks. When this completes @c
1610 * pDecodedItem contains the put-together string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001611 *
1612 * Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001613 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001614static QCBORError
1615QCBORDecode_Private_GetNextFullString(QCBORDecodeContext *pMe,
1616 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001617{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001618 /* Aproximate stack usage
1619 * 64-bit 32-bit
1620 * local vars 32 16
1621 * 2 UsefulBufs 32 16
1622 * QCBORItem 56 52
1623 * TOTAL 120 74
1624 */
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001625 QCBORError uReturn;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001626
1627 /* A note about string allocation -- Memory for strings is
1628 * allocated either because 1) indefinte-length string chunks are
1629 * being coalecsed or 2) caller has requested all strings be
1630 * allocated. The first case is handed below here. The second case
1631 * is handled in DecodeString if the bAllocate is true. That
1632 * boolean originates here with pMe->bStringAllocateAll immediately
1633 * below. That is, QCBOR_Private_DecodeAtomicDataItem() is called
1634 * in two different contexts here 1) main-line processing which is
1635 * where definite-length strings need to be allocated if
1636 * bStringAllocateAll is true and 2) processing chunks of
1637 * indefinite-lengths strings in in which case there must be no
1638 * allocation.
1639 */
1640
1641
1642 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, pMe->bStringAllocateAll, pDecodedItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001643 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001644 goto Done;
1645 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001646
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001647 /* This is where out-of-place break is detected for the whole
1648 * decoding stack. Break is an error for everything that calls
1649 * QCBORDecode_Private_GetNextFullString(), so the check is
1650 * centralized here.
1651 */
1652 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
1653 uReturn = QCBOR_ERR_BAD_BREAK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001654 goto Done;
1655 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001656
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001657
1658 /* Skip out if not an indefinite-length string */
1659 const uint8_t uStringType = pDecodedItem->uDataType;
1660 if(uStringType != QCBOR_TYPE_BYTE_STRING &&
1661 uStringType != QCBOR_TYPE_TEXT_STRING) {
1662 goto Done;
1663 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001664 if(pDecodedItem->val.string.len != QCBOR_STRING_LENGTH_INDEFINITE) {
1665 goto Done;
1666 }
1667
1668#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001669 /* Can't decode indefinite-length strings without a string allocator */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001670 if(!pMe->StringAllocator.pfAllocator) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001671 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1672 goto Done;
1673 }
1674
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001675 /* Loop getting chunks of the indefinite-length string */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001676 UsefulBufC FullString = NULLUsefulBufC;
1677
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001678 for(;;) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001679 /* Get QCBORItem for next chunk */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001680 QCBORItem StringChunkItem;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001681 /* Pass false to DecodeAtomicDataItem() because the individual
1682 * string chunks in an indefinite-length must not be
1683 * allocated. They are always copied into the allocated
1684 * contiguous buffer allocated here.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001685 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001686 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &StringChunkItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001687 if(uReturn) {
1688 break;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001689 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001690
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001691 /* Is item is the marker for end of the indefinite-length string? */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001692 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001693 /* String is complete */
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001694 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301695 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001696 break;
1697 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001698
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001699 /* All chunks must be of the same type, the type of the item
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001700 * that introduces the indefinite-length string. This also
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001701 * catches errors where the chunk is not a string at all and an
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001702 * indefinite-length string inside an indefinite-length string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001703 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001704 if(StringChunkItem.uDataType != uStringType ||
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001705 StringChunkItem.val.string.len == QCBOR_STRING_LENGTH_INDEFINITE) {
1706 uReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001707 break;
1708 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001709
David Navarro9123e5b2022-03-28 16:04:03 +02001710 if (StringChunkItem.val.string.len > 0) {
1711 /* The first time throurgh FullString.ptr is NULL and this is
1712 * equivalent to StringAllocator_Allocate(). Subsequently it is
1713 * not NULL and a reallocation happens.
1714 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001715 UsefulBuf NewMem = StringAllocator_Reallocate(&(pMe->StringAllocator),
David Navarro9123e5b2022-03-28 16:04:03 +02001716 FullString.ptr,
1717 FullString.len + StringChunkItem.val.string.len);
David Navarro9123e5b2022-03-28 16:04:03 +02001718 if(UsefulBuf_IsNULL(NewMem)) {
1719 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1720 break;
1721 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001722
David Navarro9123e5b2022-03-28 16:04:03 +02001723 /* Copy new string chunk to the end of accumulated string */
1724 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001725 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001726 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001727
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001728 if(uReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
1729 /* Getting the item failed, clean up the allocated memory */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001730 StringAllocator_Free(&(pMe->StringAllocator), FullString.ptr);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001731 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001732#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1733 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1734#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001735
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001736Done:
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001737 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001738}
1739
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001740
Laurence Lundblade37286c02022-09-03 10:05:02 -07001741#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001742/**
1743 * @brief This converts a tag number to a shorter mapped value for storage.
1744 *
1745 * @param[in] pMe The decode context.
1746 * @param[in] uUnMappedTag The tag number to map
1747 * @param[out] puMappedTagNumer The stored tag number.
1748 *
1749 * @return error code.
1750 *
1751 * The main point of mapping tag numbers is make QCBORItem
1752 * smaller. With this mapping storage of 4 tags takes up 8
1753 * bytes. Without, it would take up 32 bytes.
1754 *
1755 * This maps tag numbers greater than QCBOR_LAST_UNMAPPED_TAG.
1756 * QCBOR_LAST_UNMAPPED_TAG is a little smaller than MAX_UINT16.
1757 *
1758 * See also UnMapTagNumber() and @ref QCBORItem.
1759 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001760static QCBORError
1761QCBORDecode_Private_MapTagNumber(QCBORDecodeContext *pMe,
1762 const uint64_t uUnMappedTag,
1763 uint16_t *puMappedTagNumer)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001764{
1765 if(uUnMappedTag > QCBOR_LAST_UNMAPPED_TAG) {
1766 unsigned uTagMapIndex;
1767 /* Is there room in the tag map, or is it in it already? */
1768 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
1769 if(pMe->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID64) {
1770 break;
1771 }
1772 if(pMe->auMappedTags[uTagMapIndex] == uUnMappedTag) {
1773 break;
1774 }
1775 }
1776 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
1777 return QCBOR_ERR_TOO_MANY_TAGS;
1778 }
1779
1780 /* Covers the cases where tag is new and were it is already in the map */
1781 pMe->auMappedTags[uTagMapIndex] = uUnMappedTag;
1782 *puMappedTagNumer = (uint16_t)(uTagMapIndex + QCBOR_LAST_UNMAPPED_TAG + 1);
1783
1784 } else {
1785 *puMappedTagNumer = (uint16_t)uUnMappedTag;
1786 }
1787
1788 return QCBOR_SUCCESS;
1789}
1790
1791
1792/**
1793 * @brief This converts a mapped tag number to the actual tag number.
1794 *
1795 * @param[in] pMe The decode context.
1796 * @param[in] uMappedTagNumber The stored tag number.
1797 *
1798 * @return The actual tag number is returned or
1799 * @ref CBOR_TAG_INVALID64 on error.
1800 *
1801 * This is the reverse of MapTagNumber()
1802 */
1803static uint64_t
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001804QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe,
1805 const uint16_t uMappedTagNumber)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001806{
1807 if(uMappedTagNumber <= QCBOR_LAST_UNMAPPED_TAG) {
1808 return uMappedTagNumber;
1809 } else if(uMappedTagNumber == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07001810 return CBOR_TAG_INVALID64;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001811 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001812 /* This won't be negative because of code below in
1813 * MapTagNumber()
1814 */
1815 const unsigned uIndex = uMappedTagNumber - (QCBOR_LAST_UNMAPPED_TAG + 1);
1816 return pMe->auMappedTags[uIndex];
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001817 }
1818}
Laurence Lundblade37286c02022-09-03 10:05:02 -07001819#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001820
Laurence Lundblade9b334962020-08-27 10:55:53 -07001821
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001822/**
1823 * @brief Aggregate all tags wrapping a data item (decode layer 4).
1824 *
1825 * @param[in] pMe Decoder context
1826 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001827 *
1828 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1829 * features
1830 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1831 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1832 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1833 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1834 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1835 * of half-precision disabled
1836 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1837 * float decode is disabled.
1838 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1839 * simple type in input.
1840 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1841 * in input, but indefinite
1842 * lengths disabled.
1843 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1844 * but no string allocator.
1845 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1846 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1847 * input, but indefinite-length
1848 * strings are disabled.
1849 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001850 *
1851 * This loops getting atomic data items until one is not a tag
1852 * number. Usually this is largely pass-through because most
1853 * item are not tag numbers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001854 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001855static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001856QCBORDecode_Private_GetNextTagNumber(QCBORDecodeContext *pMe,
1857 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001858{
Laurence Lundblade37286c02022-09-03 10:05:02 -07001859#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001860 /* Accummulate the tags from multiple items here and then copy them
1861 * into the last item, the non-tag item.
1862 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001863 uint16_t auItemsTags[QCBOR_MAX_TAGS_PER_ITEM];
1864
1865 /* Initialize to CBOR_TAG_INVALID16 */
1866 #if CBOR_TAG_INVALID16 != 0xffff
1867 /* Be sure the memset does the right thing. */
1868 #err CBOR_TAG_INVALID16 tag not defined as expected
1869 #endif
1870 memset(auItemsTags, 0xff, sizeof(auItemsTags));
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001871
Laurence Lundblade9b334962020-08-27 10:55:53 -07001872 QCBORError uReturn = QCBOR_SUCCESS;
1873
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001874 /* Loop fetching data items until the item fetched is not a tag */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001875 for(;;) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001876 QCBORError uErr = QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07001877 if(uErr != QCBOR_SUCCESS) {
1878 uReturn = uErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001879 goto Done;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001880 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001881
Laurence Lundblade9b334962020-08-27 10:55:53 -07001882 if(pDecodedItem->uDataType != QCBOR_TYPE_TAG) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001883 /* Successful exit from loop; maybe got some tags, maybe not */
1884 memcpy(pDecodedItem->uTags, auItemsTags, sizeof(auItemsTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001885 break;
1886 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001887
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001888 if(auItemsTags[QCBOR_MAX_TAGS_PER_ITEM - 1] != CBOR_TAG_INVALID16) {
1889 /* No room in the tag list */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001890 uReturn = QCBOR_ERR_TOO_MANY_TAGS;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001891 /* Continue on to get all tags wrapping this item even though
1892 * it is erroring out in the end. This allows decoding to
1893 * continue. This is a resource limit error, not a problem
1894 * with being well-formed CBOR.
1895 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001896 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001897 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001898 /* Slide tags over one in the array to make room at index 0.
1899 * Must use memmove because the move source and destination
1900 * overlap.
1901 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001902 memmove(&auItemsTags[1],
1903 auItemsTags,
1904 sizeof(auItemsTags) - sizeof(auItemsTags[0]));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001905
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001906 /* Map the tag */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001907 uint16_t uMappedTagNumber = 0;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001908 uReturn = QCBORDecode_Private_MapTagNumber(pMe, pDecodedItem->val.uTagV, &uMappedTagNumber);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001909 /* Continue even on error so as to consume all tags wrapping
1910 * this data item so decoding can go on. If MapTagNumber()
1911 * errors once it will continue to error.
1912 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001913 auItemsTags[0] = uMappedTagNumber;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001914 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001915
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001916Done:
Laurence Lundblade9b334962020-08-27 10:55:53 -07001917 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001918
Laurence Lundblade37286c02022-09-03 10:05:02 -07001919#else /* QCBOR_DISABLE_TAGS */
1920
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07001921 return QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07001922
1923#endif /* QCBOR_DISABLE_TAGS */
1924}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001925
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001926
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001927/**
1928 * @brief Combine a map entry label and value into one item (decode layer 3).
1929 *
1930 * @param[in] pMe Decoder context
1931 * @param[out] pDecodedItem The decoded item that work is done on.
1932 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001933 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1934 * features
1935 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1936 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1937 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1938 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1939 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1940 * of half-precision disabled
1941 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1942 * float decode is disabled.
1943 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1944 * simple type in input.
1945 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1946 * in input, but indefinite
1947 * lengths disabled.
1948 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1949 * but no string allocator.
1950 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1951 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1952 * input, but indefinite-length
1953 * strings are disabled.
1954 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1955 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1956 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001957 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001958 * If the current nesting level is a map, then this combines pairs of
1959 * items into one data item with a label and value.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001960 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001961 * This is passthrough if the current nesting level is not a map.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001962 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001963 * This also implements maps-as-array mode where a map is treated like
1964 * an array to allow caller to do their own label processing.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001965 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001966static QCBORError
1967QCBORDecode_Private_GetNextMapEntry(QCBORDecodeContext *pMe,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001968 QCBORItem *pDecodedItem,
1969 uint32_t *puLabelEndOffset)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001970{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001971 QCBORItem LabelItem;
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001972 QCBORError uErr, uErr2;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001973
1974 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1975 if(QCBORDecode_IsUnrecoverableError(uErr)) {
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001976 goto Done;
1977 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001978
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001979 if(!DecodeNesting_IsCurrentTypeMap(&(pMe->nesting))) {
1980 /* Not decoding a map. Nothing to do. */
1981 /* When decoding maps-as-arrays, the type will be
1982 * QCBOR_TYPE_MAP_AS_ARRAY and this function will exit
1983 * here. This is now map processing for maps-as-arrays is not
1984 * done. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001985 goto Done;
1986 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001987
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001988 /* Decoding a map entry, so the item decoded above was the label */
1989 LabelItem = *pDecodedItem;
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001990
1991 if(puLabelEndOffset != NULL) {
1992 /* Cast is OK because lengths are all 32-bit in QCBOR */
1993 *puLabelEndOffset = (uint32_t)UsefulInputBuf_Tell(&(pMe->InBuf));
1994 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001995
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001996 /* Get the value of the map item */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001997 uErr2 = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1998 if(QCBORDecode_IsUnrecoverableError(uErr2)) {
1999 uErr = uErr2;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002000 goto Done;
2001 }
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002002 if(uErr2 != QCBOR_SUCCESS) {
2003 /* The recoverable error for the value overrides the recoverable error for the label, if there was an error for the label */
2004 uErr = uErr2;
2005 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002006
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002007 /* Combine the label item and value item into one */
2008 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
2009 pDecodedItem->uLabelType = LabelItem.uDataType;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09002010
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002011#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
2012 /* QCBOR_DECODE_MODE_MAP_STRINGS_ONLY might have been a bad idea. Maybe
2013 * get rid of it in QCBOR 2.0
2014 */
2015 if(pMe->uDecodeMode == QCBOR_DECODE_MODE_MAP_STRINGS_ONLY &&
2016 LabelItem.uDataType != QCBOR_TYPE_TEXT_STRING) {
2017 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
2018 goto Done;
2019 }
2020#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
2021
2022 switch(LabelItem.uDataType) {
2023 case QCBOR_TYPE_INT64:
2024 pDecodedItem->label.int64 = LabelItem.val.int64;
2025 break;
2026
2027#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
2028 case QCBOR_TYPE_UINT64:
2029 pDecodedItem->label.uint64 = LabelItem.val.uint64;
2030 break;
2031
2032 case QCBOR_TYPE_TEXT_STRING:
2033 case QCBOR_TYPE_BYTE_STRING:
2034 pDecodedItem->label.string = LabelItem.val.string;
2035 break;
2036#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
2037
2038 default:
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002039 /* It is possible to skip over labels that are non-aggregate
2040 * types like floats, but not to skip over labels that are
2041 * arrays or maps. We might eventually handle more label
2042 * types like floats as they are not too hard and we now
2043 * have QCBOR_DISABLE_NON_INTEGER_LABELS */
2044 if(!pMe->bAllowAllLabels || QCBORItem_IsMapOrArray(LabelItem)) {
2045 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
2046 goto Done;
2047 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002048 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002049
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002050Done:
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002051 return uErr;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002052}
2053
2054
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002055#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002056/**
2057 * @brief Peek and see if next data item is a break;
2058 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002059 * param[in] pUIB UsefulInputBuf to read from.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002060 * @param[out] pbNextIsBreak Indicate if next was a break or not.
2061 *
2062 * @return Any decoding error.
2063 *
2064 * See if next item is a CBOR break. If it is, it is consumed,
2065 * if not it is not consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07002066*/
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002067static QCBORError
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002068QCBOR_Private_NextIsBreak(QCBORDecodeContext *pMe, bool *pbNextIsBreak)
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002069{
2070 *pbNextIsBreak = false;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002071 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) != 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002072 QCBORItem Peek;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002073 size_t uPeek = UsefulInputBuf_Tell(&(pMe->InBuf));
2074 QCBORError uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &Peek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002075 if(uReturn != QCBOR_SUCCESS) {
2076 return uReturn;
2077 }
2078 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002079 /* It is not a break, rewind so it can be processed normally. */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002080 UsefulInputBuf_Seek(&(pMe->InBuf), uPeek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002081 } else {
2082 *pbNextIsBreak = true;
2083 }
2084 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002085
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002086 return QCBOR_SUCCESS;
2087}
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002088#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002089
2090
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002091/**
2092 * @brief Ascend up nesting levels if all items in them have been consumed.
2093 *
2094 * @param[in] pMe The decode context.
2095 * @param[in] bMarkEnd If true mark end of maps/arrays with count of zero.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002096 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002097 *
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002098 * An item was just consumed, now figure out if it was the
2099 * end of an array/map map that can be closed out. That
2100 * may in turn close out the above array/map...
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002101 *
2102 * When ascending indefinite-length arrays and maps, this will correctly
2103 * consume the break for the level above. This is a problem for the
2104 * implementation of QCBORDecode_GetArray() that must not return
2105 * that break. @c pbBreak is set to true to indicate that one
2106 * byte should be removed.
2107 *
2108 * Improvement: this could reduced further if indef is disabled
2109 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002110static QCBORError
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002111QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd, bool *pbBreak)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002112{
2113 QCBORError uReturn;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002114
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002115 /* Loop ascending nesting levels as long as there is ascending to do */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002116 while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002117 if(pbBreak) {
2118 *pbBreak = false;
2119 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002120
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002121 if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) {
2122 /* Nesting level is bstr-wrapped CBOR */
2123
2124 /* Ascent for bstr-wrapped CBOR is always by explicit call
2125 * so no further ascending can happen.
2126 */
2127 break;
2128
2129 } else if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
2130 /* Level is a definite-length array/map */
2131
2132 /* Decrement the item count the definite-length array/map */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002133 DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(&(pMe->nesting));
2134 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002135 /* Didn't close out array/map, so all work here is done */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002136 break;
2137 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002138 /* All items in a definite-length array were consumed so it
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002139 * is time to ascend one level. This happens below.
2140 */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002141
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002142#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002143 } else {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002144 /* Level is an indefinite-length array/map. */
2145
2146 /* Check for a break which is what ends indefinite-length arrays/maps */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002147 bool bIsBreak = false;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002148 uReturn = QCBOR_Private_NextIsBreak(pMe, &bIsBreak);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002149 if(uReturn != QCBOR_SUCCESS) {
2150 goto Done;
2151 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002152
2153 if(!bIsBreak) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002154 /* Not a break so array/map does not close out. All work is done */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002155 break;
2156 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002157
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002158 /* It was a break in an indefinitelength map / array so
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002159 * it is time to ascend one level.
2160 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002161 if(pbBreak) {
2162 *pbBreak = true;
2163 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002164
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002165#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002166 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002167
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002168
2169 /* All items in the array/map have been consumed. */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002170
Laurence Lundblade93d89472020-10-03 22:30:50 -07002171 /* But ascent in bounded mode is only by explicit call to
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002172 * QCBORDecode_ExitBoundedMode().
2173 */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07002174 if(DecodeNesting_IsCurrentBounded(&(pMe->nesting))) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002175 /* Set the count to zero for definite-length arrays to indicate
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002176 * cursor is at end of bounded array/map */
Laurence Lundbladed0304932020-06-27 10:59:38 -07002177 if(bMarkEnd) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002178 /* Used for definite and indefinite to signal end */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07002179 DecodeNesting_ZeroMapOrArrayCount(&(pMe->nesting));
Laurence Lundbladed0304932020-06-27 10:59:38 -07002180
Laurence Lundblade2c1faf92020-06-26 22:43:56 -07002181 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002182 break;
2183 }
2184
2185 /* Finally, actually ascend one level. */
2186 DecodeNesting_Ascend(&(pMe->nesting));
2187 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002188
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002189 uReturn = QCBOR_SUCCESS;
2190
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002191#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002192Done:
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002193#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
2194
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002195 return uReturn;
2196}
2197
2198
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002199/**
2200 * @brief Ascending & Descending out of nesting levels (decode layer 2).
2201 *
2202 * @param[in] pMe Decoder context
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002203 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002204 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002205
2206 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
2207 * features
2208 * @retval QCBOR_ERR_HIT_END Unexpected end of input
2209 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
2210 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
2211 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
2212 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
2213 * of half-precision disabled
2214 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
2215 * float decode is disabled.
2216 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
2217 * simple type in input.
2218 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
2219 * in input, but indefinite
2220 * lengths disabled.
2221 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
2222 * but no string allocator.
2223 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
2224 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
2225 * input, but indefinite-length
2226 * strings are disabled.
2227 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
2228 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
2229 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
2230 * @retval QCBOR_ERR_NO_MORE_ITEMS Need more items for map or array.
2231 * @retval QCBOR_ERR_BAD_BREAK Indefinite-length break in wrong
2232 * place.
2233 * @retval QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP Nesting deeper than QCBOR
2234 * can handle.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002235 *
2236 * This handles the traversal descending into and asecnding out of
2237 * maps, arrays and bstr-wrapped CBOR. It figures out the ends of
2238 * definite- and indefinte-length maps and arrays by looking at the
2239 * item count or finding CBOR breaks. It detects the ends of the
2240 * top-level sequence and of bstr-wrapped CBOR by byte count.
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002241 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002242static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002243QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002244 bool *pbBreak,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002245 QCBORItem *pDecodedItem,
2246 uint32_t *puLabelEndOffset)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002247{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002248 QCBORError uReturn;
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002249 /* ==== First: figure out if at the end of a traversal ==== */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002250
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002251 /* If out of bytes to consume, it is either the end of the
2252 * top-level sequence of some bstr-wrapped CBOR that was entered.
2253 *
2254 * In the case of bstr-wrapped CBOR, the length of the
2255 * UsefulInputBuf was set to that of the bstr-wrapped CBOR. When
2256 * the bstr-wrapped CBOR is exited, the length is set back to the
2257 * top-level's length or to the next highest bstr-wrapped CBOR.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002258 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002259 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) == 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002260 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002261 goto Done;
2262 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07002263
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002264 /* Check to see if at the end of a bounded definite-length map or
2265 * array. The check for a break ending indefinite-length array is
2266 * later in QCBORDecode_NestLevelAscender().
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002267 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002268 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002269 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002270 goto Done;
2271 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002272
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002273 /* ==== Next: not at the end, so get another item ==== */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002274 uReturn = QCBORDecode_Private_GetNextMapEntry(pMe, pDecodedItem, puLabelEndOffset);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002275 if(QCBORDecode_IsUnrecoverableError(uReturn)) {
2276 /* Error is so bad that traversal is not possible. */
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002277 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002278 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05302279
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002280 /* Record the nesting level for this data item before processing
2281 * any of decrementing and descending.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002282 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002283 pDecodedItem->uNestingLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002284
Laurence Lundblade642282a2020-06-23 12:00:33 -07002285
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002286 /* ==== Next: Process the item for descent, ascent, decrement... ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002287 if(QCBORItem_IsMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002288 /* If the new item is a map or array, descend.
2289 *
2290 * Empty indefinite-length maps and arrays are descended into,
2291 * but then ascended out of in the next chunk of code.
2292 *
2293 * Maps and arrays do count as items in the map/array that
2294 * encloses them so a decrement needs to be done for them too,
2295 * but that is done only when all the items in them have been
2296 * processed, not when they are opened with the exception of an
2297 * empty map or array.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002298 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002299 QCBORError uDescendErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002300 uDescendErr = DecodeNesting_DescendMapOrArray(&(pMe->nesting),
Laurence Lundbladeb95afec2024-08-26 10:51:28 -07002301 pDecodedItem->uDataType,
2302 pDecodedItem->val.uCount);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002303 if(uDescendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002304 /* This error is probably a traversal error and it overrides
2305 * the non-traversal error.
2306 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002307 uReturn = uDescendErr;
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002308 goto Done;
2309 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002310 }
2311
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002312 if(!QCBORItem_IsMapOrArray(*pDecodedItem) ||
2313 QCBORItem_IsEmptyDefiniteLengthMapOrArray(*pDecodedItem) ||
2314 QCBORItem_IsIndefiniteLengthMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002315 /* The following cases are handled here:
2316 * - A non-aggregate item like an integer or string
2317 * - An empty definite-length map or array
2318 * - An indefinite-length map or array that might be empty or might not.
2319 *
2320 * QCBORDecode_NestLevelAscender() does the work of decrementing the count
2321 * for an definite-length map/array and break detection for an
2322 * indefinite-0length map/array. If the end of the map/array was
2323 * reached, then it ascends nesting levels, possibly all the way
2324 * to the top level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002325 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002326 QCBORError uAscendErr;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002327 uAscendErr = QCBORDecode_Private_NestLevelAscender(pMe, true, pbBreak);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002328 if(uAscendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002329 /* This error is probably a traversal error and it overrides
2330 * the non-traversal error.
2331 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002332 uReturn = uAscendErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002333 goto Done;
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002334 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05302335 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002336
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002337 /* ==== Last: tell the caller the nest level of the next item ==== */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002338 /* Tell the caller what level is next. This tells them what
2339 * maps/arrays were closed out and makes it possible for them to
2340 * reconstruct the tree with just the information returned in a
2341 * QCBORItem.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002342 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002343 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07002344 /* At end of a bounded map/array; uNextNestLevel 0 to indicate this */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002345 pDecodedItem->uNextNestLevel = 0;
2346 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002347 pDecodedItem->uNextNestLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002348 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002349
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002350Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002351 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002352}
2353
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002354
Laurence Lundblade37286c02022-09-03 10:05:02 -07002355#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002356/**
2357 * @brief Shift 0th tag out of the tag list.
2358 *
2359 * pDecodedItem[in,out] The data item to convert.
2360 *
2361 * The 0th tag is discarded. \ref CBOR_TAG_INVALID16 is
2362 * shifted into empty slot at the end of the tag list.
2363 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002364static void
2365QCBOR_Private_ShiftTags(QCBORItem *pDecodedItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002366{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002367 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM-1; i++) {
2368 pDecodedItem->uTags[i] = pDecodedItem->uTags[i+1];
2369 }
2370 pDecodedItem->uTags[QCBOR_MAX_TAGS_PER_ITEM-1] = CBOR_TAG_INVALID16;
Laurence Lundblade9b334962020-08-27 10:55:53 -07002371}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002372#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002373
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002374
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002375/**
2376 * @brief Convert different epoch date formats in to the QCBOR epoch date format
2377 *
2378 * pDecodedItem[in,out] The data item to convert.
2379 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002380 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2381 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2382 * floating-point date disabled.
2383 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2384 * all floating-point disabled.
2385 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2386 * error decoding date.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002387 *
2388 * The epoch date tag defined in QCBOR allows for floating-point
2389 * dates. It even allows a protocol to flop between date formats when
2390 * ever it wants. Floating-point dates aren't that useful as they are
2391 * only needed for dates beyond the age of the earth.
2392 *
2393 * This converts all the date formats into one format of an unsigned
2394 * integer plus a floating-point fraction.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002395 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002396static QCBORError
2397QCBOR_Private_DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002398{
Laurence Lundbladec7114722020-08-13 05:11:40 -07002399 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002400
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002401#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade59289e52019-12-30 13:44:37 -08002402 pDecodedItem->val.epochDate.fSecondsFraction = 0;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002403#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002404
2405 switch (pDecodedItem->uDataType) {
2406
2407 case QCBOR_TYPE_INT64:
2408 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
2409 break;
2410
2411 case QCBOR_TYPE_UINT64:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002412 /* This only happens for CBOR type 0 > INT64_MAX so it is
2413 * always an overflow.
2414 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07002415 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2416 goto Done;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002417 break;
2418
2419 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade9682a532020-06-06 18:33:04 -07002420 case QCBOR_TYPE_FLOAT:
2421#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade59289e52019-12-30 13:44:37 -08002422 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002423 /* Convert working value to double if input was a float */
Laurence Lundblade3ed0bca2020-07-14 22:50:10 -07002424 const double d = pDecodedItem->uDataType == QCBOR_TYPE_DOUBLE ?
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002425 pDecodedItem->val.dfnum :
2426 (double)pDecodedItem->val.fnum;
2427
2428 /* The conversion from float to integer requires overflow
2429 * detection since floats can be much larger than integers.
2430 * This implementation errors out on these large float values
2431 * since they are beyond the age of the earth.
2432 *
2433 * These constants for the overflow check are computed by the
2434 * compiler. They are not computed at run time.
2435 *
2436 * The factor of 0x7ff is added/subtracted to avoid a
2437 * rounding error in the wrong direction when the compiler
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002438 * computes these constants. There is rounding because a
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002439 * 64-bit integer has 63 bits of precision where a double
2440 * only has 53 bits. Without the 0x7ff factor, the compiler
2441 * may round up and produce a double for the bounds check
2442 * that is larger than can be stored in a 64-bit integer. The
2443 * amount of 0x7ff is picked because it has 11 bits set.
2444 *
2445 * Without the 0x7ff there is a ~30 minute range of time
2446 * values 10 billion years in the past and in the future
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002447 * where this code could go wrong. Some compilers
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002448 * generate a warning or error without the 0x7ff.
2449 */
2450 const double dDateMax = (double)(INT64_MAX - 0x7ff);
2451 const double dDateMin = (double)(INT64_MIN + 0x7ff);
2452
2453 if(isnan(d) || d > dDateMax || d < dDateMin) {
Laurence Lundbladec7114722020-08-13 05:11:40 -07002454 uReturn = QCBOR_ERR_DATE_OVERFLOW;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002455 goto Done;
2456 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002457
2458 /* The actual conversion */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002459 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
Laurence Lundblade2feb1e12020-07-15 03:50:45 -07002460 pDecodedItem->val.epochDate.fSecondsFraction =
2461 d - (double)pDecodedItem->val.epochDate.nSeconds;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002462 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002463#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade4b270642020-08-14 12:53:07 -07002464
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002465 uReturn = QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundblade4b270642020-08-14 12:53:07 -07002466 goto Done;
2467
Laurence Lundblade9682a532020-06-06 18:33:04 -07002468#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002469 break;
2470
2471 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002472 /* It's the arrays and maps that are unrecoverable because
2473 * they are not consumed here. Since this is just an error
2474 * condition, no extra code is added here to make the error
2475 * recoverable for non-arrays and maps like strings. */
2476 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002477 goto Done;
2478 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002479
Laurence Lundblade59289e52019-12-30 13:44:37 -08002480 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
2481
2482Done:
Laurence Lundbladec7114722020-08-13 05:11:40 -07002483 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002484}
2485
2486
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002487/**
2488 * @brief Convert the days epoch date.
2489 *
2490 * pDecodedItem[in,out] The data item to convert.
2491 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002492 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2493 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2494 * floating-point date disabled.
2495 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2496 * all floating-point disabled.
2497 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2498 * error decoding date.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002499 *
2500 * This is much simpler than the other epoch date format because
2501 * floating-porint is not allowed. This is mostly a simple type check.
2502 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002503static QCBORError
2504QCBOR_Private_DecodeDaysEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002505{
2506 QCBORError uReturn = QCBOR_SUCCESS;
2507
2508 switch (pDecodedItem->uDataType) {
2509
2510 case QCBOR_TYPE_INT64:
2511 pDecodedItem->val.epochDays = pDecodedItem->val.int64;
2512 break;
2513
2514 case QCBOR_TYPE_UINT64:
2515 /* This only happens for CBOR type 0 > INT64_MAX so it is
2516 * always an overflow.
2517 */
2518 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2519 goto Done;
2520 break;
2521
2522 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002523 /* It's the arrays and maps that are unrecoverable because
2524 * they are not consumed here. Since this is just an error
2525 * condition, no extra code is added here to make the error
2526 * recoverable for non-arrays and maps like strings. */
2527 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002528 goto Done;
2529 break;
2530 }
2531
2532 pDecodedItem->uDataType = QCBOR_TYPE_DAYS_EPOCH;
2533
2534Done:
2535 return uReturn;
2536}
2537
2538
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002539#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade37286c02022-09-03 10:05:02 -07002540
2541/* Forward declaration is necessary for
2542 * QCBORDecode_MantissaAndExponent(). to be able to decode bignum
2543 * tags in the mantissa. If the mantissa is a decimal fraction or big
2544 * float in error, this will result in a recurive call to
2545 * QCBORDecode_MantissaAndExponent(), but the recursion will unwined
2546 * correctly and the correct error is returned.
2547 */
2548static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002549QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2550 QCBORItem *pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002551
2552
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002553/**
2554 * @brief Decode decimal fractions and big floats.
2555 *
2556 * @param[in] pMe The decode context.
2557 * @param[in,out] pDecodedItem On input the array data item that
2558 * holds the mantissa and exponent. On
2559 * output the decoded mantissa and
2560 * exponent.
2561 *
2562 * @returns Decoding errors from getting primitive data items or
2563 * \ref QCBOR_ERR_BAD_EXP_AND_MANTISSA.
2564 *
Laurence Lundblade37286c02022-09-03 10:05:02 -07002565 * When called pDecodedItem must be the array with two members, the
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002566 * exponent and mantissa.
2567 *
2568 * This will fetch and decode the exponent and mantissa and put the
2569 * result back into pDecodedItem.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002570 *
2571 * This does no checking or processing of tag numbers. That is to be
2572 * done by the code that calls this.
2573 *
2574 * This stuffs the type of the mantissa into pDecodedItem with the expectation
2575 * the caller will process it.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002576 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002577static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002578QCBORDecode_Private_ExpMantissa(QCBORDecodeContext *pMe,
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002579 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002580{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002581 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002582
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002583 /* --- Make sure it is an array; track nesting level of members --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002584 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002585 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002586 goto Done;
2587 }
2588
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002589 /* A check for pDecodedItem->val.uCount == 2 would work for
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002590 * definite-length arrays, but not for indefinite. Instead remember
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002591 * the nesting level the two integers must be at, which is one
2592 * deeper than that of the array.
2593 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002594 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
2595
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002596 /* --- Get the exponent --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002597 QCBORItem exponentItem;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002598 uReturn = QCBORDecode_GetNext(pMe, &exponentItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002599 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002600 goto Done;
2601 }
2602 if(exponentItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002603 /* Array is empty or a map/array encountered when expecting an int */
2604 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002605 goto Done;
2606 }
2607 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002608 /* Data arriving as an unsigned int < INT64_MAX has been
2609 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2610 * also means that the only data arriving here of type
2611 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2612 * and thus an error that will get handled in the next else.
2613 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002614 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
2615 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002616 /* Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX */
2617 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002618 goto Done;
2619 }
2620
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002621 /* --- Get the mantissa --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002622 QCBORItem mantissaItem;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002623 uReturn = QCBORDecode_GetNext(pMe, &mantissaItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002624 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002625 goto Done;
2626 }
2627 if(mantissaItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002628 /* Mantissa missing or map/array encountered when expecting number */
2629 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002630 goto Done;
2631 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002632 /* Stuff the mantissa data type into the item to send it up to the
2633 * the next level. */
2634 pDecodedItem->uDataType = mantissaItem.uDataType;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002635 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002636 /* Data arriving as an unsigned int < INT64_MAX has been
2637 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2638 * also means that the only data arriving here of type
2639 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2640 * and thus an error that will get handled in an else below.
2641 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002642 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002643#ifndef QCBOR_DISABLE_TAGS
2644 /* With tags fully disabled a big number mantissa will error out
2645 * in the call to QCBORDecode_GetNextWithTags() because it has
2646 * a tag number.
2647 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07002648 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM ||
2649 mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002650 /* Got a good big num mantissa */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002651 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002652#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002653 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002654 /* Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX */
2655 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002656 goto Done;
2657 }
2658
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002659 /* --- Check that array only has the two numbers --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002660 if(mantissaItem.uNextNestLevel == nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002661 /* Extra items in the decimal fraction / big float */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002662 /* Improvement: this should probably be an unrecoverable error. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002663 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002664 goto Done;
2665 }
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002666 pDecodedItem->uNextNestLevel = mantissaItem.uNextNestLevel;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002667
2668Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002669 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002670}
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002671#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002672
2673
Laurence Lundblade37286c02022-09-03 10:05:02 -07002674#ifndef QCBOR_DISABLE_TAGS
2675
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002676#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002677/**
2678 * @brief Decode the MIME type tag
2679 *
2680 * @param[in,out] pDecodedItem The item to decode.
2681 *
2682 * Handle the text and binary MIME type tags. Slightly too complicated
2683 * f or ProcessTaggedString() because the RFC 7049 MIME type was
2684 * incorreclty text-only.
2685 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002686static QCBORError
2687QCBOR_Private_DecodeMIME(QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002688{
2689 if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) {
2690 pDecodedItem->uDataType = QCBOR_TYPE_MIME;
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07002691 } else if(pDecodedItem->uDataType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002692 pDecodedItem->uDataType = QCBOR_TYPE_BINARY_MIME;
2693 } else {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002694 /* It's the arrays and maps that are unrecoverable because
2695 * they are not consumed here. Since this is just an error
2696 * condition, no extra code is added here to make the error
2697 * recoverable for non-arrays and maps like strings. */
2698 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002699 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002700
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002701 return QCBOR_SUCCESS;
2702}
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002703#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002704
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002705/**
Laurence Lundblade99615302020-11-29 11:19:47 -08002706 * Table of CBOR tags whose content is either a text string or a byte
2707 * string. The table maps the CBOR tag to the QCBOR type. The high-bit
2708 * of uQCBORtype indicates the content should be a byte string rather
2709 * than a text string
2710 */
2711struct StringTagMapEntry {
2712 uint16_t uTagNumber;
2713 uint8_t uQCBORtype;
2714};
2715
2716#define IS_BYTE_STRING_BIT 0x80
2717#define QCBOR_TYPE_MASK ~IS_BYTE_STRING_BIT
2718
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002719static const struct StringTagMapEntry QCBOR_Private_StringTagMap[] = {
Laurence Lundblade99615302020-11-29 11:19:47 -08002720 {CBOR_TAG_DATE_STRING, QCBOR_TYPE_DATE_STRING},
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002721 {CBOR_TAG_DAYS_STRING, QCBOR_TYPE_DAYS_STRING},
Laurence Lundblade99615302020-11-29 11:19:47 -08002722 {CBOR_TAG_POS_BIGNUM, QCBOR_TYPE_POSBIGNUM | IS_BYTE_STRING_BIT},
2723 {CBOR_TAG_NEG_BIGNUM, QCBOR_TYPE_NEGBIGNUM | IS_BYTE_STRING_BIT},
2724 {CBOR_TAG_CBOR, QBCOR_TYPE_WRAPPED_CBOR | IS_BYTE_STRING_BIT},
2725 {CBOR_TAG_URI, QCBOR_TYPE_URI},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002726#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002727 {CBOR_TAG_B64URL, QCBOR_TYPE_BASE64URL},
2728 {CBOR_TAG_B64, QCBOR_TYPE_BASE64},
2729 {CBOR_TAG_REGEX, QCBOR_TYPE_REGEX},
2730 {CBOR_TAG_BIN_UUID, QCBOR_TYPE_UUID | IS_BYTE_STRING_BIT},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002731#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade99615302020-11-29 11:19:47 -08002732 {CBOR_TAG_CBOR_SEQUENCE, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE | IS_BYTE_STRING_BIT},
2733 {CBOR_TAG_INVALID16, QCBOR_TYPE_NONE}
2734};
2735
2736
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002737/**
2738 * @brief Process standard CBOR tags whose content is a string
2739 *
2740 * @param[in] uTag The tag.
2741 * @param[in,out] pDecodedItem The data item.
2742 *
2743 * @returns This returns QCBOR_SUCCESS if the tag was procssed,
2744 * \ref QCBOR_ERR_UNSUPPORTED if the tag was not processed and
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002745 * \ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT if the content type was wrong for the tag.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002746 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002747 * Process the CBOR tags that whose content is a byte string or a text
2748 * string and for which the string is just passed on to the caller.
2749 *
2750 * This maps the CBOR tag to the QCBOR type and checks the content
2751 * type. Nothing more. It may not be the most important
Laurence Lundbladec02e13e2020-12-06 05:45:41 -08002752 * functionality, but it part of implementing as much of RFC 8949 as
Laurence Lundblade99615302020-11-29 11:19:47 -08002753 * possible.
Laurence Lundblade99615302020-11-29 11:19:47 -08002754 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002755static QCBORError
2756QCBOR_Private_ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002757{
Laurence Lundblade99615302020-11-29 11:19:47 -08002758 /* This only works on tags that were not mapped; no need for other yet */
2759 if(uTag > QCBOR_LAST_UNMAPPED_TAG) {
2760 return QCBOR_ERR_UNSUPPORTED;
2761 }
2762
2763 unsigned uIndex;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002764 for(uIndex = 0; QCBOR_Private_StringTagMap[uIndex].uTagNumber != CBOR_TAG_INVALID16; uIndex++) {
2765 if(QCBOR_Private_StringTagMap[uIndex].uTagNumber == uTag) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002766 break;
2767 }
2768 }
2769
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002770 const uint8_t uQCBORType = QCBOR_Private_StringTagMap[uIndex].uQCBORtype;
Laurence Lundblade99615302020-11-29 11:19:47 -08002771 if(uQCBORType == QCBOR_TYPE_NONE) {
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002772 /* repurpose this error to mean not handled here */
Laurence Lundblade99615302020-11-29 11:19:47 -08002773 return QCBOR_ERR_UNSUPPORTED;
2774 }
2775
2776 uint8_t uExpectedType = QCBOR_TYPE_TEXT_STRING;
2777 if(uQCBORType & IS_BYTE_STRING_BIT) {
2778 uExpectedType = QCBOR_TYPE_BYTE_STRING;
2779 }
2780
2781 if(pDecodedItem->uDataType != uExpectedType) {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002782 /* It's the arrays and maps that are unrecoverable because
2783 * they are not consumed here. Since this is just an error
2784 * condition, no extra code is added here to make the error
2785 * recoverable for non-arrays and maps like strings. */
2786 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002787 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002788
Laurence Lundblade99615302020-11-29 11:19:47 -08002789 pDecodedItem->uDataType = (uint8_t)(uQCBORType & QCBOR_TYPE_MASK);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002790 return QCBOR_SUCCESS;
2791}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002792#endif /* QCBOR_DISABLE_TAGS */
2793
2794
2795#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002796/**
2797 * @brief Figures out data type for exponent mantissa tags.
2798 *
2799 * @param[in] uTagToProcess Either @ref CBOR_TAG_DECIMAL_FRACTION or
2800 * @ref CBOR_TAG_BIG_FLOAT.
2801 * @param[in] pDecodedItem Item being decoded.
2802 *
2803 * @returns One of the 6 values between \ref QCBOR_TYPE_DECIMAL_FRACTION
2804 * and @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM.
2805 *
2806 * Does mapping between a CBOR tag number and a QCBOR type. with a
2807 * little bit of logic and arithmatic.
2808 *
2809 * Used in serveral contexts. Does the work where sometimes the data
2810 * item is explicitly tagged and sometimes not.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002811 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002812static uint8_t
2813QCBOR_Private_ExpMantissaDataType(const uint16_t uTagToProcess,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002814 const QCBORItem *pDecodedItem)
Laurence Lundblade37286c02022-09-03 10:05:02 -07002815{
2816 uint8_t uBase = uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ?
2817 QCBOR_TYPE_DECIMAL_FRACTION :
2818 QCBOR_TYPE_BIGFLOAT;
2819 if(pDecodedItem->uDataType != QCBOR_TYPE_INT64) {
2820 uBase = (uint8_t)(uBase + pDecodedItem->uDataType - QCBOR_TYPE_POSBIGNUM + 1);
2821 }
2822 return uBase;
2823}
2824#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002825
2826
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002827/**
2828 * @brief Decode tag content for select tags (decoding layer 1).
2829 *
2830 * @param[in] pMe The decode context.
2831 * @param[out] pDecodedItem The decoded item.
2832 *
2833 * @return Decoding error code.
2834 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002835 * CBOR tag numbers for the item were decoded in GetNext_TaggedItem(),
2836 * but the whole tag was not decoded. Here, the whole tags (tag number
2837 * and tag content) that are supported by QCBOR are decoded. This is a
2838 * quick pass through for items that are not tags.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002839 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002840static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002841QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2842 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002843{
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002844 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002845
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002846 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pDecodedItem, NULL);
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002847 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002848 goto Done;
2849 }
2850
Laurence Lundblade37286c02022-09-03 10:05:02 -07002851#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002852 /* When there are no tag numbers for the item, this exits first
2853 * thing and effectively does nothing.
2854 *
2855 * This loops over all the tag numbers accumulated for this item
2856 * trying to decode and interpret them. This stops at the end of
2857 * the list or at the first tag number that can't be interpreted by
2858 * this code. This is effectively a recursive processing of the
2859 * tags number list that handles nested tags.
2860 */
2861 while(1) {
2862 /* Don't bother to unmap tags via QCBORITem.uTags since this
2863 * code only works on tags less than QCBOR_LAST_UNMAPPED_TAG.
2864 */
2865 const uint16_t uTagToProcess = pDecodedItem->uTags[0];
Laurence Lundblade59289e52019-12-30 13:44:37 -08002866
Laurence Lundblade99615302020-11-29 11:19:47 -08002867 if(uTagToProcess == CBOR_TAG_INVALID16) {
2868 /* Hit the end of the tag list. A successful exit. */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002869 break;
2870
Laurence Lundblade99615302020-11-29 11:19:47 -08002871 } else if(uTagToProcess == CBOR_TAG_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002872 uReturn = QCBOR_Private_DecodeDateEpoch(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002873
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002874 } else if(uTagToProcess == CBOR_TAG_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002875 uReturn = QCBOR_Private_DecodeDaysEpoch(pDecodedItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002876
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002877#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade99615302020-11-29 11:19:47 -08002878 } else if(uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ||
2879 uTagToProcess == CBOR_TAG_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002880 uReturn = QCBORDecode_Private_ExpMantissa(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002881 /* --- Which is it, decimal fraction or a bigfloat? --- */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002882 pDecodedItem->uDataType = QCBOR_Private_ExpMantissaDataType(uTagToProcess, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002883
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002884#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002885#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002886 } else if(uTagToProcess == CBOR_TAG_MIME ||
2887 uTagToProcess == CBOR_TAG_BINARY_MIME) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002888 uReturn = QCBOR_Private_DecodeMIME(pDecodedItem);
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002889#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002890
Laurence Lundblade99615302020-11-29 11:19:47 -08002891 } else {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002892 /* See if it is a passthrough byte/text string tag; process if so */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002893 uReturn = QCBOR_Private_ProcessTaggedString(pDecodedItem->uTags[0], pDecodedItem);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002894
Laurence Lundblade99615302020-11-29 11:19:47 -08002895 if(uReturn == QCBOR_ERR_UNSUPPORTED) {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002896 /* It wasn't a passthrough byte/text string tag so it is
Laurence Lundblade99615302020-11-29 11:19:47 -08002897 * an unknown tag. This is the exit from the loop on the
2898 * first unknown tag. It is a successful exit.
2899 */
2900 uReturn = QCBOR_SUCCESS;
2901 break;
2902 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002903 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002904
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002905 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002906 /* Error exit from the loop */
2907 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002908 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002909
2910 /* A tag was successfully processed, shift it out of the list of
2911 * tags returned. This is the loop increment.
2912 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002913 QCBOR_Private_ShiftTags(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002914 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002915#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002916
2917Done:
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002918 return uReturn;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002919}
2920
2921
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002922/**
2923 * @brief Consume an entire map or array including its contents.
2924 *
2925 * @param[in] pMe The decoder context.
2926 * @param[in] pItemToConsume The array/map whose contents are to be
2927 * consumed.
2928 * @param[out] puNextNestLevel The next nesting level after the item was
2929 * fully consumed.
2930 *
2931 * This may be called when @c pItemToConsume is not an array or
2932 * map. In that case, this is just a pass through for @c puNextNestLevel
2933 * since there is nothing to do.
2934 */
2935static QCBORError
2936QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
2937 const QCBORItem *pItemToConsume,
2938 bool *pbBreak,
2939 uint8_t *puNextNestLevel)
2940{
2941 QCBORError uReturn;
2942 QCBORItem Item;
2943
2944 /* If it is a map or array, this will tell if it is empty. */
2945 const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel);
2946
2947 if(QCBORItem_IsMapOrArray(*pItemToConsume) && !bIsEmpty) {
2948 /* There is only real work to do for non-empty maps and arrays */
2949
2950 /* This works for definite- and indefinite-length maps and
2951 * arrays by using the nesting level
2952 */
2953 do {
2954 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pbBreak, &Item, NULL);
2955 if(QCBORDecode_IsUnrecoverableError(uReturn) ||
2956 uReturn == QCBOR_ERR_NO_MORE_ITEMS) {
2957 goto Done;
2958 }
2959 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
2960
2961 *puNextNestLevel = Item.uNextNestLevel;
2962
2963 uReturn = QCBOR_SUCCESS;
2964
2965 } else {
2966 /* pItemToConsume is not a map or array. Just pass the nesting
2967 * level through. */
2968 *puNextNestLevel = pItemToConsume->uNextNestLevel;
2969
2970 uReturn = QCBOR_SUCCESS;
2971 }
2972
2973Done:
2974 return uReturn;
2975}
2976
2977
2978/*
2979 *
2980 * This consumes the next item. It returns the starting position of
2981 * the label and the length of the label. It also returns the nest
2982 * level of the item consumed.
2983 */
2984static QCBORError
2985QCBORDecode_Private_GetLabelAndConsume(QCBORDecodeContext *pMe,
2986 uint8_t *puNestLevel,
2987 size_t *puLabelStart,
2988 size_t *puLabelLen)
2989{
2990 QCBORError uErr;
2991 QCBORItem Item;
2992 uint8_t uLevel;
2993 uint32_t uLabelOffset;
2994
2995 /* Get the label and consume it should it be complex */
2996 *puLabelStart = UsefulInputBuf_Tell(&(pMe->InBuf));
2997
2998 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, &Item, &uLabelOffset);
2999 if(uErr != QCBOR_SUCCESS) {
3000 goto Done;
3001 }
3002 *puLabelLen = uLabelOffset - *puLabelStart;
3003 *puNestLevel = Item.uNestingLevel;
3004 uErr = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uLevel);
3005
3006Done:
3007 return uErr;
3008}
3009
3010
3011/* Loop over items in a map until the end of the map looking for
3012 * duplicates. This starts at the current position in the map, not at
3013 * the beginning of the map.
3014 *
3015 * This saves and restores the traversal cursor and nest tracking so
3016 * they are the same on exit as they were on entry.
3017 */
3018static QCBORError
3019QCBORDecode_Private_CheckDups(QCBORDecodeContext *pMe,
3020 const uint8_t uNestLevel,
3021 const size_t uCompareLabelStart,
3022 const size_t uCompareLabelLen)
3023{
3024 QCBORError uErr;
3025 size_t uLabelStart;
3026 size_t uLabelLen;
3027 uint8_t uLevel;
3028 int nCompare;
3029
3030 const QCBORDecodeNesting SaveNesting = pMe->nesting;
3031 const UsefulInputBuf Save = pMe->InBuf;
3032
3033 do {
3034 uErr = QCBORDecode_Private_GetLabelAndConsume(pMe, &uLevel, &uLabelStart, &uLabelLen);
3035 if(uErr != QCBOR_SUCCESS) {
3036 if(uErr == QCBOR_ERR_NO_MORE_ITEMS) {
3037 uErr = QCBOR_SUCCESS; /* Successful end */
3038 }
3039 break;
3040 }
3041
3042 if(uLevel != uNestLevel) {
3043 break; /* Successful end of loop */
3044 }
3045
3046 /* This check for dups works for labels that are preferred
3047 * serialization and are not maps. If the labels are not in
3048 * preferred serialization, then the check has to be more
3049 * complicated and is type-specific because it uses the decoded
3050 * value, not the encoded CBOR. It is further complicated for
3051 * maps because the order of items in a map that is a label
3052 * doesn't matter when checking that is is the duplicate of
3053 * another map that is a label. QCBOR so far only turns on this
3054 * dup checking as part of CDE checking which requires preferred
3055 * serialization. See 5.6 in RFC 8949.
3056 */
3057 nCompare = UsefulInputBuf_Compare(&(pMe->InBuf),
3058 uCompareLabelStart, uCompareLabelLen,
3059 uLabelStart, uLabelLen);
3060 if(nCompare == 0) {
3061 uErr = QCBOR_ERR_DUPLICATE_LABEL;
3062 break;
3063 }
3064 } while (1);
3065
3066 pMe->nesting = SaveNesting;
3067 pMe->InBuf = Save;
3068
3069 return uErr;
3070}
3071
3072
3073/* This does sort order and duplicate detection on a map. The and all
3074 * it's members must be in preferred serialization so the comparisons
3075 * work correctly.
3076 */
3077static QCBORError
3078QCBORDecode_Private_CheckMap(QCBORDecodeContext *pMe, const QCBORItem *pMapToCheck)
3079{
3080 QCBORError uErr;
3081 uint8_t uNestLevel;
3082 size_t offset2, offset1, length2, length1;
3083
3084 const QCBORDecodeNesting SaveNesting = pMe->nesting;
3085 const UsefulInputBuf Save = pMe->InBuf;
3086 pMe->bAllowAllLabels = 1;
3087
3088 /* This loop runs over all the items in the map once, comparing
3089 * each adjacent pair for correct ordering. It also calls CheckDup
3090 * on each one which also runs over the remaining items in the map
3091 * checking for duplicates. So duplicate checking runs in n^2.
3092 */
3093
3094 offset2 = SIZE_MAX;
3095 length2 = SIZE_MAX; // To avoid uninitialized warning
3096 while(1) {
3097 uErr = QCBORDecode_Private_GetLabelAndConsume(pMe, &uNestLevel, &offset1, &length1);
3098 if(uErr != QCBOR_SUCCESS) {
3099 if(uErr == QCBOR_ERR_NO_MORE_ITEMS) {
3100 uErr = QCBOR_SUCCESS; /* Successful exit from loop */
3101 }
3102 break;
3103 }
3104
3105 if(uNestLevel < pMapToCheck->uNextNestLevel) {
3106 break; /* Successful exit from loop */
3107 }
3108
3109 if(offset2 != SIZE_MAX) {
3110 /* Check that the labels are ordered. Check is not done the
3111 * first time through the loop when offset2 is unset. Since
3112 * this does comparison of the items in encoded form they
3113 * must be preferred serialization encoded. See RFC 8949
3114 * 4.2.1.
3115 */
3116 if(UsefulInputBuf_Compare(&(pMe->InBuf), offset2, length2, offset1, length1) > 0) {
3117 uErr = QCBOR_ERR_UNSORTED;
3118 break;
3119 }
3120 }
3121
3122 uErr = QCBORDecode_Private_CheckDups(pMe, pMapToCheck->uNextNestLevel, offset1, length1);
3123 if(uErr != QCBOR_SUCCESS) {
3124 break;
3125 }
3126
3127 offset2 = offset1;
3128 length2 = length1;
3129 }
3130
3131 pMe->bAllowAllLabels = 0;
3132 pMe->nesting = SaveNesting;
3133 pMe->InBuf = Save;
3134
3135 return uErr;
3136}
3137
3138
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08003139/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003140 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08003141 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003142QCBORError
3143QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
3144{
3145 QCBORError uErr;
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07003146 uErr = QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem);
3147#ifndef QCBOR_DISABLE_CONFORMANCE
3148 if(uErr == QCBOR_SUCCESS && pMe->uDecodeMode >= QCBOR_ENCODE_MODE_CDE && pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
3149 /* Traverse map checking sort order and for duplicates */
3150 uErr = QCBORDecode_Private_CheckMap(pMe, pDecodedItem);
3151 }
3152#endif /* ! QCBOR_DISABLE_CONFORMANCE */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003153 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08003154 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
3155 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
3156 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003157 return uErr;
Laurence Lundblade59289e52019-12-30 13:44:37 -08003158}
3159
3160
3161/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003162 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08003163 */
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08003164QCBORError
3165QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
3166{
3167 const QCBORDecodeNesting SaveNesting = pMe->nesting;
3168 const UsefulInputBuf Save = pMe->InBuf;
3169
3170 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
3171
3172 pMe->nesting = SaveNesting;
3173 pMe->InBuf = Save;
3174
3175 return uErr;
3176}
3177
3178
3179/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003180 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08003181 */
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003182void
3183QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
3184{
3185 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08003186 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
3187 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003188 return;
3189 }
3190
3191 pMe->uLastError = (uint8_t)QCBORDecode_PeekNext(pMe, pDecodedItem);
3192}
3193
3194
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003195static void
3196QCBORDecode_Private_CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem)
3197{
3198#ifndef QCBOR_DISABLE_TAGS
3199 memcpy(pMe->uLastTags, pItem->uTags, sizeof(pItem->uTags));
3200#else
3201 (void)pMe;
3202 (void)pItem;
3203#endif
3204}
3205
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003206/*
3207 * Public function, see header qcbor/qcbor_decode.h file
3208 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003209void
3210QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07003211{
3212 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08003213 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
3214 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07003215 return;
3216 }
3217
3218 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem);
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003219 QCBORDecode_Private_CopyTags(pMe, pDecodedItem);
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07003220}
3221
3222
3223/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003224 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07003225 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07003226QCBORError
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003227QCBORDecode_GetNextWithTags(QCBORDecodeContext *pMe,
3228 QCBORItem *pDecodedItem,
3229 QCBORTagListOut *pTags)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07003230{
Laurence Lundblade37286c02022-09-03 10:05:02 -07003231#ifndef QCBOR_DISABLE_TAGS
3232
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003233 QCBORError uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07003234
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003235 uReturn = QCBORDecode_GetNext(pMe, pDecodedItem);
3236 if(uReturn != QCBOR_SUCCESS) {
3237 return uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07003238 }
3239
3240 if(pTags != NULL) {
3241 pTags->uNumUsed = 0;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003242 /* Reverse the order because pTags is reverse of QCBORItem.uTags. */
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003243 for(int nTagIndex = QCBOR_MAX_TAGS_PER_ITEM-1; nTagIndex >=0; nTagIndex--) {
3244 if(pDecodedItem->uTags[nTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07003245 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07003246 }
3247 if(pTags->uNumUsed >= pTags->uNumAllocated) {
3248 return QCBOR_ERR_TOO_MANY_TAGS;
3249 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003250 pTags->puTags[pTags->uNumUsed] = QCBORDecode_Private_UnMapTagNumber(pMe,pDecodedItem->uTags[nTagIndex]);
Laurence Lundblade830fbf92020-05-31 17:22:33 -07003251 pTags->uNumUsed++;
3252 }
3253 }
3254
3255 return QCBOR_SUCCESS;
Laurence Lundblade37286c02022-09-03 10:05:02 -07003256
3257#else /* QCBOR_DISABLE_TAGS */
3258 (void)pMe;
3259 (void)pDecodedItem;
3260 (void)pTags;
3261 return QCBOR_ERR_TAGS_DISABLED;
3262#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07003263}
3264
3265
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07003266/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003267 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05303268 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003269bool
3270QCBORDecode_IsTagged(QCBORDecodeContext *pMe,
3271 const QCBORItem *pItem,
3272 uint64_t uTag)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07003273{
Laurence Lundblade37286c02022-09-03 10:05:02 -07003274#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003275 for(unsigned uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) {
3276 if(pItem->uTags[uTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07003277 break;
3278 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003279 if(QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uTagIndex]) == uTag) {
Laurence Lundbladef71e1622020-08-06 18:52:13 -07003280 return true;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07003281 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07003282 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07003283#else /* QCBOR_TAGS_DISABLED */
3284 (void)pMe;
3285 (void)pItem;
3286 (void)uTag;
3287#endif /* QCBOR_TAGS_DISABLED */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003288
Laurence Lundbladef71e1622020-08-06 18:52:13 -07003289 return false;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07003290}
3291
3292
3293/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003294 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07003295 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003296QCBORError
3297QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07003298{
Laurence Lundblade87495732021-02-26 10:05:55 -07003299 if(puConsumed != NULL) {
3300 *puConsumed = pMe->InBuf.cursor;
3301 }
3302
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003303 QCBORError uReturn = pMe->uLastError;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003304
3305 if(uReturn != QCBOR_SUCCESS) {
3306 goto Done;
3307 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003308
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003309 /* Error out if all the maps/arrays are not closed out */
3310 if(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003311 uReturn = QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08003312 goto Done;
3313 }
3314
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003315 /* Error out if not all the bytes are consumed */
3316 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf))) {
Laurence Lundblade085d7952020-07-24 10:26:30 -07003317 uReturn = QCBOR_ERR_EXTRA_BYTES;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08003318 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003319
Laurence Lundblade20b533d2018-10-08 20:44:53 +08003320Done:
Laurence Lundblade87495732021-02-26 10:05:55 -07003321 return uReturn;
3322}
3323
3324
3325/*
3326 * Public function, see header qcbor/qcbor_decode.h file
3327 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003328QCBORError
3329QCBORDecode_Finish(QCBORDecodeContext *pMe)
Laurence Lundblade87495732021-02-26 10:05:55 -07003330{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003331#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003332 /* Call the destructor for the string allocator if there is one.
3333 * Always called, even if there are errors; always have to clean up.
3334 */
3335 StringAllocator_Destruct(&(pMe->StringAllocator));
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003336#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003337
Laurence Lundblade87495732021-02-26 10:05:55 -07003338 return QCBORDecode_PartialFinish(pMe, NULL);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07003339}
3340
3341
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07003342/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003343 * Public function, see header qcbor/qcbor_decode.h file
3344 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003345uint64_t
3346QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
3347 const QCBORItem *pItem,
3348 uint32_t uIndex)
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07003349{
Laurence Lundblade37286c02022-09-03 10:05:02 -07003350#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade88e9db22020-11-02 03:56:33 -08003351 if(pItem->uDataType == QCBOR_TYPE_NONE) {
3352 return CBOR_TAG_INVALID64;
3353 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003354 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
3355 return CBOR_TAG_INVALID64;
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07003356 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003357 return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uIndex]);
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07003358 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07003359#else /* QCBOR_DISABLE_TAGS */
3360 (void)pMe;
3361 (void)pItem;
3362 (void)uIndex;
3363
3364 return CBOR_TAG_INVALID64;
3365#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07003366}
3367
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003368
Laurence Lundblade9b334962020-08-27 10:55:53 -07003369/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003370 * Public function, see header qcbor/qcbor_decode.h file
3371 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003372uint64_t
3373QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe,
3374 uint32_t uIndex)
Laurence Lundblade9b334962020-08-27 10:55:53 -07003375{
Laurence Lundblade37286c02022-09-03 10:05:02 -07003376#ifndef QCBOR_DISABLE_TAGS
3377
Laurence Lundblade88e9db22020-11-02 03:56:33 -08003378 if(pMe->uLastError != QCBOR_SUCCESS) {
3379 return CBOR_TAG_INVALID64;
3380 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003381 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
3382 return CBOR_TAG_INVALID64;
3383 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003384 return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->uLastTags[uIndex]);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003385 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07003386#else /* QCBOR_DISABLE_TAGS */
3387 (void)pMe;
3388 (void)uIndex;
3389
3390 return CBOR_TAG_INVALID64;
3391#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003392}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07003393
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07003394
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003395
3396
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003397#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladef6531662018-12-04 10:42:22 +09003398
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003399/* ===========================================================================
3400 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003401
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003402 This implements a simple sting allocator for indefinite-length
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003403 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
3404 implements the function type QCBORStringAllocate and allows easy
3405 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09003406
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003407 This particular allocator is built-in for convenience. The caller
3408 can implement their own. All of this following code will get
3409 dead-stripped if QCBORDecode_SetMemPool() is not called.
3410
3411 This is a very primitive memory allocator. It does not track
3412 individual allocations, only a high-water mark. A free or
3413 reallocation must be of the last chunk allocated.
3414
3415 The size of the pool and offset to free memory are packed into the
3416 first 8 bytes of the memory pool so we don't have to keep them in
3417 the decode context. Since the address of the pool may not be
3418 aligned, they have to be packed and unpacked as if they were
3419 serialized data of the wire or such.
3420
3421 The sizes packed in are uint32_t to be the same on all CPU types
3422 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08003423 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003424
3425
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003426static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08003427MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003428{
3429 // Use of UsefulInputBuf is overkill, but it is convenient.
3430 UsefulInputBuf UIB;
3431
Laurence Lundbladeee851742020-01-08 08:37:05 -08003432 // Just assume the size here. It was checked during SetUp so
3433 // the assumption is safe.
Laurence Lundblade93d89472020-10-03 22:30:50 -07003434 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem,QCBOR_DECODE_MIN_MEM_POOL_SIZE});
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003435 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
3436 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
3437 return UsefulInputBuf_GetError(&UIB);
3438}
3439
3440
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003441static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08003442MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003443{
3444 // Use of UsefulOutBuf is overkill, but convenient. The
3445 // length check performed here is useful.
3446 UsefulOutBuf UOB;
3447
3448 UsefulOutBuf_Init(&UOB, Pool);
3449 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
3450 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
3451 return UsefulOutBuf_GetError(&UOB);
3452}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003453
3454
3455/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003456 Internal function for an allocation, reallocation free and destuct.
3457
3458 Having only one function rather than one each per mode saves space in
3459 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003460
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003461 Code Reviewers: THIS FUNCTION DOES POINTER MATH
3462 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08003463static UsefulBuf
3464MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003465{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003466 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003467
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003468 uint32_t uPoolSize;
3469 uint32_t uFreeOffset;
3470
3471 if(uNewSize > UINT32_MAX) {
3472 // This allocator is only good up to 4GB. This check should
3473 // optimize out if sizeof(size_t) == sizeof(uint32_t)
3474 goto Done;
3475 }
3476 const uint32_t uNewSize32 = (uint32_t)uNewSize;
3477
3478 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
3479 goto Done;
3480 }
3481
3482 if(uNewSize) {
3483 if(pMem) {
3484 // REALLOCATION MODE
3485 // Calculate pointer to the end of the memory pool. It is
3486 // assumed that pPool + uPoolSize won't wrap around by
3487 // assuming the caller won't pass a pool buffer in that is
3488 // not in legitimate memory space.
3489 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
3490
3491 // Check that the pointer for reallocation is in the range of the
3492 // pool. This also makes sure that pointer math further down
3493 // doesn't wrap under or over.
3494 if(pMem >= pPool && pMem < pPoolEnd) {
3495 // Offset to start of chunk for reallocation. This won't
3496 // wrap under because of check that pMem >= pPool. Cast
3497 // is safe because the pool is always less than UINT32_MAX
3498 // because of check in QCBORDecode_SetMemPool().
3499 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3500
3501 // Check to see if the allocation will fit. uPoolSize -
3502 // uMemOffset will not wrap under because of check that
3503 // pMem is in the range of the uPoolSize by check above.
3504 if(uNewSize <= uPoolSize - uMemOffset) {
3505 ReturnValue.ptr = pMem;
3506 ReturnValue.len = uNewSize;
3507
3508 // Addition won't wrap around over because uNewSize was
3509 // checked to be sure it is less than the pool size.
3510 uFreeOffset = uMemOffset + uNewSize32;
3511 }
3512 }
3513 } else {
3514 // ALLOCATION MODE
3515 // uPoolSize - uFreeOffset will not underflow because this
3516 // pool implementation makes sure uFreeOffset is always
3517 // smaller than uPoolSize through this check here and
3518 // reallocation case.
3519 if(uNewSize <= uPoolSize - uFreeOffset) {
3520 ReturnValue.len = uNewSize;
3521 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08003522 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003523 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003524 }
3525 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003526 if(pMem) {
3527 // FREE MODE
3528 // Cast is safe because of limit on pool size in
3529 // QCBORDecode_SetMemPool()
3530 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3531 } else {
3532 // DESTRUCT MODE
3533 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003534 }
3535 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003536
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003537 UsefulBuf Pool = {pPool, uPoolSize};
3538 MemPool_Pack(Pool, uFreeOffset);
3539
3540Done:
3541 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003542}
3543
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003544
Laurence Lundbladef6531662018-12-04 10:42:22 +09003545/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003546 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09003547 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003548QCBORError
3549QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
3550 UsefulBuf Pool,
3551 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003552{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003553 // The pool size and free mem offset are packed into the beginning
Dave Thaler93c01182022-08-06 15:08:35 -04003554 // of the pool memory. This compile time check makes sure the
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003555 // constant in the header is correct. This check should optimize
3556 // down to nothing.
Dave Thaler93c01182022-08-06 15:08:35 -04003557#ifdef _MSC_VER
3558#pragma warning(push)
3559#pragma warning(disable:4127) // conditional expression is constant
3560#endif
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003561 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003562 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003563 }
Dave Thaler93c01182022-08-06 15:08:35 -04003564#ifdef _MSC_VER
3565#pragma warning(pop)
3566#endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003567
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003568 // The pool size and free offset packed in to the beginning of pool
3569 // memory are only 32-bits. This check will optimize out on 32-bit
3570 // machines.
3571 if(Pool.len > UINT32_MAX) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003572 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003573 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003574
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003575 // This checks that the pool buffer given is big enough.
3576 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003577 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003578 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003579
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003580 QCBORDecode_SetUpAllocator(pMe, MemPool_Function, Pool.ptr, bAllStrings);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003581
Laurence Lundblade30816f22018-11-10 13:40:22 +07003582 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003583}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003584#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003585
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003586
3587
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003588/*
3589 * Public function, see header qcbor/qcbor_decode.h file
3590 */
3591void
3592QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003593{
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003594 QCBORDecode_VGetNext(pMe, pDecodedItem);
3595
3596 if(pMe->uLastError == QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003597 pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL,
Máté Tóth-Pálc6d59682021-05-26 18:55:30 +02003598 &pDecodedItem->uNextNestLevel);
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003599 }
3600}
3601
3602
Laurence Lundblade11654912024-05-09 11:49:24 -07003603/*
3604 * Public function, see header qcbor/qcbor_decode.h file
3605 */
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003606QCBORError
3607QCBORDecode_EndCheck(QCBORDecodeContext *pMe)
Laurence Lundblade11654912024-05-09 11:49:24 -07003608{
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003609 size_t uCursorOffset;
3610 QCBORError uErr;
Laurence Lundblade11654912024-05-09 11:49:24 -07003611
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003612 uErr = QCBORDecode_GetError(pMe);
3613 if(uErr != QCBOR_SUCCESS) {
3614 return uErr;
Laurence Lundblade11654912024-05-09 11:49:24 -07003615 }
3616
3617 uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
3618
3619 if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003620 return QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade11654912024-05-09 11:49:24 -07003621 }
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003622
3623 return QCBOR_SUCCESS;
Laurence Lundblade11654912024-05-09 11:49:24 -07003624}
3625
3626
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003627/**
3628 * @brief Rewind cursor to start as if map or array were just entered.
3629 *
3630 * @param[in] pMe The decoding context
3631 *
3632 * This affects the nesting tracking and the UsefulInputBuf.
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003633 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003634static void
3635QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003636{
3637 /* Reset nesting tracking to the deepest bounded level */
3638 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3639
3640 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3641
3642 /* Reposition traversal cursor to the start of the map/array */
3643 UsefulInputBuf_Seek(&(pMe->InBuf),
3644 DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
3645}
3646
3647
3648/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003649 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003650 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003651void
3652QCBORDecode_Rewind(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003653{
3654 if(pMe->nesting.pCurrentBounded != NULL) {
3655 /* In a bounded map, array or bstr-wrapped CBOR */
3656
3657 if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
3658 /* In bstr-wrapped CBOR. */
3659
3660 /* Reposition traversal cursor to start of wrapping byte string */
3661 UsefulInputBuf_Seek(&(pMe->InBuf),
3662 pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
3663 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3664
3665 } else {
3666 /* In a map or array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003667 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003668 }
3669
3670 } else {
3671 /* Not in anything bounded */
3672
3673 /* Reposition traversal cursor to the start of input CBOR */
3674 UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
3675
3676 /* Reset nesting tracking to beginning of input. */
3677 DecodeNesting_Init(&(pMe->nesting));
3678 }
3679
3680 pMe->uLastError = QCBOR_SUCCESS;
3681}
3682
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003683
Laurence Lundblade9b334962020-08-27 10:55:53 -07003684
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003685
3686
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003687typedef struct {
3688 void *pCBContext;
3689 QCBORItemCallback pfCallback;
3690} MapSearchCallBack;
3691
3692typedef struct {
3693 size_t uStartOffset;
3694 uint16_t uItemCount;
3695} MapSearchInfo;
3696
3697
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003698/**
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003699 * @brief Search a map for a set of items.
3700 *
3701 * @param[in] pMe The decode context to search.
3702 * @param[in,out] pItemArray The items to search for and the items found.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003703 * @param[out] pInfo Several bits of meta-info returned by search.
3704 * @param[in] pCallBack Callback object or @c NULL.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003705 *
3706 * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map.
3707 *
3708 * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label)
3709 * were found for one of the labels being
3710 * search for. This duplicate detection is
3711 * only performed for items in pItemArray,
3712 * not every item in the map.
3713 *
3714 * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was
3715 * wrong for the matchd label.
3716 *
3717 * @retval Also errors returned by QCBORDecode_GetNext().
3718 *
3719 * On input, \c pItemArray contains a list of labels and data types of
3720 * items to be found.
3721 *
3722 * On output, the fully retrieved items are filled in with values and
3723 * such. The label was matched, so it never changes.
3724 *
3725 * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE.
3726 *
3727 * This also finds the ends of maps and arrays when they are exited.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003728 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003729static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003730QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
3731 QCBORItem *pItemArray,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003732 MapSearchInfo *pInfo,
3733 MapSearchCallBack *pCallBack)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003734{
Laurence Lundbladee6f15112020-07-23 18:44:16 -07003735 QCBORError uReturn;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003736 uint64_t uFoundItemBitMap = 0;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07003737
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003738 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003739 uReturn = pMe->uLastError;
3740 goto Done2;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003741 }
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003742
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003743 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) &&
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003744 pItemArray->uLabelType != QCBOR_TYPE_NONE) {
3745 /* QCBOR_TYPE_NONE as first item indicates just looking
3746 for the end of an array, so don't give error. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003747 uReturn = QCBOR_ERR_MAP_NOT_ENTERED;
3748 goto Done2;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003749 }
3750
Laurence Lundblade085d7952020-07-24 10:26:30 -07003751 if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) {
3752 // It is an empty bounded array or map
3753 if(pItemArray->uLabelType == QCBOR_TYPE_NONE) {
3754 // Just trying to find the end of the map or array
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003755 pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003756 uReturn = QCBOR_SUCCESS;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003757 } else {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003758 // Nothing is ever found in an empty array or map. All items
3759 // are marked as not found below.
Laurence Lundblade085d7952020-07-24 10:26:30 -07003760 uReturn = QCBOR_SUCCESS;
3761 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003762 goto Done2;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003763 }
3764
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003765 QCBORDecodeNesting SaveNesting;
Laurence Lundblade11654912024-05-09 11:49:24 -07003766 size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003767 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3768
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003769 /* Reposition to search from the start of the map / array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003770 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundblade1341c592020-04-11 14:19:05 -07003771
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003772 /*
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003773 Loop over all the items in the map or array. Each item
3774 could be a map or array, but label matching is only at
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003775 the main level. This handles definite- and indefinite-
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003776 length maps and arrays. The only reason this is ever
3777 called on arrays is to find their end position.
3778
3779 This will always run over all items in order to do
3780 duplicate detection.
3781
3782 This will exit with failure if it encounters an
3783 unrecoverable error, but continue on for recoverable
3784 errors.
3785
3786 If a recoverable error occurs on a matched item, then
3787 that error code is returned.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003788 */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07003789 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003790 if(pInfo) {
3791 pInfo->uItemCount = 0;
3792 }
Máté Tóth-Pál2f2aa5f2021-05-17 21:35:09 +02003793 uint8_t uNextNestLevel;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003794 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003795 /* Remember offset of the item because sometimes it has to be returned */
Laurence Lundblade1341c592020-04-11 14:19:05 -07003796 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003797
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003798 /* Get the item */
3799 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003800 /* QCBORDecode_Private_GetNextTagContent() rather than GetNext()
3801 * because a label match is performed on recoverable errors to
3802 * be able to return the the error code for the found item. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003803 QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003804 if(QCBORDecode_IsUnrecoverableError(uResult)) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003805 /* The map/array can't be decoded when unrecoverable errors occur */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003806 uReturn = uResult;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003807 goto Done;
3808 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003809 if(uResult == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003810 /* Unexpected end of map or array. */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003811 uReturn = uResult;
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003812 goto Done;
3813 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003814
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003815 /* See if item has one of the labels that are of interest */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003816 bool bMatched = false;
3817 for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003818 if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003819 /* A label match has been found */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003820 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
3821 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003822 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003823 }
Laurence Lundblade63926052021-03-29 16:05:51 -07003824 if(uResult != QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003825 /* The label matches, but the data item is in error.
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003826 * It is OK to have recoverable errors on items that
3827 * are not matched. */
Laurence Lundblade63926052021-03-29 16:05:51 -07003828 uReturn = uResult;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003829 goto Done;
3830 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003831 if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) {
Laurence Lundblade63926052021-03-29 16:05:51 -07003832 /* The data item is not of the type(s) requested */
3833 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003834 goto Done;
3835 }
3836
Laurence Lundblade1341c592020-04-11 14:19:05 -07003837 /* Successful match. Return the item. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003838 pItemArray[nIndex] = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003839 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003840 if(pInfo) {
3841 pInfo->uStartOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003842 }
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003843 bMatched = true;
3844 }
3845 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003846
3847
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003848 if(!bMatched && pCallBack != NULL) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003849 /*
3850 Call the callback on unmatched labels.
3851 (It is tempting to do duplicate detection here, but that would
3852 require dynamic memory allocation because the number of labels
3853 that might be encountered is unbounded.)
3854 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003855 uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item);
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003856 if(uReturn != QCBOR_SUCCESS) {
3857 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003858 }
3859 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003860
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003861 /*
3862 Consume the item whether matched or not. This
3863 does the work of traversing maps and array and
3864 everything in them. In this loop only the
3865 items at the current nesting level are examined
3866 to match the labels.
3867 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003868 uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel);
Laurence Lundbladec7114722020-08-13 05:11:40 -07003869 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003870 goto Done;
3871 }
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003872
3873 if(pInfo) {
3874 pInfo->uItemCount++;
3875 }
3876
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003877 } while (uNextNestLevel >= uMapNestLevel);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003878
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003879 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003880
3881 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003882
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003883 // Check here makes sure that this won't accidentally be
3884 // QCBOR_MAP_OFFSET_CACHE_INVALID which is larger than
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003885 // QCBOR_MAX_DECODE_INPUT_SIZE.
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -08003886 // Cast to uint32_t to possibly address cases where SIZE_MAX < UINT32_MAX
3887 if((uint32_t)uEndOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003888 uReturn = QCBOR_ERR_INPUT_TOO_LARGE;
3889 goto Done;
3890 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003891 /* Cast OK because encoded CBOR is limited to UINT32_MAX */
3892 pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003893
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003894 Done:
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003895 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade11654912024-05-09 11:49:24 -07003896 UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos);
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003897
3898 Done2:
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003899 /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */
Laurence Lundbladec7114722020-08-13 05:11:40 -07003900 for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003901 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003902 pItemArray[i].uDataType = QCBOR_TYPE_NONE;
3903 pItemArray[i].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003904 }
3905 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003906
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003907 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003908}
3909
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003910
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003911/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003912 * Public function, see header qcbor/qcbor_decode.h file
3913 */
3914void
3915QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
3916 int64_t nLabel,
3917 uint8_t uQcborType,
3918 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003919{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003920 if(pMe->uLastError != QCBOR_SUCCESS) {
3921 return;
3922 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003923
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003924 QCBORItem OneItemSeach[2];
3925 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3926 OneItemSeach[0].label.int64 = nLabel;
3927 OneItemSeach[0].uDataType = uQcborType;
3928 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003929
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003930 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003931
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003932 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003933 pItem->uDataType = QCBOR_TYPE_NONE;
3934 pItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003935 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003936 }
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003937
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003938 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003939 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003940 }
3941
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003942 *pItem = OneItemSeach[0];
3943 QCBORDecode_Private_CopyTags(pMe, pItem);
3944
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003945 Done:
3946 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003947}
3948
3949
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003950/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003951 * Public function, see header qcbor/qcbor_decode.h file
3952 */
3953void
3954QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
3955 const char *szLabel,
3956 uint8_t uQcborType,
3957 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003958{
Laurence Lundbladeda095972020-06-06 18:35:33 -07003959 if(pMe->uLastError != QCBOR_SUCCESS) {
3960 return;
3961 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003962
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003963#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003964 QCBORItem OneItemSeach[2];
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003965 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3966 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3967 OneItemSeach[0].uDataType = uQcborType;
3968 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003969
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003970 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
3971
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003972 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003973 pItem->uDataType = QCBOR_TYPE_NONE;
3974 pItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003975 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003976 }
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003977 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003978 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003979 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003980 }
3981
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003982 *pItem = OneItemSeach[0];
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003983 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003984
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003985Done:
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003986#else
3987 (void)pMe;
3988 (void)szLabel;
3989 (void)uQcborType;
3990 (void)pItem;
3991 QCBORError uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
3992#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
3993
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003994 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003995}
3996
3997
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003998
3999/**
4000 * @brief Semi-private. Get pointer, length and item for an array or map.
4001 *
4002 * @param[in] pMe The decode context.
4003 * @param[in] uType CBOR major type, either array/map.
4004 * @param[out] pItem The item for the array/map.
4005 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
4006 *
4007 * The next item to be decoded must be a map or array as specified by \c uType.
4008 *
4009 * \c pItem will be filled in with the label and tags of the array or map
4010 * in addition to \c pEncodedCBOR giving the pointer and length of the
4011 * encoded CBOR.
4012 *
4013 * When this is complete, the traversal cursor is at the end of the array or
4014 * map that was retrieved.
4015 */
4016void
4017QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe,
4018 const uint8_t uType,
4019 QCBORItem *pItem,
4020 UsefulBufC *pEncodedCBOR)
4021{
4022 QCBORError uErr;
4023 uint8_t uNestLevel;
4024 size_t uStartingCursor;
4025 size_t uStartOfReturned;
4026 size_t uEndOfReturned;
4027 size_t uTempSaveCursor;
4028 bool bInMap;
4029 QCBORItem LabelItem;
4030 bool EndedByBreak;
4031
4032 uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
4033 bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting));
4034
4035 /* Could call GetNext here, but don't need to because this
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07004036 * is only interested in arrays and maps. TODO: switch to GetNext()? */
4037 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem, NULL);
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004038 if(uErr != QCBOR_SUCCESS) {
4039 pMe->uLastError = (uint8_t)uErr;
4040 return;
4041 }
4042
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004043 uint8_t uItemDataType = pItem->uDataType;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004044#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004045 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
4046 uItemDataType = QCBOR_TYPE_ARRAY;
4047 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004048#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004049
4050 if(uItemDataType != uType) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004051 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4052 return;
4053 }
4054
4055 if(bInMap) {
4056 /* If the item is in a map, the start of the array/map
4057 * itself, not the label, must be found. Do this by
4058 * rewinding to the starting position and fetching
4059 * just the label data item. QCBORDecode_Private_GetNextTagNumber()
4060 * doesn't do any of the array/map item counting or nesting
4061 * level tracking. Used here it will just fetech the label
4062 * data item.
4063 *
4064 * Have to save the cursor and put it back to the position
4065 * after the full item once the label as been fetched by
4066 * itself.
4067 */
4068 uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
4069 UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor);
4070
4071 /* Item has been fetched once so safe to ignore error */
4072 (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem);
4073
4074 uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
4075 UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor);
4076 } else {
4077 uStartOfReturned = uStartingCursor;
4078 }
4079
4080 /* Consume the entire array/map to find the end */
4081 uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel);
4082 if(uErr != QCBOR_SUCCESS) {
4083 pMe->uLastError = (uint8_t)uErr;
4084 goto Done;
4085 }
4086
4087 /* Fill in returned values */
4088 uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
4089 if(EndedByBreak) {
4090 /* When ascending nesting levels, a break for the level above
4091 * was consumed. That break is not a part of what is consumed here. */
4092 uEndOfReturned--;
4093 }
4094 pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned);
4095 pEncodedCBOR->len = uEndOfReturned - uStartOfReturned;
4096
4097Done:
4098 return;
4099}
4100
4101
4102/**
4103 * @brief Semi-private. Get pointer, length and item count of an array or map.
4104 *
4105 * @param[in] pMe The decode context.
4106 * @param[in] pTarget The label and type of the array or map to retrieve.
4107 * @param[out] pItem The item for the array/map.
4108 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
4109 *
4110 * The next item to be decoded must be a map or array as specified by \c uType.
4111 *
4112 * When this is complete, the traversal cursor is unchanged.
4113 */void
4114QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe,
4115 QCBORItem *pTarget,
4116 QCBORItem *pItem,
4117 UsefulBufC *pEncodedCBOR)
4118{
4119 MapSearchInfo Info;
4120 QCBORDecodeNesting SaveNesting;
4121 size_t uSaveCursor;
4122
4123 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL);
4124 if(pMe->uLastError != QCBOR_SUCCESS) {
4125 return;
4126 }
4127
4128 /* Save the whole position of things so they can be restored.
4129 * so the cursor position is unchanged by this operation, like
4130 * all the other GetXxxxInMap() operations. */
4131 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
4132 uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
4133
4134 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
4135 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
4136 QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR);
4137
4138 UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor);
4139 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
4140}
4141
4142
4143
4144
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004145/**
4146 * @brief Is a QCBOR_TYPE in the type list?
4147 *
4148 * @param[in] uDataType Type to check for.
4149 * @param[in] puTypeList List to check.
4150 *
4151 * @retval QCBOR_SUCCESS If in the list.
4152 * @retval QCBOR_ERR_UNEXPECTED_TYPE Not in the list.
4153 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07004154static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004155QCBOR_Private_CheckTypeList(const int uDataType,
4156 const uint8_t puTypeList[QCBOR_TAGSPEC_NUM_TYPES])
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004157{
4158 for(size_t i = 0; i < QCBOR_TAGSPEC_NUM_TYPES; i++) {
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08004159 if(uDataType == puTypeList[i]) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004160 return QCBOR_SUCCESS;
4161 }
4162 }
4163 return QCBOR_ERR_UNEXPECTED_TYPE;
4164}
4165
Laurence Lundblade67257dc2020-07-27 03:33:37 -07004166
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004167/**
Laurence Lundblade37286c02022-09-03 10:05:02 -07004168 * Match a tag/type specification against the type of the item.
4169 *
4170 * @param[in] TagSpec Specification for matching tags.
4171 * @param[in] pItem The item to check.
4172 *
4173 * @retval QCBOR_SUCCESS \c uDataType is allowed by @c TagSpec
4174 * @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec
4175 *
4176 * This checks the item data type of untagged items as well as of
4177 * tagged items against a specification to see if decoding should
4178 * proceed.
4179 *
4180 * This relies on the automatic tag decoding done by QCBOR that turns
4181 * tag numbers into particular QCBOR_TYPEs so there is no actual
4182 * comparsion of tag numbers, just of QCBOR_TYPEs.
4183 *
4184 * This checks the data item type as possibly representing the tag
4185 * number or as the tag content type.
4186 *
4187 * If QCBOR_DISABLE_TAGS is #defined, this primarily checks the item
4188 * data type against the allowed tag content types. It will also error out
4189 * if the caller tries to require a tag because there is no way that can
4190 * ever be fulfilled.
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004191 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07004192static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004193QCBOR_Private_CheckTagRequirement(const QCBOR_Private_TagSpec TagSpec,
4194 const QCBORItem *pItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07004195{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08004196 const int nItemType = pItem->uDataType; /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004197 const int nTagReq = TagSpec.uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
4198
4199#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08004200 /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade9b334962020-08-27 10:55:53 -07004201 if(!(TagSpec.uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS) &&
4202 pItem->uTags[0] != CBOR_TAG_INVALID16) {
4203 /* There are tags that QCBOR couldn't process on this item and
Laurence Lundblade37286c02022-09-03 10:05:02 -07004204 * the caller has told us there should not be.
4205 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07004206 return QCBOR_ERR_UNEXPECTED_TYPE;
4207 }
4208
Laurence Lundblade9b334962020-08-27 10:55:53 -07004209 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
Laurence Lundblade37286c02022-09-03 10:05:02 -07004210 /* Must match the tag number and only the tag */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004211 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07004212 }
4213
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004214 QCBORError uReturn = QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07004215 if(uReturn == QCBOR_SUCCESS) {
4216 return QCBOR_SUCCESS;
4217 }
4218
4219 if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
4220 /* Must match the content type and only the content type.
Laurence Lundblade37286c02022-09-03 10:05:02 -07004221 * There was no match just above so it is a fail. */
Laurence Lundblade9b334962020-08-27 10:55:53 -07004222 return QCBOR_ERR_UNEXPECTED_TYPE;
4223 }
4224
Laurence Lundblade37286c02022-09-03 10:05:02 -07004225 /* QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG: If here it can match either the tag or the content
4226 * and it hasn't matched the content, so the end
4227 * result is whether it matches the tag. This is
4228 * the tag optional case that the CBOR standard discourages.
4229 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07004230
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004231 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07004232
Laurence Lundblade37286c02022-09-03 10:05:02 -07004233#else /* QCBOR_DISABLE_TAGS */
4234 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
4235 return QCBOR_ERR_UNEXPECTED_TYPE;
4236 }
4237
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07004238 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade37286c02022-09-03 10:05:02 -07004239
4240#endif /* QCBOR_DISABLE_TAGS */
4241}
Laurence Lundblade9b334962020-08-27 10:55:53 -07004242
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004243
4244/**
4245 * @brief Get an item by label to match a tag specification.
4246 *
4247 * @param[in] pMe The decode context.
4248 * @param[in] nLabel The label to search map for.
4249 * @param[in] TagSpec The tag number specification to match.
4250 * @param[out] pItem The item found.
4251 *
4252 * This finds the item with the given label in currently open
4253 * map. Then checks that its tag number and types matches the tag
4254 * specification. If not, an error is set in the decode context.
4255 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004256static void
4257QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
4258 const int64_t nLabel,
4259 const QCBOR_Private_TagSpec TagSpec,
4260 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004261{
4262 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
4263 if(pMe->uLastError != QCBOR_SUCCESS) {
4264 return;
4265 }
4266
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004267 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004268}
4269
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07004270
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004271/**
4272 * @brief Get an item by label to match a tag specification.
4273 *
4274 * @param[in] pMe The decode context.
4275 * @param[in] szLabel The label to search map for.
4276 * @param[in] TagSpec The tag number specification to match.
4277 * @param[out] pItem The item found.
4278 *
4279 * This finds the item with the given label in currently open
4280 * map. Then checks that its tag number and types matches the tag
4281 * specification. If not, an error is set in the decode context.
4282 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004283static void
4284QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
4285 const char *szLabel,
4286 const QCBOR_Private_TagSpec TagSpec,
4287 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004288{
4289 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
4290 if(pMe->uLastError != QCBOR_SUCCESS) {
4291 return;
4292 }
4293
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004294 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004295}
4296
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004297
4298/**
4299 * @brief Semi-private to get an string by label to match a tag specification.
4300 *
4301 * @param[in] pMe The decode context.
4302 * @param[in] nLabel The label to search map for.
4303 * @param[in] TagSpec The tag number specification to match.
4304 * @param[out] pString The string found.
4305 *
4306 * This finds the string with the given label in currently open
4307 * map. Then checks that its tag number and types matches the tag
4308 * specification. If not, an error is set in the decode context.
4309 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004310void
4311QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
4312 const int64_t nLabel,
4313 const QCBOR_Private_TagSpec TagSpec,
4314 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004315{
4316 QCBORItem Item;
4317 QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
4318 if(pMe->uLastError == QCBOR_SUCCESS) {
4319 *pString = Item.val.string;
4320 }
4321}
4322
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004323
4324/**
4325 * @brief Semi-private to get an string by label to match a tag specification.
4326 *
4327 * @param[in] pMe The decode context.
4328 * @param[in] szLabel The label to search map for.
4329 * @param[in] TagSpec The tag number specification to match.
4330 * @param[out] pString The string found.
4331 *
4332 * This finds the string with the given label in currently open
4333 * map. Then checks that its tag number and types matches the tag
4334 * specification. If not, an error is set in the decode context.
4335 */void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004336QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
4337 const char * szLabel,
4338 const QCBOR_Private_TagSpec TagSpec,
4339 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004340{
4341 QCBORItem Item;
4342 QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
4343 if(pMe->uLastError == QCBOR_SUCCESS) {
4344 *pString = Item.val.string;
4345 }
4346}
Laurence Lundblade1341c592020-04-11 14:19:05 -07004347
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004348
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004349/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004350 * Public function, see header qcbor/qcbor_decode.h file
4351 */
4352void
4353QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004354{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004355 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL);
Laurence Lundblade5f53f832020-09-03 12:00:14 -07004356 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004357}
4358
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004359/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004360 * Public function, see header qcbor/qcbor_decode.h file
4361 */
4362void
4363QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe,
4364 QCBORItem *pItemList,
4365 void *pCallbackCtx,
4366 QCBORItemCallback pfCB)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004367{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004368 MapSearchCallBack CallBack;
4369 CallBack.pCBContext = pCallbackCtx;
4370 CallBack.pfCallback = pfCB;
4371
4372 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack);
4373
Laurence Lundblade5f53f832020-09-03 12:00:14 -07004374 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004375}
4376
4377
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004378/**
4379 * @brief Search for a map/array by label and enter it
4380 *
4381 * @param[in] pMe The decode context.
4382 * @param[in] pSearch The map/array to search for.
4383 *
4384 * @c pSearch is expected to contain one item of type map or array
4385 * with the label specified. The current bounded map will be searched for
4386 * this and if found will be entered.
4387 *
4388 * If the label is not found, or the item found is not a map or array,
4389 * the error state is set.
4390 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004391static void
4392QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07004393{
Laurence Lundblade323f8a92020-09-06 19:43:09 -07004394 // The first item in pSearch is the one that is to be
4395 // entered. It should be the only one filled in. Any other
4396 // will be ignored unless it causes an error.
Laurence Lundblade34691b92020-05-18 22:25:25 -07004397 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07004398 return;
4399 }
4400
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004401 MapSearchInfo Info;
4402 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pSearch, &Info, NULL);
Laurence Lundblade34691b92020-05-18 22:25:25 -07004403 if(pMe->uLastError != QCBOR_SUCCESS) {
4404 return;
4405 }
4406
Laurence Lundblade9b334962020-08-27 10:55:53 -07004407 if(pSearch->uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004408 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004409 return;
4410 }
4411
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004412
4413 /* The map or array was found. Now enter it.
4414 *
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004415 * QCBORDecode_EnterBoundedMapOrArray() used here, requires the
4416 * next item for the pre-order traversal cursor to be the map/array
4417 * found by MapSearch(). The next few lines of code force the
4418 * cursor to that.
4419 *
4420 * There is no need to retain the old cursor because
4421 * QCBORDecode_EnterBoundedMapOrArray() will set it to the
4422 * beginning of the map/array being entered.
4423 *
4424 * The cursor is forced by: 1) setting the input buffer position to
4425 * the item offset found by MapSearch(), 2) setting the map/array
4426 * counter to the total in the map/array, 3) setting the nesting
4427 * level. Setting the map/array counter to the total is not
4428 * strictly correct, but this is OK because this cursor only needs
4429 * to be used to get one item and MapSearch() has already found it
4430 * confirming it exists.
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004431 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004432 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004433
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004434 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
4435
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004436 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07004437
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004438 QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004439}
4440
4441
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004442/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004443 * Public function, see header qcbor/qcbor_decode.h file
4444 */
4445void
4446QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004447{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004448 QCBORItem OneItemSeach[2];
4449 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4450 OneItemSeach[0].label.int64 = nLabel;
4451 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4452 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004453
Laurence Lundblade9b334962020-08-27 10:55:53 -07004454 /* The map to enter was found, now finish off entering it. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004455 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004456}
4457
4458
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004459/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004460 * Public function, see header qcbor/qcbor_decode.h file
4461 */
4462void
4463QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004464{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004465#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004466 QCBORItem OneItemSeach[2];
4467 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4468 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4469 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4470 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004471
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004472 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004473#else
4474 (void)szLabel;
4475 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
4476#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004477}
4478
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004479/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004480 * Public function, see header qcbor/qcbor_decode.h file
4481 */
4482void
4483QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07004484{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004485 QCBORItem OneItemSeach[2];
4486 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4487 OneItemSeach[0].label.int64 = nLabel;
4488 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4489 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004490
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004491 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07004492}
4493
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004494/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004495 * Public function, see header qcbor/qcbor_decode.h file
4496 */
4497void
4498QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundblade34691b92020-05-18 22:25:25 -07004499{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004500#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004501 QCBORItem OneItemSeach[2];
4502 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4503 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4504 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4505 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004506
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004507 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004508#else
4509 (void)szLabel;
4510 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
4511#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade1341c592020-04-11 14:19:05 -07004512}
4513
4514
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004515/**
4516 * @brief Semi-private to do the the work for EnterMap() and EnterArray().
4517 *
4518 * @param[in] pMe The decode context
4519 * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY.
4520 * @param[out] pItem The data item for the map or array entered.
4521 *
4522 * The next item in the traversal must be a map or array. This
4523 * consumes that item and does the book keeping to enter the map or
4524 * array.
4525 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004526void
4527QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe,
4528 const uint8_t uType,
4529 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004530{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004531 QCBORError uErr;
4532
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004533 /* Must only be called on maps and arrays. */
Laurence Lundblade34691b92020-05-18 22:25:25 -07004534 if(pMe->uLastError != QCBOR_SUCCESS) {
4535 // Already in error state; do nothing.
4536 return;
4537 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07004538
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004539 /* Get the data item that is the map or array being entered. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004540 QCBORItem Item;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004541 uErr = QCBORDecode_GetNext(pMe, &Item);
4542 if(uErr != QCBOR_SUCCESS) {
4543 goto Done;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07004544 }
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004545
4546 uint8_t uItemDataType = Item.uDataType;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004547
4548#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004549 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) {
4550 uItemDataType = QCBOR_TYPE_ARRAY;
4551 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004552#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
4553
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004554 if(uItemDataType != uType) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004555 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
4556 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004557 }
4558
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004559 QCBORDecode_Private_CopyTags(pMe, &Item);
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004560
4561
Laurence Lundbladef0499502020-08-01 11:55:57 -07004562 const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
Laurence Lundblade085d7952020-07-24 10:26:30 -07004563 if(bIsEmpty) {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004564 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
4565 // Undo decrement done by QCBORDecode_GetNext() so the the
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004566 // the decrement when exiting the map/array works correctly
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004567 pMe->nesting.pCurrent->u.ma.uCountCursor++;
4568 }
Laurence Lundblade93d89472020-10-03 22:30:50 -07004569 // Special case to increment nesting level for zero-length maps
4570 // and arrays entered in bounded mode.
Laurence Lundbladee6f15112020-07-23 18:44:16 -07004571 DecodeNesting_Descend(&(pMe->nesting), uType);
4572 }
4573
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004574 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004575
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004576 uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty,
4577 UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004578
Laurence Lundblade6545d1b2020-10-14 11:13:13 -07004579 if(pItem != NULL) {
4580 *pItem = Item;
4581 }
4582
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004583Done:
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004584 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004585}
4586
Laurence Lundblade02625d42020-06-25 14:41:41 -07004587
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004588/**
4589 * @brief Exit a bounded map, array or bstr (semi-private).
4590 *
4591 * @param[in] pMe Decode context.
4592 * @param[in] uEndOffset The input buffer offset of the end of item exited.
4593 *
4594 * @returns QCBOR_SUCCESS or an error code.
4595 *
4596 * This is the common work for exiting a level that is a bounded map,
4597 * array or bstr wrapped CBOR.
4598 *
4599 * One chunk of work is to set up the pre-order traversal so it is at
4600 * the item just after the bounded map, array or bstr that is being
4601 * exited. This is somewhat complex.
4602 *
4603 * The other work is to level-up the bounded mode to next higest
4604 * bounded mode or the top level if there isn't one.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004605 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004606static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004607QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
4608 const uint32_t uEndOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004609{
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004610 QCBORError uErr;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004611
Laurence Lundblade02625d42020-06-25 14:41:41 -07004612 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004613 * First the pre-order-traversal byte offset is positioned to the
4614 * item just after the bounded mode item that was just consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004615 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004616 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
4617
Laurence Lundblade02625d42020-06-25 14:41:41 -07004618 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004619 * Next, set the current nesting level to one above the bounded
4620 * level that was just exited.
4621 *
4622 * DecodeNesting_CheckBoundedType() is always called before this
4623 * and makes sure pCurrentBounded is valid.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004624 */
4625 DecodeNesting_LevelUpCurrent(&(pMe->nesting));
4626
4627 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004628 * This does the complex work of leveling up the pre-order
4629 * traversal when the end of a map or array or another bounded
4630 * level is reached. It may do nothing, or ascend all the way to
4631 * the top level.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004632 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004633 uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004634 if(uErr != QCBOR_SUCCESS) {
4635 goto Done;
4636 }
4637
Laurence Lundblade02625d42020-06-25 14:41:41 -07004638 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004639 * This makes the next highest bounded level the current bounded
4640 * level. If there is no next highest level, then no bounded mode
4641 * is in effect.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004642 */
4643 DecodeNesting_LevelUpBounded(&(pMe->nesting));
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004644
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004645 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004646
4647Done:
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004648 return uErr;
4649}
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004650
Laurence Lundblade02625d42020-06-25 14:41:41 -07004651
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004652/**
4653 * @brief Get started exiting a map or array (semi-private)
4654 *
4655 * @param[in] pMe The decode context
4656 * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP
4657 *
4658 * This does some work for map and array exiting (but not
4659 * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel()
4660 * is called to do the rest.
4661 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004662void
4663QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe,
4664 const uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004665{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004666 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07004667 /* Already in error state; do nothing. */
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004668 return;
4669 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004670
Laurence Lundblade02625d42020-06-25 14:41:41 -07004671 QCBORError uErr;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004672
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004673 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004674 uErr = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004675 goto Done;
4676 }
4677
Laurence Lundblade02625d42020-06-25 14:41:41 -07004678 /*
4679 Have to set the offset to the end of the map/array
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004680 that is being exited. If there is no cached value,
Laurence Lundblade02625d42020-06-25 14:41:41 -07004681 from previous map search, then do a dummy search.
4682 */
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004683 if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004684 QCBORItem Dummy;
4685 Dummy.uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004686 uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL);
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004687 if(uErr != QCBOR_SUCCESS) {
4688 goto Done;
4689 }
4690 }
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004691
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004692 uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004693
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004694Done:
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004695 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004696}
4697
4698
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004699/**
4700 * @brief The main work of entering some byte-string wrapped CBOR.
4701 *
4702 * @param[in] pMe The decode context.
4703 * @param[in] pItem The byte string item.
4704 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX
4705 * @param[out] pBstr Pointer and length of byte string entered.
4706 *
4707 * This is called once the byte string item has been decoded to do all
4708 * the book keeping work for descending a nesting level into the
4709 * nested CBOR.
4710 *
4711 * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement.
4712 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004713static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004714QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe,
4715 const QCBORItem *pItem,
4716 const uint8_t uTagRequirement,
4717 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004718{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004719 if(pBstr) {
4720 *pBstr = NULLUsefulBufC;
4721 }
4722
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004723 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004724 /* Already in error state; do nothing. */
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004725 return pMe->uLastError;
4726 }
4727
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004728 QCBORError uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004729
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004730 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004731 {
4732 uTagRequirement,
4733 {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE},
4734 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4735 };
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004736
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004737 uError = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004738 if(uError != QCBOR_SUCCESS) {
4739 goto Done;
4740 }
4741
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004742 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004743 /* Reverse the decrement done by GetNext() for the bstr so the
4744 * increment in QCBORDecode_NestLevelAscender() called by
4745 * ExitBoundedLevel() will work right.
4746 */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004747 DecodeNesting_ReverseDecrement(&(pMe->nesting));
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07004748 }
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004749
4750 if(pBstr) {
4751 *pBstr = pItem->val.string;
4752 }
4753
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004754 /* This saves the current length of the UsefulInputBuf and then
4755 * narrows the UsefulInputBuf to start and length of the wrapped
4756 * CBOR that is being entered.
4757 *
4758 * Most of these calls are simple inline accessors so this doesn't
4759 * amount to much code.
4760 */
4761
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004762 const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004763 /* This check makes the cast of uPreviousLength to uint32_t below safe. */
4764 if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004765 uError = QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladef76a2622020-08-06 19:51:03 -07004766 goto Done;
4767 }
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004768
4769 const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
4770 pItem->val.string.ptr);
4771 /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
4772 if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
4773 /* This should never happen because pItem->val.string.ptr should
4774 * always be valid since it was just returned.
4775 */
4776 uError = QCBOR_ERR_INPUT_TOO_LARGE;
4777 goto Done;
4778 }
4779
4780 const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
4781
4782 UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004783 UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004784
Laurence Lundblade02625d42020-06-25 14:41:41 -07004785 uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004786 (uint32_t)uPreviousLength,
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004787 (uint32_t)uStartOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004788Done:
4789 return uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004790}
4791
4792
Laurence Lundblade02625d42020-06-25 14:41:41 -07004793/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004794 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004795 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004796void
4797QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe,
4798 const uint8_t uTagRequirement,
4799 UsefulBufC *pBstr)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004800{
4801 if(pMe->uLastError != QCBOR_SUCCESS) {
4802 // Already in error state; do nothing.
4803 return;
4804 }
4805
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004806 /* Get the data item that is the byte string being entered */
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004807 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004808 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4809 if(pMe->uLastError != QCBOR_SUCCESS) {
4810 return;
4811 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004812
Laurence Lundblade31fddb72024-05-13 13:03:35 -07004813 if(Item.uDataAlloc) {
4814 pMe->uLastError = QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
4815 return;
4816 }
4817
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004818 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4819 &Item,
4820 uTagRequirement,
4821 pBstr);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004822}
4823
4824
Laurence Lundblade02625d42020-06-25 14:41:41 -07004825/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004826 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004827 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004828void
4829QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe,
4830 const int64_t nLabel,
4831 const uint8_t uTagRequirement,
4832 UsefulBufC *pBstr)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004833{
4834 QCBORItem Item;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004835 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004836
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004837 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4838 &Item,
4839 uTagRequirement,
4840 pBstr);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004841}
4842
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004843
Laurence Lundblade02625d42020-06-25 14:41:41 -07004844/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004845 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004846 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004847void
4848QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe,
4849 const char *szLabel,
4850 const uint8_t uTagRequirement,
4851 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004852{
4853 QCBORItem Item;
4854 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4855
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004856 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4857 &Item,
4858 uTagRequirement,
4859 pBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004860}
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004861
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004862
Laurence Lundblade02625d42020-06-25 14:41:41 -07004863/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004864 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004865 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004866void
4867QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004868{
Laurence Lundblade02625d42020-06-25 14:41:41 -07004869 if(pMe->uLastError != QCBOR_SUCCESS) {
4870 // Already in error state; do nothing.
4871 return;
4872 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004873
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004874 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004875 pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade02625d42020-06-25 14:41:41 -07004876 return;
4877 }
4878
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004879 const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
4880
Laurence Lundblade02625d42020-06-25 14:41:41 -07004881 /*
4882 Reset the length of the UsefulInputBuf to what it was before
4883 the bstr wrapped CBOR was entered.
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004884 */
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004885 UsefulInputBuf_SetBufferLength(&(pMe->InBuf),
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004886 DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004887
4888
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004889 QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004890 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004891}
4892
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004893
Laurence Lundbladee6430642020-03-14 21:15:44 -07004894
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004895/**
4896 * @brief Process simple type true and false, a boolean
4897 *
4898 * @param[in] pMe The decode context.
4899 * @param[in] pItem The item with either true or false.
4900 * @param[out] pBool The boolean value output.
4901 *
4902 * Sets the internal error if the item isn't a true or a false. Also
4903 * records any tag numbers as the tag numbers of the last item.
4904 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004905static void
4906QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe,
4907 const QCBORItem *pItem,
4908 bool *pBool)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004909{
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004910 if(pMe->uLastError != QCBOR_SUCCESS) {
4911 /* Already in error state, do nothing */
4912 return;
4913 }
4914
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004915 switch(pItem->uDataType) {
4916 case QCBOR_TYPE_TRUE:
4917 *pBool = true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004918 break;
4919
4920 case QCBOR_TYPE_FALSE:
4921 *pBool = false;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004922 break;
4923
4924 default:
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004925 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004926 break;
4927 }
4928}
Laurence Lundbladee6430642020-03-14 21:15:44 -07004929
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004930
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004931/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004932 * Public function, see header qcbor/qcbor_decode.h file
4933 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004934void
4935QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004936{
Laurence Lundbladec4537442020-04-14 18:53:22 -07004937 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07004938 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004939 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004940}
4941
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004942
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004943/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004944 * Public function, see header qcbor/qcbor_decode.h file
4945 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004946void
4947QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe,
4948 const int64_t nLabel,
4949 bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004950{
4951 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004952 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004953 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004954}
4955
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004956
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004957/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004958 * Public function, see header qcbor/qcbor_decode.h file
4959 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004960void
4961QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe,
4962 const char *szLabel,
4963 bool *pValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004964{
4965 QCBORItem Item;
4966 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004967 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004968}
4969
4970
Laurence Lundblade3888f002024-06-12 21:20:56 -07004971/**
4972 * @brief Process simple values.
4973 *
4974 * @param[in] pMe The decode context.
4975 * @param[in] pItem The item with the simple value.
4976 * @param[out] puSimple The simple value output.
4977 *
4978 * Sets the internal error if the item isn't a true or a false. Also
4979 * records any tag numbers as the tag numbers of the last item.
4980 */
4981static void
4982QCBORDecode_Private_ProcessSimple(QCBORDecodeContext *pMe,
4983 const QCBORItem *pItem,
4984 uint8_t *puSimple)
4985{
4986 if(pMe->uLastError != QCBOR_SUCCESS) {
4987 return;
4988 }
4989
4990 /* It's kind of lame to remap true...undef back to simple values, but
4991 * this function isn't used much and to not do it would require
4992 * changing GetNext() behavior in an incompatible way.
4993 */
4994 switch(pItem->uDataType) {
4995 case QCBOR_TYPE_UKNOWN_SIMPLE:
4996 *puSimple = pItem->val.uSimple;
4997 break;
4998
4999 case QCBOR_TYPE_TRUE:
5000 *puSimple = CBOR_SIMPLEV_TRUE;
5001 break;
5002
5003 case QCBOR_TYPE_FALSE:
5004 *puSimple = CBOR_SIMPLEV_FALSE;
5005 break;
5006
5007 case QCBOR_TYPE_NULL:
5008 *puSimple = CBOR_SIMPLEV_NULL;
5009 break;
5010
5011 case QCBOR_TYPE_UNDEF:
5012 *puSimple = CBOR_SIMPLEV_UNDEF;
5013 break;
5014
5015 default:
5016 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
5017 return;
5018 }
Laurence Lundblade3888f002024-06-12 21:20:56 -07005019}
5020
5021/*
5022 * Public function, see header qcbor/qcbor_decode.h file
5023 */
5024void
5025QCBORDecode_GetSimple(QCBORDecodeContext *pMe, uint8_t *puSimple)
5026{
5027 QCBORItem Item;
Laurence Lundblade3888f002024-06-12 21:20:56 -07005028 QCBORDecode_VGetNext(pMe, &Item);
5029 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimple);
5030}
5031
5032/*
5033 * Public function, see header qcbor/qcbor_decode.h file
5034 */
5035void
5036QCBORDecode_GetSimpleInMapN(QCBORDecodeContext *pMe,
5037 int64_t nLabel,
5038 uint8_t *puSimpleValue)
5039{
5040 QCBORItem Item;
5041 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3888f002024-06-12 21:20:56 -07005042 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
5043}
5044
5045/*
5046 * Public function, see header qcbor/qcbor_decode.h file
5047 */
5048void
5049QCBORDecode_GetSimpleInMapSZ(QCBORDecodeContext *pMe,
5050 const char *szLabel,
5051 uint8_t *puSimpleValue)
5052{
5053 QCBORItem Item;
5054 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3888f002024-06-12 21:20:56 -07005055 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
5056}
5057
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005058
Laurence Lundbladec7114722020-08-13 05:11:40 -07005059
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005060/**
5061 * @brief Common processing for an epoch date.
5062 *
5063 * @param[in] pMe The decode context.
5064 * @param[in] pItem The item with the date.
5065 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
5066 * @param[out] pnTime The returned date.
5067 *
5068 * Common processing for the date tag. Mostly make sure the tag
5069 * content is correct and copy forward any further other tag numbers.
5070 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005071static void
5072QCBORDecode_Private_ProcessEpochDate(QCBORDecodeContext *pMe,
5073 QCBORItem *pItem,
5074 const uint8_t uTagRequirement,
5075 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07005076{
5077 if(pMe->uLastError != QCBOR_SUCCESS) {
5078 // Already in error state, do nothing
5079 return;
5080 }
5081
5082 QCBORError uErr;
5083
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005084 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladec7114722020-08-13 05:11:40 -07005085 {
5086 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07005087 {QCBOR_TYPE_DATE_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
5088 {QCBOR_TYPE_INT64, QCBOR_TYPE_DOUBLE, QCBOR_TYPE_FLOAT, QCBOR_TYPE_UINT64}
Laurence Lundbladec7114722020-08-13 05:11:40 -07005089 };
5090
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005091 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07005092 if(uErr != QCBOR_SUCCESS) {
5093 goto Done;
5094 }
5095
5096 if(pItem->uDataType != QCBOR_TYPE_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005097 uErr = QCBOR_Private_DecodeDateEpoch(pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07005098 if(uErr != QCBOR_SUCCESS) {
5099 goto Done;
5100 }
5101 }
5102
5103 *pnTime = pItem->val.epochDate.nSeconds;
5104
5105Done:
5106 pMe->uLastError = (uint8_t)uErr;
5107}
5108
5109
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005110
5111/*
5112 * Public function, see header qcbor/qcbor_spiffy_decode.h file
5113 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005114void
5115QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
5116 uint8_t uTagRequirement,
5117 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07005118{
Laurence Lundbladec7114722020-08-13 05:11:40 -07005119 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07005120 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005121 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07005122}
5123
5124
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005125/*
5126 * Public function, see header qcbor/qcbor_spiffy_decode.h file
5127 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07005128void
5129QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
5130 int64_t nLabel,
5131 uint8_t uTagRequirement,
5132 int64_t *pnTime)
5133{
5134 QCBORItem Item;
5135 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005136 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07005137}
5138
5139
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005140/*
5141 * Public function, see header qcbor/qcbor_spiffy_decode.h file
5142 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07005143void
5144QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
5145 const char *szLabel,
5146 uint8_t uTagRequirement,
5147 int64_t *pnTime)
5148{
5149 QCBORItem Item;
5150 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005151 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07005152}
5153
5154
5155
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005156/**
5157 * @brief Common processing for an epoch date.
5158 *
5159 * @param[in] pMe The decode context.
5160 * @param[in] pItem The item with the date.
5161 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
5162 * @param[out] pnDays The returned day count.
5163 *
5164 * Common processing for the RFC 8943 day-count tag. Mostly make sure
5165 * the tag content is correct and copy forward any further other tag
5166 * numbers.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005167 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005168static void
5169QCBORDecode_Private_ProcessEpochDays(QCBORDecodeContext *pMe,
5170 QCBORItem *pItem,
5171 uint8_t uTagRequirement,
5172 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005173{
5174 if(pMe->uLastError != QCBOR_SUCCESS) {
5175 /* Already in error state, do nothing */
5176 return;
5177 }
5178
5179 QCBORError uErr;
5180
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005181 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005182 {
5183 uTagRequirement,
5184 {QCBOR_TYPE_DAYS_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
5185 {QCBOR_TYPE_INT64, QCBOR_TYPE_UINT64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
5186 };
5187
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005188 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005189 if(uErr != QCBOR_SUCCESS) {
5190 goto Done;
5191 }
5192
5193 if(pItem->uDataType != QCBOR_TYPE_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005194 uErr = QCBOR_Private_DecodeDaysEpoch(pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005195 if(uErr != QCBOR_SUCCESS) {
5196 goto Done;
5197 }
5198 }
5199
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005200 *pnDays = pItem->val.epochDays;
5201
5202Done:
5203 pMe->uLastError = (uint8_t)uErr;
5204}
5205
5206
5207/*
5208 * Public function, see header qcbor/qcbor_decode.h
5209 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005210void
5211QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe,
5212 uint8_t uTagRequirement,
5213 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005214{
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005215 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07005216 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005217 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005218}
5219
5220
5221/*
5222 * Public function, see header qcbor/qcbor_decode.h
5223 */
5224void
5225QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe,
5226 int64_t nLabel,
5227 uint8_t uTagRequirement,
5228 int64_t *pnDays)
5229{
5230 QCBORItem Item;
5231 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005232 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005233}
5234
5235
5236/*
5237 * Public function, see header qcbor/qcbor_decode.h
5238 */
5239void
5240QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe,
5241 const char *szLabel,
5242 uint8_t uTagRequirement,
5243 int64_t *pnDays)
5244{
5245 QCBORItem Item;
5246 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005247 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005248}
5249
5250
5251
Laurence Lundblade37286c02022-09-03 10:05:02 -07005252/*
5253 * @brief Get a string that matches the type/tag specification.
5254 */
5255void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005256QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
5257 const QCBOR_Private_TagSpec TagSpec,
5258 UsefulBufC *pBstr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005259{
Laurence Lundbladec4537442020-04-14 18:53:22 -07005260 QCBORItem Item;
5261
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07005262 QCBORDecode_VGetNext(pMe, &Item);
5263 if(pMe->uLastError) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005264 return;
5265 }
5266
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005267 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005268
5269 if(pMe->uLastError == QCBOR_SUCCESS) {
5270 *pBstr = Item.val.string;
Laurence Lundbladeab40c6f2020-08-28 11:24:58 -07005271 } else {
5272 *pBstr = NULLUsefulBufC;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005273 }
5274}
5275
Laurence Lundbladec4537442020-04-14 18:53:22 -07005276
5277
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005278
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005279/**
5280 * @brief Common processing for a big number tag.
5281 *
5282 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
5283 * @param[in] pItem The item with the date.
5284 * @param[out] pValue The returned big number
5285 * @param[out] pbIsNegative The returned sign of the big number.
5286 *
5287 * Common processing for the big number tag. Mostly make sure
5288 * the tag content is correct and copy forward any further other tag
5289 * numbers.
5290 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07005291static QCBORError
Laurence Lundblade14ce2282024-07-24 22:13:35 -07005292QCBOR_Private_ProcessBigNum(const uint8_t uTagRequirement,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005293 const QCBORItem *pItem,
5294 UsefulBufC *pValue,
5295 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005296{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005297 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005298 {
5299 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07005300 {QCBOR_TYPE_POSBIGNUM, QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
5301 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005302 };
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005303
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005304 QCBORError uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005305 if(uErr != QCBOR_SUCCESS) {
5306 return uErr;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005307 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005308
5309 *pValue = pItem->val.string;
5310
5311 if(pItem->uDataType == QCBOR_TYPE_POSBIGNUM) {
5312 *pbIsNegative = false;
5313 } else if(pItem->uDataType == QCBOR_TYPE_NEGBIGNUM) {
5314 *pbIsNegative = true;
5315 }
5316
5317 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005318}
5319
5320
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005321/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005322 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005323 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005324void
5325QCBORDecode_GetBignum(QCBORDecodeContext *pMe,
5326 const uint8_t uTagRequirement,
5327 UsefulBufC *pValue,
5328 bool *pbIsNegative)
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005329{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005330 QCBORItem Item;
Laurence Lundblade14ce2282024-07-24 22:13:35 -07005331
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07005332 QCBORDecode_VGetNext(pMe, &Item);
5333 if(pMe->uLastError) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005334 return;
5335 }
5336
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005337 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
5338 &Item,
5339 pValue,
5340 pbIsNegative);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005341}
5342
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005343
Laurence Lundblade4e2da002020-06-13 23:08:31 -07005344/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005345 * Public function, see header qcbor/qcbor_spiffy_decode.h
5346 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005347void
5348QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe,
5349 const int64_t nLabel,
5350 const uint8_t uTagRequirement,
5351 UsefulBufC *pValue,
5352 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005353{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005354 QCBORItem Item;
5355 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005356 if(pMe->uLastError != QCBOR_SUCCESS) {
5357 return;
5358 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005359
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005360 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
5361 &Item,
5362 pValue,
5363 pbIsNegative);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005364}
5365
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005366
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005367/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005368 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005369 */
5370void
5371QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe,
5372 const char *szLabel,
5373 const uint8_t uTagRequirement,
5374 UsefulBufC *pValue,
5375 bool *pbIsNegative)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005376{
5377 QCBORItem Item;
5378 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005379 if(pMe->uLastError != QCBOR_SUCCESS) {
5380 return;
5381 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005382
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005383 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
5384 &Item,
5385 pValue,
5386 pbIsNegative);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005387}
5388
5389
5390
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005391/**
5392 * @brief Common processing for MIME tag (semi-private).
5393 *
5394 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
5395 * @param[in] pItem The item with the date.
5396 * @param[out] pMessage The returned MIME message.
5397 * @param[out] pbIsTag257 If true, binary MIME, if not, text MIME.
5398 *
5399 * Common processing for the MIME tag. Mostly make sure the tag
5400 * content is correct and copy forward any further other tag
5401 * numbers. See QCBORDecode_GetMIMEMessage().
5402 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07005403QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005404QCBORDecode_Private_GetMIME(const uint8_t uTagRequirement,
Laurence Lundblade37286c02022-09-03 10:05:02 -07005405 const QCBORItem *pItem,
5406 UsefulBufC *pMessage,
5407 bool *pbIsTag257)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005408{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005409 const QCBOR_Private_TagSpec TagSpecText =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005410 {
5411 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07005412 {QCBOR_TYPE_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
5413 {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005414 };
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005415 const QCBOR_Private_TagSpec TagSpecBinary =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005416 {
5417 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07005418 {QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
5419 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005420 };
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005421
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005422 QCBORError uReturn;
Laurence Lundblade9b334962020-08-27 10:55:53 -07005423
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005424 if(QCBOR_Private_CheckTagRequirement(TagSpecText, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005425 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07005426 if(pbIsTag257 != NULL) {
5427 *pbIsTag257 = false;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005428 }
5429 uReturn = QCBOR_SUCCESS;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005430 } else if(QCBOR_Private_CheckTagRequirement(TagSpecBinary, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005431 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07005432 if(pbIsTag257 != NULL) {
5433 *pbIsTag257 = true;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005434 }
5435 uReturn = QCBOR_SUCCESS;
5436
5437 } else {
5438 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
5439 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07005440
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005441 return uReturn;
5442}
5443
Laurence Lundblade93d89472020-10-03 22:30:50 -07005444// Improvement: add methods for wrapped CBOR, a simple alternate
5445// to EnterBstrWrapped
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005446
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005447
5448
5449
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005450#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundbladee6430642020-03-14 21:15:44 -07005451
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005452/**
5453 * @brief Prototype for conversion of exponent and mantissa to unsigned integer.
5454 *
5455 * @param[in] uMantissa The mantissa.
5456 * @param[in] nExponent The exponent.
5457 * @param[out] puResult The resulting integer.
5458 *
5459 * Concrete implementations of this are for exponent base 10 and 2 supporting
5460 * decimal fractions and big floats.
5461 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005462typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005463
5464
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005465/**
5466 * @brief Base 10 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5467 *
5468 * @param[in] uMantissa The unsigned integer mantissa.
5469 * @param[in] nExponent The signed integer exponent.
5470 * @param[out] puResult Place to return the unsigned integer result.
5471 *
5472 * This computes: mantissa * 10 ^^ exponent as for a decimal fraction. The output is a 64-bit
5473 * unsigned integer.
5474 *
5475 * There are many inputs for which the result will not fit in the
5476 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5477 * be returned.
5478 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005479static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005480QCBOR_Private_Exponentitate10(const uint64_t uMantissa,
5481 int64_t nExponent,
5482 uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005483{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005484 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005485
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005486 if(uResult != 0) {
5487 /* This loop will run a maximum of 19 times because
5488 * UINT64_MAX < 10 ^^ 19. More than that will cause
5489 * exit with the overflow error
5490 */
5491 for(; nExponent > 0; nExponent--) {
5492 if(uResult > UINT64_MAX / 10) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005493 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005494 }
5495 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005496 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005497
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005498 for(; nExponent < 0; nExponent++) {
5499 uResult = uResult / 10;
5500 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005501 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005502 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005503 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005504 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005505 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07005506
5507 *puResult = uResult;
5508
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005509 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005510}
5511
5512
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005513/**
5514 * @brief Base 2 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5515 *
5516 * @param[in] uMantissa The unsigned integer mantissa.
5517 * @param[in] nExponent The signed integer exponent.
5518 * @param[out] puResult Place to return the unsigned integer result.
5519 *
5520 * This computes: mantissa * 2 ^^ exponent as for a big float. The
5521 * output is a 64-bit unsigned integer.
5522 *
5523 * There are many inputs for which the result will not fit in the
5524 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5525 * be returned.
5526 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005527static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005528QCBOR_Private_Exponentitate2(const uint64_t uMantissa,
5529 int64_t nExponent,
5530 uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005531{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005532 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005533
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005534 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005535
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005536 /* This loop will run a maximum of 64 times because INT64_MAX <
5537 * 2^31. More than that will cause exit with the overflow error
Laurence Lundbladee6430642020-03-14 21:15:44 -07005538 */
5539 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005540 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005541 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005542 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005543 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005544 nExponent--;
5545 }
5546
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005547 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005548 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005549 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005550 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005551 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005552 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005553 }
5554
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005555 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005556
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005557 return QCBOR_SUCCESS;
5558}
5559
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005560
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005561/**
5562 * @brief Exponentiate a signed mantissa and signed exponent to produce a signed result.
5563 *
5564 * @param[in] nMantissa Signed integer mantissa.
5565 * @param[in] nExponent Signed integer exponent.
5566 * @param[out] pnResult Place to put the signed integer result.
5567 * @param[in] pfExp Exponentiation function.
5568 *
5569 * @returns Error code
5570 *
5571 * \c pfExp performs exponentiation on and unsigned mantissa and
5572 * produces an unsigned result. This converts the mantissa from signed
5573 * and converts the result to signed. The exponentiation function is
5574 * either for base 2 or base 10 (and could be other if needed).
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005575 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005576static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005577QCBOR_Private_ExponentiateNN(const int64_t nMantissa,
5578 const int64_t nExponent,
5579 int64_t *pnResult,
5580 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005581{
5582 uint64_t uResult;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005583 uint64_t uMantissa;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005584
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005585 /* Take the absolute value and put it into an unsigned. */
5586 if(nMantissa >= 0) {
5587 /* Positive case is straightforward */
5588 uMantissa = (uint64_t)nMantissa;
5589 } else if(nMantissa != INT64_MIN) {
5590 /* The common negative case. See next. */
5591 uMantissa = (uint64_t)-nMantissa;
5592 } else {
5593 /* int64_t and uint64_t are always two's complement per the
5594 * C standard (and since QCBOR uses these it only works with
5595 * two's complement, which is pretty much universal these
5596 * days). The range of a negative two's complement integer is
5597 * one more that than a positive, so the simple code above might
5598 * not work all the time because you can't simply negate the
5599 * value INT64_MIN because it can't be represented in an
5600 * int64_t. -INT64_MIN can however be represented in a
5601 * uint64_t. Some compilers seem to recognize this case for the
5602 * above code and put the correct value in uMantissa, however
5603 * they are not required to do this by the C standard. This next
5604 * line does however work for all compilers.
5605 *
5606 * This does assume two's complement where -INT64_MIN ==
5607 * INT64_MAX + 1 (which wouldn't be true for one's complement or
5608 * sign and magnitude (but we know we're using two's complement
5609 * because int64_t requires it)).
5610 *
5611 * See these, particularly the detailed commentary:
5612 * https://stackoverflow.com/questions/54915742/does-c99-mandate-a-int64-t-type-be-available-always
5613 * https://stackoverflow.com/questions/37301078/is-negating-int-min-undefined-behaviour
5614 */
5615 uMantissa = (uint64_t)INT64_MAX+1;
5616 }
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005617
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005618 /* Call the exponentiator passed for either base 2 or base 10.
5619 * Here is where most of the overflow errors are caught. */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005620 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
5621 if(uReturn) {
5622 return uReturn;
5623 }
5624
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005625 /* Convert back to the sign of the original mantissa */
5626 if(nMantissa >= 0) {
5627 if(uResult > INT64_MAX) {
5628 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5629 }
5630 *pnResult = (int64_t)uResult;
5631 } else {
5632 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
5633 * of INT64_MIN. This assumes two's compliment representation
5634 * where INT64_MIN is one increment farther from 0 than
5635 * INT64_MAX. Trying to write -INT64_MIN doesn't work to get
5636 * this because the compiler makes it an int64_t which can't
5637 * represent -INT64_MIN. Also see above.
5638 */
5639 if(uResult > (uint64_t)INT64_MAX+1) {
5640 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5641 }
5642 *pnResult = -(int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005643 }
5644
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005645 return QCBOR_SUCCESS;
5646}
5647
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005648
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005649/**
5650 * @brief Exponentiate an unsigned mantissa and signed exponent to produce an unsigned result.
5651 *
5652 * @param[in] nMantissa Signed integer mantissa.
5653 * @param[in] nExponent Signed integer exponent.
5654 * @param[out] puResult Place to put the signed integer result.
5655 * @param[in] pfExp Exponentiation function.
5656 *
5657 * @returns Error code
5658 *
5659 * \c pfExp performs exponentiation on and unsigned mantissa and
5660 * produces an unsigned result. This errors out if the mantissa
5661 * is negative because the output is unsigned.
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005662 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005663static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005664QCBOR_Private_ExponentitateNU(const int64_t nMantissa,
5665 const int64_t nExponent,
5666 uint64_t *puResult,
5667 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005668{
5669 if(nMantissa < 0) {
5670 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5671 }
5672
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005673 /* Cast to unsigned is OK because of check for negative.
5674 * Cast to unsigned is OK because UINT64_MAX > INT64_MAX.
5675 * Exponentiation is straight forward
5676 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005677 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
5678}
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005679
5680
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005681/**
5682 * @brief Exponentiate an usnigned mantissa and unsigned exponent to produce an unsigned result.
5683 *
5684 * @param[in] uMantissa Unsigned integer mantissa.
5685 * @param[in] nExponent Unsigned integer exponent.
5686 * @param[out] puResult Place to put the unsigned integer result.
5687 * @param[in] pfExp Exponentiation function.
5688 *
5689 * @returns Error code
5690 *
5691 * \c pfExp performs exponentiation on and unsigned mantissa and
5692 * produces an unsigned result so this is just a wrapper that does
5693 * nothing (and is likely inlined).
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005694 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005695static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005696QCBOR_Private_ExponentitateUU(const uint64_t uMantissa,
5697 const int64_t nExponent,
5698 uint64_t *puResult,
5699 fExponentiator pfExp)
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005700{
5701 return (*pfExp)(uMantissa, nExponent, puResult);
5702}
5703
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005704#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005705
5706
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005707
5708
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005709/**
5710 * @brief Convert a CBOR big number to a uint64_t.
5711 *
5712 * @param[in] BigNum Bytes of the big number to convert.
5713 * @param[in] uMax Maximum value allowed for the result.
5714 * @param[out] pResult Place to put the unsigned integer result.
5715 *
5716 * @returns Error code
5717 *
5718 * Many values will overflow because a big num can represent a much
5719 * larger range than uint64_t.
5720 */
5721static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005722QCBOR_Private_ConvertBigNumToUnsigned(const UsefulBufC BigNum,
5723 const uint64_t uMax,
5724 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005725{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005726 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005727
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005728 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005729 const uint8_t *pByte = BigNum.ptr;
5730 size_t uLen = BigNum.len;
5731 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07005732 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005733 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005734 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07005735 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005736 }
5737
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005738 *pResult = uResult;
5739 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005740}
5741
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005742
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005743/**
5744 * @brief Convert a CBOR postive big number to a uint64_t.
5745 *
5746 * @param[in] BigNum Bytes of the big number to convert.
5747 * @param[out] pResult Place to put the unsigned integer result.
5748 *
5749 * @returns Error code
5750 *
5751 * Many values will overflow because a big num can represent a much
5752 * larger range than uint64_t.
5753 */
5754static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005755QCBOR_Private_ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum,
5756 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005757{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005758 return QCBOR_Private_ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005759}
5760
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005761
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005762/**
5763 * @brief Convert a CBOR positive big number to an int64_t.
5764 *
5765 * @param[in] BigNum Bytes of the big number to convert.
5766 * @param[out] pResult Place to put the signed integer result.
5767 *
5768 * @returns Error code
5769 *
5770 * Many values will overflow because a big num can represent a much
5771 * larger range than int64_t.
5772 */
5773static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005774QCBOR_Private_ConvertPositiveBigNumToSigned(const UsefulBufC BigNum,
5775 int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005776{
5777 uint64_t uResult;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005778 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5779 INT64_MAX,
5780 &uResult);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005781 if(uError) {
5782 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005783 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005784 /* Cast is safe because ConvertBigNumToUnsigned limits to INT64_MAX */
Laurence Lundbladee6430642020-03-14 21:15:44 -07005785 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005786 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005787}
5788
5789
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005790/**
5791 * @brief Convert a CBOR negative big number to an int64_t.
5792 *
5793 * @param[in] BigNum Bytes of the big number to convert.
5794 * @param[out] pnResult Place to put the signed integer result.
5795 *
5796 * @returns Error code
5797 *
5798 * Many values will overflow because a big num can represent a much
5799 * larger range than int64_t.
5800 */
5801static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005802QCBOR_Private_ConvertNegativeBigNumToSigned(const UsefulBufC BigNum,
5803 int64_t *pnResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005804{
5805 uint64_t uResult;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005806 /* The negative integer furthest from zero for a C int64_t is
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005807 * INT64_MIN which is expressed as -INT64_MAX - 1. The value of a
5808 * negative number in CBOR is computed as -n - 1 where n is the
5809 * encoded integer, where n is what is in the variable BigNum. When
5810 * converting BigNum to a uint64_t, the maximum value is thus
5811 * INT64_MAX, so that when it -n - 1 is applied to it the result
5812 * will never be further from 0 than INT64_MIN.
5813 *
5814 * -n - 1 <= INT64_MIN.
5815 * -n - 1 <= -INT64_MAX - 1
5816 * n <= INT64_MAX.
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005817 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005818 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5819 INT64_MAX,
5820 &uResult);
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005821 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005822 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005823 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005824
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005825 /* Now apply -n - 1. The cast is safe because
5826 * ConvertBigNumToUnsigned() is limited to INT64_MAX which does fit
5827 * is the largest positive integer that an int64_t can
5828 * represent. */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005829 *pnResult = -(int64_t)uResult - 1;
5830
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005831 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005832}
5833
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005834
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005835
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005836
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005837/**
5838 * @brief Convert integers and floats to an int64_t.
5839 *
5840 * @param[in] pItem The item to convert.
5841 * @param[in] uConvertTypes Bit mask list of conversion options.
5842 * @param[out] pnValue The resulting converted value.
5843 *
5844 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5845 * in uConvertTypes.
5846 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5847 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5848 * or too small.
5849 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005850static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005851QCBOR_Private_ConvertInt64(const QCBORItem *pItem,
5852 const uint32_t uConvertTypes,
5853 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005854{
5855 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005856 case QCBOR_TYPE_FLOAT:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005857 case QCBOR_TYPE_DOUBLE:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005858#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005859 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005860 /* https://pubs.opengroup.org/onlinepubs/009695399/functions/llround.html
5861 http://www.cplusplus.com/reference/cmath/llround/
5862 */
5863 // Not interested in FE_INEXACT
5864 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005865 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5866 *pnValue = llround(pItem->val.dfnum);
5867 } else {
5868 *pnValue = lroundf(pItem->val.fnum);
5869 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005870 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5871 // llround() shouldn't result in divide by zero, but catch
5872 // it here in case it unexpectedly does. Don't try to
5873 // distinguish between the various exceptions because it seems
5874 // they vary by CPU, compiler and OS.
5875 return QCBOR_ERR_FLOAT_EXCEPTION;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005876 }
5877 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005878 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005879 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005880#else
5881 return QCBOR_ERR_HW_FLOAT_DISABLED;
5882#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005883 break;
5884
5885 case QCBOR_TYPE_INT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005886 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005887 *pnValue = pItem->val.int64;
5888 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005889 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005890 }
5891 break;
5892
5893 case QCBOR_TYPE_UINT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005894 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005895 if(pItem->val.uint64 < INT64_MAX) {
5896 *pnValue = pItem->val.int64;
5897 } else {
5898 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5899 }
5900 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005901 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005902 }
5903 break;
5904
Laurence Lundblade2d493002024-02-01 11:09:17 -07005905 case QCBOR_TYPE_65BIT_NEG_INT:
5906 /* This type occurs if the value won't fit into int64_t
5907 * so this is always an error. */
5908 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5909 break;
5910
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005911 default:
5912 return QCBOR_ERR_UNEXPECTED_TYPE;
5913 }
5914 return QCBOR_SUCCESS;
5915}
5916
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005917
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005918/**
5919 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5920 *
5921 * @param[in] pMe The decode context.
5922 * @param[in] uConvertTypes Bit mask list of conversion options.
5923 * @param[out] pnValue Result of the conversion.
5924 * @param[in,out] pItem Temporary space to store Item, returned item.
5925 *
5926 * See QCBORDecode_GetInt64Convert().
5927 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005928void
5929QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pMe,
5930 uint32_t uConvertTypes,
5931 int64_t *pnValue,
5932 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005933{
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07005934 QCBORDecode_VGetNext(pMe, pItem);
5935 if(pMe->uLastError) {
Laurence Lundbladee6430642020-03-14 21:15:44 -07005936 return;
5937 }
5938
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005939 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005940 uConvertTypes,
5941 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005942}
5943
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005944/**
5945 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5946 *
5947 * @param[in] pMe The decode context.
5948 * @param[in] nLabel Label to find in map.
5949 * @param[in] uConvertTypes Bit mask list of conversion options.
5950 * @param[out] pnValue Result of the conversion.
5951 * @param[in,out] pItem Temporary space to store Item, returned item.
5952 *
5953 * See QCBORDecode_GetInt64ConvertInMapN().
5954 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005955void
5956QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pMe,
5957 int64_t nLabel,
5958 uint32_t uConvertTypes,
5959 int64_t *pnValue,
5960 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005961{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005962 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005963 if(pMe->uLastError != QCBOR_SUCCESS) {
5964 return;
5965 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005966
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005967 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5968 uConvertTypes,
5969 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005970}
5971
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005972/**
5973 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5974 *
5975 * @param[in] pMe The decode context.
5976 * @param[in] szLabel Label to find in map.
5977 * @param[in] uConvertTypes Bit mask list of conversion options.
5978 * @param[out] pnValue Result of the conversion.
5979 * @param[in,out] pItem Temporary space to store Item, returned item.
5980 *
5981 * See QCBORDecode_GetInt64ConvertInMapSZ().
5982 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005983void
5984QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5985 const char * szLabel,
5986 uint32_t uConvertTypes,
5987 int64_t *pnValue,
5988 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005989{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005990 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005991 if(pMe->uLastError != QCBOR_SUCCESS) {
5992 return;
5993 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005994
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005995 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5996 uConvertTypes,
5997 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005998}
5999
6000
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006001/**
6002 * @brief Convert many number types to an int64_t.
6003 *
6004 * @param[in] pItem The item to convert.
6005 * @param[in] uConvertTypes Bit mask list of conversion options.
6006 * @param[out] pnValue The resulting converted value.
6007 *
6008 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6009 * in uConvertTypes.
6010 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6011 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6012 * or too small.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006013 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006014static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006015QCBOR_Private_Int64ConvertAll(const QCBORItem *pItem,
6016 const uint32_t uConvertTypes,
6017 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006018{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006019 switch(pItem->uDataType) {
6020
6021 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006022 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006023 return QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006024 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006025 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07006026 }
6027 break;
6028
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006029 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006030 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006031 return QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006032 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006033 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07006034 }
6035 break;
6036
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006037#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006038 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006039 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006040 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006041 pItem->val.expAndMantissa.nExponent,
6042 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006043 &QCBOR_Private_Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006044 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006045 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006046 }
6047 break;
6048
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006049 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006050 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006051 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006052 pItem->val.expAndMantissa.nExponent,
6053 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006054 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006055 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006056 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006057 }
6058 break;
6059
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006060 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006061 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006062 int64_t nMantissa;
6063 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006064 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006065 if(uErr) {
6066 return uErr;
6067 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006068 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006069 pItem->val.expAndMantissa.nExponent,
6070 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006071 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006072 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006073 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006074 }
6075 break;
6076
6077 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006078 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006079 int64_t nMantissa;
6080 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006081 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006082 if(uErr) {
6083 return uErr;
6084 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006085 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006086 pItem->val.expAndMantissa.nExponent,
6087 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006088 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006089 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006090 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006091 }
6092 break;
6093
6094 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006095 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006096 int64_t nMantissa;
6097 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006098 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006099 if(uErr) {
6100 return uErr;
6101 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006102 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006103 pItem->val.expAndMantissa.nExponent,
6104 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006105 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006106 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006107 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006108 }
6109 break;
6110
6111 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006112 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006113 int64_t nMantissa;
6114 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006115 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006116 if(uErr) {
6117 return uErr;
6118 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006119 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006120 pItem->val.expAndMantissa.nExponent,
6121 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006122 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006123 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006124 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07006125 }
6126 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006127#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006128
Laurence Lundbladee6430642020-03-14 21:15:44 -07006129
Laurence Lundbladec4537442020-04-14 18:53:22 -07006130 default:
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006131 return QCBOR_ERR_UNEXPECTED_TYPE; }
Laurence Lundbladec4537442020-04-14 18:53:22 -07006132}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006133
6134
Laurence Lundbladec4537442020-04-14 18:53:22 -07006135/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006136 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006137 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006138void
6139QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe,
6140 const uint32_t uConvertTypes,
6141 int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07006142{
6143 QCBORItem Item;
6144
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006145 QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07006146
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006147 if(pMe->uLastError == QCBOR_SUCCESS) {
6148 // The above conversion succeeded
6149 return;
6150 }
6151
Laurence Lundbladef6c86662020-05-12 02:08:00 -07006152 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006153 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07006154 return;
6155 }
6156
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006157 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
6158 uConvertTypes,
6159 pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006160}
6161
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006162
6163/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006164 * Public function, see header qcbor/qcbor_decode.h file
6165 */
6166void
6167QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
6168 const int64_t nLabel,
6169 const uint32_t uConvertTypes,
6170 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006171{
6172 QCBORItem Item;
6173
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006174 QCBORDecode_Private_GetInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006175 nLabel,
6176 uConvertTypes,
6177 pnValue,
6178 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006179
6180 if(pMe->uLastError == QCBOR_SUCCESS) {
6181 // The above conversion succeeded
6182 return;
6183 }
6184
6185 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6186 // The above conversion failed in a way that code below can't correct
6187 return;
6188 }
6189
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006190 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
6191 uConvertTypes,
6192 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006193}
6194
6195
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006196/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006197 * Public function, see header qcbor/qcbor_decode.h file
6198 */
6199void
6200QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
6201 const char *szLabel,
6202 const uint32_t uConvertTypes,
6203 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006204{
6205 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006206 QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006207 szLabel,
6208 uConvertTypes,
6209 pnValue,
6210 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006211
6212 if(pMe->uLastError == QCBOR_SUCCESS) {
6213 // The above conversion succeeded
6214 return;
6215 }
6216
6217 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6218 // The above conversion failed in a way that code below can't correct
6219 return;
6220 }
6221
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006222 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
6223 uConvertTypes,
6224 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006225}
6226
6227
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006228/**
6229 * @brief Convert many number types to an uint64_t.
6230 *
6231 * @param[in] pItem The item to convert.
6232 * @param[in] uConvertTypes Bit mask list of conversion options.
6233 * @param[out] puValue The resulting converted value.
6234 *
6235 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6236 * in uConvertTypes.
6237 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6238 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6239 * or too small.
6240 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006241static QCBORError
6242QCBOR_Private_ConvertUInt64(const QCBORItem *pItem,
6243 const uint32_t uConvertTypes,
6244 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006245{
6246 switch(pItem->uDataType) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006247 case QCBOR_TYPE_DOUBLE:
6248 case QCBOR_TYPE_FLOAT:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006249#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006250 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006251 // Can't use llround here because it will not convert values
6252 // greater than INT64_MAX and less than UINT64_MAX that
6253 // need to be converted so it is more complicated.
6254 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
6255 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
6256 if(isnan(pItem->val.dfnum)) {
6257 return QCBOR_ERR_FLOAT_EXCEPTION;
6258 } else if(pItem->val.dfnum < 0) {
6259 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6260 } else {
6261 double dRounded = round(pItem->val.dfnum);
6262 // See discussion in DecodeDateEpoch() for
6263 // explanation of - 0x7ff
6264 if(dRounded > (double)(UINT64_MAX- 0x7ff)) {
6265 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
6266 }
6267 *puValue = (uint64_t)dRounded;
6268 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006269 } else {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006270 if(isnan(pItem->val.fnum)) {
6271 return QCBOR_ERR_FLOAT_EXCEPTION;
6272 } else if(pItem->val.fnum < 0) {
6273 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6274 } else {
6275 float fRounded = roundf(pItem->val.fnum);
6276 // See discussion in DecodeDateEpoch() for
6277 // explanation of - 0x7ff
6278 if(fRounded > (float)(UINT64_MAX- 0x7ff)) {
6279 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
6280 }
6281 *puValue = (uint64_t)fRounded;
6282 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006283 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006284 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
6285 // round() and roundf() shouldn't result in exceptions here, but
6286 // catch them to be robust and thorough. Don't try to
6287 // distinguish between the various exceptions because it seems
6288 // they vary by CPU, compiler and OS.
6289 return QCBOR_ERR_FLOAT_EXCEPTION;
6290 }
6291
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006292 } else {
6293 return QCBOR_ERR_UNEXPECTED_TYPE;
6294 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006295#else
6296 return QCBOR_ERR_HW_FLOAT_DISABLED;
6297#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006298 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006299
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006300 case QCBOR_TYPE_INT64:
6301 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
6302 if(pItem->val.int64 >= 0) {
6303 *puValue = (uint64_t)pItem->val.int64;
6304 } else {
6305 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6306 }
6307 } else {
6308 return QCBOR_ERR_UNEXPECTED_TYPE;
6309 }
6310 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006311
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006312 case QCBOR_TYPE_UINT64:
6313 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade2d493002024-02-01 11:09:17 -07006314 *puValue = pItem->val.uint64;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006315 } else {
6316 return QCBOR_ERR_UNEXPECTED_TYPE;
6317 }
6318 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006319
Laurence Lundblade2d493002024-02-01 11:09:17 -07006320 case QCBOR_TYPE_65BIT_NEG_INT:
6321 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6322
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006323 default:
6324 return QCBOR_ERR_UNEXPECTED_TYPE;
6325 }
6326
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006327 return QCBOR_SUCCESS;
6328}
Laurence Lundbladec4537442020-04-14 18:53:22 -07006329
6330
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006331/**
6332 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
6333 *
6334 * @param[in] pMe The decode context.
6335 * @param[in] uConvertTypes Bit mask list of conversion options.
6336 * @param[out] puValue Result of the conversion.
6337 * @param[in,out] pItem Temporary space to store Item, returned item.
6338 *
6339 * See QCBORDecode_GetUInt64Convert().
6340 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006341void
6342QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pMe,
6343 const uint32_t uConvertTypes,
6344 uint64_t *puValue,
6345 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07006346{
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07006347 QCBORDecode_VGetNext(pMe, pItem);
6348 if(pMe->uLastError) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006349 return;
6350 }
6351
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07006352 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006353 uConvertTypes,
6354 puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07006355}
6356
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006357
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006358/**
6359 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
6360 *
6361 * @param[in] pMe The decode context.
6362 * @param[in] nLabel Label to find in map.
6363 * @param[in] uConvertTypes Bit mask list of conversion options.
6364 * @param[out] puValue Result of the conversion.
6365 * @param[in,out] pItem Temporary space to store Item, returned item.
6366 *
6367 * See QCBORDecode_GetUInt64ConvertInMapN().
6368 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006369void
6370QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe,
6371 const int64_t nLabel,
6372 const uint32_t uConvertTypes,
6373 uint64_t *puValue,
6374 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006375{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006376 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006377 if(pMe->uLastError != QCBOR_SUCCESS) {
6378 return;
6379 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006380
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006381 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
6382 uConvertTypes,
6383 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006384}
6385
6386
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006387/**
6388 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
6389 *
6390 * @param[in] pMe The decode context.
6391 * @param[in] szLabel Label to find in map.
6392 * @param[in] uConvertTypes Bit mask list of conversion options.
6393 * @param[out] puValue Result of the conversion.
6394 * @param[in,out] pItem Temporary space to store Item, returned item.
6395 *
6396 * See QCBORDecode_GetUInt64ConvertInMapSZ().
6397 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006398void
6399QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
6400 const char *szLabel,
6401 const uint32_t uConvertTypes,
6402 uint64_t *puValue,
6403 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006404{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006405 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006406 if(pMe->uLastError != QCBOR_SUCCESS) {
6407 return;
6408 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006409
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006410 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
6411 uConvertTypes,
6412 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006413}
6414
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006415
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006416/**
6417 * @brief Convert many number types to an unt64_t.
6418 *
6419 * @param[in] pItem The item to convert.
6420 * @param[in] uConvertTypes Bit mask list of conversion options.
6421 * @param[out] puValue The resulting converted value.
6422 *
6423 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6424 * in uConvertTypes.
6425 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6426 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6427 * or too small.
6428 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006429static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006430QCBOR_Private_UInt64ConvertAll(const QCBORItem *pItem,
6431 const uint32_t uConvertTypes,
6432 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006433{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08006434 switch(pItem->uDataType) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006435
6436 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006437 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006438 return QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006439 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006440 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006441 }
6442 break;
6443
6444 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006445 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006446 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6447 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006448 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006449 }
6450 break;
6451
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006452#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006453
6454 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006455 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006456 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006457 pItem->val.expAndMantissa.nExponent,
6458 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006459 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006460 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006461 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006462 }
6463 break;
6464
6465 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006466 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006467 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006468 pItem->val.expAndMantissa.nExponent,
6469 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006470 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006471 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006472 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006473 }
6474 break;
6475
6476 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006477 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006478 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006479 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006480 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006481 if(uErr != QCBOR_SUCCESS) {
6482 return uErr;
6483 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006484 return QCBOR_Private_ExponentitateUU(uMantissa,
6485 pItem->val.expAndMantissa.nExponent,
6486 puValue,
6487 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006488 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006489 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006490 }
6491 break;
6492
6493 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006494 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006495 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6496 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006497 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006498 }
6499 break;
6500
6501 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006502 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006503 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006504 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006505 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum,
6506 &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006507 if(uErr != QCBOR_SUCCESS) {
6508 return uErr;
6509 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006510 return QCBOR_Private_ExponentitateUU(uMantissa,
6511 pItem->val.expAndMantissa.nExponent,
6512 puValue,
6513 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006514 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006515 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006516 }
6517 break;
6518
6519 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006520 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006521 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6522 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006523 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006524 }
6525 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006526#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006527 default:
6528 return QCBOR_ERR_UNEXPECTED_TYPE;
6529 }
6530}
6531
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006532
Laurence Lundblade4e2da002020-06-13 23:08:31 -07006533/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006534 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006535 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006536void
6537QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe,
6538 const uint32_t uConvertTypes,
6539 uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006540{
6541 QCBORItem Item;
6542
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006543 QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006544
Laurence Lundbladef6c86662020-05-12 02:08:00 -07006545 if(pMe->uLastError == QCBOR_SUCCESS) {
6546 // The above conversion succeeded
6547 return;
6548 }
6549
6550 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6551 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07006552 return;
6553 }
6554
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006555 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6556 uConvertTypes,
6557 puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006558}
6559
Laurence Lundbladec4537442020-04-14 18:53:22 -07006560
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006561/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006562 * Public function, see header qcbor/qcbor_decode.h file
6563 */
6564void
6565QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
6566 const int64_t nLabel,
6567 const uint32_t uConvertTypes,
6568 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006569{
6570 QCBORItem Item;
6571
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006572 QCBORDecode_Private_GetUInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006573 nLabel,
6574 uConvertTypes,
6575 puValue,
6576 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006577
6578 if(pMe->uLastError == QCBOR_SUCCESS) {
6579 // The above conversion succeeded
6580 return;
6581 }
6582
6583 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6584 // The above conversion failed in a way that code below can't correct
6585 return;
6586 }
6587
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006588 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6589 uConvertTypes,
6590 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006591}
6592
6593
6594/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006595 * Public function, see header qcbor/qcbor_decode.h file
6596 */
6597void
6598QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
6599 const char *szLabel,
6600 const uint32_t uConvertTypes,
6601 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006602{
6603 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006604 QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006605 szLabel,
6606 uConvertTypes,
6607 puValue,
6608 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006609
6610 if(pMe->uLastError == QCBOR_SUCCESS) {
6611 // The above conversion succeeded
6612 return;
6613 }
6614
6615 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6616 // The above conversion failed in a way that code below can't correct
6617 return;
6618 }
6619
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006620 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6621 uConvertTypes,
6622 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006623}
6624
6625
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006626
6627
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006628#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006629/**
6630 * @brief Basic conversions to a double.
6631 *
6632 * @param[in] pItem The item to convert
6633 * @param[in] uConvertTypes Bit flags indicating source types for conversion
6634 * @param[out] pdValue The value converted to a double
6635 *
6636 * This does the conversions that don't need much object code,
6637 * the conversions from int, uint and float to double.
6638 *
6639 * See QCBOR_Private_DoubleConvertAll() for the full set
6640 * of conversions.
6641 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006642static QCBORError
6643QCBOR_Private_ConvertDouble(const QCBORItem *pItem,
6644 const uint32_t uConvertTypes,
6645 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006646{
6647 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006648 case QCBOR_TYPE_FLOAT:
6649#ifndef QCBOR_DISABLE_FLOAT_HW_USE
6650 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6651 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006652 // Simple cast does the job.
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006653 *pdValue = (double)pItem->val.fnum;
6654 } else {
6655 return QCBOR_ERR_UNEXPECTED_TYPE;
6656 }
6657 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006658#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006659 return QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006660#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006661 break;
6662
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006663 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006664 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6665 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006666 *pdValue = pItem->val.dfnum;
6667 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006668 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006669 }
6670 }
6671 break;
6672
6673 case QCBOR_TYPE_INT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006674#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006675 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006676 // A simple cast seems to do the job with no worry of exceptions.
6677 // There will be precision loss for some values.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006678 *pdValue = (double)pItem->val.int64;
6679
6680 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006681 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006682 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006683#else
6684 return QCBOR_ERR_HW_FLOAT_DISABLED;
6685#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006686 break;
6687
6688 case QCBOR_TYPE_UINT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006689#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006690 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006691 // A simple cast seems to do the job with no worry of exceptions.
6692 // There will be precision loss for some values.
6693 *pdValue = (double)pItem->val.uint64;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006694 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006695 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006696 }
6697 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006698#else
6699 return QCBOR_ERR_HW_FLOAT_DISABLED;
6700#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006701
Laurence Lundblade2d493002024-02-01 11:09:17 -07006702 case QCBOR_TYPE_65BIT_NEG_INT:
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -08006703#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade14ce2282024-07-24 22:13:35 -07006704 // TODO: don't use float HW. We have the function to do it.
Laurence Lundblade2d493002024-02-01 11:09:17 -07006705 *pdValue = -(double)pItem->val.uint64 - 1;
6706 break;
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -08006707#else
6708 return QCBOR_ERR_HW_FLOAT_DISABLED;
6709#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade2d493002024-02-01 11:09:17 -07006710
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006711 default:
6712 return QCBOR_ERR_UNEXPECTED_TYPE;
6713 }
6714
6715 return QCBOR_SUCCESS;
6716}
6717
6718
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006719/**
6720 * @brief Almost-public method to decode a number and convert to double (semi-private).
6721 *
6722 * @param[in] pMe The decode context.
6723 * @param[in] uConvertTypes Bit mask list of conversion options
6724 * @param[out] pdValue The output of the conversion.
6725 * @param[in,out] pItem Temporary space to store Item, returned item.
6726 *
6727 * See QCBORDecode_GetDoubleConvert().
6728 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006729void
6730QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pMe,
6731 const uint32_t uConvertTypes,
6732 double *pdValue,
6733 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07006734{
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07006735 QCBORDecode_VGetNext(pMe, pItem);
6736 if(pMe->uLastError) {
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006737 return;
6738 }
6739
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006740 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006741 uConvertTypes,
6742 pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006743}
Laurence Lundbladec4537442020-04-14 18:53:22 -07006744
Laurence Lundbladec4537442020-04-14 18:53:22 -07006745
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006746/**
6747 * @brief Almost-public method to decode a number and convert to double (semi-private).
6748 *
6749 * @param[in] pMe The decode context.
6750 * @param[in] nLabel Label to find in map.
6751 * @param[in] uConvertTypes Bit mask list of conversion options
6752 * @param[out] pdValue The output of the conversion.
6753 * @param[in,out] pItem Temporary space to store Item, returned item.
6754 *
6755 * See QCBORDecode_GetDoubleConvertInMapN().
6756 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006757void
6758QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pMe,
6759 const int64_t nLabel,
6760 const uint32_t uConvertTypes,
6761 double *pdValue,
6762 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006763{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006764 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006765 if(pMe->uLastError != QCBOR_SUCCESS) {
6766 return;
6767 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006768
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006769 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6770 uConvertTypes,
6771 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006772}
6773
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006774
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006775/**
6776 * @brief Almost-public method to decode a number and convert to double (semi-private).
6777 *
6778 * @param[in] pMe The decode context.
6779 * @param[in] szLabel Label to find in map.
6780 * @param[in] uConvertTypes Bit mask list of conversion options
6781 * @param[out] pdValue The output of the conversion.
6782 * @param[in,out] pItem Temporary space to store Item, returned item.
6783 *
6784 * See QCBORDecode_GetDoubleConvertInMapSZ().
6785 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006786void
6787QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe,
6788 const char *szLabel,
6789 const uint32_t uConvertTypes,
6790 double *pdValue,
6791 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006792{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006793 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006794 if(pMe->uLastError != QCBOR_SUCCESS) {
6795 return;
6796 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006797
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006798 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6799 uConvertTypes,
6800 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006801}
6802
6803
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006804#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006805/**
6806 * @brief Convert a big number to double-precision float.
6807 *
6808 * @param[in] BigNum The big number to convert
6809 *
6810 * @returns The double value.
6811 *
6812 * This will always succeed. It will lose precision for larger
6813 * numbers. If the big number is too large to fit (more than
6814 * 1.7976931348623157E+308) infinity will be returned. NaN is never
6815 * returned.
6816 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006817static double
6818QCBOR_Private_ConvertBigNumToDouble(const UsefulBufC BigNum)
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006819{
6820 double dResult;
6821
6822 dResult = 0.0;
6823 const uint8_t *pByte = BigNum.ptr;
6824 size_t uLen = BigNum.len;
6825 /* This will overflow and become the float value INFINITY if the number
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006826 * is too large to fit. */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006827 while(uLen--) {
6828 dResult = (dResult * 256.0) + (double)*pByte++;
6829 }
6830
6831 return dResult;
6832}
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006833#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6834
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006835
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006836
6837
6838/**
6839 * @brief Convert many number types to a double.
6840 *
6841 * @param[in] pItem The item to convert.
6842 * @param[in] uConvertTypes Bit mask list of conversion options.
6843 * @param[out] pdValue The resulting converted value.
6844 *
6845 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6846 * in uConvertTypes.
6847 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6848 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6849 * or too small.
6850 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006851static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006852QCBOR_Private_DoubleConvertAll(const QCBORItem *pItem,
6853 const uint32_t uConvertTypes,
6854 double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006855{
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006856#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07006857 /*
Laurence Lundblade16a207a2021-09-18 17:22:46 -07006858 * What Every Computer Scientist Should Know About Floating-Point Arithmetic
6859 * https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
6860 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006861 switch(pItem->uDataType) {
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006862
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006863#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006864 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006865 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006866 // Underflow gives 0, overflow gives infinity
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006867 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6868 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
6869 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006870 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006871 }
6872 break;
6873
6874 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006875 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006876 // Underflow gives 0, overflow gives infinity
6877 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6878 exp2((double)pItem->val.expAndMantissa.nExponent);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006879 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006880 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006881 }
6882 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006883#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006884
6885 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006886 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006887 *pdValue = QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006888 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006889 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006890 }
6891 break;
6892
6893 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006894 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006895 *pdValue = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006896 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006897 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006898 }
6899 break;
6900
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006901#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006902 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006903 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006904 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006905 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6906 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006907 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006908 }
6909 break;
6910
6911 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006912 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006913 double dMantissa = -QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006914 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6915 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006916 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006917 }
6918 break;
6919
6920 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006921 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006922 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006923 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6924 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006925 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006926 }
6927 break;
6928
6929 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006930 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006931 double dMantissa = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006932 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6933 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006934 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006935 }
6936 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006937#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006938
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006939 default:
6940 return QCBOR_ERR_UNEXPECTED_TYPE;
6941 }
6942
6943 return QCBOR_SUCCESS;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006944
6945#else
6946 (void)pItem;
6947 (void)uConvertTypes;
6948 (void)pdValue;
6949 return QCBOR_ERR_HW_FLOAT_DISABLED;
6950#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6951
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006952}
6953
6954
6955/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006956 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006957 */
6958void
6959QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe,
6960 const uint32_t uConvertTypes,
6961 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006962{
6963
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006964 QCBORItem Item;
6965
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006966 QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006967
6968 if(pMe->uLastError == QCBOR_SUCCESS) {
6969 // The above conversion succeeded
6970 return;
6971 }
6972
6973 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6974 // The above conversion failed in a way that code below can't correct
6975 return;
6976 }
6977
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006978 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6979 uConvertTypes,
6980 pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006981}
6982
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006983
6984/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006985 * Public function, see header qcbor/qcbor_decode.h file
6986 */
6987void
6988QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe,
6989 const int64_t nLabel,
6990 const uint32_t uConvertTypes,
6991 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006992{
6993 QCBORItem Item;
6994
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006995 QCBORDecode_Private_GetDoubleConvertInMapN(pMe,
6996 nLabel,
6997 uConvertTypes,
6998 pdValue,
6999 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07007000
7001 if(pMe->uLastError == QCBOR_SUCCESS) {
7002 // The above conversion succeeded
7003 return;
7004 }
7005
7006 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
7007 // The above conversion failed in a way that code below can't correct
7008 return;
7009 }
7010
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007011 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
7012 uConvertTypes,
7013 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07007014}
7015
7016
7017/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007018 * Public function, see header qcbor/qcbor_decode.h file
7019 */
7020void
7021QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe,
7022 const char *szLabel,
7023 const uint32_t uConvertTypes,
7024 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07007025{
7026 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007027 QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe,
7028 szLabel,
7029 uConvertTypes,
7030 pdValue,
7031 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07007032
7033 if(pMe->uLastError == QCBOR_SUCCESS) {
7034 // The above conversion succeeded
7035 return;
7036 }
7037
7038 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
7039 // The above conversion failed in a way that code below can't correct
7040 return;
7041 }
7042
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007043 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
7044 uConvertTypes,
7045 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07007046}
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02007047#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007048
7049
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007050
7051
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07007052#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007053/**
7054 * @brief Convert an integer to a big number
7055 *
7056 * @param[in] uInt The integer to convert.
7057 * @param[in] Buffer The buffer to output the big number to.
7058 *
7059 * @returns The big number or NULLUsefulBufC is the buffer is to small.
7060 *
7061 * This always succeeds unless the buffer is too small.
7062 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007063static UsefulBufC
7064QCBOR_Private_ConvertIntToBigNum(uint64_t uInt, const UsefulBuf Buffer)
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07007065{
7066 while((uInt & 0xff00000000000000UL) == 0) {
7067 uInt = uInt << 8;
7068 };
7069
7070 UsefulOutBuf UOB;
7071
7072 UsefulOutBuf_Init(&UOB, Buffer);
7073
7074 while(uInt) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07007075 UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff00000000000000UL) >> 56));
7076 uInt = uInt << 8;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07007077 }
7078
7079 return UsefulOutBuf_OutUBuf(&UOB);
7080}
7081
7082
Laurence Lundblade37286c02022-09-03 10:05:02 -07007083/**
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07007084 * @brief Check and/or complete exponent and mantissa item.
Laurence Lundblade37286c02022-09-03 10:05:02 -07007085 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07007086 * @param[in] pMe The decoder context.
7087 * @param[in] TagSpec Expected type(s).
7088 * @param[in,out] pItem See below.
Laurence Lundblade37286c02022-09-03 10:05:02 -07007089 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07007090 * This is for decimal fractions and big floats, both of which are an
7091 * exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07007092 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07007093 * If the item item had a tag number indicating it was a
7094 * decimal fraction or big float, then the input @c pItem will
7095 * have been decoded as exponent and mantissa. If there was
7096 * no tag number, the caller is asking this be decoded as a
7097 * big float or decimal fraction and @c pItem just has the
7098 * first item in an exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07007099 *
7100 * On output, the item is always a fully decoded decimal fraction or
7101 * big float.
7102 *
7103 * This errors out if the input type does not meet the TagSpec.
7104 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07007105static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007106QCBOR_Private_ExpMantissaTypeHandler(QCBORDecodeContext *pMe,
7107 const QCBOR_Private_TagSpec TagSpec,
7108 QCBORItem *pItem)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007109{
7110 QCBORError uErr;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007111
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07007112 /* pItem could either be a decoded exponent and mantissa or
7113 * the opening array of an undecoded exponent and mantissa. This
Laurence Lundblade37286c02022-09-03 10:05:02 -07007114 * check will succeed on either, but doesn't say which it was.
7115 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007116 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07007117 if(uErr != QCBOR_SUCCESS) {
7118 goto Done;
7119 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007120
Laurence Lundblade37286c02022-09-03 10:05:02 -07007121 if(pItem->uDataType == QCBOR_TYPE_ARRAY) {
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07007122 /* The item is an array, which means is is an undecoded exponent
7123 * and mantissa. This call consumes the items in the array and
7124 * results in a decoded exponent and mantissa in pItem. This is
Laurence Lundblade37286c02022-09-03 10:05:02 -07007125 * the case where there was no tag.
7126 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007127 uErr = QCBORDecode_Private_ExpMantissa(pMe, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007128 if(uErr != QCBOR_SUCCESS) {
7129 goto Done;
7130 }
7131
Laurence Lundblade37286c02022-09-03 10:05:02 -07007132 /* The above decode didn't determine whether it is a decimal
7133 * fraction or big num. Which of these two depends on what the
7134 * caller wants it decoded as since there is no tag, so fish the
7135 * type out of the TagSpec. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007136 pItem->uDataType = QCBOR_Private_ExpMantissaDataType(TagSpec.uTaggedTypes[0], pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07007137
7138 /* No need to check the type again. All that we need to know was
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07007139 * that it decoded correctly as a exponent and mantissa. The
Laurence Lundblade37286c02022-09-03 10:05:02 -07007140 * QCBOR type is set out by what was requested.
7141 */
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007142 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07007143
7144 /* If the item was not an array and the check passed, then
7145 * it is a fully decoded big float or decimal fraction and
7146 * matches what is requested.
7147 */
7148
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007149Done:
7150 return uErr;
7151}
7152
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007153
Laurence Lundblade37286c02022-09-03 10:05:02 -07007154/* Some notes from the work to disable tags.
7155 *
7156 * The API for big floats and decimal fractions seems good.
7157 * If there's any issue with it it's that the code size to
7158 * implement is a bit large because of the conversion
7159 * to/from int and bignum that is required. There is no API
7160 * that doesn't do the conversion so dead stripping will never
7161 * leave that code out.
7162 *
7163 * The implementation itself seems correct, but not as clean
7164 * and neat as it could be. It could probably be smaller too.
7165 *
7166 * The implementation has three main parts / functions
7167 * - The decoding of the array of two
7168 * - All the tag and type checking for the various API functions
7169 * - Conversion to/from bignum and int
7170 *
7171 * The type checking seems like it wastes the most code for
7172 * what it needs to do.
7173 *
7174 * The inlining for the conversion is probably making the
7175 * overall code base larger.
7176 *
7177 * The tests cases could be organized a lot better and be
7178 * more thorough.
7179 *
7180 * Seems also like there could be more common code in the
7181 * first tier part of the public API. Some functions only
7182 * vary by a TagSpec.
7183 */
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007184
7185/**
7186 * @brief Common processor for exponent and mantissa.
7187 *
7188 * @param[in] pMe The decode context.
7189 * @param[in] TagSpec The expected/allowed tags.
7190 * @param[in] pItem The data item to process.
7191 * @param[out] pnMantissa The returned mantissa as an int64_t.
7192 * @param[out] pnExponent The returned exponent as an int64_t.
7193 *
7194 * This handles exponent and mantissa for base 2 and 10. This
7195 * is limited to a mantissa that is an int64_t. See also
7196 * QCBORDecode_Private_ProcessExpMantissaBig().
7197 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007198static void
7199QCBOR_Private_ProcessExpMantissa(QCBORDecodeContext *pMe,
7200 const QCBOR_Private_TagSpec TagSpec,
7201 QCBORItem *pItem,
7202 int64_t *pnMantissa,
7203 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007204{
7205 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007206
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07007207 if(pMe->uLastError) {
7208 return;
7209 }
7210
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007211 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007212 if(uErr != QCBOR_SUCCESS) {
7213 goto Done;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007214 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007215
Laurence Lundblade9b334962020-08-27 10:55:53 -07007216 switch (pItem->uDataType) {
7217
7218 case QCBOR_TYPE_DECIMAL_FRACTION:
7219 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade9b334962020-08-27 10:55:53 -07007220 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade37286c02022-09-03 10:05:02 -07007221 *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
Laurence Lundblade9b334962020-08-27 10:55:53 -07007222 break;
7223
Laurence Lundblade37286c02022-09-03 10:05:02 -07007224#ifndef QCBOR_DISABLE_TAGS
7225 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundblade9b334962020-08-27 10:55:53 -07007226 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
7227 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
7228 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007229 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07007230 break;
7231
7232 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
7233 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
7234 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007235 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07007236 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07007237#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07007238
7239 default:
7240 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
7241 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007242
7243 Done:
7244 pMe->uLastError = (uint8_t)uErr;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007245}
7246
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007247
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007248/**
7249 * @brief Decode exponent and mantissa into a big number.
7250 *
7251 * @param[in] pMe The decode context.
7252 * @param[in] TagSpec The expected/allowed tags.
7253 * @param[in] pItem Item to decode and convert.
7254 * @param[in] BufferForMantissa Buffer to output mantissa into.
7255 * @param[out] pMantissa The output mantissa.
7256 * @param[out] pbIsNegative The sign of the output.
7257 * @param[out] pnExponent The mantissa of the output.
7258 *
7259 * This is the common processing of a decimal fraction or a big float
7260 * into a big number. This will decode and consume all the CBOR items
7261 * that make up the decimal fraction or big float.
7262 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007263static void
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007264QCBORDecode_Private_ProcessExpMantissaBig(QCBORDecodeContext *pMe,
7265 const QCBOR_Private_TagSpec TagSpec,
7266 QCBORItem *pItem,
7267 const UsefulBuf BufferForMantissa,
7268 UsefulBufC *pMantissa,
7269 bool *pbIsNegative,
7270 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007271{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007272 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007273
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07007274 if(pMe->uLastError != QCBOR_SUCCESS) {
7275 return;
7276 }
7277
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007278 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007279 if(uErr != QCBOR_SUCCESS) {
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007280 goto Done;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007281 }
7282
7283 uint64_t uMantissa;
7284
7285 switch (pItem->uDataType) {
7286
7287 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007288 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07007289 /* See comments in ExponentiateNN() on handling INT64_MIN */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007290 if(pItem->val.expAndMantissa.Mantissa.nInt >= 0) {
7291 uMantissa = (uint64_t)pItem->val.expAndMantissa.Mantissa.nInt;
7292 *pbIsNegative = false;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07007293 } else if(pItem->val.expAndMantissa.Mantissa.nInt != INT64_MIN) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007294 uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt;
7295 *pbIsNegative = true;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07007296 } else {
7297 uMantissa = (uint64_t)INT64_MAX+1;
7298 *pbIsNegative = true;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007299 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007300 *pMantissa = QCBOR_Private_ConvertIntToBigNum(uMantissa,
7301 BufferForMantissa);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007302 *pnExponent = pItem->val.expAndMantissa.nExponent;
7303 break;
7304
Laurence Lundblade37286c02022-09-03 10:05:02 -07007305#ifndef QCBOR_DISABLE_TAGS
7306 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007307 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007308 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007309 *pnExponent = pItem->val.expAndMantissa.nExponent;
7310 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
7311 *pbIsNegative = false;
7312 break;
7313
7314 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007315 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007316 *pnExponent = pItem->val.expAndMantissa.nExponent;
7317 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
7318 *pbIsNegative = true;
7319 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07007320#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007321
7322 default:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007323 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007324 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007325
7326Done:
7327 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007328}
7329
7330
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007331/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007332 * Public function, see header qcbor/qcbor_decode.h file
7333 */
7334void
7335QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe,
7336 const uint8_t uTagRequirement,
7337 int64_t *pnMantissa,
7338 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007339{
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007340 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07007341 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007342
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007343 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007344 {
7345 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007346 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7347 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7348 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007349 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007350
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007351 QCBOR_Private_ProcessExpMantissa(pMe,
7352 TagSpec,
7353 &Item,
7354 pnMantissa,
7355 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007356}
7357
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007358
7359/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007360 * Public function, see header qcbor/qcbor_decode.h file
7361 */
7362void
7363QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe,
7364 const int64_t nLabel,
7365 const uint8_t uTagRequirement,
7366 int64_t *pnMantissa,
7367 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007368{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007369 QCBORItem Item;
7370 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7371
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007372 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007373 {
7374 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007375 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7376 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7377 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007378 };
7379
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007380 QCBOR_Private_ProcessExpMantissa(pMe,
7381 TagSpec,
7382 &Item,
7383 pnMantissa,
7384 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007385}
7386
7387
7388/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007389 * Public function, see header qcbor/qcbor_decode.h file
7390 */
7391void
7392QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
7393 const char *szLabel,
7394 const uint8_t uTagRequirement,
7395 int64_t *pnMantissa,
7396 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007397{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007398 QCBORItem Item;
7399 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7400
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007401 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007402 {
7403 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007404 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7405 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7406 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007407 };
Laurence Lundblade9b334962020-08-27 10:55:53 -07007408
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007409 QCBOR_Private_ProcessExpMantissa(pMe,
7410 TagSpec,
7411 &Item,
7412 pnMantissa,
7413 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007414}
7415
7416
7417/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007418 * Public function, see header qcbor/qcbor_decode.h file
7419 */
7420void
7421QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe,
7422 const uint8_t uTagRequirement,
7423 const UsefulBuf MantissaBuffer,
7424 UsefulBufC *pMantissa,
7425 bool *pbMantissaIsNegative,
7426 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007427{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007428 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07007429 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007430
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007431 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007432 {
7433 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007434 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7435 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7436 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007437 };
7438
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007439 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7440 TagSpec,
7441 &Item,
7442 MantissaBuffer,
7443 pMantissa,
7444 pbMantissaIsNegative,
7445 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007446}
7447
7448
7449/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007450 * Public function, see header qcbor/qcbor_decode.h file
7451 */
7452void
7453QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe,
7454 const int64_t nLabel,
7455 const uint8_t uTagRequirement,
7456 const UsefulBuf BufferForMantissa,
7457 UsefulBufC *pMantissa,
7458 bool *pbIsNegative,
7459 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007460{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007461
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007462 QCBORItem Item;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007463 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007464
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007465 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007466 {
7467 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007468 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7469 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7470 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007471 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007472
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007473 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7474 TagSpec,
7475 &Item,
7476 BufferForMantissa,
7477 pMantissa,
7478 pbIsNegative,
7479 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007480}
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007481
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007482
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007483/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007484 * Public function, see header qcbor/qcbor_decode.h file
7485 */
7486void
7487QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe,
7488 const char *szLabel,
7489 const uint8_t uTagRequirement,
7490 const UsefulBuf BufferForMantissa,
7491 UsefulBufC *pMantissa,
7492 bool *pbIsNegative,
7493 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007494{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007495 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007496 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007497
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007498 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007499 {
7500 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007501 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7502 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7503 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007504 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007505
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007506 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7507 TagSpec,
7508 &Item,
7509 BufferForMantissa,
7510 pMantissa,
7511 pbIsNegative,
7512 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007513}
7514
7515
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007516/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007517 * Public function, see header qcbor/qcbor_decode.h file
7518 */
7519void
7520QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe,
7521 const uint8_t uTagRequirement,
7522 int64_t *pnMantissa,
7523 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007524{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007525 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07007526 QCBORDecode_VGetNext(pMe, &Item);
7527
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007528 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007529 {
7530 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007531 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7532 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7533 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007534 };
7535
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007536 QCBOR_Private_ProcessExpMantissa(pMe,
7537 TagSpec,
7538 &Item,
7539 pnMantissa,
7540 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007541}
7542
7543
7544/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007545 * Public function, see header qcbor/qcbor_decode.h file
7546 */
7547void
7548QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe,
7549 const int64_t nLabel,
7550 const uint8_t uTagRequirement,
7551 int64_t *pnMantissa,
7552 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007553{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007554 QCBORItem Item;
7555 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007556
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007557 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007558 {
7559 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007560 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7561 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7562 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007563 };
7564
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007565 QCBOR_Private_ProcessExpMantissa(pMe,
7566 TagSpec,
7567 &Item,
7568 pnMantissa,
7569 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007570}
7571
7572
7573/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007574 * Public function, see header qcbor/qcbor_decode.h file
7575 */
7576void
7577QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe,
7578 const char *szLabel,
7579 const uint8_t uTagRequirement,
7580 int64_t *pnMantissa,
7581 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007582{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007583 QCBORItem Item;
7584 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007585
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007586 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007587 {
7588 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007589 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7590 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7591 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007592 };
7593
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007594 QCBOR_Private_ProcessExpMantissa(pMe,
7595 TagSpec,
7596 &Item,
7597 pnMantissa,
7598 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007599}
7600
7601
7602/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007603 * Public function, see header qcbor/qcbor_decode.h file
7604 */
7605void
7606QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe,
7607 const uint8_t uTagRequirement,
7608 const UsefulBuf MantissaBuffer,
7609 UsefulBufC *pMantissa,
7610 bool *pbMantissaIsNegative,
7611 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007612{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007613 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07007614 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007615
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007616 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007617 {
7618 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007619 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7620 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7621 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007622 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007623
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007624 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7625 TagSpec,
7626 &Item,
7627 MantissaBuffer,
7628 pMantissa,
7629 pbMantissaIsNegative,
7630 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007631}
7632
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007633
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007634/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007635 * Public function, see header qcbor/qcbor_decode.h file
7636 */
7637void
7638QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe,
7639 const int64_t nLabel,
7640 const uint8_t uTagRequirement,
7641 const UsefulBuf BufferForMantissa,
7642 UsefulBufC *pMantissa,
7643 bool *pbIsNegative,
7644 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007645{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007646 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007647 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007648
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007649 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007650 {
7651 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007652 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7653 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7654 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007655 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007656
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007657 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7658 TagSpec,
7659 &Item,
7660 BufferForMantissa,
7661 pMantissa,
7662 pbIsNegative,
7663 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007664}
7665
7666
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007667/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007668 * Public function, see header qcbor/qcbor_decode.h file
7669 */
7670void
7671QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe,
7672 const char *szLabel,
7673 const uint8_t uTagRequirement,
7674 const UsefulBuf BufferForMantissa,
7675 UsefulBufC *pMantissa,
7676 bool *pbIsNegative,
7677 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007678{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007679 QCBORItem Item;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007680 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007681
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007682 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007683 {
7684 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007685 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7686 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7687 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007688 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007689
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007690 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7691 TagSpec,
7692 &Item,
7693 BufferForMantissa,
7694 pMantissa,
7695 pbIsNegative,
7696 pnExponent);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007697}
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007698
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07007699#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007700
7701
7702#if !defined(USEFULBUF_DISABLE_ALL_FLOAT) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
7703/*
7704 * Public function, see header qcbor/qcbor_spiffy_decode.h file
7705 */
7706void
7707QCBORDecode_GetNumberConvertPrecisely(QCBORDecodeContext *pMe,
7708 QCBORItem *pNumber)
7709{
7710 QCBORItem Item;
7711 struct IEEE754_ToInt ToInt;
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007712 double dNum;
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007713 QCBORError uError;
7714
7715 if(pMe->uLastError != QCBOR_SUCCESS) {
7716 return;
7717 }
7718
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007719 // TODO:VGetNext?
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007720 uError = QCBORDecode_GetNext(pMe, &Item);
7721 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007722 *pNumber = Item;
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007723 pMe->uLastError = (uint8_t)uError;
7724 return;
7725 }
7726
7727 switch(Item.uDataType) {
7728 case QCBOR_TYPE_INT64:
7729 case QCBOR_TYPE_UINT64:
7730 *pNumber = Item;
7731 break;
7732
7733 case QCBOR_TYPE_DOUBLE:
7734 ToInt = IEEE754_DoubleToInt(Item.val.dfnum);
7735 if(ToInt.type == IEEE754_ToInt_IS_INT) {
7736 pNumber->uDataType = QCBOR_TYPE_INT64;
7737 pNumber->val.int64 = ToInt.integer.is_signed;
7738 } else if(ToInt.type == IEEE754_ToInt_IS_UINT) {
7739 if(ToInt.integer.un_signed <= INT64_MAX) {
7740 /* Do the same as base QCBOR integer decoding */
7741 pNumber->uDataType = QCBOR_TYPE_INT64;
7742 pNumber->val.int64 = (int64_t)ToInt.integer.un_signed;
7743 } else {
7744 pNumber->uDataType = QCBOR_TYPE_UINT64;
7745 pNumber->val.uint64 = ToInt.integer.un_signed;
7746 }
7747 } else {
7748 *pNumber = Item;
7749 }
7750 break;
7751
7752 case QCBOR_TYPE_FLOAT:
7753 ToInt = IEEE754_SingleToInt(Item.val.fnum);
7754 if(ToInt.type == IEEE754_ToInt_IS_INT) {
7755 pNumber->uDataType = QCBOR_TYPE_INT64;
7756 pNumber->val.int64 = ToInt.integer.is_signed;
7757 } else if(ToInt.type == IEEE754_ToInt_IS_UINT) {
7758 if(ToInt.integer.un_signed <= INT64_MAX) {
7759 /* Do the same as base QCBOR integer decoding */
7760 pNumber->uDataType = QCBOR_TYPE_INT64;
7761 pNumber->val.int64 = (int64_t)ToInt.integer.un_signed;
7762 } else {
7763 pNumber->uDataType = QCBOR_TYPE_UINT64;
7764 pNumber->val.uint64 = ToInt.integer.un_signed;
7765 }
7766 } else {
7767 *pNumber = Item;
7768 }
7769 break;
7770
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007771 case QCBOR_TYPE_65BIT_NEG_INT:
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007772 if(Item.val.uint64 == UINT64_MAX) {
7773 /* The value -18446744073709551616 is encoded as an
7774 * unsigned 18446744073709551615. It's a whole number that
7775 * needs to be returned as a double. It can't be handled
7776 * by IEEE754_UintToDouble because 18446744073709551616
7777 * doesn't fit into a uint64_t. You can't get it by adding
7778 * 1 to 18446744073709551615.
7779 */
7780 pNumber->val.dfnum = -18446744073709551616.0;
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007781 pNumber->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007782 } else {
7783 dNum = IEEE754_UintToDouble(Item.val.uint64 + 1, 1);
7784 if(dNum == IEEE754_UINT_TO_DOUBLE_OOB) {
7785 *pNumber = Item;
7786 } else {
7787 pNumber->val.dfnum = dNum;
7788 pNumber->uDataType = QCBOR_TYPE_DOUBLE;
7789 }
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007790 }
7791 break;
7792
7793 default:
7794 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
7795 pNumber->uDataType = QCBOR_TYPE_NONE;
7796 break;
7797 }
7798}
7799
7800#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT && ! QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007801
7802
7803static UsefulBufC
7804QCBORDecode_IntToBigNum(uint64_t uNum,
7805 const UsefulBuf BigNumBuf)
7806{
7807 UsefulOutBuf OB;
7808
7809 /* With a UsefulOutBuf, there's no pointer math here. */
7810 UsefulOutBuf_Init(&OB, BigNumBuf);
7811
7812 /* Must copy one byte even if zero. The loop, mask and shift
7813 * algorithm provides endian conversion.
7814 */
7815 do {
7816 UsefulOutBuf_InsertByte(&OB, uNum & 0xff, 0);
7817 uNum >>= 8;
7818 } while(uNum);
7819
7820 return UsefulOutBuf_OutUBuf(&OB);
7821}
7822
7823
7824static UsefulBufC
7825QCBORDecode_Private_RemoveLeadingZeros(UsefulBufC String)
7826{
7827 while(String.len > 1) {
7828 if(*(const uint8_t *)String.ptr) {
7829 break;
7830 }
7831 String.len--;
7832 String.ptr = (const uint8_t *)String.ptr + 1;
7833 }
7834
7835 return String;
7836}
7837
7838
7839/* Add one to the big number and put the result in a new UsefulBufC
7840 * from storage in UsefulBuf.
7841 *
7842 * Leading zeros must be removed before calling this.
7843 *
7844 * Code Reviewers: THIS FUNCTION DOES POINTER MATH
7845 */
7846static UsefulBufC
7847QCBORDecode_BigNumCopyPlusOne(UsefulBufC BigNum,
7848 UsefulBuf BigNumBuf)
7849{
7850 uint8_t uCarry;
7851 uint8_t uSourceValue;
7852 const uint8_t *pSource;
7853 uint8_t *pDest;
7854 ptrdiff_t uDestBytesLeft;
7855
7856 /* Start adding at the LSB */
7857 pSource = &((const uint8_t *)BigNum.ptr)[BigNum.len-1];
7858 pDest = &((uint8_t *)BigNumBuf.ptr)[BigNumBuf.len-1];
7859
7860 uCarry = 1; /* Gets set back to zero if add the next line doesn't wrap */
7861 *pDest = *pSource + 1;
7862 while(1) {
7863 /* Wrap around from 0xff to 0 is a defined operation for
7864 unsigned addition in C. */
7865 if(*pDest != 0) {
7866 /* The add operation didn't wrap so no more carry. This
7867 * funciton only adds one, so when there is no more carry,
7868 * carrying is over to the end.
7869 */
7870 uCarry = 0;
7871 }
7872
7873 uDestBytesLeft = pDest - (uint8_t *)BigNumBuf.ptr;
7874 if(pSource <= (const uint8_t *)BigNum.ptr && uCarry == 0) {
7875 break; /* Successful exit */
7876 }
7877 if(pSource > (const uint8_t *)BigNum.ptr) {
7878 uSourceValue = *--pSource;
7879 } else {
7880 /* All source bytes processed, but not the last carry */
7881 uSourceValue = 0;
7882 }
7883
7884 pDest--;
7885 if(uDestBytesLeft < 0) {
7886 return NULLUsefulBufC; /* Not enough space in destination buffer */
7887 }
7888
7889 *pDest = uSourceValue + uCarry;
7890 }
7891
7892 return (UsefulBufC){pDest, BigNumBuf.len - (size_t)uDestBytesLeft};
7893}
7894
7895
7896/* This returns 1 when uNum is 0 */
7897static size_t
7898QCBORDecode_Private_CountNonZeroBytes(uint64_t uNum)
7899{
7900 size_t uCount = 0;
7901 do {
7902 uCount++;
7903 uNum >>= 8;
7904 } while(uNum);
7905
7906 return uCount;
7907}
7908
7909
7910/*
7911 * Public function, see header qcbor/qcbor_decode.h
7912 */
7913QCBORError
7914QCBORDecode_BignumPreferred(const QCBORItem Item,
7915 UsefulBuf BigNumBuf,
7916 UsefulBufC *pBigNum,
7917 bool *pbIsNegative)
7918{
7919 QCBORError uResult;
7920 size_t uLen;
7921 UsefulBufC BigNum;
7922 int uType;
7923
7924 uType = Item.uDataType;
7925 if(uType == QCBOR_TYPE_BYTE_STRING) {
7926 uType = *pbIsNegative ? QCBOR_TYPE_POSBIGNUM : QCBOR_TYPE_NEGBIGNUM;
7927 }
7928
7929 static const uint8_t Zero[] = {0x00};
7930 BigNum = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(Zero);
7931 if((uType == QCBOR_TYPE_POSBIGNUM || uType == QCBOR_TYPE_NEGBIGNUM) &&
7932 Item.val.bigNum.len) {
7933 BigNum = QCBORDecode_Private_RemoveLeadingZeros(Item.val.bigNum);
7934 }
7935
7936 /* Compute required length so it can be returned if buffer is too small */
7937 switch(uType) {
7938 case QCBOR_TYPE_INT64:
7939 uLen = QCBORDecode_Private_CountNonZeroBytes((uint64_t)(Item.val.int64 < 0 ? -Item.val.int64 : Item.val.int64));
7940 break;
7941
7942 case QCBOR_TYPE_UINT64:
7943 uLen = QCBORDecode_Private_CountNonZeroBytes(Item.val.uint64);
7944 break;
7945
7946 case QCBOR_TYPE_65BIT_NEG_INT:
7947 uLen = Item.val.uint64 == UINT64_MAX ? 9 : QCBORDecode_Private_CountNonZeroBytes(Item.val.uint64);
7948 break;
7949
7950 case QCBOR_TYPE_POSBIGNUM:
7951 uLen = BigNum.len;
7952 break;
7953
7954 case QCBOR_TYPE_NEGBIGNUM:
7955 uLen = BigNum.len;
7956 if(UsefulBuf_IsValue(BigNum, 0xff) == SIZE_MAX) {
7957 uLen++;
7958 }
7959 break;
7960
7961 default:
7962 uLen = 0;
7963 }
7964
7965 *pBigNum = (UsefulBufC){NULL, uLen};
7966
7967 if(BigNumBuf.len < uLen || uLen == 0 || BigNumBuf.ptr == NULL) {
7968 return BigNumBuf.ptr == NULL ? QCBOR_SUCCESS : QCBOR_ERR_BUFFER_TOO_SMALL;
7969 /* Buffer is too short or type is wrong */
7970 }
7971
7972 uResult = QCBOR_SUCCESS;
7973
7974 if(uType == QCBOR_TYPE_POSBIGNUM) {
7975 *pBigNum = UsefulBuf_Copy(BigNumBuf, BigNum);
7976 *pbIsNegative = false;
7977 } else if(uType == QCBOR_TYPE_UINT64) {
7978 *pBigNum = QCBORDecode_IntToBigNum(Item.val.uint64, BigNumBuf);
7979 *pbIsNegative = false;
7980 } else if(uType == QCBOR_TYPE_INT64) {
7981 *pbIsNegative = Item.val.int64 < 0;
7982 *pBigNum = QCBORDecode_IntToBigNum((uint64_t)(*pbIsNegative ? -Item.val.int64 : Item.val.int64), BigNumBuf);
7983 } else if(uType == QCBOR_TYPE_65BIT_NEG_INT) {
7984 *pbIsNegative = true;
7985 if(Item.val.uint64 == UINT64_MAX) {
7986 /* The one value that can't be done with a computation
7987 * because it would overflow a uint64_t*/
7988 static const uint8_t TwoToThe64[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
7989 *pBigNum = UsefulBuf_Copy(BigNumBuf, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(TwoToThe64));
7990 } else {
7991 *pBigNum = QCBORDecode_IntToBigNum(Item.val.uint64 + 1, BigNumBuf);
7992 }
7993 } else if(uType == QCBOR_TYPE_NEGBIGNUM) {
7994 /* The messy one. Take the stuff in the buffer and copy it to
7995 * the new buffer, adding one to it. This might be one byte
7996 * bigger than the original because of the carry from adding
7997 * one.*/
7998 *pbIsNegative = true;
7999 *pBigNum = QCBORDecode_BigNumCopyPlusOne(BigNum, BigNumBuf);
8000
8001 } else {
8002 uResult = QCBOR_ERR_UNEXPECTED_TYPE;
8003 }
8004
8005 return uResult;
8006}
8007
8008
8009static QCBORError
8010QCBOR_Private_ProcessPreferredBigNum(const uint8_t uTagRequirement,
8011 const QCBORItem *pItem,
8012 UsefulBuf BigNumBuf,
8013 UsefulBufC *pValue,
8014 bool *pbIsNegative)
8015{
8016 if(pItem->uDataType != QCBOR_TYPE_INT64 &&
8017 pItem->uDataType != QCBOR_TYPE_UINT64 &&
8018 pItem->uDataType != QCBOR_TYPE_65BIT_NEG_INT) {
8019
8020 /* The integer types are always OK. If it's not an integer type drop
8021 * in to the tag type checking system. */
8022 const QCBOR_Private_TagSpec TagSpec =
8023 {
8024 uTagRequirement,
8025 {QCBOR_TYPE_POSBIGNUM, QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
8026 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
8027 };
8028
8029 QCBORError uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
8030 if(uErr != QCBOR_SUCCESS) {
8031 return uErr;
8032 }
8033 }
8034
8035 return QCBORDecode_BignumPreferred(*pItem, BigNumBuf, pValue, pbIsNegative);
8036}
8037
8038
8039/*
8040 * Public function, see header qcbor/qcbor_decode.h
8041 */
8042void
8043QCBORDecode_GetBigNumPreferred(QCBORDecodeContext *pMe,
8044 const uint8_t uTagRequirement,
8045 UsefulBuf BigNumBuf,
8046 UsefulBufC *pValue,
8047 bool *pbIsNegative)
8048{
8049 QCBORItem Item;
8050
8051 if(pMe->uLastError != QCBOR_SUCCESS) {
8052 /* Already in error state, do nothing */
8053 return;
8054 }
8055
8056 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
8057 if(uError != QCBOR_SUCCESS) {
8058 pMe->uLastError = (uint8_t)uError;
8059 return;
8060 }
8061
8062 QCBOR_Private_ProcessPreferredBigNum(uTagRequirement, &Item, BigNumBuf, pValue, pbIsNegative);
8063}
8064
8065
8066/*
8067 * Public function, see header qcbor/qcbor_decode.h
8068 */
8069void
8070QCBORDecode_GetPreferredBignumInMapN(QCBORDecodeContext *pMe,
8071 const int64_t nLabel,
8072 const uint8_t uTagRequirement,
8073 UsefulBuf BigNumBuf,
8074 UsefulBufC *pValue,
8075 bool *pbIsNegative)
8076{
8077 QCBORItem Item;
8078 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
8079 if(pMe->uLastError != QCBOR_SUCCESS) {
8080 return;
8081 }
8082
8083 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessPreferredBigNum(uTagRequirement,
8084 &Item,
8085 BigNumBuf,
8086 pValue,
8087 pbIsNegative);
8088}
8089
8090/*
8091 * Public function, see header qcbor/qcbor_decode.h
8092 */
8093void
8094QCBORDecode_GetPreferredBignumInMapSZ(QCBORDecodeContext *pMe,
8095 const char * szLabel,
8096 const uint8_t uTagRequirement,
8097 UsefulBuf BigNumBuf,
8098 UsefulBufC *pValue,
8099 bool *pbIsNegative)
8100{
8101 QCBORItem Item;
8102 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
8103 if(pMe->uLastError != QCBOR_SUCCESS) {
8104 return;
8105 }
8106
8107 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessPreferredBigNum(uTagRequirement,
8108 &Item,
8109 BigNumBuf,
8110 pValue,
8111 pbIsNegative);
8112}
8113
8114