blob: 5edd2d6fb9df03e6594ab2b182157b34061bd3ac [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 Lundblade721b56e2024-10-22 03:02:04 -070037#include "qcbor/qcbor_tag_decode.h"
Laurence Lundblade3f1318a2021-01-04 18:26:44 -080038#include "ieee754.h" /* Does not use math.h */
Laurence Lundbladec7114722020-08-13 05:11:40 -070039
40#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade3f1318a2021-01-04 18:26:44 -080041
42#include <math.h> /* For isnan(), llround(), llroudf(), round(), roundf(),
43 * pow(), exp2()
44 */
45#include <fenv.h> /* feclearexcept(), fetestexcept() */
46
Laurence Lundbladee2c893c2020-12-26 17:41:53 -080047#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070048
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070049
Laurence Lundblade68cb61c2023-02-12 13:21:44 -080050#if (defined(__GNUC__) && !defined(__clang__))
Laurence Lundblade8e36f812024-01-26 10:59:29 -070051/*
Laurence Lundblade68cb61c2023-02-12 13:21:44 -080052 * This is how the -Wmaybe-uninitialized compiler warning is
53 * handled. It can’t be ignored because some version of gcc enable it
54 * with -Wall which is a common and useful gcc warning option. It also
55 * can’t be ignored because it is the goal of QCBOR to compile clean
56 * out of the box in all environments.
57 *
58 * The big problem with -Wmaybe-uninitialized is that it generates
59 * false positives. It complains things are uninitialized when they
60 * are not. This is because it is not a thorough static analyzer. This
61 * is why “maybe” is in its name. The problem is it is just not
62 * thorough enough to understand all the code (and someone saw fit to
63 * put it in gcc and worse to enable it with -Wall).
64 *
65 * One solution would be to change the code so -Wmaybe-uninitialized
66 * doesn’t get confused, for example adding an unnecessary extra
67 * initialization to zero. (If variables were truly uninitialized, the
68 * correct path is to understand the code thoroughly and set them to
69 * the correct value at the correct time; in essence this is already
70 * done; -Wmaybe-uninitialized just can’t tell). This path is not
71 * taken because it makes the code bigger and is kind of the tail
72 * wagging the dog.
73 *
74 * The solution here is to just use a pragma to disable it for the
75 * whole file. Disabling it for each line makes the code fairly ugly
76 * requiring #pragma to push, pop and ignore. Another reason is the
77 * warnings issues vary by version of gcc and which optimization
78 * optimizations are selected. Another reason is that compilers other
79 * than gcc don’t have -Wmaybe-uninitialized.
80 *
81 * One may ask how to be sure these warnings are false positives and
82 * not real issues. 1) The code has been read carefully to check. 2)
83 * Testing is pretty thorough. 3) This code has been run through
84 * thorough high-quality static analyzers.
85 *
86 * In particularly, most of the warnings are about
87 * Item.Item->uDataType being uninitialized. QCBORDecode_GetNext()
88 * *always* sets this value and test case confirm
89 * this. -Wmaybe-uninitialized just can't tell.
90 *
91 * https://stackoverflow.com/questions/5080848/disable-gcc-may-be-used-uninitialized-on-a-particular-variable
92 */
93#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
Laurence Lundblade8e36f812024-01-26 10:59:29 -070094#endif
Laurence Lundblade68cb61c2023-02-12 13:21:44 -080095
96
97
Laurence Lundblade3f1318a2021-01-04 18:26:44 -080098
Laurence Lundbladea9489f82020-09-12 13:50:56 -070099#define SIZEOF_C_ARRAY(array,type) (sizeof(array)/sizeof(type))
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700100
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700101
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800102
103
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700104static bool
105QCBORItem_IsMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700106{
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700107 const uint8_t uDataType = Item.uDataType;
Laurence Lundblade02625d42020-06-25 14:41:41 -0700108 return uDataType == QCBOR_TYPE_MAP ||
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700109#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
110 uDataType == QCBOR_TYPE_MAP_AS_ARRAY ||
111#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
112 uDataType == QCBOR_TYPE_ARRAY;
Laurence Lundblade02625d42020-06-25 14:41:41 -0700113}
114
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700115static bool
116QCBORItem_IsEmptyDefiniteLengthMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700117{
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700118 if(!QCBORItem_IsMapOrArray(Item)){
Laurence Lundblade02625d42020-06-25 14:41:41 -0700119 return false;
120 }
121
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700122 if(Item.val.uCount != 0) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700123 return false;
124 }
125 return true;
126}
127
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700128static bool
129QCBORItem_IsIndefiniteLengthMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700130{
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800131#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700132 if(!QCBORItem_IsMapOrArray(Item)){
Laurence Lundblade02625d42020-06-25 14:41:41 -0700133 return false;
134 }
135
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700136 if(Item.val.uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700137 return false;
138 }
139 return true;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800140#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700141 (void)Item;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800142 return false;
143#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700144}
145
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700146/* Return true if the labels in Item1 and Item2 are the same.
147 Works only for integer and string labels. Returns false
148 for any other type. */
149static bool
150QCBORItem_MatchLabel(const QCBORItem Item1, const QCBORItem Item2)
151{
152 if(Item1.uLabelType == QCBOR_TYPE_INT64) {
153 if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
154 return true;
155 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700156#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700157 } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
158 if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
159 return true;
160 }
161 } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
162 if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
163 return true;
164 }
165 } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
166 if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
167 return true;
168 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700169#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700170 }
171
172 /* Other label types are never matched */
173 return false;
174}
175
176
177/*
178 Returns true if Item1 and Item2 are the same type
179 or if either are of QCBOR_TYPE_ANY.
180 */
181static bool
182QCBORItem_MatchType(const QCBORItem Item1, const QCBORItem Item2)
183{
184 if(Item1.uDataType == Item2.uDataType) {
185 return true;
186 } else if(Item1.uDataType == QCBOR_TYPE_ANY) {
187 return true;
188 } else if(Item2.uDataType == QCBOR_TYPE_ANY) {
189 return true;
190 }
191 return false;
192}
193
Laurence Lundblade02625d42020-06-25 14:41:41 -0700194
Laurence Lundbladeee851742020-01-08 08:37:05 -0800195/*===========================================================================
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700196 DecodeNesting -- Tracking array/map/sequence/bstr-wrapped nesting
Laurence Lundbladeee851742020-01-08 08:37:05 -0800197 ===========================================================================*/
198
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700199/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800200 * See comments about and typedef of QCBORDecodeNesting in qcbor_private.h,
201 * the data structure all these functions work on.
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700202 */
203
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700204
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700205static uint8_t
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700206DecodeNesting_GetCurrentLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700207{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700208 const ptrdiff_t nLevel = pNesting->pCurrent - &(pNesting->pLevels[0]);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800209 /* Limit in DecodeNesting_Descend against more than
210 * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
Laurence Lundblade02625d42020-06-25 14:41:41 -0700211 */
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700212 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700213}
214
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700215
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700216static uint8_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700217DecodeNesting_GetBoundedModeLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700218{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700219 const ptrdiff_t nLevel = pNesting->pCurrentBounded - &(pNesting->pLevels[0]);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800220 /* Limit in DecodeNesting_Descend against more than
221 * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
Laurence Lundblade02625d42020-06-25 14:41:41 -0700222 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700223 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700224}
225
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700226
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700227static uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700228DecodeNesting_GetMapOrArrayStart(const QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700229{
230 return pNesting->pCurrentBounded->u.ma.uStartOffset;
231}
232
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700233
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700234static bool
Laurence Lundblade085d7952020-07-24 10:26:30 -0700235DecodeNesting_IsBoundedEmpty(const QCBORDecodeNesting *pNesting)
236{
237 if(pNesting->pCurrentBounded->u.ma.uCountCursor == QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
238 return true;
239 } else {
240 return false;
241 }
242}
243
244
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700245static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700246DecodeNesting_IsCurrentAtTop(const QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700247{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700248 if(pNesting->pCurrent == &(pNesting->pLevels[0])) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700249 return true;
250 } else {
251 return false;
252 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700253}
254
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700255
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700256static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700257DecodeNesting_IsCurrentDefiniteLength(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700258{
259 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800260 /* Not a map or array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700261 return false;
262 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800263
264#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700265 if(pNesting->pCurrent->u.ma.uCountTotal == QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800266 /* Is indefinite */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700267 return false;
268 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800269
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800270#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
271
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800272 /* All checks passed; is a definte length map or array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700273 return true;
274}
275
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700276static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700277DecodeNesting_IsCurrentBstrWrapped(const QCBORDecodeNesting *pNesting)
Laurence Lundblade642282a2020-06-23 12:00:33 -0700278{
279 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800280 /* is a byte string */
Laurence Lundblade642282a2020-06-23 12:00:33 -0700281 return true;
282 }
283 return false;
284}
285
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700286
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700287static bool
288DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700289{
290 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
291 return true;
292 }
Laurence Lundblade02625d42020-06-25 14:41:41 -0700293 if(pNesting->pCurrent->u.ma.uStartOffset != QCBOR_NON_BOUNDED_OFFSET) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700294 return true;
295 }
296 return false;
297}
298
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700299
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700300static void
301DecodeNesting_SetMapOrArrayBoundedMode(QCBORDecodeNesting *pNesting, bool bIsEmpty, size_t uStart)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700302{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800303 /* Should be only called on maps and arrays */
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700304 /*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800305 * DecodeNesting_EnterBoundedMode() checks to be sure uStart is not
306 * larger than DecodeNesting_EnterBoundedMode which keeps it less than
307 * uin32_t so the cast is safe.
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700308 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700309 pNesting->pCurrent->u.ma.uStartOffset = (uint32_t)uStart;
Laurence Lundblade085d7952020-07-24 10:26:30 -0700310
311 if(bIsEmpty) {
312 pNesting->pCurrent->u.ma.uCountCursor = QCBOR_COUNT_INDICATES_ZERO_LENGTH;
313 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700314}
315
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700316
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700317static void
318DecodeNesting_ClearBoundedMode(QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700319{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700320 pNesting->pCurrent->u.ma.uStartOffset = QCBOR_NON_BOUNDED_OFFSET;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700321}
322
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700323
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700324static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700325DecodeNesting_IsAtEndOfBoundedLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700326{
327 if(pNesting->pCurrentBounded == NULL) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800328 /* No bounded map or array set up */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700329 return false;
330 }
331 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800332 /* Not a map or array; end of those is by byte count */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700333 return false;
334 }
Laurence Lundblade6ab01fb2020-10-01 13:04:49 -0700335 if(!DecodeNesting_IsCurrentBounded(pNesting)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800336 /* In a traveral at a level deeper than the bounded level */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700337 return false;
338 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800339 /* Works for both definite- and indefinitelength maps/arrays */
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800340 if(pNesting->pCurrentBounded->u.ma.uCountCursor != 0 &&
341 pNesting->pCurrentBounded->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800342 /* Count is not zero, still unconsumed item */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700343 return false;
344 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800345 /* All checks passed, got to the end of an array or map*/
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700346 return true;
347}
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700348
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700349
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700350static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700351DecodeNesting_IsEndOfDefiniteLengthMapOrArray(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700352{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800353 /* Must only be called on map / array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700354 if(pNesting->pCurrent->u.ma.uCountCursor == 0) {
355 return true;
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700356 } else {
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700357 return false;
358 }
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700359}
360
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700361
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700362static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700363DecodeNesting_IsCurrentTypeMap(const QCBORDecodeNesting *pNesting)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700364{
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700365 if(pNesting->pCurrent->uLevelType == CBOR_MAJOR_TYPE_MAP) {
366 return true;
367 } else {
368 return false;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700369 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700370}
371
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700372
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700373static bool
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700374DecodeNesting_IsBoundedType(const QCBORDecodeNesting *pNesting, uint8_t uType)
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700375{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700376 if(pNesting->pCurrentBounded == NULL) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700377 return false;
378 }
Laurence Lundblade02625d42020-06-25 14:41:41 -0700379
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700380 uint8_t uItemDataType = pNesting->pCurrentBounded->uLevelType;
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700381#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700382 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
383 uItemDataType = QCBOR_TYPE_ARRAY;
384 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700385#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700386
387 if(uItemDataType != uType) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700388 return false;
389 }
390
391 return true;
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700392}
393
Laurence Lundblade02625d42020-06-25 14:41:41 -0700394
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700395static void
Laurence Lundblade6c8a4442020-06-22 22:16:11 -0700396DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700397{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800398 /* Only call on a definite-length array / map */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700399 pNesting->pCurrent->u.ma.uCountCursor--;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700400}
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700401
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700402
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700403static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700404DecodeNesting_ReverseDecrement(QCBORDecodeNesting *pNesting)
405{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800406 /* Only call on a definite-length array / map */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700407 pNesting->pCurrent->u.ma.uCountCursor++;
408}
409
410
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700411static void
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700412DecodeNesting_Ascend(QCBORDecodeNesting *pNesting)
413{
414 pNesting->pCurrent--;
415}
416
Laurence Lundblade02625d42020-06-25 14:41:41 -0700417
418static QCBORError
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700419DecodeNesting_Descend(QCBORDecodeNesting *pNesting, uint8_t uType)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700420{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800421 /* Error out if nesting is too deep */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700422 if(pNesting->pCurrent >= &(pNesting->pLevels[QCBOR_MAX_ARRAY_NESTING])) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700423 return QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP;
Laurence Lundblade02625d42020-06-25 14:41:41 -0700424 }
425
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800426 /* The actual descend */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700427 pNesting->pCurrent++;
428
429 pNesting->pCurrent->uLevelType = uType;
430
431 return QCBOR_SUCCESS;
432}
433
434
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700435static QCBORError
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800436DecodeNesting_EnterBoundedMapOrArray(QCBORDecodeNesting *pNesting,
437 bool bIsEmpty,
438 size_t uOffset)
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700439{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700440 /*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800441 * Should only be called on map/array.
442 *
443 * Have descended into this before this is called. The job here is
444 * just to mark it in bounded mode.
445 *
446 * Check against QCBOR_MAX_DECODE_INPUT_SIZE make sure that
447 * uOffset doesn't collide with QCBOR_NON_BOUNDED_OFFSET.
448 *
449 * Cast of uOffset to uint32_t for cases where SIZE_MAX < UINT32_MAX.
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700450 */
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -0800451 if((uint32_t)uOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700452 return QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700453 }
454
Laurence Lundblade0750fc42020-06-20 21:02:34 -0700455 pNesting->pCurrentBounded = pNesting->pCurrent;
Laurence Lundblade085d7952020-07-24 10:26:30 -0700456
457 DecodeNesting_SetMapOrArrayBoundedMode(pNesting, bIsEmpty, uOffset);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700458
459 return QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700460}
461
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700462
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700463static QCBORError
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700464DecodeNesting_DescendMapOrArray(QCBORDecodeNesting *pNesting,
Laurence Lundbladeb95afec2024-08-26 10:51:28 -0700465 const uint8_t uQCBORType,
466 const uint16_t uCount)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700467{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700468 QCBORError uError = QCBOR_SUCCESS;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700469
470 if(uCount == 0) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800471 /* Nothing to do for empty definite-length arrays. They are just are
472 * effectively the same as an item that is not a map or array.
473 */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700474 goto Done;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800475 /* Empty indefinite-length maps and arrays are handled elsewhere */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700476 }
477
Laurence Lundbladeb95afec2024-08-26 10:51:28 -0700478 /* Rely on check in QCBOR_Private_DecodeArrayOrMap() for definite-length
479 * arrays and maps that are too long */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700480
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700481 uError = DecodeNesting_Descend(pNesting, uQCBORType);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700482 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700483 goto Done;
484 }
485
Laurence Lundbladeb95afec2024-08-26 10:51:28 -0700486 pNesting->pCurrent->u.ma.uCountCursor = uCount;
487 pNesting->pCurrent->u.ma.uCountTotal = uCount;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700488
489 DecodeNesting_ClearBoundedMode(pNesting);
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700490
491Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700492 return uError;;
493}
494
495
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700496static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700497DecodeNesting_LevelUpCurrent(QCBORDecodeNesting *pNesting)
498{
499 pNesting->pCurrent = pNesting->pCurrentBounded - 1;
500}
501
502
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700503static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700504DecodeNesting_LevelUpBounded(QCBORDecodeNesting *pNesting)
505{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700506 while(pNesting->pCurrentBounded != &(pNesting->pLevels[0])) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700507 pNesting->pCurrentBounded--;
508 if(DecodeNesting_IsCurrentBounded(pNesting)) {
509 break;
510 }
511 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700512}
513
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800514
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700515static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700516DecodeNesting_SetCurrentToBoundedLevel(QCBORDecodeNesting *pNesting)
517{
518 pNesting->pCurrent = pNesting->pCurrentBounded;
519}
520
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700521
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700522static QCBORError
Laurence Lundblade02625d42020-06-25 14:41:41 -0700523DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting,
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700524 uint32_t uEndOffset,
525 uint32_t uStartOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700526{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700527 QCBORError uError;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700528
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700529 uError = DecodeNesting_Descend(pNesting, QCBOR_TYPE_BYTE_STRING);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700530 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700531 goto Done;
532 }
533
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800534 /* Fill in the new byte string level */
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700535 pNesting->pCurrent->u.bs.uSavedEndOffset = uEndOffset;
536 pNesting->pCurrent->u.bs.uBstrStartOffset = uStartOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700537
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800538 /* Bstr wrapped levels are always bounded */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700539 pNesting->pCurrentBounded = pNesting->pCurrent;
540
541Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700542 return uError;;
543}
544
Laurence Lundbladed0304932020-06-27 10:59:38 -0700545
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700546static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700547DecodeNesting_ZeroMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700548{
549 pNesting->pCurrent->u.ma.uCountCursor = 0;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700550}
551
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700552
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700553static void
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800554DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting)
555{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700556 if(pNesting->pCurrent->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
557 pNesting->pCurrentBounded->u.ma.uCountCursor = pNesting->pCurrentBounded->u.ma.uCountTotal;
558 }
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800559}
560
561
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700562static void
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700563DecodeNesting_Init(QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700564{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700565 /* Assumes that *pNesting has been zero'd before this call. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700566 pNesting->pLevels[0].uLevelType = QCBOR_TYPE_BYTE_STRING;
567 pNesting->pCurrent = &(pNesting->pLevels[0]);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700568}
569
570
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700571static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800572DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting,
573 QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700574{
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700575 *pSave = *pNesting;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700576}
577
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700578
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700579static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800580DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting,
581 const QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700582{
583 *pNesting = *pSave;
584}
585
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700586
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700587static uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700588DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700589{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700590 return pMe->pCurrentBounded->u.bs.uSavedEndOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700591}
592
593
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800594
595
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800596#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladeee851742020-01-08 08:37:05 -0800597/*===========================================================================
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800598 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
599
600 The following four functions are pretty wrappers for invocation of
601 the string allocator supplied by the caller.
602
Laurence Lundbladeee851742020-01-08 08:37:05 -0800603 ===========================================================================*/
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800604
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700605static void
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800606StringAllocator_Free(const QCBORInternalAllocator *pMe, const void *pMem)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800607{
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300608 /* This cast to uintptr_t suppresses the "-Wcast-qual" warnings.
609 * This is the one place where the const needs to be cast away so const can
610 * be use in the rest of the code.
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800611 */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300612 (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, 0);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800613}
614
Laurence Lundbladeee851742020-01-08 08:37:05 -0800615// StringAllocator_Reallocate called with pMem NULL is
616// equal to StringAllocator_Allocate()
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700617static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800618StringAllocator_Reallocate(const QCBORInternalAllocator *pMe,
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800619 const void *pMem,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800620 size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800621{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800622 /* See comment in StringAllocator_Free() */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300623 return (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, uSize);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800624}
625
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700626static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800627StringAllocator_Allocate(const QCBORInternalAllocator *pMe, size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800628{
629 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
630}
631
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700632static void
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800633StringAllocator_Destruct(const QCBORInternalAllocator *pMe)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800634{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800635 /* See comment in StringAllocator_Free() */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800636 if(pMe->pfAllocator) {
637 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
638 }
639}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800640#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800641
642
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800643
644
Laurence Lundbladeee851742020-01-08 08:37:05 -0800645/*===========================================================================
646 QCBORDecode -- The main implementation of CBOR decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700647
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800648 See qcbor/qcbor_decode.h for definition of the object
649 used here: QCBORDecodeContext
Laurence Lundbladeee851742020-01-08 08:37:05 -0800650 ===========================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700651/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800652 * Public function, see header file
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700653 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700654void
655QCBORDecode_Init(QCBORDecodeContext *pMe,
656 UsefulBufC EncodedCBOR,
657 QCBORDecodeMode nDecodeMode)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700658{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800659 memset(pMe, 0, sizeof(QCBORDecodeContext));
660 UsefulInputBuf_Init(&(pMe->InBuf), EncodedCBOR);
661 /* Don't bother with error check on decode mode. If a bad value is
662 * passed it will just act as if the default normal mode of 0 was set.
663 */
664 pMe->uDecodeMode = (uint8_t)nDecodeMode;
665 DecodeNesting_Init(&(pMe->nesting));
666
667 /* Inialize me->auMappedTags to CBOR_TAG_INVALID16. See
668 * GetNext_TaggedItem() and MapTagNumber(). */
669 memset(pMe->auMappedTags, 0xff, sizeof(pMe->auMappedTags));
Laurence Lundblade721b56e2024-10-22 03:02:04 -0700670
671 pMe->uTagNumberCheckOffset = SIZE_MAX;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700672}
673
674
Laurence Lundblade721b56e2024-10-22 03:02:04 -0700675/*
676 * Public function, see header file
677 */
678void
679QCBORDecode_CompatibilityV1(QCBORDecodeContext *pMe)
680{
681 pMe->uDecodeMode |= QCBOR_DECODE_UNPROCESSED_TAG_NUMBERS;
682#ifndef QCBOR_DISABLE_TAGS
683 QCBORDecode_InstallTagDecoders(pMe, QCBORDecode_TagDecoderTablev1, NULL);
684#endif /* ! QCBOR_DISABLE_TAGS */
685}
686
687
688
689
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800690#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
691
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700692/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800693 * Public function, see header file
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700694 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700695void
696QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
697 QCBORStringAllocate pfAllocateFunction,
698 void *pAllocateContext,
699 bool bAllStrings)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700700{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800701 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
702 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
703 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700704}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800705#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700706
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800707
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800708
709
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800710
711
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700712/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800713 * Decoding items is done in six layers, one calling the next one
714 * down. If a layer has no work to do for a particular item, it
715 * returns quickly.
716 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700717 * 1. QCBORDecode_Private_GetNextTagContent - The top layer processes
718 * tagged data items, turning them into the local C representation.
719 * For the most simple it is just associating a QCBOR_TYPE with the
720 * data. For the complex ones that an aggregate of data items, there
721 * is some further decoding and some limited recursion.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800722 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700723 * 2. QCBORDecode_Private_GetNextMapOrArray - This manages the
724 * beginnings and ends of maps and arrays. It tracks descending into
725 * and ascending out of maps/arrays. It processes breaks that
726 * terminate indefinite-length maps and arrays.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800727 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700728 * 3. QCBORDecode_Private_GetNextMapEntry - This handles the combining
729 * of two items, the label and the data, that make up a map entry. It
730 * only does work on maps. It combines the label and data items into
731 * one labeled item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800732 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700733 * 4. QCBORDecode_Private_GetNextTagNumber - This decodes type 6 tag
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800734 * numbers. It turns the tag numbers into bit flags associated with
735 * the data item. No actual decoding of the contents of the tag is
736 * performed here.
737 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700738 * 5. QCBORDecode_Private_GetNextFullString - This assembles the
739 * sub-items that make up an indefinite-length string into one string
740 * item. It uses the string allocator to create contiguous space for
741 * the item. It processes all breaks that are part of
742 * indefinite-length strings.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800743 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700744 * 6. QCBOR_Private_DecodeAtomicDataItem - This decodes the atomic
745 * data items in CBOR. Each atomic data item has a "major type", an
746 * integer "argument" and optionally some content. For text and byte
747 * strings, the content is the bytes that make up the string. These
748 * are the smallest data items that are considered to be well-formed.
749 * The content may also be other data items in the case of aggregate
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800750 * types. They are not handled in this layer.
751 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700752 * This uses about 350 bytes of stack. This number comes from
753 * instrumenting (printf address of stack variables) the code on x86
754 * compiled for size optimization.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700755 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800756
757
758/*
759 * Note about use of int and unsigned variables.
760 *
761 * See http://www.unix.org/whitepapers/64bit.html for reasons int is
762 * used carefully here, and in particular why it isn't used in the
763 * public interface. Also see
764 * https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers
765 *
766 * Int is used for values that need less than 16-bits and would be
767 * subject to integer promotion and result in complaining from static
768 * analyzers.
769 */
770
771
772/**
773 * @brief Decode the CBOR head, the type and argument.
774 *
775 * @param[in] pUInBuf The input buffer to read from.
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700776 * @param[in] bRequirePreferred Require preferred serialization for argument.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800777 * @param[out] pnMajorType The decoded major type.
778 * @param[out] puArgument The decoded argument.
779 * @param[out] pnAdditionalInfo The decoded Lower 5 bits of initial byte.
780 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -0700781 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved features
782 * @retval QCBOR_ERR_HIT_END Unexpected end of input
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800783 *
784 * This decodes the CBOR "head" that every CBOR data item has. See
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700785 * longer description in QCBOREncode_EncodeHead().
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800786 *
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700787 * This does the network to host byte order conversion. The conversion
788 * here also provides the conversion for floats in addition to that
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800789 * for lengths, tags and integer values.
790 *
791 * The int type is preferred to uint8_t for some variables as this
792 * avoids integer promotions, can reduce code size and makes static
793 * analyzers happier.
794 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700795static QCBORError
796QCBOR_Private_DecodeHead(UsefulInputBuf *pUInBuf,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700797#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
798 bool bRequirePreferred,
799#endif
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700800 int *pnMajorType,
801 uint64_t *puArgument,
802 int *pnAdditionalInfo)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700803{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800804 QCBORError uReturn;
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700805 uint64_t uArgument;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800806
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700807 /* Get and break down initial byte that every CBOR data item has */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800808 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800809 const int nTmpMajorType = nInitialByte >> 5;
810 const int nAdditionalInfo = nInitialByte & 0x1f;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800811
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800812 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800813 /* Need to get 1,2,4 or 8 additional argument bytes. Map
814 * LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length.
815 */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800816 static const uint8_t aIterate[] = {1,2,4,8};
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800817
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800818 /* Loop getting all the bytes in the argument */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800819 uArgument = 0;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800820 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700821 /* This shift-and-add gives the endian conversion. */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800822 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
823 }
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700824
825#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
826 /* If requested, check that argument is in preferred form */
827 if(bRequirePreferred) {
828 uint64_t uMinArgument;
829
830 if(nAdditionalInfo == LEN_IS_ONE_BYTE) {
831 if(uArgument < 24) {
832 uReturn = QCBOR_ERR_PREFERRED_CONFORMANCE;
833 goto Done;
834 }
835 } else {
836 if(nTmpMajorType != CBOR_MAJOR_TYPE_SIMPLE) {
837 /* Check only if not a floating-point number */
838 int nArgLen = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE - 1];
839 uMinArgument = UINT64_MAX >> ((int)sizeof(uint64_t) - nArgLen) * 8;
840 if(uArgument <= uMinArgument) {
841 uReturn = QCBOR_ERR_PREFERRED_CONFORMANCE;
842 goto Done;
843 }
844 }
845 }
846 }
847#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
848
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800849 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800850 /* The reserved and thus-far unused additional info values */
851 uReturn = QCBOR_ERR_UNSUPPORTED;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800852 goto Done;
853 } else {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700854#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
855 if(bRequirePreferred && nAdditionalInfo == LEN_IS_INDEFINITE) {
856 uReturn = QCBOR_ERR_PREFERRED_CONFORMANCE;
857 goto Done;
858 }
859#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
860
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800861 /* Less than 24, additional info is argument or 31, an
862 * indefinite-length. No more bytes to get.
863 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800864 uArgument = (uint64_t)nAdditionalInfo;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700865 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800866
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700867 if(UsefulInputBuf_GetError(pUInBuf)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800868 uReturn = QCBOR_ERR_HIT_END;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700869 goto Done;
870 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800871
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800872 /* All successful if arrived here. */
873 uReturn = QCBOR_SUCCESS;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800874 *pnMajorType = nTmpMajorType;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800875 *puArgument = uArgument;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800876 *pnAdditionalInfo = nAdditionalInfo;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800877
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700878Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800879 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700880}
881
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800882
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800883/**
884 * @brief Decode integer types, major types 0 and 1.
885 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700886 * @param[in] nMajorType The CBOR major type (0 or 1).
887 * @param[in] uArgument The argument from the head.
888 * @param[in] nAdditionalInfo So it can be error-checked.
889 * @param[out] pDecodedItem The filled in decoded item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800890 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700891 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered.
892 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800893 *
894 * Must only be called when major type is 0 or 1.
895 *
896 * CBOR doesn't explicitly specify two's compliment for integers but
897 * all CPUs use it these days and the test vectors in the RFC are
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700898 * so. All integers in encoded CBOR are unsigned and the CBOR major
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800899 * type indicates positive or negative. CBOR can express positive
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700900 * integers up to 2^64 - 1 negative integers down to -2^64. Note that
901 * negative numbers can be one more
902 * away from zero than positive because there is no negative zero.
903 *
904 * The "65-bit negs" are values CBOR can encode that can't fit
905 * into an int64_t or uint64_t. They decoded as a special type
906 * QCBOR_TYPE_65BIT_NEG_INT. Not that this type does NOT
907 * take into account the offset of one for CBOR negative integers.
908 * It must be applied to get the correct value. Applying this offset
909 * would overflow a uint64_t.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700910 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700911static QCBORError
912QCBOR_Private_DecodeInteger(const int nMajorType,
913 const uint64_t uArgument,
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700914 const int nAdditionalInfo,
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700915 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700916{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800917 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800918
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700919 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
920 uReturn = QCBOR_ERR_BAD_INT;
921 goto Done;
922 }
923
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700924 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800925 if (uArgument <= INT64_MAX) {
926 pDecodedItem->val.int64 = (int64_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700927 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800928
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700929 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800930 pDecodedItem->val.uint64 = uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700931 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700932 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800933
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700934 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800935 if(uArgument <= INT64_MAX) {
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700936 /* INT64_MIN is one further away from 0 than INT64_MAX
937 * so the -1 here doesn't overflow. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800938 pDecodedItem->val.int64 = (-(int64_t)uArgument) - 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700939 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800940
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700941 } else {
Laurence Lundblade2d493002024-02-01 11:09:17 -0700942 pDecodedItem->val.uint64 = uArgument;
943 pDecodedItem->uDataType = QCBOR_TYPE_65BIT_NEG_INT;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700944 }
945 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800946
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700947Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800948 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700949}
950
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800951
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700952/**
953 * @brief Decode text and byte strings
954 *
955 * @param[in] pMe Decoder context.
956 * @param[in] bAllocate Whether to allocate and copy string.
957 * @param[in] nMajorType Whether it is a byte or text string.
958 * @param[in] uStrLen The length of the string.
959 * @param[in] nAdditionalInfo Whether it is an indefinite-length string.
960 * @param[out] pDecodedItem The filled-in decoded item.
961 *
962 * @retval QCBOR_ERR_HIT_END Unexpected end of input.
963 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
964 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
965 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator
966 *
967 * This reads @c uStrlen bytes from the input and fills in @c
968 * pDecodedItem. If @c bAllocate is true, then memory for the string
969 * is allocated.
970 */
971static QCBORError
972QCBOR_Private_DecodeString(QCBORDecodeContext *pMe,
973 const bool bAllocate,
974 const int nMajorType,
975 const uint64_t uStrLen,
976 const int nAdditionalInfo,
977 QCBORItem *pDecodedItem)
978{
979 QCBORError uReturn = QCBOR_SUCCESS;
980
981 /* ---- Figure out the major type ---- */
982 #if CBOR_MAJOR_TYPE_BYTE_STRING + 4 != QCBOR_TYPE_BYTE_STRING
983 #error QCBOR_TYPE_BYTE_STRING not lined up with major type
984 #endif
985
986 #if CBOR_MAJOR_TYPE_TEXT_STRING + 4 != QCBOR_TYPE_TEXT_STRING
987 #error QCBOR_TYPE_TEXT_STRING not lined up with major type
988 #endif
989 pDecodedItem->uDataType = (uint8_t)(nMajorType + 4);
990
991 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
992 /* --- Just the head of an indefinite-length string --- */
993 pDecodedItem->val.string = (UsefulBufC){NULL, QCBOR_STRING_LENGTH_INDEFINITE};
994
995 } else {
996 /* --- A definite-length string --- */
997 /* --- (which might be a chunk of an indefinte-length string) --- */
998
999 /* CBOR lengths can be 64 bits, but size_t is not 64 bits on all
1000 * CPUs. This check makes the casts to size_t below safe.
1001 *
1002 * The max is 4 bytes less than the largest sizeof() so this can be
1003 * tested by putting a SIZE_MAX length in the CBOR test input (no
1004 * one will care the limit on strings is 4 bytes shorter).
1005 */
1006 if(uStrLen > SIZE_MAX-4) {
1007 uReturn = QCBOR_ERR_STRING_TOO_LONG;
1008 goto Done;
1009 }
1010
1011 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(&(pMe->InBuf), (size_t)uStrLen);
1012 if(UsefulBuf_IsNULLC(Bytes)) {
1013 /* Failed to get the bytes for this string item */
1014 uReturn = QCBOR_ERR_HIT_END;
1015 goto Done;
1016 }
1017
1018 if(bAllocate) {
1019#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
1020 /* --- Put string in allocated memory --- */
1021
1022 /* Note that this is not where allocation to coalesce
1023 * indefinite-length strings is done. This is for when the
1024 * caller has requested all strings be allocated. Disabling
1025 * indefinite length strings also disables this allocate-all
1026 * option.
1027 */
1028
1029 if(pMe->StringAllocator.pfAllocator == NULL) {
1030 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1031 goto Done;
1032 }
1033 UsefulBuf NewMem = StringAllocator_Allocate(&(pMe->StringAllocator), (size_t)uStrLen);
1034 if(UsefulBuf_IsNULL(NewMem)) {
1035 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1036 goto Done;
1037 }
1038 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
1039 pDecodedItem->uDataAlloc = 1;
1040#else
1041 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1042#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1043 } else {
1044 /* --- Normal case with no string allocator --- */
1045 pDecodedItem->val.string = Bytes;
1046 }
1047 }
1048
1049Done:
1050 return uReturn;
1051}
1052
1053
1054/**
1055 * @brief Decode array or map.
1056 *
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001057 * @param[in] uDecodeMode3Bit Decoder mode.
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001058 * @param[in] nMajorType Whether it is a byte or text string.
1059 * @param[in] uItemCount The length of the string.
1060 * @param[in] nAdditionalInfo Whether it is an indefinite-length.
1061 * @param[out] pDecodedItem The filled-in decoded item.
1062 *
1063 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinites disabled.
1064 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map.
1065 *
1066 * Not much to do for arrays and maps. Just the type item count (but a
1067 * little messy because of ifdefs for indefinite-lengths and
1068 * map-as-array decoding).
1069 *
1070 * This also does the bulk of the work for @ref
1071 * QCBOR_DECODE_MODE_MAP_AS_ARRAY, a special mode to handle
1072 * arbitrarily complex map labels. This ifdefs out with
1073 * QCBOR_DISABLE_NON_INTEGER_LABELS.
1074 */
1075static QCBORError
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001076QCBOR_Private_DecodeArrayOrMap(const uint8_t uDecodeMode3Bit,
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001077 const int nMajorType,
Laurence Lundbladeb95afec2024-08-26 10:51:28 -07001078 uint64_t uItemCount,
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001079 const int nAdditionalInfo,
1080 QCBORItem *pDecodedItem)
1081{
1082 QCBORError uReturn;
1083
1084 /* ------ Sort out the data type ------ */
1085 #if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
1086 #error QCBOR_TYPE_ARRAY value not lined up with major type
1087 #endif
1088
1089 #if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
1090 #error QCBOR_TYPE_MAP value not lined up with major type
1091 #endif
1092 pDecodedItem->uDataType = (uint8_t)nMajorType;
1093#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001094 if(uDecodeMode3Bit == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001095 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
1096 }
1097#else
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001098 (void)uDecodeMode3Bit;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001099#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
1100
1101 uReturn = QCBOR_SUCCESS;
1102
1103 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1104 /* ------ Indefinite-length array/map ----- */
1105#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
1106 pDecodedItem->val.uCount = QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH;
1107#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1108 uReturn = QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED;
1109#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1110 } else {
Laurence Lundbladeb95afec2024-08-26 10:51:28 -07001111 /* ----- Definite-length array/map ----- */
1112 if(uItemCount > (nMajorType == QCBOR_TYPE_MAP ? QCBOR_MAX_ITEMS_IN_MAP : QCBOR_MAX_ITEMS_IN_ARRAY)) {
1113 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001114
Laurence Lundbladeb95afec2024-08-26 10:51:28 -07001115 } else {
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001116#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001117 if(uDecodeMode3Bit == QCBOR_DECODE_MODE_MAP_AS_ARRAY && nMajorType == QCBOR_TYPE_MAP) {
Laurence Lundbladeb95afec2024-08-26 10:51:28 -07001118 /* ------ Map as array ------ */
1119 uItemCount *= 2;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001120 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001121#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundbladeb95afec2024-08-26 10:51:28 -07001122
1123 /* cast OK because of check above */
1124 pDecodedItem->val.uCount = (uint16_t)uItemCount;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001125 }
1126 }
1127
1128 return uReturn;
1129}
1130
1131
1132/**
1133 * @brief Decode a tag number.
1134 *
1135 * @param[in] uTagNumber The length of the string.
1136 * @param[in] nAdditionalInfo So this can be error-checked.
1137 * @param[out] pDecodedItem The filled-in decoded item.
1138 *
1139 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo is LEN_IS_INDEFINITE.
1140 * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined.
1141 *
1142 * Not much to do for tags, but fill in pDecodedItem and check for
1143 * error in nAdditionalInfo.
1144 */
1145static QCBORError
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001146QCBOR_Private_DecodeTagNumber(const uint64_t uTagNumber,
1147 const int nAdditionalInfo,
1148 QCBORItem *pDecodedItem)
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001149{
1150#ifndef QCBOR_DISABLE_TAGS
1151 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1152 return QCBOR_ERR_BAD_INT;
1153 } else {
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001154 pDecodedItem->val.uTagNumber = uTagNumber;
1155 pDecodedItem->uDataType = QCBOR_TYPE_TAG_NUMBER;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001156 return QCBOR_SUCCESS;
1157 }
1158#else /* QCBOR_DISABLE_TAGS */
1159 (void)nAdditionalInfo;
Laurence Lundblade6c9a8242024-06-12 20:34:52 -07001160 (void)uTagNumber;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001161 (void)pDecodedItem;
1162 return QCBOR_ERR_TAGS_DISABLED;
1163#endif /* QCBOR_DISABLE_TAGS */
1164}
1165
1166
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001167#ifndef USEFULBUF_DISABLE_ALL_FLOAT
1168
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001169#if !defined(QCBOR_DISABLE_DECODE_CONFORMANCE) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
1170
1171static QCBORError
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001172QCBORDecode_Private_HalfConformance(const double d, const uint8_t uDecodeMode3Bit)
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001173{
1174 struct IEEE754_ToInt ToInt;
1175
1176 /* Only need to check for conversion to integer because
1177 * half-precision is always preferred serialization. Don't
1178 * need special checker for half-precision because whole
1179 * numbers always convert perfectly from half to double.
1180 *
1181 * This catches half-precision with NaN payload too.
1182 *
1183 * The only thing allowed here is a double/half-precision that
1184 * can't be converted to anything but a double.
1185 */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001186 if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_DCBOR) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001187 ToInt = IEEE754_DoubleToInt(d);
1188 if(ToInt.type != QCBOR_TYPE_DOUBLE) {
1189 return QCBOR_ERR_DCBOR_CONFORMANCE;
1190 }
1191 }
1192
1193 return QCBOR_SUCCESS;
1194}
1195
1196
1197static QCBORError
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001198QCBORDecode_Private_SingleConformance(const float f, const uint8_t uDecodeMode3Bit)
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001199{
1200 struct IEEE754_ToInt ToInt;
1201 IEEE754_union ToSmaller;
1202
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001203 if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_DCBOR) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001204 /* See if it could have been encoded as an integer */
1205 ToInt = IEEE754_SingleToInt(f);
1206 if(ToInt.type == IEEE754_ToInt_IS_INT || ToInt.type == IEEE754_ToInt_IS_UINT) {
1207 return QCBOR_ERR_DCBOR_CONFORMANCE;
1208 }
1209
1210 /* Make sure there is no NaN payload */
1211 if(IEEE754_SingleHasNaNPayload(f)) {
1212 return QCBOR_ERR_DCBOR_CONFORMANCE;
1213 }
1214 }
1215
1216 /* See if it could have been encoded shorter */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001217 if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_PREFERRED) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001218 ToSmaller = IEEE754_SingleToHalf(f, true);
1219 if(ToSmaller.uSize != sizeof(float)) {
1220 return QCBOR_ERR_PREFERRED_CONFORMANCE;
1221 }
1222 }
1223
1224 return QCBOR_SUCCESS;
1225}
1226
1227
1228static QCBORError
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001229QCBORDecode_Private_DoubleConformance(const double d, uint8_t uDecodeMode3Bit)
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001230{
1231 struct IEEE754_ToInt ToInt;
1232 IEEE754_union ToSmaller;
1233
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001234 if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_DCBOR) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001235 /* See if it could have been encoded as an integer */
1236 ToInt = IEEE754_DoubleToInt(d);
1237 if(ToInt.type == IEEE754_ToInt_IS_INT || ToInt.type == IEEE754_ToInt_IS_UINT) {
1238 return QCBOR_ERR_DCBOR_CONFORMANCE;
1239 }
1240 /* Make sure there is no NaN payload */
1241 if(IEEE754_DoubleHasNaNPayload(d)) {
1242 return QCBOR_ERR_DCBOR_CONFORMANCE;
1243 }
1244 }
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001245
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001246 /* See if it could have been encoded shorter */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001247 if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_PREFERRED) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001248 ToSmaller = IEEE754_DoubleToSmaller(d, true, true);
1249 if(ToSmaller.uSize != sizeof(double)) {
1250 return QCBOR_ERR_PREFERRED_CONFORMANCE;
1251 }
1252 }
1253
1254 return QCBOR_SUCCESS;
1255}
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001256#else /* ! QCBOR_DISABLE_DECODE_CONFORMANCE && ! QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001257
1258static QCBORError
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001259QCBORDecode_Private_SingleConformance(const float f, uint8_t uDecodeMode3Bit)
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001260{
1261 (void)f;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001262 if(uDecodeMode3Bit>= QCBOR_DECODE_MODE_PREFERRED) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001263 return QCBOR_ERR_CANT_CHECK_FLOAT_CONFORMANCE;
1264 } else {
1265 return QCBOR_SUCCESS;
1266 }
1267}
1268
1269static QCBORError
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001270QCBORDecode_Private_DoubleConformance(const double d, uint8_t uDecodeMode3Bit)
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001271{
1272 (void)d;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001273 if(uDecodeMode3Bit>= QCBOR_DECODE_MODE_PREFERRED) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001274 return QCBOR_ERR_CANT_CHECK_FLOAT_CONFORMANCE;
1275 } else {
1276 return QCBOR_SUCCESS;
1277 }
1278}
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001279#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE && ! QCBOR_DISABLE_PREFERRED_FLOAT */
1280
1281
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001282/*
1283 * Decode a float
1284 */
1285static QCBORError
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001286QCBOR_Private_DecodeFloat(const uint8_t uDecodeMode3Bit,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001287 const int nAdditionalInfo,
1288 const uint64_t uArgument,
1289 QCBORItem *pDecodedItem)
1290{
1291 QCBORError uReturn = QCBOR_SUCCESS;
1292 float single;
1293
1294 (void)single; /* Avoid unused error from various #ifndefs */
1295
1296 switch(nAdditionalInfo) {
1297 case HALF_PREC_FLOAT: /* 25 */
1298#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
1299 /* Half-precision is returned as a double. The cast to
1300 * uint16_t is safe because the encoded value was 16 bits. It
1301 * was widened to 64 bits to be passed in here.
1302 */
1303 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uArgument);
1304 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
1305
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001306 uReturn = QCBORDecode_Private_HalfConformance(pDecodedItem->val.dfnum, uDecodeMode3Bit);
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001307 if(uReturn != QCBOR_SUCCESS) {
1308 break;
1309 }
1310#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
1311 uReturn = FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS);
1312 break;
1313
1314 case SINGLE_PREC_FLOAT: /* 26 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001315 /* Single precision is normally returned as a double since
1316 * double is widely supported, there is no loss of precision,
1317 * it makes it easy for the caller in most cases and it can
1318 * be converted back to single with no loss of precision
1319 *
1320 * The cast to uint32_t is safe because the encoded value was
1321 * 32 bits. It was widened to 64 bits to be passed in here.
1322 */
1323 single = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uArgument);
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001324 uReturn = QCBORDecode_Private_SingleConformance(single, uDecodeMode3Bit);
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001325 if(uReturn != QCBOR_SUCCESS) {
1326 break;
1327 }
1328
1329#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1330 /* In the normal case, use HW to convert float to
1331 * double. */
1332 pDecodedItem->val.dfnum = (double)single;
1333 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
1334#else /* QCBOR_DISABLE_FLOAT_HW_USE */
1335 /* Use of float HW is disabled, return as a float. */
1336 pDecodedItem->val.fnum = single;
1337 pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
1338
1339 /* IEEE754_FloatToDouble() could be used here to return as
1340 * a double, but it adds object code and most likely
1341 * anyone disabling FLOAT HW use doesn't care about floats
1342 * and wants to save object code.
1343 */
1344#endif /* ! QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001345 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
1346 break;
1347
1348 case DOUBLE_PREC_FLOAT: /* 27 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001349 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uArgument);
1350 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
1351
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001352 uReturn = QCBORDecode_Private_DoubleConformance(pDecodedItem->val.dfnum, uDecodeMode3Bit);
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001353 if(uReturn != QCBOR_SUCCESS) {
1354 break;
1355 }
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001356 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
1357 break;
1358 }
1359
1360 return uReturn;
1361}
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001362#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */
1363
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001364
1365
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001366/* Make sure #define value line up as DecodeSimple counts on this. */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001367#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
1368#error QCBOR_TYPE_FALSE macro value wrong
1369#endif
1370
1371#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
1372#error QCBOR_TYPE_TRUE macro value wrong
1373#endif
1374
1375#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
1376#error QCBOR_TYPE_NULL macro value wrong
1377#endif
1378
1379#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
1380#error QCBOR_TYPE_UNDEF macro value wrong
1381#endif
1382
Laurence Lundblade0f99d692018-09-26 14:39:28 -07001383#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
1384#error QCBOR_TYPE_BREAK macro value wrong
1385#endif
1386
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001387#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
1388#error QCBOR_TYPE_DOUBLE macro value wrong
1389#endif
1390
1391#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
1392#error QCBOR_TYPE_FLOAT macro value wrong
1393#endif
1394
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001395/**
1396 * @brief Decode major type 7 -- true, false, floating-point, break...
1397 *
1398 * @param[in] nAdditionalInfo The lower five bits from the initial byte.
1399 * @param[in] uArgument The argument from the head.
1400 * @param[out] pDecodedItem The filled in decoded item.
1401 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001402 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1403 * of half-precision disabled
1404 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all float
1405 * decode is disabled.
1406 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of simple
1407 * type in input.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001408 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001409static QCBORError
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001410QCBOR_Private_DecodeType7(const uint8_t uDecodeMode3Bit,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001411 const int nAdditionalInfo,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001412 const uint64_t uArgument,
1413 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001414{
1415 QCBORError uReturn = QCBOR_SUCCESS;
1416
1417 /* uAdditionalInfo is 5 bits from the initial byte. Compile time
1418 * checks above make sure uAdditionalInfo values line up with
1419 * uDataType values. DecodeHead() never returns an AdditionalInfo
1420 * > 0x1f so cast is safe.
1421 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001422 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001423
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001424 switch(nAdditionalInfo) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001425 /* No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they
1426 * are caught before this is called.
1427 */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001428
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001429 case HALF_PREC_FLOAT: /* 25 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001430 case SINGLE_PREC_FLOAT: /* 26 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001431 case DOUBLE_PREC_FLOAT: /* 27 */
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001432#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001433 uReturn = QCBOR_Private_DecodeFloat(uDecodeMode3Bit, nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001434#else
1435 uReturn = QCBOR_ERR_ALL_FLOAT_DISABLED;
1436#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001437 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001438
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001439 case CBOR_SIMPLEV_FALSE: /* 20 */
1440 case CBOR_SIMPLEV_TRUE: /* 21 */
1441 case CBOR_SIMPLEV_NULL: /* 22 */
1442 case CBOR_SIMPLEV_UNDEF: /* 23 */
1443 case CBOR_SIMPLE_BREAK: /* 31 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001444#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001445 if(uDecodeMode3Bit >= QCBOR_ENCODE_MODE_DCBOR &&
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001446 nAdditionalInfo == CBOR_SIMPLEV_UNDEF) {
1447 uReturn = QCBOR_ERR_DCBOR_CONFORMANCE;
1448 goto Done;
1449 }
1450#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001451 break; /* nothing to do */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001452
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001453 case CBOR_SIMPLEV_ONEBYTE: /* 24 */
1454 if(uArgument <= CBOR_SIMPLE_BREAK) {
1455 /* This takes out f8 00 ... f8 1f which should be encoded
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001456 * as e0 … f7 -- preferred serialization check for simple values.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001457 */
1458 uReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001459 goto Done;
1460 }
Laurence Lundblade5e390822019-01-06 12:35:01 -08001461 /* FALLTHROUGH */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001462
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001463 default: /* 0-19 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001464#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001465 if(uDecodeMode3Bit >= QCBOR_ENCODE_MODE_DCBOR &&
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001466 (uArgument < CBOR_SIMPLEV_FALSE || uArgument > CBOR_SIMPLEV_NULL)) {
1467 uReturn = QCBOR_ERR_DCBOR_CONFORMANCE;
1468 goto Done;
1469 }
1470#endif /* !QCBOR_DISABLE_DECODE_CONFORMANCE */
1471
1472 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
1473 /* QCBOR_Private_DecodeHead() will make uArgument equal to
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001474 * nAdditionalInfo when nAdditionalInfo is < 24. This cast is
1475 * safe because the 2, 4 and 8 byte lengths of uNumber are in
1476 * the double/float cases above
Laurence Lundbladeee851742020-01-08 08:37:05 -08001477 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001478 pDecodedItem->val.uSimple = (uint8_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001479 break;
1480 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001481
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001482Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001483 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001484}
1485
1486
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001487/**
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001488 * @brief Decode a single primitive data item (decode layer 6).
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001489 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001490 * @param[in] pMe Decoder context.
1491 * @param[in] bAllocateStrings If true, use allocator for strings.
1492 * @param[out] pDecodedItem The filled-in decoded item.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001493 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001494 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1495 * features
1496 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1497 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1498 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1499 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001500 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001501 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1502 * of half-precision disabled
1503 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1504 * float decode is disabled.
1505 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1506 * simple type in input.
1507 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1508 * in input, but indefinite
1509 * lengths disabled.
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001510 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte.
1511 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map.
1512 * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001513 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001514 * This decodes the most primitive/atomic data item. It does no
1515 * combining of data items.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001516 */
1517static QCBORError
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001518QCBOR_Private_DecodeAtomicDataItem(QCBORDecodeContext *pMe,
1519 const bool bAllocateStrings,
1520 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001521{
1522 QCBORError uReturn;
Laurence Lundbladede2e1502024-08-26 11:37:05 -07001523 int nMajorType = 0;
1524 uint64_t uArgument = 0;
1525 int nAdditionalInfo = 0;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001526 uint8_t uDecodeMode3Bit = pMe->uDecodeMode & QCBOR_DECODE_MODE_MASK;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001527
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001528 memset(pDecodedItem, 0, sizeof(QCBORItem));
1529
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001530 /* Decode the "head" that every CBOR item has into the major type,
1531 * argument and the additional info.
1532 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001533 uReturn = QCBOR_Private_DecodeHead(&(pMe->InBuf),
1534#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
1535 // TODO: make this prettier; will optimizer take out stuff without ifdef?
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001536 uDecodeMode3Bit >= QCBOR_DECODE_MODE_PREFERRED,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001537#endif /* !QCBOR_DISABLE_DECODE_CONFORMANCE */
1538 &nMajorType,
1539 &uArgument,
1540 &nAdditionalInfo);
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001541
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001542 if(uReturn != QCBOR_SUCCESS) {
1543 return uReturn;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001544 }
1545
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001546 /* All the functions below get inlined by the optimizer. This code
1547 * is easier to read with them all being similar functions, even if
1548 * some functions don't do much.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001549 */
1550 switch (nMajorType) {
1551 case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
1552 case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001553 return QCBOR_Private_DecodeInteger(nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001554 break;
1555
1556 case CBOR_MAJOR_TYPE_BYTE_STRING: /* Major type 2 */
1557 case CBOR_MAJOR_TYPE_TEXT_STRING: /* Major type 3 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001558 return QCBOR_Private_DecodeString(pMe, bAllocateStrings, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001559 break;
1560
1561 case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */
1562 case CBOR_MAJOR_TYPE_MAP: /* Major type 5 */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001563 return QCBOR_Private_DecodeArrayOrMap(uDecodeMode3Bit, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001564 break;
1565
1566 case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001567 return QCBOR_Private_DecodeTagNumber(uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001568 break;
1569
1570 case CBOR_MAJOR_TYPE_SIMPLE:
1571 /* Major type 7: float, double, true, false, null... */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001572 return QCBOR_Private_DecodeType7(uDecodeMode3Bit, nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001573 break;
1574
1575 default:
1576 /* Never happens because DecodeHead() should never return > 7 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001577 return QCBOR_ERR_UNSUPPORTED;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001578 break;
1579 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001580}
1581
1582
1583/**
1584 * @brief Process indefinite-length strings (decode layer 5).
1585 *
1586 * @param[in] pMe Decoder context
1587 * @param[out] pDecodedItem The decoded item that work is done on.
1588 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001589 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1590 * features
1591 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1592 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1593 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1594 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1595 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1596 * of half-precision disabled
1597 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1598 * float decode is disabled.
1599 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1600 * simple type in input.
1601 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1602 * in input, but indefinite
1603 * lengths disabled.
1604 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1605 * but no string allocator.
1606 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1607 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1608 * input, but indefinite-length
1609 * strings are disabled.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001610 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001611 * If @c pDecodedItem is not an indefinite-length string, this does nothing.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001612 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001613 * If it is, this loops getting the subsequent chunk data items that
1614 * make up the string. The string allocator is used to make a
1615 * contiguous buffer for the chunks. When this completes @c
1616 * pDecodedItem contains the put-together string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001617 *
1618 * Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001619 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001620static QCBORError
1621QCBORDecode_Private_GetNextFullString(QCBORDecodeContext *pMe,
1622 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001623{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001624 /* Aproximate stack usage
1625 * 64-bit 32-bit
1626 * local vars 32 16
1627 * 2 UsefulBufs 32 16
1628 * QCBORItem 56 52
1629 * TOTAL 120 74
1630 */
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001631 QCBORError uReturn;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001632
1633 /* A note about string allocation -- Memory for strings is
1634 * allocated either because 1) indefinte-length string chunks are
1635 * being coalecsed or 2) caller has requested all strings be
1636 * allocated. The first case is handed below here. The second case
1637 * is handled in DecodeString if the bAllocate is true. That
1638 * boolean originates here with pMe->bStringAllocateAll immediately
1639 * below. That is, QCBOR_Private_DecodeAtomicDataItem() is called
1640 * in two different contexts here 1) main-line processing which is
1641 * where definite-length strings need to be allocated if
1642 * bStringAllocateAll is true and 2) processing chunks of
1643 * indefinite-lengths strings in in which case there must be no
1644 * allocation.
1645 */
1646
1647
1648 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, pMe->bStringAllocateAll, pDecodedItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001649 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001650 goto Done;
1651 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001652
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001653 /* This is where out-of-place break is detected for the whole
1654 * decoding stack. Break is an error for everything that calls
1655 * QCBORDecode_Private_GetNextFullString(), so the check is
1656 * centralized here.
1657 */
1658 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
1659 uReturn = QCBOR_ERR_BAD_BREAK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001660 goto Done;
1661 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001662
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001663
1664 /* Skip out if not an indefinite-length string */
1665 const uint8_t uStringType = pDecodedItem->uDataType;
1666 if(uStringType != QCBOR_TYPE_BYTE_STRING &&
1667 uStringType != QCBOR_TYPE_TEXT_STRING) {
1668 goto Done;
1669 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001670 if(pDecodedItem->val.string.len != QCBOR_STRING_LENGTH_INDEFINITE) {
1671 goto Done;
1672 }
1673
1674#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001675 /* Can't decode indefinite-length strings without a string allocator */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001676 if(!pMe->StringAllocator.pfAllocator) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001677 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1678 goto Done;
1679 }
1680
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001681 /* Loop getting chunks of the indefinite-length string */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001682 UsefulBufC FullString = NULLUsefulBufC;
1683
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001684 for(;;) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001685 /* Get QCBORItem for next chunk */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001686 QCBORItem StringChunkItem;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001687 /* Pass false to DecodeAtomicDataItem() because the individual
1688 * string chunks in an indefinite-length must not be
1689 * allocated. They are always copied into the allocated
1690 * contiguous buffer allocated here.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001691 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001692 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &StringChunkItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001693 if(uReturn) {
1694 break;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001695 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001696
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001697 /* Is item is the marker for end of the indefinite-length string? */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001698 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001699 /* String is complete */
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001700 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301701 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001702 break;
1703 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001704
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001705 /* All chunks must be of the same type, the type of the item
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001706 * that introduces the indefinite-length string. This also
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001707 * catches errors where the chunk is not a string at all and an
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001708 * indefinite-length string inside an indefinite-length string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001709 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001710 if(StringChunkItem.uDataType != uStringType ||
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001711 StringChunkItem.val.string.len == QCBOR_STRING_LENGTH_INDEFINITE) {
1712 uReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001713 break;
1714 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001715
David Navarro9123e5b2022-03-28 16:04:03 +02001716 if (StringChunkItem.val.string.len > 0) {
1717 /* The first time throurgh FullString.ptr is NULL and this is
1718 * equivalent to StringAllocator_Allocate(). Subsequently it is
1719 * not NULL and a reallocation happens.
1720 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001721 UsefulBuf NewMem = StringAllocator_Reallocate(&(pMe->StringAllocator),
David Navarro9123e5b2022-03-28 16:04:03 +02001722 FullString.ptr,
1723 FullString.len + StringChunkItem.val.string.len);
David Navarro9123e5b2022-03-28 16:04:03 +02001724 if(UsefulBuf_IsNULL(NewMem)) {
1725 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1726 break;
1727 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001728
David Navarro9123e5b2022-03-28 16:04:03 +02001729 /* Copy new string chunk to the end of accumulated string */
1730 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001731 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001732 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001733
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001734 if(uReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
1735 /* Getting the item failed, clean up the allocated memory */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001736 StringAllocator_Free(&(pMe->StringAllocator), FullString.ptr);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001737 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001738#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1739 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1740#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001741
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001742Done:
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001743 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001744}
1745
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001746
Laurence Lundblade37286c02022-09-03 10:05:02 -07001747#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001748/**
1749 * @brief This converts a tag number to a shorter mapped value for storage.
1750 *
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001751 * @param[in] pMe The decode context.
1752 * @param[in] uUnMappedTag The tag number to map
1753 * @param[out] puMappedTagNumber The stored tag number.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001754 *
1755 * @return error code.
1756 *
1757 * The main point of mapping tag numbers is make QCBORItem
1758 * smaller. With this mapping storage of 4 tags takes up 8
1759 * bytes. Without, it would take up 32 bytes.
1760 *
1761 * This maps tag numbers greater than QCBOR_LAST_UNMAPPED_TAG.
1762 * QCBOR_LAST_UNMAPPED_TAG is a little smaller than MAX_UINT16.
1763 *
1764 * See also UnMapTagNumber() and @ref QCBORItem.
1765 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001766static QCBORError
1767QCBORDecode_Private_MapTagNumber(QCBORDecodeContext *pMe,
1768 const uint64_t uUnMappedTag,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001769 uint16_t *puMappedTagNumber)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001770{
1771 if(uUnMappedTag > QCBOR_LAST_UNMAPPED_TAG) {
1772 unsigned uTagMapIndex;
1773 /* Is there room in the tag map, or is it in it already? */
1774 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
1775 if(pMe->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID64) {
1776 break;
1777 }
1778 if(pMe->auMappedTags[uTagMapIndex] == uUnMappedTag) {
1779 break;
1780 }
1781 }
1782 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
1783 return QCBOR_ERR_TOO_MANY_TAGS;
1784 }
1785
1786 /* Covers the cases where tag is new and were it is already in the map */
1787 pMe->auMappedTags[uTagMapIndex] = uUnMappedTag;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001788 *puMappedTagNumber = (uint16_t)(uTagMapIndex + QCBOR_LAST_UNMAPPED_TAG + 1);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001789
1790 } else {
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001791 *puMappedTagNumber = (uint16_t)uUnMappedTag;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001792 }
1793
1794 return QCBOR_SUCCESS;
1795}
1796
1797
1798/**
1799 * @brief This converts a mapped tag number to the actual tag number.
1800 *
1801 * @param[in] pMe The decode context.
1802 * @param[in] uMappedTagNumber The stored tag number.
1803 *
1804 * @return The actual tag number is returned or
1805 * @ref CBOR_TAG_INVALID64 on error.
1806 *
1807 * This is the reverse of MapTagNumber()
1808 */
1809static uint64_t
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001810QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe,
1811 const uint16_t uMappedTagNumber)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001812{
1813 if(uMappedTagNumber <= QCBOR_LAST_UNMAPPED_TAG) {
1814 return uMappedTagNumber;
1815 } else if(uMappedTagNumber == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07001816 return CBOR_TAG_INVALID64;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001817 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001818 /* This won't be negative because of code below in
1819 * MapTagNumber()
1820 */
1821 const unsigned uIndex = uMappedTagNumber - (QCBOR_LAST_UNMAPPED_TAG + 1);
1822 return pMe->auMappedTags[uIndex];
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001823 }
1824}
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001825
1826
1827static const struct QCBORTagDecoderEntry *
1828QCBORDecode_Private_LookUpTagDecoder(const struct QCBORTagDecoderEntry *pTagContentTable,
1829 const uint64_t uTagNumber)
1830{
1831 const struct QCBORTagDecoderEntry *pTE;
1832
1833 if(pTagContentTable == NULL) {
1834 return NULL;
1835 }
1836
1837 for(pTE = pTagContentTable; pTE->uTagNumber != CBOR_TAG_INVALID64; pTE++) {
1838 if(pTE->uTagNumber == uTagNumber || pTE->uTagNumber == CBOR_TAG_ANY) {
1839 break;
1840 }
1841 }
1842
1843 if(pTE->uTagNumber == CBOR_TAG_INVALID64) {
1844 return NULL;
1845 }
1846
1847 return pTE;
1848}
1849#endif /* ! QCBOR_DISABLE_TAGS */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001850
Laurence Lundblade9b334962020-08-27 10:55:53 -07001851
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001852/**
1853 * @brief Aggregate all tags wrapping a data item (decode layer 4).
1854 *
1855 * @param[in] pMe Decoder context
1856 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001857 *
1858 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1859 * features
1860 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1861 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1862 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1863 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1864 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1865 * of half-precision disabled
1866 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1867 * float decode is disabled.
1868 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1869 * simple type in input.
1870 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1871 * in input, but indefinite
1872 * lengths disabled.
1873 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1874 * but no string allocator.
1875 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1876 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1877 * input, but indefinite-length
1878 * strings are disabled.
1879 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001880 *
1881 * This loops getting atomic data items until one is not a tag
1882 * number. Usually this is largely pass-through because most
1883 * item are not tag numbers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001884 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001885static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001886QCBORDecode_Private_GetNextTagNumber(QCBORDecodeContext *pMe,
1887 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001888{
Laurence Lundblade37286c02022-09-03 10:05:02 -07001889#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001890 int nIndex;
1891 QCBORError uErr;
1892 uint16_t uMappedTagNumber;
1893 QCBORError uReturn;
1894
1895 /* Accummulate the tag numbers from multiple items here and then
1896 * copy them into the last item, the non-tag-number item.
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001897 */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001898 QCBORMappedTagNumbers auTagNumbers;;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001899
1900 /* Initialize to CBOR_TAG_INVALID16 */
1901 #if CBOR_TAG_INVALID16 != 0xffff
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001902 /* Be sure the memset is initializing to CBOR_TAG_INVALID16 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001903 #err CBOR_TAG_INVALID16 tag not defined as expected
1904 #endif
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001905 memset(auTagNumbers, 0xff, sizeof(auTagNumbers));
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001906
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001907 /* Loop fetching data items until the item fetched is not a tag number */
1908 uReturn = QCBOR_SUCCESS;
1909 for(nIndex = 0; ; nIndex++) {
1910 uErr = QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07001911 if(uErr != QCBOR_SUCCESS) {
1912 uReturn = uErr;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001913 break;
1914 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001915
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001916 if(pDecodedItem->uDataType != QCBOR_TYPE_TAG_NUMBER) {
1917 /* Successful exit from loop; maybe got some tags, maybe not */
1918 memcpy(pDecodedItem->auTagNumbers, auTagNumbers, sizeof(auTagNumbers));
1919 break;
1920 }
1921
1922 if(nIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
1923 /* No room in the item's tag number array */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001924 uReturn = QCBOR_ERR_TOO_MANY_TAGS;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001925 /* Continue on to get all tag numbers wrapping this item even
1926 * though it is erroring out in the end. This allows decoding
1927 * to continue. This is a QCBOR resource limit error, not a
1928 * problem with being well-formed CBOR.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001929 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001930 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001931 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001932
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001933 /* Map the tag number */
1934 uMappedTagNumber = 0;
1935 uReturn = QCBORDecode_Private_MapTagNumber(pMe, pDecodedItem->val.uTagNumber, &uMappedTagNumber);
1936 /* Continue even on error so as to consume all tag numbers
1937 * wrapping this data item so decoding can go on. If
1938 * QCBORDecode_Private_MapTagNumber() errors once it will
1939 * continue to error.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001940 */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001941
1942 auTagNumbers[nIndex] = uMappedTagNumber;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001943 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001944
Laurence Lundblade9b334962020-08-27 10:55:53 -07001945 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001946
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001947#else /* ! QCBOR_DISABLE_TAGS */
Laurence Lundblade37286c02022-09-03 10:05:02 -07001948
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07001949 return QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07001950
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001951#endif /* ! QCBOR_DISABLE_TAGS */
Laurence Lundblade37286c02022-09-03 10:05:02 -07001952}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001953
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001954
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001955/**
1956 * @brief Combine a map entry label and value into one item (decode layer 3).
1957 *
1958 * @param[in] pMe Decoder context
1959 * @param[out] pDecodedItem The decoded item that work is done on.
1960 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001961 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1962 * features
1963 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1964 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1965 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1966 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1967 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1968 * of half-precision disabled
1969 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1970 * float decode is disabled.
1971 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1972 * simple type in input.
1973 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1974 * in input, but indefinite
1975 * lengths disabled.
1976 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1977 * but no string allocator.
1978 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1979 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1980 * input, but indefinite-length
1981 * strings are disabled.
1982 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1983 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1984 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001985 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001986 * If the current nesting level is a map, then this combines pairs of
1987 * items into one data item with a label and value.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001988 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001989 * This is passthrough if the current nesting level is not a map.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001990 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001991 * This also implements maps-as-array mode where a map is treated like
1992 * an array to allow caller to do their own label processing.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001993 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001994static QCBORError
1995QCBORDecode_Private_GetNextMapEntry(QCBORDecodeContext *pMe,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001996 QCBORItem *pDecodedItem,
1997 uint32_t *puLabelEndOffset)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001998{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001999 QCBORItem LabelItem;
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002000 QCBORError uErr, uErr2;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002001
2002 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
2003 if(QCBORDecode_IsUnrecoverableError(uErr)) {
Laurence Lundblade742df4a2018-10-13 20:07:17 +08002004 goto Done;
2005 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002006
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002007 if(!DecodeNesting_IsCurrentTypeMap(&(pMe->nesting))) {
2008 /* Not decoding a map. Nothing to do. */
2009 /* When decoding maps-as-arrays, the type will be
2010 * QCBOR_TYPE_MAP_AS_ARRAY and this function will exit
2011 * here. This is now map processing for maps-as-arrays is not
2012 * done. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002013 goto Done;
2014 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08002015
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002016 /* Decoding a map entry, so the item decoded above was the label */
2017 LabelItem = *pDecodedItem;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002018
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002019 if(puLabelEndOffset != NULL) {
2020 /* Cast is OK because lengths are all 32-bit in QCBOR */
2021 *puLabelEndOffset = (uint32_t)UsefulInputBuf_Tell(&(pMe->InBuf));
2022 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08002023
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002024 /* Get the value of the map item */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002025 uErr2 = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
2026 if(QCBORDecode_IsUnrecoverableError(uErr2)) {
2027 uErr = uErr2;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002028 goto Done;
2029 }
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002030 if(uErr2 != QCBOR_SUCCESS) {
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002031 /* The recoverable error for the value overrides the recoverable
2032 * error for the label, if there was an error for the label */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002033 uErr = uErr2;
2034 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002035
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002036 /* Combine the label item and value item into one */
2037 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
2038 pDecodedItem->uLabelType = LabelItem.uDataType;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09002039
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002040#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002041 /* TODO: QCBOR_DECODE_MODE_MAP_STRINGS_ONLY might have been a bad idea. Maybe
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002042 * get rid of it in QCBOR 2.0
2043 */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002044 if((pMe->uDecodeMode & QCBOR_DECODE_MODE_MASK) == QCBOR_DECODE_MODE_MAP_STRINGS_ONLY &&
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002045 LabelItem.uDataType != QCBOR_TYPE_TEXT_STRING) {
2046 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
2047 goto Done;
2048 }
2049#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
2050
2051 switch(LabelItem.uDataType) {
2052 case QCBOR_TYPE_INT64:
2053 pDecodedItem->label.int64 = LabelItem.val.int64;
2054 break;
2055
2056#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
2057 case QCBOR_TYPE_UINT64:
2058 pDecodedItem->label.uint64 = LabelItem.val.uint64;
2059 break;
2060
2061 case QCBOR_TYPE_TEXT_STRING:
2062 case QCBOR_TYPE_BYTE_STRING:
2063 pDecodedItem->label.string = LabelItem.val.string;
2064 break;
2065#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
2066
2067 default:
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002068 /* It is possible to skip over labels that are non-aggregate
2069 * types like floats, but not to skip over labels that are
2070 * arrays or maps. We might eventually handle more label
2071 * types like floats as they are not too hard and we now
2072 * have QCBOR_DISABLE_NON_INTEGER_LABELS */
2073 if(!pMe->bAllowAllLabels || QCBORItem_IsMapOrArray(LabelItem)) {
2074 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
2075 goto Done;
2076 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002077 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002078
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002079Done:
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002080 return uErr;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002081}
2082
2083
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002084#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002085/**
2086 * @brief Peek and see if next data item is a break;
2087 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002088 * param[in] pUIB UsefulInputBuf to read from.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002089 * @param[out] pbNextIsBreak Indicate if next was a break or not.
2090 *
2091 * @return Any decoding error.
2092 *
2093 * See if next item is a CBOR break. If it is, it is consumed,
2094 * if not it is not consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07002095*/
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002096static QCBORError
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002097QCBOR_Private_NextIsBreak(QCBORDecodeContext *pMe, bool *pbNextIsBreak)
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002098{
2099 *pbNextIsBreak = false;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002100 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) != 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002101 QCBORItem Peek;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002102 size_t uPeek = UsefulInputBuf_Tell(&(pMe->InBuf));
2103 QCBORError uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &Peek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002104 if(uReturn != QCBOR_SUCCESS) {
2105 return uReturn;
2106 }
2107 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002108 /* It is not a break, rewind so it can be processed normally. */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002109 UsefulInputBuf_Seek(&(pMe->InBuf), uPeek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002110 } else {
2111 *pbNextIsBreak = true;
2112 }
2113 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002114
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002115 return QCBOR_SUCCESS;
2116}
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002117#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002118
2119
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002120/**
2121 * @brief Ascend up nesting levels if all items in them have been consumed.
2122 *
2123 * @param[in] pMe The decode context.
2124 * @param[in] bMarkEnd If true mark end of maps/arrays with count of zero.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002125 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002126 *
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002127 * An item was just consumed, now figure out if it was the
2128 * end of an array/map map that can be closed out. That
2129 * may in turn close out the above array/map...
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002130 *
2131 * When ascending indefinite-length arrays and maps, this will correctly
2132 * consume the break for the level above. This is a problem for the
2133 * implementation of QCBORDecode_GetArray() that must not return
2134 * that break. @c pbBreak is set to true to indicate that one
2135 * byte should be removed.
2136 *
2137 * Improvement: this could reduced further if indef is disabled
2138 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002139static QCBORError
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002140QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd, bool *pbBreak)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002141{
2142 QCBORError uReturn;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002143
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002144 /* Loop ascending nesting levels as long as there is ascending to do */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002145 while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002146 if(pbBreak) {
2147 *pbBreak = false;
2148 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002149
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002150 if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) {
2151 /* Nesting level is bstr-wrapped CBOR */
2152
2153 /* Ascent for bstr-wrapped CBOR is always by explicit call
2154 * so no further ascending can happen.
2155 */
2156 break;
2157
2158 } else if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
2159 /* Level is a definite-length array/map */
2160
2161 /* Decrement the item count the definite-length array/map */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002162 DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(&(pMe->nesting));
2163 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002164 /* Didn't close out array/map, so all work here is done */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002165 break;
2166 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002167 /* All items in a definite-length array were consumed so it
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002168 * is time to ascend one level. This happens below.
2169 */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002170
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002171#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002172 } else {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002173 /* Level is an indefinite-length array/map. */
2174
2175 /* Check for a break which is what ends indefinite-length arrays/maps */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002176 bool bIsBreak = false;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002177 uReturn = QCBOR_Private_NextIsBreak(pMe, &bIsBreak);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002178 if(uReturn != QCBOR_SUCCESS) {
2179 goto Done;
2180 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002181
2182 if(!bIsBreak) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002183 /* Not a break so array/map does not close out. All work is done */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002184 break;
2185 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002186
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002187 /* It was a break in an indefinitelength map / array so
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002188 * it is time to ascend one level.
2189 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002190 if(pbBreak) {
2191 *pbBreak = true;
2192 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002193
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002194#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002195 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002196
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002197
2198 /* All items in the array/map have been consumed. */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002199
Laurence Lundblade93d89472020-10-03 22:30:50 -07002200 /* But ascent in bounded mode is only by explicit call to
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002201 * QCBORDecode_ExitBoundedMode().
2202 */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07002203 if(DecodeNesting_IsCurrentBounded(&(pMe->nesting))) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002204 /* Set the count to zero for definite-length arrays to indicate
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002205 * cursor is at end of bounded array/map */
Laurence Lundbladed0304932020-06-27 10:59:38 -07002206 if(bMarkEnd) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002207 /* Used for definite and indefinite to signal end */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07002208 DecodeNesting_ZeroMapOrArrayCount(&(pMe->nesting));
Laurence Lundbladed0304932020-06-27 10:59:38 -07002209
Laurence Lundblade2c1faf92020-06-26 22:43:56 -07002210 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002211 break;
2212 }
2213
2214 /* Finally, actually ascend one level. */
2215 DecodeNesting_Ascend(&(pMe->nesting));
2216 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002217
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002218 uReturn = QCBOR_SUCCESS;
2219
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002220#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002221Done:
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002222#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
2223
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002224 return uReturn;
2225}
2226
2227
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002228/**
2229 * @brief Ascending & Descending out of nesting levels (decode layer 2).
2230 *
2231 * @param[in] pMe Decoder context
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002232 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002233 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002234
2235 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
2236 * features
2237 * @retval QCBOR_ERR_HIT_END Unexpected end of input
2238 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
2239 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
2240 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
2241 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
2242 * of half-precision disabled
2243 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
2244 * float decode is disabled.
2245 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
2246 * simple type in input.
2247 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
2248 * in input, but indefinite
2249 * lengths disabled.
2250 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
2251 * but no string allocator.
2252 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
2253 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
2254 * input, but indefinite-length
2255 * strings are disabled.
2256 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
2257 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
2258 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
2259 * @retval QCBOR_ERR_NO_MORE_ITEMS Need more items for map or array.
2260 * @retval QCBOR_ERR_BAD_BREAK Indefinite-length break in wrong
2261 * place.
2262 * @retval QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP Nesting deeper than QCBOR
2263 * can handle.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002264 *
2265 * This handles the traversal descending into and asecnding out of
2266 * maps, arrays and bstr-wrapped CBOR. It figures out the ends of
2267 * definite- and indefinte-length maps and arrays by looking at the
2268 * item count or finding CBOR breaks. It detects the ends of the
2269 * top-level sequence and of bstr-wrapped CBOR by byte count.
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002270 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002271static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002272QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002273 bool *pbBreak,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002274 QCBORItem *pDecodedItem,
2275 uint32_t *puLabelEndOffset)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002276{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002277 QCBORError uReturn;
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002278 /* ==== First: figure out if at the end of a traversal ==== */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002279
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002280 /* If out of bytes to consume, it is either the end of the
2281 * top-level sequence of some bstr-wrapped CBOR that was entered.
2282 *
2283 * In the case of bstr-wrapped CBOR, the length of the
2284 * UsefulInputBuf was set to that of the bstr-wrapped CBOR. When
2285 * the bstr-wrapped CBOR is exited, the length is set back to the
2286 * top-level's length or to the next highest bstr-wrapped CBOR.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002287 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002288 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) == 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002289 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002290 goto Done;
2291 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07002292
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002293 /* Check to see if at the end of a bounded definite-length map or
2294 * array. The check for a break ending indefinite-length array is
2295 * later in QCBORDecode_NestLevelAscender().
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002296 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002297 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002298 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002299 goto Done;
2300 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002301
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002302 /* ==== Next: not at the end, so get another item ==== */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002303 uReturn = QCBORDecode_Private_GetNextMapEntry(pMe, pDecodedItem, puLabelEndOffset);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002304 if(QCBORDecode_IsUnrecoverableError(uReturn)) {
2305 /* Error is so bad that traversal is not possible. */
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002306 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002307 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05302308
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002309 /* Record the nesting level for this data item before processing
2310 * any of decrementing and descending.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002311 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002312 pDecodedItem->uNestingLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002313
Laurence Lundblade642282a2020-06-23 12:00:33 -07002314
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002315 /* ==== Next: Process the item for descent, ascent, decrement... ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002316 if(QCBORItem_IsMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002317 /* If the new item is a map or array, descend.
2318 *
2319 * Empty indefinite-length maps and arrays are descended into,
2320 * but then ascended out of in the next chunk of code.
2321 *
2322 * Maps and arrays do count as items in the map/array that
2323 * encloses them so a decrement needs to be done for them too,
2324 * but that is done only when all the items in them have been
2325 * processed, not when they are opened with the exception of an
2326 * empty map or array.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002327 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002328 QCBORError uDescendErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002329 uDescendErr = DecodeNesting_DescendMapOrArray(&(pMe->nesting),
Laurence Lundbladeb95afec2024-08-26 10:51:28 -07002330 pDecodedItem->uDataType,
2331 pDecodedItem->val.uCount);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002332 if(uDescendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002333 /* This error is probably a traversal error and it overrides
2334 * the non-traversal error.
2335 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002336 uReturn = uDescendErr;
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002337 goto Done;
2338 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002339 }
2340
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002341 if(!QCBORItem_IsMapOrArray(*pDecodedItem) ||
2342 QCBORItem_IsEmptyDefiniteLengthMapOrArray(*pDecodedItem) ||
2343 QCBORItem_IsIndefiniteLengthMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002344 /* The following cases are handled here:
2345 * - A non-aggregate item like an integer or string
2346 * - An empty definite-length map or array
2347 * - An indefinite-length map or array that might be empty or might not.
2348 *
2349 * QCBORDecode_NestLevelAscender() does the work of decrementing the count
2350 * for an definite-length map/array and break detection for an
2351 * indefinite-0length map/array. If the end of the map/array was
2352 * reached, then it ascends nesting levels, possibly all the way
2353 * to the top level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002354 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002355 QCBORError uAscendErr;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002356 uAscendErr = QCBORDecode_Private_NestLevelAscender(pMe, true, pbBreak);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002357 if(uAscendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002358 /* This error is probably a traversal error and it overrides
2359 * the non-traversal error.
2360 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002361 uReturn = uAscendErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002362 goto Done;
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002363 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05302364 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002365
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002366 /* ==== Last: tell the caller the nest level of the next item ==== */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002367 /* Tell the caller what level is next. This tells them what
2368 * maps/arrays were closed out and makes it possible for them to
2369 * reconstruct the tree with just the information returned in a
2370 * QCBORItem.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002371 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002372 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07002373 /* At end of a bounded map/array; uNextNestLevel 0 to indicate this */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002374 pDecodedItem->uNextNestLevel = 0;
2375 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002376 pDecodedItem->uNextNestLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002377 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002378
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002379Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002380 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002381}
2382
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002383
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002384/**
2385 * @brief Decode tag content for select tags (decoding layer 1).
2386 *
2387 * @param[in] pMe The decode context.
2388 * @param[out] pDecodedItem The decoded item.
2389 *
2390 * @return Decoding error code.
2391 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002392 * CBOR tag numbers for the item were decoded in GetNext_TaggedItem(),
2393 * but the whole tag was not decoded. Here, the whole tags (tag number
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002394 * and tag content) are decoded. This is a
Laurence Lundblade99615302020-11-29 11:19:47 -08002395 * quick pass through for items that are not tags.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002396 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002397static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002398QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2399 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002400{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002401 QCBORError uErr;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002402
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002403 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pDecodedItem, NULL);
2404
2405#ifndef QCBOR_DISABLE_TAGS
2406 uint64_t uTagNumber;
2407 int nTagIndex;
2408 const struct QCBORTagDecoderEntry *pTagDecoder;
2409
2410 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002411 goto Done;
2412 }
2413
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002414 /* Loop over tag numbers in reverse, those closest to content first */
2415 for(nTagIndex = QCBOR_MAX_TAGS_PER_ITEM-1; nTagIndex >= 0; nTagIndex--) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002416
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002417 if(pDecodedItem->auTagNumbers[nTagIndex] == CBOR_TAG_INVALID16) {
2418 continue; /* Empty slot, skip to next */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002419 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002420
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002421 /* See if there's a content decoder for it */
2422 uTagNumber = QCBORDecode_Private_UnMapTagNumber(pMe, pDecodedItem->auTagNumbers[nTagIndex]);
2423 pTagDecoder = QCBORDecode_Private_LookUpTagDecoder(pMe->pTagDecoderTable, uTagNumber);
2424 if(pTagDecoder == NULL) {
2425 break; /* Successful exist -- a tag that we can't decode */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002426 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002427
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002428 /* Call the content decoder */
2429 uErr = pTagDecoder->pfContentDecoder(pMe, pMe->pTagDecodersContext, pTagDecoder->uTagNumber, pDecodedItem);
2430 if(uErr != QCBOR_SUCCESS) {
2431 break; /* Error exit from the loop */
2432 }
2433
2434 /* Remove tag number from list since its content was decoded */
2435 pDecodedItem->auTagNumbers[nTagIndex] = CBOR_TAG_INVALID16;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002436 }
2437
2438Done:
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002439#endif /* ! QCBOR_DISABLE_TAGS */
2440
2441 return uErr;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002442}
2443
2444
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002445/**
2446 * @brief Consume an entire map or array including its contents.
2447 *
2448 * @param[in] pMe The decoder context.
2449 * @param[in] pItemToConsume The array/map whose contents are to be
2450 * consumed.
2451 * @param[out] puNextNestLevel The next nesting level after the item was
2452 * fully consumed.
2453 *
2454 * This may be called when @c pItemToConsume is not an array or
2455 * map. In that case, this is just a pass through for @c puNextNestLevel
2456 * since there is nothing to do.
2457 */
2458static QCBORError
2459QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
2460 const QCBORItem *pItemToConsume,
2461 bool *pbBreak,
2462 uint8_t *puNextNestLevel)
2463{
2464 QCBORError uReturn;
2465 QCBORItem Item;
2466
2467 /* If it is a map or array, this will tell if it is empty. */
2468 const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel);
2469
2470 if(QCBORItem_IsMapOrArray(*pItemToConsume) && !bIsEmpty) {
2471 /* There is only real work to do for non-empty maps and arrays */
2472
2473 /* This works for definite- and indefinite-length maps and
2474 * arrays by using the nesting level
2475 */
2476 do {
2477 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pbBreak, &Item, NULL);
2478 if(QCBORDecode_IsUnrecoverableError(uReturn) ||
2479 uReturn == QCBOR_ERR_NO_MORE_ITEMS) {
2480 goto Done;
2481 }
2482 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
2483
2484 *puNextNestLevel = Item.uNextNestLevel;
2485
2486 uReturn = QCBOR_SUCCESS;
2487
2488 } else {
2489 /* pItemToConsume is not a map or array. Just pass the nesting
2490 * level through. */
2491 *puNextNestLevel = pItemToConsume->uNextNestLevel;
2492
2493 uReturn = QCBOR_SUCCESS;
2494 }
2495
2496Done:
2497 return uReturn;
2498}
2499
2500
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002501#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002502/*
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002503 * This consumes the next item. It returns the starting position of
2504 * the label and the length of the label. It also returns the nest
2505 * level of the item consumed.
2506 */
2507static QCBORError
2508QCBORDecode_Private_GetLabelAndConsume(QCBORDecodeContext *pMe,
2509 uint8_t *puNestLevel,
2510 size_t *puLabelStart,
2511 size_t *puLabelLen)
2512{
2513 QCBORError uErr;
2514 QCBORItem Item;
2515 uint8_t uLevel;
2516 uint32_t uLabelOffset;
2517
2518 /* Get the label and consume it should it be complex */
2519 *puLabelStart = UsefulInputBuf_Tell(&(pMe->InBuf));
2520
2521 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, &Item, &uLabelOffset);
2522 if(uErr != QCBOR_SUCCESS) {
2523 goto Done;
2524 }
2525 *puLabelLen = uLabelOffset - *puLabelStart;
2526 *puNestLevel = Item.uNestingLevel;
2527 uErr = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uLevel);
2528
2529Done:
2530 return uErr;
2531}
2532
2533
2534/* Loop over items in a map until the end of the map looking for
2535 * duplicates. This starts at the current position in the map, not at
2536 * the beginning of the map.
2537 *
2538 * This saves and restores the traversal cursor and nest tracking so
2539 * they are the same on exit as they were on entry.
2540 */
2541static QCBORError
2542QCBORDecode_Private_CheckDups(QCBORDecodeContext *pMe,
2543 const uint8_t uNestLevel,
2544 const size_t uCompareLabelStart,
2545 const size_t uCompareLabelLen)
2546{
2547 QCBORError uErr;
2548 size_t uLabelStart;
2549 size_t uLabelLen;
2550 uint8_t uLevel;
2551 int nCompare;
2552
2553 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2554 const UsefulInputBuf Save = pMe->InBuf;
2555
2556 do {
2557 uErr = QCBORDecode_Private_GetLabelAndConsume(pMe, &uLevel, &uLabelStart, &uLabelLen);
2558 if(uErr != QCBOR_SUCCESS) {
2559 if(uErr == QCBOR_ERR_NO_MORE_ITEMS) {
2560 uErr = QCBOR_SUCCESS; /* Successful end */
2561 }
2562 break;
2563 }
2564
2565 if(uLevel != uNestLevel) {
2566 break; /* Successful end of loop */
2567 }
2568
2569 /* This check for dups works for labels that are preferred
2570 * serialization and are not maps. If the labels are not in
2571 * preferred serialization, then the check has to be more
2572 * complicated and is type-specific because it uses the decoded
2573 * value, not the encoded CBOR. It is further complicated for
2574 * maps because the order of items in a map that is a label
2575 * doesn't matter when checking that is is the duplicate of
2576 * another map that is a label. QCBOR so far only turns on this
2577 * dup checking as part of CDE checking which requires preferred
2578 * serialization. See 5.6 in RFC 8949.
2579 */
2580 nCompare = UsefulInputBuf_Compare(&(pMe->InBuf),
2581 uCompareLabelStart, uCompareLabelLen,
2582 uLabelStart, uLabelLen);
2583 if(nCompare == 0) {
2584 uErr = QCBOR_ERR_DUPLICATE_LABEL;
2585 break;
2586 }
2587 } while (1);
2588
2589 pMe->nesting = SaveNesting;
2590 pMe->InBuf = Save;
2591
2592 return uErr;
2593}
2594
2595
2596/* This does sort order and duplicate detection on a map. The and all
2597 * it's members must be in preferred serialization so the comparisons
2598 * work correctly.
2599 */
2600static QCBORError
2601QCBORDecode_Private_CheckMap(QCBORDecodeContext *pMe, const QCBORItem *pMapToCheck)
2602{
2603 QCBORError uErr;
2604 uint8_t uNestLevel;
2605 size_t offset2, offset1, length2, length1;
2606
2607 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2608 const UsefulInputBuf Save = pMe->InBuf;
2609 pMe->bAllowAllLabels = 1;
2610
2611 /* This loop runs over all the items in the map once, comparing
2612 * each adjacent pair for correct ordering. It also calls CheckDup
2613 * on each one which also runs over the remaining items in the map
2614 * checking for duplicates. So duplicate checking runs in n^2.
2615 */
2616
2617 offset2 = SIZE_MAX;
2618 length2 = SIZE_MAX; // To avoid uninitialized warning
2619 while(1) {
2620 uErr = QCBORDecode_Private_GetLabelAndConsume(pMe, &uNestLevel, &offset1, &length1);
2621 if(uErr != QCBOR_SUCCESS) {
2622 if(uErr == QCBOR_ERR_NO_MORE_ITEMS) {
2623 uErr = QCBOR_SUCCESS; /* Successful exit from loop */
2624 }
2625 break;
2626 }
2627
2628 if(uNestLevel < pMapToCheck->uNextNestLevel) {
2629 break; /* Successful exit from loop */
2630 }
2631
2632 if(offset2 != SIZE_MAX) {
2633 /* Check that the labels are ordered. Check is not done the
2634 * first time through the loop when offset2 is unset. Since
2635 * this does comparison of the items in encoded form they
2636 * must be preferred serialization encoded. See RFC 8949
2637 * 4.2.1.
2638 */
2639 if(UsefulInputBuf_Compare(&(pMe->InBuf), offset2, length2, offset1, length1) > 0) {
2640 uErr = QCBOR_ERR_UNSORTED;
2641 break;
2642 }
2643 }
2644
2645 uErr = QCBORDecode_Private_CheckDups(pMe, pMapToCheck->uNextNestLevel, offset1, length1);
2646 if(uErr != QCBOR_SUCCESS) {
2647 break;
2648 }
2649
2650 offset2 = offset1;
2651 length2 = length1;
2652 }
2653
2654 pMe->bAllowAllLabels = 0;
2655 pMe->nesting = SaveNesting;
2656 pMe->InBuf = Save;
2657
2658 return uErr;
2659}
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002660#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
2661
2662static QCBORError
2663QCBORDecode_Private_GetItemChecks(QCBORDecodeContext *pMe,
2664 QCBORError uErr,
2665 const size_t uOffset,
2666 QCBORItem *pDecodedItem)
2667{
2668 (void)pMe; /* Avoid warning for next two ifdefs */
2669 (void)uOffset;
2670
2671#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
2672 if(uErr == QCBOR_SUCCESS &&
2673 (pMe->uDecodeMode & QCBOR_DECODE_MODE_MASK) >= QCBOR_ENCODE_MODE_CDE &&
2674 pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
2675 /* Traverse map checking sort order and for duplicates */
2676 uErr = QCBORDecode_Private_CheckMap(pMe, pDecodedItem);
2677 }
2678#endif /* ! QCBOR_DISABLE_CONFORMANCE */
2679
2680#ifndef QCBOR_DISABLE_TAGS
2681 if(uErr == QCBOR_SUCCESS &&
2682 !(pMe->uDecodeMode & QCBOR_DECODE_UNPROCESSED_TAG_NUMBERS) &&
2683 pDecodedItem->auTagNumbers[0] != CBOR_TAG_INVALID16) {
2684 /* Not QCBOR v1; there are tag numbers -- check they were consumed */
2685 if(uOffset != pMe->uTagNumberCheckOffset || pMe->uTagNumberIndex != 255) {
2686 uErr = QCBOR_ERR_UNPROCESSED_TAG_NUMBER;
2687 }
2688 }
2689#endif /* ! QCBOR_DISABLE_TAGS */
2690
2691 if(uErr != QCBOR_SUCCESS) {
2692 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2693 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
2694 }
2695
2696 return uErr;
2697}
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002698
2699
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002700/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002701 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002702 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002703QCBORError
2704QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2705{
2706 QCBORError uErr;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002707 size_t uOffset;
2708
2709 uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002710 uErr = QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem);
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002711 uErr = QCBORDecode_Private_GetItemChecks(pMe, uErr, uOffset, pDecodedItem);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002712 return uErr;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002713}
2714
2715
2716/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002717 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08002718 */
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002719QCBORError
2720QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2721{
2722 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2723 const UsefulInputBuf Save = pMe->InBuf;
2724
2725 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
2726
2727 pMe->nesting = SaveNesting;
2728 pMe->InBuf = Save;
2729
2730 return uErr;
2731}
2732
2733
2734/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002735 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002736 */
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002737void
2738QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2739{
2740 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002741 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2742 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002743 return;
2744 }
2745
2746 pMe->uLastError = (uint8_t)QCBORDecode_PeekNext(pMe, pDecodedItem);
2747}
2748
2749
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002750static void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002751QCBORDecode_Private_SaveTagNumbers(QCBORDecodeContext *pMe, const QCBORItem *pItem)
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002752{
2753#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002754 memcpy(pMe->auLastTags, pItem->auTagNumbers, sizeof(pItem->auTagNumbers));
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002755#else
2756 (void)pMe;
2757 (void)pItem;
2758#endif
2759}
2760
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002761/*
2762 * Public function, see header qcbor/qcbor_decode.h file
2763 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002764void
2765QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002766{
2767 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002768 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2769 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002770 return;
2771 }
2772
2773 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem);
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002774 QCBORDecode_Private_SaveTagNumbers(pMe, pDecodedItem);
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002775}
2776
2777
2778/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002779 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002780 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002781QCBORError
2782QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002783{
Laurence Lundblade87495732021-02-26 10:05:55 -07002784 if(puConsumed != NULL) {
2785 *puConsumed = pMe->InBuf.cursor;
2786 }
2787
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002788 QCBORError uReturn = pMe->uLastError;
Laurence Lundblade085d7952020-07-24 10:26:30 -07002789
2790 if(uReturn != QCBOR_SUCCESS) {
2791 goto Done;
2792 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002793
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002794 /* Error out if all the maps/arrays are not closed out */
2795 if(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002796 uReturn = QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002797 goto Done;
2798 }
2799
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002800 /* Error out if not all the bytes are consumed */
2801 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf))) {
Laurence Lundblade085d7952020-07-24 10:26:30 -07002802 uReturn = QCBOR_ERR_EXTRA_BYTES;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002803 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002804
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002805Done:
Laurence Lundblade87495732021-02-26 10:05:55 -07002806 return uReturn;
2807}
2808
2809
2810/*
2811 * Public function, see header qcbor/qcbor_decode.h file
2812 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002813QCBORError
2814QCBORDecode_Finish(QCBORDecodeContext *pMe)
Laurence Lundblade87495732021-02-26 10:05:55 -07002815{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002816#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002817 /* Call the destructor for the string allocator if there is one.
2818 * Always called, even if there are errors; always have to clean up.
2819 */
2820 StringAllocator_Destruct(&(pMe->StringAllocator));
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002821#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002822
Laurence Lundblade87495732021-02-26 10:05:55 -07002823 return QCBORDecode_PartialFinish(pMe, NULL);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002824}
2825
2826
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002827#ifndef QCBOR_DISABLE_TAGS
2828/*
2829 * Public function, see header qcbor/qcbor_decode.h file
2830 */
2831uint64_t
2832QCBORDecode_GetNthTagNumber(const QCBORDecodeContext *pMe,
2833 const QCBORItem *pItem,
2834 uint8_t uIndex)
2835{
2836 if(pItem->uDataType == QCBOR_TYPE_NONE) {
2837 return CBOR_TAG_INVALID64;
2838 }
2839 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2840 return CBOR_TAG_INVALID64;
2841 }
2842
2843 return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->auTagNumbers[uIndex]);
2844}
2845
2846
2847/*
2848 * Public function, see header qcbor/qcbor_decode.h file
2849 */
2850uint64_t
2851QCBORDecode_GetNthTagNumberOfLast(QCBORDecodeContext *pMe,
2852 uint8_t uIndex)
2853{
2854 if(pMe->uLastError != QCBOR_SUCCESS) {
2855 return CBOR_TAG_INVALID64;
2856 }
2857 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2858 return CBOR_TAG_INVALID64;
2859 }
2860
2861 return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->auLastTags[uIndex]);
2862}
2863
2864
2865/*
2866 * Public function, see header qcbor/qcbor_decode.h file
2867 */
2868static uint64_t
2869QCBORDecode_Private_GetNthTagNumberReverse(const QCBORDecodeContext *pMe,
2870 const uint16_t puTagNumbers[],
2871 const uint32_t uIndex)
2872{
2873 uint32_t uArrayIndex;
2874
2875 /* Find number of tag numbers */
2876 for(uArrayIndex = QCBOR_MAX_TAGS_PER_ITEM-1; uArrayIndex > 0; uArrayIndex--) {
2877 if(puTagNumbers[uArrayIndex] != CBOR_TAG_INVALID16) {
2878 break;
2879 }
2880 }
2881 if(uIndex > uArrayIndex) {
2882 return CBOR_TAG_INVALID64;
2883 }
2884
2885 return QCBORDecode_Private_UnMapTagNumber(pMe, puTagNumbers[uArrayIndex - uIndex]);
2886}
2887
2888
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002889/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002890 * Public function, see header qcbor/qcbor_decode.h file
2891 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002892uint64_t
2893QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
2894 const QCBORItem *pItem,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002895 const uint32_t uIndex)
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002896{
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002897 if(pItem->uDataType == QCBOR_TYPE_NONE) {
2898 return CBOR_TAG_INVALID64;
2899 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002900
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002901 return QCBORDecode_Private_GetNthTagNumberReverse(pMe, pItem->auTagNumbers, uIndex);
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002902}
2903
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002904
Laurence Lundblade9b334962020-08-27 10:55:53 -07002905/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002906 * Public function, see header qcbor/qcbor_decode.h file
2907 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002908uint64_t
2909QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe,
2910 uint32_t uIndex)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002911{
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002912 if(pMe->uLastError != QCBOR_SUCCESS) {
2913 return CBOR_TAG_INVALID64;
2914 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002915 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2916 return CBOR_TAG_INVALID64;
Laurence Lundblade9b334962020-08-27 10:55:53 -07002917 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002918
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002919 return QCBORDecode_Private_GetNthTagNumberReverse(pMe, pMe->auLastTags, uIndex);
Laurence Lundblade9b334962020-08-27 10:55:53 -07002920}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002921
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002922
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002923/*
2924 * Public function, see header qcbor/qcbor_decode.h file
2925 */
2926QCBORError
2927QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pMe, uint64_t *puTagNumber)
2928{
2929 QCBORItem Item;
2930 size_t uOffset;
2931 QCBORError uErr;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002932
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002933 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2934 const UsefulInputBuf Save = pMe->InBuf;
2935
2936 uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
2937 if(uOffset == pMe->uTagNumberCheckOffset) {
2938 pMe->uTagNumberIndex++;
2939 } else {
2940 pMe->uTagNumberIndex = 0;
2941 }
2942
2943 *puTagNumber = CBOR_TAG_INVALID64;
2944 uErr = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
2945 if(uErr) {
2946 return uErr;
2947 }
2948
2949 *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &Item, pMe->uTagNumberIndex);
2950 if(*puTagNumber == CBOR_TAG_INVALID64 ||
2951 QCBORDecode_GetNthTagNumber(pMe, &Item, pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
2952 pMe->uTagNumberIndex = QCBOR_ALL_TAGS_PROCESSED;
2953 }
2954 pMe->uTagNumberCheckOffset = uOffset;
2955
2956 pMe->nesting = SaveNesting;
2957 pMe->InBuf = Save;
2958
2959 return QCBOR_SUCCESS;
2960}
2961
2962
2963/*
2964 * Public function, see header qcbor/qcbor_decode.h file
2965 */
2966void
2967QCBORDecode_VGetNextTagNumber(QCBORDecodeContext *pMe, uint64_t *puTagNumber)
2968{
2969 pMe->uLastError = (uint8_t)QCBORDecode_GetNextTagNumber(pMe, puTagNumber);
2970}
2971
2972#endif /* ! QCBOR_DISABLE_TAGS */
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002973
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002974#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladef6531662018-12-04 10:42:22 +09002975
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002976/* ===========================================================================
2977 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002978
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002979 This implements a simple sting allocator for indefinite-length
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002980 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
2981 implements the function type QCBORStringAllocate and allows easy
2982 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09002983
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002984 This particular allocator is built-in for convenience. The caller
2985 can implement their own. All of this following code will get
2986 dead-stripped if QCBORDecode_SetMemPool() is not called.
2987
2988 This is a very primitive memory allocator. It does not track
2989 individual allocations, only a high-water mark. A free or
2990 reallocation must be of the last chunk allocated.
2991
2992 The size of the pool and offset to free memory are packed into the
2993 first 8 bytes of the memory pool so we don't have to keep them in
2994 the decode context. Since the address of the pool may not be
2995 aligned, they have to be packed and unpacked as if they were
2996 serialized data of the wire or such.
2997
2998 The sizes packed in are uint32_t to be the same on all CPU types
2999 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08003000 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003001
3002
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003003static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08003004MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003005{
3006 // Use of UsefulInputBuf is overkill, but it is convenient.
3007 UsefulInputBuf UIB;
3008
Laurence Lundbladeee851742020-01-08 08:37:05 -08003009 // Just assume the size here. It was checked during SetUp so
3010 // the assumption is safe.
Laurence Lundblade93d89472020-10-03 22:30:50 -07003011 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem,QCBOR_DECODE_MIN_MEM_POOL_SIZE});
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003012 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
3013 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
3014 return UsefulInputBuf_GetError(&UIB);
3015}
3016
3017
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003018static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08003019MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003020{
3021 // Use of UsefulOutBuf is overkill, but convenient. The
3022 // length check performed here is useful.
3023 UsefulOutBuf UOB;
3024
3025 UsefulOutBuf_Init(&UOB, Pool);
3026 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
3027 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
3028 return UsefulOutBuf_GetError(&UOB);
3029}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003030
3031
3032/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003033 Internal function for an allocation, reallocation free and destuct.
3034
3035 Having only one function rather than one each per mode saves space in
3036 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003037
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003038 Code Reviewers: THIS FUNCTION DOES POINTER MATH
3039 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08003040static UsefulBuf
3041MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003042{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003043 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003044
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003045 uint32_t uPoolSize;
3046 uint32_t uFreeOffset;
3047
3048 if(uNewSize > UINT32_MAX) {
3049 // This allocator is only good up to 4GB. This check should
3050 // optimize out if sizeof(size_t) == sizeof(uint32_t)
3051 goto Done;
3052 }
3053 const uint32_t uNewSize32 = (uint32_t)uNewSize;
3054
3055 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
3056 goto Done;
3057 }
3058
3059 if(uNewSize) {
3060 if(pMem) {
3061 // REALLOCATION MODE
3062 // Calculate pointer to the end of the memory pool. It is
3063 // assumed that pPool + uPoolSize won't wrap around by
3064 // assuming the caller won't pass a pool buffer in that is
3065 // not in legitimate memory space.
3066 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
3067
3068 // Check that the pointer for reallocation is in the range of the
3069 // pool. This also makes sure that pointer math further down
3070 // doesn't wrap under or over.
3071 if(pMem >= pPool && pMem < pPoolEnd) {
3072 // Offset to start of chunk for reallocation. This won't
3073 // wrap under because of check that pMem >= pPool. Cast
3074 // is safe because the pool is always less than UINT32_MAX
3075 // because of check in QCBORDecode_SetMemPool().
3076 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3077
3078 // Check to see if the allocation will fit. uPoolSize -
3079 // uMemOffset will not wrap under because of check that
3080 // pMem is in the range of the uPoolSize by check above.
3081 if(uNewSize <= uPoolSize - uMemOffset) {
3082 ReturnValue.ptr = pMem;
3083 ReturnValue.len = uNewSize;
3084
3085 // Addition won't wrap around over because uNewSize was
3086 // checked to be sure it is less than the pool size.
3087 uFreeOffset = uMemOffset + uNewSize32;
3088 }
3089 }
3090 } else {
3091 // ALLOCATION MODE
3092 // uPoolSize - uFreeOffset will not underflow because this
3093 // pool implementation makes sure uFreeOffset is always
3094 // smaller than uPoolSize through this check here and
3095 // reallocation case.
3096 if(uNewSize <= uPoolSize - uFreeOffset) {
3097 ReturnValue.len = uNewSize;
3098 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08003099 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003100 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003101 }
3102 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003103 if(pMem) {
3104 // FREE MODE
3105 // Cast is safe because of limit on pool size in
3106 // QCBORDecode_SetMemPool()
3107 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3108 } else {
3109 // DESTRUCT MODE
3110 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003111 }
3112 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003113
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003114 UsefulBuf Pool = {pPool, uPoolSize};
3115 MemPool_Pack(Pool, uFreeOffset);
3116
3117Done:
3118 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003119}
3120
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003121
Laurence Lundbladef6531662018-12-04 10:42:22 +09003122/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003123 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09003124 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003125QCBORError
3126QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
3127 UsefulBuf Pool,
3128 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003129{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003130 // The pool size and free mem offset are packed into the beginning
Dave Thaler93c01182022-08-06 15:08:35 -04003131 // of the pool memory. This compile time check makes sure the
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003132 // constant in the header is correct. This check should optimize
3133 // down to nothing.
Dave Thaler93c01182022-08-06 15:08:35 -04003134#ifdef _MSC_VER
3135#pragma warning(push)
3136#pragma warning(disable:4127) // conditional expression is constant
3137#endif
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003138 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003139 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003140 }
Dave Thaler93c01182022-08-06 15:08:35 -04003141#ifdef _MSC_VER
3142#pragma warning(pop)
3143#endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003144
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003145 // The pool size and free offset packed in to the beginning of pool
3146 // memory are only 32-bits. This check will optimize out on 32-bit
3147 // machines.
3148 if(Pool.len > UINT32_MAX) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003149 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003150 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003151
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003152 // This checks that the pool buffer given is big enough.
3153 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003154 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003155 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003156
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003157 QCBORDecode_SetUpAllocator(pMe, MemPool_Function, Pool.ptr, bAllStrings);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003158
Laurence Lundblade30816f22018-11-10 13:40:22 +07003159 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003160}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003161#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003162
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003163
3164
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003165/*
3166 * Public function, see header qcbor/qcbor_decode.h file
3167 */
3168void
3169QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003170{
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003171 QCBORDecode_VGetNext(pMe, pDecodedItem);
3172
3173 if(pMe->uLastError == QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003174 pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL,
Máté Tóth-Pálc6d59682021-05-26 18:55:30 +02003175 &pDecodedItem->uNextNestLevel);
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003176 }
3177}
3178
3179
Laurence Lundblade11654912024-05-09 11:49:24 -07003180/*
3181 * Public function, see header qcbor/qcbor_decode.h file
3182 */
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003183QCBORError
3184QCBORDecode_EndCheck(QCBORDecodeContext *pMe)
Laurence Lundblade11654912024-05-09 11:49:24 -07003185{
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003186 size_t uCursorOffset;
3187 QCBORError uErr;
Laurence Lundblade11654912024-05-09 11:49:24 -07003188
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003189 uErr = QCBORDecode_GetError(pMe);
3190 if(uErr != QCBOR_SUCCESS) {
3191 return uErr;
Laurence Lundblade11654912024-05-09 11:49:24 -07003192 }
3193
3194 uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
3195
3196 if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003197 return QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade11654912024-05-09 11:49:24 -07003198 }
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003199
3200 return QCBOR_SUCCESS;
Laurence Lundblade11654912024-05-09 11:49:24 -07003201}
3202
3203
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003204/**
3205 * @brief Rewind cursor to start as if map or array were just entered.
3206 *
3207 * @param[in] pMe The decoding context
3208 *
3209 * This affects the nesting tracking and the UsefulInputBuf.
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003210 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003211static void
3212QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003213{
3214 /* Reset nesting tracking to the deepest bounded level */
3215 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3216
3217 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3218
3219 /* Reposition traversal cursor to the start of the map/array */
3220 UsefulInputBuf_Seek(&(pMe->InBuf),
3221 DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
3222}
3223
3224
3225/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003226 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003227 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003228void
3229QCBORDecode_Rewind(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003230{
3231 if(pMe->nesting.pCurrentBounded != NULL) {
3232 /* In a bounded map, array or bstr-wrapped CBOR */
3233
3234 if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
3235 /* In bstr-wrapped CBOR. */
3236
3237 /* Reposition traversal cursor to start of wrapping byte string */
3238 UsefulInputBuf_Seek(&(pMe->InBuf),
3239 pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
3240 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3241
3242 } else {
3243 /* In a map or array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003244 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003245 }
3246
3247 } else {
3248 /* Not in anything bounded */
3249
3250 /* Reposition traversal cursor to the start of input CBOR */
3251 UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
3252
3253 /* Reset nesting tracking to beginning of input. */
3254 DecodeNesting_Init(&(pMe->nesting));
3255 }
3256
3257 pMe->uLastError = QCBOR_SUCCESS;
3258}
3259
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003260
Laurence Lundblade9b334962020-08-27 10:55:53 -07003261
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003262
3263
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003264typedef struct {
3265 void *pCBContext;
3266 QCBORItemCallback pfCallback;
3267} MapSearchCallBack;
3268
3269typedef struct {
3270 size_t uStartOffset;
3271 uint16_t uItemCount;
3272} MapSearchInfo;
3273
3274
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003275/**
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003276 * @brief Search a map for a set of items.
3277 *
3278 * @param[in] pMe The decode context to search.
3279 * @param[in,out] pItemArray The items to search for and the items found.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003280 * @param[out] pInfo Several bits of meta-info returned by search.
3281 * @param[in] pCallBack Callback object or @c NULL.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003282 *
3283 * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map.
3284 *
3285 * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label)
3286 * were found for one of the labels being
3287 * search for. This duplicate detection is
3288 * only performed for items in pItemArray,
3289 * not every item in the map.
3290 *
3291 * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was
3292 * wrong for the matchd label.
3293 *
3294 * @retval Also errors returned by QCBORDecode_GetNext().
3295 *
3296 * On input, \c pItemArray contains a list of labels and data types of
3297 * items to be found.
3298 *
3299 * On output, the fully retrieved items are filled in with values and
3300 * such. The label was matched, so it never changes.
3301 *
3302 * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE.
3303 *
3304 * This also finds the ends of maps and arrays when they are exited.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003305 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003306static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003307QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
3308 QCBORItem *pItemArray,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003309 MapSearchInfo *pInfo,
3310 MapSearchCallBack *pCallBack)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003311{
Laurence Lundbladee6f15112020-07-23 18:44:16 -07003312 QCBORError uReturn;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003313 uint64_t uFoundItemBitMap = 0;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07003314
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003315 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003316 uReturn = pMe->uLastError;
3317 goto Done2;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003318 }
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003319
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003320 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) &&
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003321 pItemArray->uLabelType != QCBOR_TYPE_NONE) {
3322 /* QCBOR_TYPE_NONE as first item indicates just looking
3323 for the end of an array, so don't give error. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003324 uReturn = QCBOR_ERR_MAP_NOT_ENTERED;
3325 goto Done2;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003326 }
3327
Laurence Lundblade085d7952020-07-24 10:26:30 -07003328 if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) {
3329 // It is an empty bounded array or map
3330 if(pItemArray->uLabelType == QCBOR_TYPE_NONE) {
3331 // Just trying to find the end of the map or array
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003332 pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003333 uReturn = QCBOR_SUCCESS;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003334 } else {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003335 // Nothing is ever found in an empty array or map. All items
3336 // are marked as not found below.
Laurence Lundblade085d7952020-07-24 10:26:30 -07003337 uReturn = QCBOR_SUCCESS;
3338 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003339 goto Done2;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003340 }
3341
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003342 QCBORDecodeNesting SaveNesting;
Laurence Lundblade11654912024-05-09 11:49:24 -07003343 size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003344 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3345
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003346 /* Reposition to search from the start of the map / array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003347 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundblade1341c592020-04-11 14:19:05 -07003348
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003349 /*
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003350 Loop over all the items in the map or array. Each item
3351 could be a map or array, but label matching is only at
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003352 the main level. This handles definite- and indefinite-
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003353 length maps and arrays. The only reason this is ever
3354 called on arrays is to find their end position.
3355
3356 This will always run over all items in order to do
3357 duplicate detection.
3358
3359 This will exit with failure if it encounters an
3360 unrecoverable error, but continue on for recoverable
3361 errors.
3362
3363 If a recoverable error occurs on a matched item, then
3364 that error code is returned.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003365 */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07003366 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003367 if(pInfo) {
3368 pInfo->uItemCount = 0;
3369 }
Máté Tóth-Pál2f2aa5f2021-05-17 21:35:09 +02003370 uint8_t uNextNestLevel;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003371 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003372 /* Remember offset of the item because sometimes it has to be returned */
Laurence Lundblade1341c592020-04-11 14:19:05 -07003373 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003374
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003375 /* Get the item */
3376 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003377 /* QCBORDecode_Private_GetNextTagContent() rather than GetNext()
3378 * because a label match is performed on recoverable errors to
3379 * be able to return the the error code for the found item. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003380 QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003381 if(QCBORDecode_IsUnrecoverableError(uResult)) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003382 /* The map/array can't be decoded when unrecoverable errors occur */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003383 uReturn = uResult;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003384 goto Done;
3385 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003386 if(uResult == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003387 /* Unexpected end of map or array. */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003388 uReturn = uResult;
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003389 goto Done;
3390 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003391
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003392 /* See if item has one of the labels that are of interest */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003393 bool bMatched = false;
3394 for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003395 if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003396 /* A label match has been found */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003397 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
3398 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003399 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003400 }
Laurence Lundblade63926052021-03-29 16:05:51 -07003401 if(uResult != QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003402 /* The label matches, but the data item is in error.
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003403 * It is OK to have recoverable errors on items that
3404 * are not matched. */
Laurence Lundblade63926052021-03-29 16:05:51 -07003405 uReturn = uResult;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003406 goto Done;
3407 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003408 if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) {
Laurence Lundblade63926052021-03-29 16:05:51 -07003409 /* The data item is not of the type(s) requested */
3410 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003411 goto Done;
3412 }
3413
Laurence Lundblade1341c592020-04-11 14:19:05 -07003414 /* Successful match. Return the item. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003415 pItemArray[nIndex] = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003416 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003417 if(pInfo) {
3418 pInfo->uStartOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003419 }
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003420 bMatched = true;
3421 }
3422 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003423
3424
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003425 if(!bMatched && pCallBack != NULL) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003426 /*
3427 Call the callback on unmatched labels.
3428 (It is tempting to do duplicate detection here, but that would
3429 require dynamic memory allocation because the number of labels
3430 that might be encountered is unbounded.)
3431 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003432 uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item);
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003433 if(uReturn != QCBOR_SUCCESS) {
3434 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003435 }
3436 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003437
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003438 /*
3439 Consume the item whether matched or not. This
3440 does the work of traversing maps and array and
3441 everything in them. In this loop only the
3442 items at the current nesting level are examined
3443 to match the labels.
3444 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003445 uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel);
Laurence Lundbladec7114722020-08-13 05:11:40 -07003446 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003447 goto Done;
3448 }
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003449
3450 if(pInfo) {
3451 pInfo->uItemCount++;
3452 }
3453
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003454 } while (uNextNestLevel >= uMapNestLevel);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003455
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003456 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003457
3458 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003459
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003460 // Check here makes sure that this won't accidentally be
3461 // QCBOR_MAP_OFFSET_CACHE_INVALID which is larger than
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003462 // QCBOR_MAX_DECODE_INPUT_SIZE.
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -08003463 // Cast to uint32_t to possibly address cases where SIZE_MAX < UINT32_MAX
3464 if((uint32_t)uEndOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003465 uReturn = QCBOR_ERR_INPUT_TOO_LARGE;
3466 goto Done;
3467 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003468 /* Cast OK because encoded CBOR is limited to UINT32_MAX */
3469 pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003470
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003471 Done:
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003472 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade11654912024-05-09 11:49:24 -07003473 UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos);
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003474
3475 Done2:
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003476 /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */
Laurence Lundbladec7114722020-08-13 05:11:40 -07003477 for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003478 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003479 pItemArray[i].uDataType = QCBOR_TYPE_NONE;
3480 pItemArray[i].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003481 }
3482 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003483
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003484 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003485}
3486
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003487
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003488/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003489 * Public function, see header qcbor/qcbor_decode.h file
3490 */
3491void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003492QCBORDecode_SeekToLabelN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003493{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003494 MapSearchInfo Info;
3495 QCBORItem OneItemSeach[2];
3496
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003497 if(pMe->uLastError != QCBOR_SUCCESS) {
3498 return;
3499 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003500
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003501 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3502 OneItemSeach[0].label.int64 = nLabel;
3503 OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
3504 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
3505
3506 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
3507 if(pMe->uLastError == QCBOR_SUCCESS) {
3508 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
3509 }
3510}
3511
3512
3513void
3514QCBORDecode_SeekToLabelSZ(QCBORDecodeContext *pMe, const char *szLabel)
3515{
3516#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
3517 MapSearchInfo Info;
3518 QCBORItem OneItemSeach[2];
3519
3520 if(pMe->uLastError != QCBOR_SUCCESS) {
3521 return;
3522 }
3523
3524 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3525 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3526 OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
3527 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
3528
3529 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
3530 if(pMe->uLastError == QCBOR_SUCCESS) {
3531 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
3532 }
3533#else
3534 (void)pMe;
3535 (void)szLabel;
3536 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
3537#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
3538}
3539
3540
3541void
3542QCBORDecode_Private_GetItemInMapNoCheck(QCBORDecodeContext *pMe,
3543 QCBORItem *OneItemSeach,
3544 QCBORItem *pItem,
3545 size_t *puOffset)
3546{
3547 QCBORError uErr;
3548 MapSearchInfo SearchInfo;
3549
3550 if(pMe->uLastError != QCBOR_SUCCESS) {
3551 return;
3552 }
3553
3554 uErr = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &SearchInfo, NULL);
3555
3556 if(uErr == QCBOR_SUCCESS && OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
3557 uErr = QCBOR_ERR_LABEL_NOT_FOUND;
3558 }
3559 *pItem = OneItemSeach[0];
3560 *puOffset = SearchInfo.uStartOffset;
3561
3562 if(uErr == QCBOR_SUCCESS) {
3563 QCBORDecode_Private_SaveTagNumbers(pMe, pItem);
3564 }
3565
3566 pMe->uLastError = (uint8_t)uErr;
3567}
3568
3569
3570static void
3571QCBORDecode_Private_GetItemInMap(QCBORDecodeContext *pMe, QCBORItem *OneItemSeach, QCBORItem *pItem)
3572{
3573 QCBORError uErr;
3574 size_t uOffset;
3575
3576 QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, &uOffset);
3577
3578 uErr = QCBORDecode_Private_GetItemChecks(pMe, pMe->uLastError, uOffset, pItem);
3579 if(uErr != QCBOR_SUCCESS) {
3580 goto Done;
3581 }
3582
3583 QCBORDecode_Private_SaveTagNumbers(pMe, pItem);
3584
3585Done:
3586 pMe->uLastError = (uint8_t)uErr;
3587}
3588
3589
3590/*
3591 * Public function, see header qcbor/qcbor_decode.h file
3592 */
3593void
3594QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
3595 const int64_t nLabel,
3596 const uint8_t uQcborType,
3597 QCBORItem *pItem)
3598{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003599 QCBORItem OneItemSeach[2];
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003600
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003601 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3602 OneItemSeach[0].label.int64 = nLabel;
3603 OneItemSeach[0].uDataType = uQcborType;
3604 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003605
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003606 QCBORDecode_Private_GetItemInMap(pMe, OneItemSeach, pItem);
3607}
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003608
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003609
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003610/**
3611 * @brief Get an item by label by type.
3612 *
3613 * @param[in] pMe The decode context.
3614 * @param[in] nLabel The label to search map for.
3615 * @param[in] uQcborType The QCBOR type to look for.
3616 * @param[out] pItem The item found.
3617 * @param[out] puOffset The offset of item for tag consumption check.
3618 *
3619 * This finds the item with the given label in currently open
3620 * map. This does not call QCBORDecode_Private_GetItemChecks()
3621 * to check tag number consumption or decode conformance.
3622 */
3623static void
3624QCBORDecode_GetItemInMapNoCheckN(QCBORDecodeContext *pMe,
3625 const int64_t nLabel,
3626 const uint8_t uQcborType,
3627 QCBORItem *pItem,
3628 size_t *puOffset)
3629{
3630 QCBORItem OneItemSeach[2];
Laurence Lundblade1341c592020-04-11 14:19:05 -07003631
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003632 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3633 OneItemSeach[0].label.int64 = nLabel;
3634 OneItemSeach[0].uDataType = uQcborType;
3635 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003636
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003637 QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, puOffset);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003638}
3639
3640
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003641/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003642 * Public function, see header qcbor/qcbor_decode.h file
3643 */
3644void
3645QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
3646 const char *szLabel,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003647 const uint8_t uQcborType,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003648 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003649{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003650#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003651 QCBORItem OneItemSeach[2];
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003652
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003653 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3654 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3655 OneItemSeach[0].uDataType = uQcborType;
3656 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003657
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003658 QCBORDecode_Private_GetItemInMap(pMe, OneItemSeach, pItem);
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003659
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003660#else
3661 (void)pMe;
3662 (void)szLabel;
3663 (void)uQcborType;
3664 (void)pItem;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003665 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003666#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003667}
3668
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003669/**
3670 * @brief Get an item by string label of a particular type
3671 *
3672 * @param[in] pMe The decode context.
3673 * @param[in] szLabel The label to search map for.
3674 * @param[in] uQcborType The QCBOR type to look for.
3675 * @param[out] pItem The item found.
3676 * @param[out] puOffset The offset of item for tag consumption check.
3677 *
3678 * This finds the item with the given label in currently open
3679 * map. This does not call QCBORDecode_Private_GetItemChecks()
3680 * to check tag number consumption or decode conformance.
3681 */
3682static void
3683QCBORDecode_GetItemInMapNoCheckSZ(QCBORDecodeContext *pMe,
3684 const char *szLabel,
3685 const uint8_t uQcborType,
3686 QCBORItem *pItem,
3687 size_t *puOffset)
3688{
3689#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
3690 QCBORItem OneItemSeach[2];
3691
3692 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3693 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3694 OneItemSeach[0].uDataType = uQcborType;
3695 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
3696
3697 QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, puOffset);
3698
3699#else
3700 (void)pMe;
3701 (void)szLabel;
3702 (void)uQcborType;
3703 (void)pItem;
3704 (void)puOffset;
3705 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
3706#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
3707}
3708
3709
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003710
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003711
3712/**
3713 * @brief Semi-private. Get pointer, length and item for an array or map.
3714 *
3715 * @param[in] pMe The decode context.
3716 * @param[in] uType CBOR major type, either array/map.
3717 * @param[out] pItem The item for the array/map.
3718 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3719 *
3720 * The next item to be decoded must be a map or array as specified by \c uType.
3721 *
3722 * \c pItem will be filled in with the label and tags of the array or map
3723 * in addition to \c pEncodedCBOR giving the pointer and length of the
3724 * encoded CBOR.
3725 *
3726 * When this is complete, the traversal cursor is at the end of the array or
3727 * map that was retrieved.
3728 */
3729void
3730QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe,
3731 const uint8_t uType,
3732 QCBORItem *pItem,
3733 UsefulBufC *pEncodedCBOR)
3734{
3735 QCBORError uErr;
3736 uint8_t uNestLevel;
3737 size_t uStartingCursor;
3738 size_t uStartOfReturned;
3739 size_t uEndOfReturned;
3740 size_t uTempSaveCursor;
3741 bool bInMap;
3742 QCBORItem LabelItem;
3743 bool EndedByBreak;
3744
3745 uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3746 bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting));
3747
3748 /* Could call GetNext here, but don't need to because this
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07003749 * is only interested in arrays and maps. TODO: switch to GetNext()? */
3750 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem, NULL);
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003751 if(uErr != QCBOR_SUCCESS) {
3752 pMe->uLastError = (uint8_t)uErr;
3753 return;
3754 }
3755
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003756 uint8_t uItemDataType = pItem->uDataType;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003757#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003758 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
3759 uItemDataType = QCBOR_TYPE_ARRAY;
3760 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003761#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003762
3763 if(uItemDataType != uType) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003764 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
3765 return;
3766 }
3767
3768 if(bInMap) {
3769 /* If the item is in a map, the start of the array/map
3770 * itself, not the label, must be found. Do this by
3771 * rewinding to the starting position and fetching
3772 * just the label data item. QCBORDecode_Private_GetNextTagNumber()
3773 * doesn't do any of the array/map item counting or nesting
3774 * level tracking. Used here it will just fetech the label
3775 * data item.
3776 *
3777 * Have to save the cursor and put it back to the position
3778 * after the full item once the label as been fetched by
3779 * itself.
3780 */
3781 uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3782 UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor);
3783
3784 /* Item has been fetched once so safe to ignore error */
3785 (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem);
3786
3787 uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3788 UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor);
3789 } else {
3790 uStartOfReturned = uStartingCursor;
3791 }
3792
3793 /* Consume the entire array/map to find the end */
3794 uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel);
3795 if(uErr != QCBOR_SUCCESS) {
3796 pMe->uLastError = (uint8_t)uErr;
3797 goto Done;
3798 }
3799
3800 /* Fill in returned values */
3801 uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3802 if(EndedByBreak) {
3803 /* When ascending nesting levels, a break for the level above
3804 * was consumed. That break is not a part of what is consumed here. */
3805 uEndOfReturned--;
3806 }
3807 pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned);
3808 pEncodedCBOR->len = uEndOfReturned - uStartOfReturned;
3809
3810Done:
3811 return;
3812}
3813
3814
3815/**
3816 * @brief Semi-private. Get pointer, length and item count of an array or map.
3817 *
3818 * @param[in] pMe The decode context.
3819 * @param[in] pTarget The label and type of the array or map to retrieve.
3820 * @param[out] pItem The item for the array/map.
3821 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3822 *
3823 * The next item to be decoded must be a map or array as specified by \c uType.
3824 *
3825 * When this is complete, the traversal cursor is unchanged.
3826 */void
3827QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe,
3828 QCBORItem *pTarget,
3829 QCBORItem *pItem,
3830 UsefulBufC *pEncodedCBOR)
3831{
3832 MapSearchInfo Info;
3833 QCBORDecodeNesting SaveNesting;
3834 size_t uSaveCursor;
3835
3836 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL);
3837 if(pMe->uLastError != QCBOR_SUCCESS) {
3838 return;
3839 }
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003840 pMe->uLastError = (uint8_t)QCBORDecode_Private_GetItemChecks(pMe, pMe->uLastError, Info.uStartOffset, pItem);
3841 if(pMe->uLastError != QCBOR_SUCCESS) {
3842 return;
3843 }
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003844
3845 /* Save the whole position of things so they can be restored.
3846 * so the cursor position is unchanged by this operation, like
3847 * all the other GetXxxxInMap() operations. */
3848 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3849 uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3850
3851 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3852 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
3853 QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR);
3854
3855 UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor);
3856 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
3857}
3858
3859
3860
3861
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003862static void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003863QCBORDecode_Private_ProcessTagOne(QCBORDecodeContext *pMe,
3864 QCBORItem *pItem,
3865 const uint8_t uTagRequirement,
3866 const uint8_t uQCBORType,
3867 const uint64_t uTagNumber,
3868 QCBORTagContentCallBack *pfCB,
3869 size_t uOffset);
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003870
3871/**
3872 * @brief Semi-private to get an string by label to match a tag specification.
3873 *
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003874 * @param[in] pMe The decode context.
3875 * @param[in] nLabel Label to search map for.
3876 * @param[in] uTagRequirement Whether or not tag number is required.
3877 * See @ref QCBOR_TAG_REQUIREMENT_TAG.
3878 * @param[in] uQCBOR_Type QCBOR type to search for.
3879 * @param[in] uTagNumber Tag number to match.
3880 * @param[out] pString The string found.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003881 *
3882 * This finds the string with the given label in currently open
3883 * map. Then checks that its tag number and types matches the tag
3884 * specification. If not, an error is set in the decode context.
3885 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003886void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003887QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
3888 const int64_t nLabel,
3889 const uint8_t uTagRequirement,
3890 const uint8_t uQCBOR_Type,
3891 const uint64_t uTagNumber,
3892 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003893{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003894 QCBORItem Item;
3895 size_t uOffset;
3896
3897 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
3898 QCBORDecode_Private_ProcessTagOne(pMe,
3899 &Item,
3900 uTagRequirement,
3901 uQCBOR_Type,
3902 uTagNumber,
3903 QCBORDecode_StringsTagCB,
3904 uOffset);
3905
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003906 if(pMe->uLastError == QCBOR_SUCCESS) {
3907 *pString = Item.val.string;
3908 }
3909}
3910
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003911
3912/**
3913 * @brief Semi-private to get an string by label to match a tag specification.
3914 *
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003915 * @param[in] pMe The decode context.
3916 * @param[in] szLabel Label to search map for.
3917 * @param[in] uTagRequirement Whether or not tag number is required.
3918 * See @ref QCBOR_TAG_REQUIREMENT_TAG.
3919 * @param[in] uQCBOR_Type QCBOR type to search for.
3920 * @param[in] uTagNumber Tag number to match.
3921 * @param[out] pString The string found.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003922 *
3923 * This finds the string with the given label in currently open
3924 * map. Then checks that its tag number and types matches the tag
3925 * specification. If not, an error is set in the decode context.
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003926 */
3927void
3928QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
3929 const char *szLabel,
3930 uint8_t uTagRequirement,
3931 uint8_t uQCBOR_Type,
3932 uint64_t uTagNumber,
3933 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003934{
3935 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003936 size_t uOffset;
3937
3938 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
3939 QCBORDecode_Private_ProcessTagOne(pMe,
3940 &Item,
3941 uTagRequirement,
3942 uQCBOR_Type,
3943 uTagNumber,
3944 QCBORDecode_StringsTagCB,
3945 uOffset);
3946
3947
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003948 if(pMe->uLastError == QCBOR_SUCCESS) {
3949 *pString = Item.val.string;
3950 }
3951}
Laurence Lundblade1341c592020-04-11 14:19:05 -07003952
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003953
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003954/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003955 * Public function, see header qcbor/qcbor_decode.h file
3956 */
3957void
3958QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003959{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003960 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003961}
3962
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003963/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003964 * Public function, see header qcbor/qcbor_decode.h file
3965 */
3966void
3967QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe,
3968 QCBORItem *pItemList,
3969 void *pCallbackCtx,
3970 QCBORItemCallback pfCB)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003971{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003972 MapSearchCallBack CallBack;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003973
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003974 CallBack.pCBContext = pCallbackCtx;
3975 CallBack.pfCallback = pfCB;
3976
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003977 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003978}
3979
3980
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003981#ifndef QCBOR_DISABLE_TAGS
3982/*
3983 * Public function, see header qcbor/qcbor_decode.h file
3984 */
3985QCBORError
3986QCBORDecode_GetNextTagNumberInMapN(QCBORDecodeContext *pMe, const int64_t nLabel, uint64_t *puTagNumber)
3987{
3988 size_t uOffset;
3989 MapSearchInfo Info;
3990 QCBORItem OneItemSeach[2];
3991
3992 if(pMe->uLastError != QCBOR_SUCCESS) {
3993 return pMe->uLastError;
3994 }
3995
3996 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3997 OneItemSeach[0].label.int64 = nLabel;
3998 OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
3999 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
4000
4001 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
4002
4003 uOffset = Info.uStartOffset;
4004 if(uOffset == pMe->uTagNumberCheckOffset) {
4005 pMe->uTagNumberIndex++;
4006 } else {
4007 pMe->uTagNumberIndex = 0;
4008 }
4009
4010 *puTagNumber = CBOR_TAG_INVALID64;
4011
4012 *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex);
4013 if(*puTagNumber == CBOR_TAG_INVALID64 ||
4014 QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
4015 pMe->uTagNumberIndex = QCBOR_ALL_TAGS_PROCESSED;
4016 }
4017 pMe->uTagNumberCheckOffset = uOffset;
4018
4019 return uReturn;
4020}
4021
4022
4023/*
4024 * Public function, see header qcbor/qcbor_decode.h file
4025 */
4026QCBORError
4027QCBORDecode_GetNextTagNumberInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint64_t *puTagNumber)
4028{
4029#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
4030 size_t uOffset;
4031 MapSearchInfo Info;
4032 QCBORItem OneItemSeach[2];
4033
4034 if(pMe->uLastError != QCBOR_SUCCESS) {
4035 return pMe->uLastError;
4036 }
4037
4038 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4039 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4040 OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
4041 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
4042
4043 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
4044
4045
4046 uOffset = Info.uStartOffset;
4047 if(uOffset == pMe->uTagNumberCheckOffset) {
4048 pMe->uTagNumberIndex++;
4049 } else {
4050 pMe->uTagNumberIndex = 0;
4051 }
4052
4053 *puTagNumber = CBOR_TAG_INVALID64;
4054
4055 *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex);
4056 if(*puTagNumber == CBOR_TAG_INVALID64 ||
4057 QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
4058 pMe->uTagNumberIndex = 255; /* All tags clear for this item */
4059 }
4060 pMe->uTagNumberCheckOffset = uOffset;
4061
4062 return uReturn;
4063#else
4064 (void)pMe;
4065 (void)szLabel;
4066 (void)puTagNumber;
4067 return QCBOR_ERR_LABEL_NOT_FOUND;
4068#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
4069}
4070#endif /* ! QCBOR_DISABLE_TAGS */
4071
4072
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004073/**
4074 * @brief Search for a map/array by label and enter it
4075 *
4076 * @param[in] pMe The decode context.
4077 * @param[in] pSearch The map/array to search for.
4078 *
4079 * @c pSearch is expected to contain one item of type map or array
4080 * with the label specified. The current bounded map will be searched for
4081 * this and if found will be entered.
4082 *
4083 * If the label is not found, or the item found is not a map or array,
4084 * the error state is set.
4085 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004086static void
4087QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07004088{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004089 QCBORError uErr;
4090 MapSearchInfo SearchInfo;
4091
Laurence Lundblade323f8a92020-09-06 19:43:09 -07004092 // The first item in pSearch is the one that is to be
4093 // entered. It should be the only one filled in. Any other
4094 // will be ignored unless it causes an error.
Laurence Lundblade34691b92020-05-18 22:25:25 -07004095 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07004096 return;
4097 }
4098
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004099 uErr = QCBORDecode_Private_MapSearch(pMe, pSearch, &SearchInfo, NULL);
4100
4101 pMe->uLastError = (uint8_t)QCBORDecode_Private_GetItemChecks(pMe, uErr, SearchInfo.uStartOffset, pSearch);
4102
Laurence Lundblade34691b92020-05-18 22:25:25 -07004103 if(pMe->uLastError != QCBOR_SUCCESS) {
4104 return;
4105 }
4106
Laurence Lundblade9b334962020-08-27 10:55:53 -07004107 if(pSearch->uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004108 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004109 return;
4110 }
4111
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004112
4113 /* The map or array was found. Now enter it.
4114 *
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004115 * QCBORDecode_EnterBoundedMapOrArray() used here, requires the
4116 * next item for the pre-order traversal cursor to be the map/array
4117 * found by MapSearch(). The next few lines of code force the
4118 * cursor to that.
4119 *
4120 * There is no need to retain the old cursor because
4121 * QCBORDecode_EnterBoundedMapOrArray() will set it to the
4122 * beginning of the map/array being entered.
4123 *
4124 * The cursor is forced by: 1) setting the input buffer position to
4125 * the item offset found by MapSearch(), 2) setting the map/array
4126 * counter to the total in the map/array, 3) setting the nesting
4127 * level. Setting the map/array counter to the total is not
4128 * strictly correct, but this is OK because this cursor only needs
4129 * to be used to get one item and MapSearch() has already found it
4130 * confirming it exists.
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004131 */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004132 UsefulInputBuf_Seek(&(pMe->InBuf), SearchInfo.uStartOffset);
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004133
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004134 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
4135
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004136 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07004137
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004138 QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004139}
4140
4141
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004142/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004143 * Public function, see header qcbor/qcbor_decode.h file
4144 */
4145void
4146QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004147{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004148 QCBORItem OneItemSeach[2];
4149 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4150 OneItemSeach[0].label.int64 = nLabel;
4151 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4152 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004153
Laurence Lundblade9b334962020-08-27 10:55:53 -07004154 /* The map to enter was found, now finish off entering it. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004155 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004156}
4157
4158
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004159/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004160 * Public function, see header qcbor/qcbor_decode.h file
4161 */
4162void
4163QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004164{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004165#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004166 QCBORItem OneItemSeach[2];
4167 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4168 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4169 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4170 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004171
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004172 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004173#else
4174 (void)szLabel;
4175 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
4176#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004177}
4178
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004179/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004180 * Public function, see header qcbor/qcbor_decode.h file
4181 */
4182void
4183QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07004184{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004185 QCBORItem OneItemSeach[2];
4186 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4187 OneItemSeach[0].label.int64 = nLabel;
4188 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4189 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004190
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004191 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07004192}
4193
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004194/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004195 * Public function, see header qcbor/qcbor_decode.h file
4196 */
4197void
4198QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundblade34691b92020-05-18 22:25:25 -07004199{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004200#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004201 QCBORItem OneItemSeach[2];
4202 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4203 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4204 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4205 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004206
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004207 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004208#else
4209 (void)szLabel;
4210 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
4211#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade1341c592020-04-11 14:19:05 -07004212}
4213
4214
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004215/**
4216 * @brief Semi-private to do the the work for EnterMap() and EnterArray().
4217 *
4218 * @param[in] pMe The decode context
4219 * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY.
4220 * @param[out] pItem The data item for the map or array entered.
4221 *
4222 * The next item in the traversal must be a map or array. This
4223 * consumes that item and does the book keeping to enter the map or
4224 * array.
4225 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004226void
4227QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe,
4228 const uint8_t uType,
4229 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004230{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004231 QCBORError uErr;
4232
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004233 /* Must only be called on maps and arrays. */
Laurence Lundblade34691b92020-05-18 22:25:25 -07004234 if(pMe->uLastError != QCBOR_SUCCESS) {
4235 // Already in error state; do nothing.
4236 return;
4237 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07004238
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004239 /* Get the data item that is the map or array being entered. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004240 QCBORItem Item;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004241 uErr = QCBORDecode_GetNext(pMe, &Item);
4242 if(uErr != QCBOR_SUCCESS) {
4243 goto Done;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07004244 }
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004245
4246 uint8_t uItemDataType = Item.uDataType;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004247
4248#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004249 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) {
4250 uItemDataType = QCBOR_TYPE_ARRAY;
4251 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004252#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
4253
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004254 if(uItemDataType != uType) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004255 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
4256 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004257 }
4258
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004259 QCBORDecode_Private_SaveTagNumbers(pMe, &Item);
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004260
4261
Laurence Lundbladef0499502020-08-01 11:55:57 -07004262 const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
Laurence Lundblade085d7952020-07-24 10:26:30 -07004263 if(bIsEmpty) {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004264 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
4265 // Undo decrement done by QCBORDecode_GetNext() so the the
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004266 // the decrement when exiting the map/array works correctly
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004267 pMe->nesting.pCurrent->u.ma.uCountCursor++;
4268 }
Laurence Lundblade93d89472020-10-03 22:30:50 -07004269 // Special case to increment nesting level for zero-length maps
4270 // and arrays entered in bounded mode.
Laurence Lundbladee6f15112020-07-23 18:44:16 -07004271 DecodeNesting_Descend(&(pMe->nesting), uType);
4272 }
4273
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004274 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004275
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004276 uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty,
4277 UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004278
Laurence Lundblade6545d1b2020-10-14 11:13:13 -07004279 if(pItem != NULL) {
4280 *pItem = Item;
4281 }
4282
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004283Done:
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004284 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004285}
4286
Laurence Lundblade02625d42020-06-25 14:41:41 -07004287
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004288/**
4289 * @brief Exit a bounded map, array or bstr (semi-private).
4290 *
4291 * @param[in] pMe Decode context.
4292 * @param[in] uEndOffset The input buffer offset of the end of item exited.
4293 *
4294 * @returns QCBOR_SUCCESS or an error code.
4295 *
4296 * This is the common work for exiting a level that is a bounded map,
4297 * array or bstr wrapped CBOR.
4298 *
4299 * One chunk of work is to set up the pre-order traversal so it is at
4300 * the item just after the bounded map, array or bstr that is being
4301 * exited. This is somewhat complex.
4302 *
4303 * The other work is to level-up the bounded mode to next higest
4304 * bounded mode or the top level if there isn't one.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004305 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004306static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004307QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
4308 const uint32_t uEndOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004309{
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004310 QCBORError uErr;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004311
Laurence Lundblade02625d42020-06-25 14:41:41 -07004312 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004313 * First the pre-order-traversal byte offset is positioned to the
4314 * item just after the bounded mode item that was just consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004315 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004316 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
4317
Laurence Lundblade02625d42020-06-25 14:41:41 -07004318 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004319 * Next, set the current nesting level to one above the bounded
4320 * level that was just exited.
4321 *
4322 * DecodeNesting_CheckBoundedType() is always called before this
4323 * and makes sure pCurrentBounded is valid.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004324 */
4325 DecodeNesting_LevelUpCurrent(&(pMe->nesting));
4326
4327 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004328 * This does the complex work of leveling up the pre-order
4329 * traversal when the end of a map or array or another bounded
4330 * level is reached. It may do nothing, or ascend all the way to
4331 * the top level.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004332 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004333 uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004334 if(uErr != QCBOR_SUCCESS) {
4335 goto Done;
4336 }
4337
Laurence Lundblade02625d42020-06-25 14:41:41 -07004338 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004339 * This makes the next highest bounded level the current bounded
4340 * level. If there is no next highest level, then no bounded mode
4341 * is in effect.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004342 */
4343 DecodeNesting_LevelUpBounded(&(pMe->nesting));
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004344
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004345 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004346
4347Done:
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004348 return uErr;
4349}
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004350
Laurence Lundblade02625d42020-06-25 14:41:41 -07004351
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004352/**
4353 * @brief Get started exiting a map or array (semi-private)
4354 *
4355 * @param[in] pMe The decode context
4356 * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP
4357 *
4358 * This does some work for map and array exiting (but not
4359 * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel()
4360 * is called to do the rest.
4361 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004362void
4363QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe,
4364 const uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004365{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004366 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07004367 /* Already in error state; do nothing. */
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004368 return;
4369 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004370
Laurence Lundblade02625d42020-06-25 14:41:41 -07004371 QCBORError uErr;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004372
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004373 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004374 uErr = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004375 goto Done;
4376 }
4377
Laurence Lundblade02625d42020-06-25 14:41:41 -07004378 /*
4379 Have to set the offset to the end of the map/array
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004380 that is being exited. If there is no cached value,
Laurence Lundblade02625d42020-06-25 14:41:41 -07004381 from previous map search, then do a dummy search.
4382 */
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004383 if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004384 QCBORItem Dummy;
4385 Dummy.uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004386 uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL);
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004387 if(uErr != QCBOR_SUCCESS) {
4388 goto Done;
4389 }
4390 }
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004391
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004392 uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004393
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004394Done:
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004395 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004396}
4397
4398
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004399// TODO: re order this file with tags stuff last. bstr is a tag thing
4400static QCBORError
4401QCBORDecode_Private_CheckTagNType(QCBORDecodeContext *pMe,
4402 const QCBORItem *pItem,
4403 const size_t uOffset,
4404 const uint8_t *uQCBORTypes,
4405 const uint64_t *uTagNumbers,
4406 const uint8_t uTagRequirement,
4407 bool *bTypeMatched);
4408
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004409/**
4410 * @brief The main work of entering some byte-string wrapped CBOR.
4411 *
4412 * @param[in] pMe The decode context.
4413 * @param[in] pItem The byte string item.
4414 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX
4415 * @param[out] pBstr Pointer and length of byte string entered.
4416 *
4417 * This is called once the byte string item has been decoded to do all
4418 * the book keeping work for descending a nesting level into the
4419 * nested CBOR.
4420 *
4421 * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement.
4422 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004423static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004424QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe,
4425 const QCBORItem *pItem,
4426 const uint8_t uTagRequirement,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004427 const size_t uOffset,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004428 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004429{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004430 bool bTypeMatched;
4431 QCBORError uError;
4432
4433 const uint8_t uTypes[] = {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE};
4434 const uint64_t uTagNumbers[] = {CBOR_TAG_CBOR, CBOR_TAG_CBOR_SEQUENCE, CBOR_TAG_INVALID64};
4435
4436
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004437 if(pBstr) {
4438 *pBstr = NULLUsefulBufC;
4439 }
4440
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004441 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004442 return pMe->uLastError;
4443 }
4444
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004445 if(pItem->uDataAlloc) {
4446 return QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004447 }
4448
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004449 uError = QCBORDecode_Private_CheckTagNType(pMe,
4450 pItem,
4451 uOffset,
4452 uTypes, // TODO: maybe this should be empty
4453 uTagNumbers,
4454 uTagRequirement,
4455 &bTypeMatched);
4456
4457 if(pItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
4458 uError = QCBOR_ERR_BAD_TAG_CONTENT; // TODO: error
4459 }
4460
4461
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004462 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004463 /* Reverse the decrement done by GetNext() for the bstr so the
4464 * increment in QCBORDecode_NestLevelAscender() called by
4465 * ExitBoundedLevel() will work right.
4466 */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004467 DecodeNesting_ReverseDecrement(&(pMe->nesting));
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07004468 }
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004469
4470 if(pBstr) {
4471 *pBstr = pItem->val.string;
4472 }
4473
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004474 /* This saves the current length of the UsefulInputBuf and then
4475 * narrows the UsefulInputBuf to start and length of the wrapped
4476 * CBOR that is being entered.
4477 *
4478 * Most of these calls are simple inline accessors so this doesn't
4479 * amount to much code.
4480 */
4481
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004482 const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004483 /* This check makes the cast of uPreviousLength to uint32_t below safe. */
4484 if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004485 uError = QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladef76a2622020-08-06 19:51:03 -07004486 goto Done;
4487 }
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004488
4489 const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
4490 pItem->val.string.ptr);
4491 /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
4492 if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
4493 /* This should never happen because pItem->val.string.ptr should
4494 * always be valid since it was just returned.
4495 */
4496 uError = QCBOR_ERR_INPUT_TOO_LARGE;
4497 goto Done;
4498 }
4499
4500 const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
4501
4502 UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004503 UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004504
Laurence Lundblade02625d42020-06-25 14:41:41 -07004505 uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004506 (uint32_t)uPreviousLength,
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004507 (uint32_t)uStartOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004508Done:
4509 return uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004510}
4511
4512
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004513static void
4514QCBORDecode_Private_GetAndTell(QCBORDecodeContext *pMe, QCBORItem *Item, size_t *uOffset)
4515{
4516#ifndef QCBOR_DISABLE_TAGS
4517 if(pMe->uLastError != QCBOR_SUCCESS) {
4518 return;
4519 }
4520
4521 *uOffset = QCBORDecode_Tell(pMe);
4522#else
4523 *uOffset = SIZE_MAX;
4524
4525#endif /* ! QCBOR_DISABLE_TAGS */
4526 pMe->uLastError = (uint8_t)QCBORDecode_Private_GetNextTagContent(pMe, Item);
4527}
4528
4529
Laurence Lundblade02625d42020-06-25 14:41:41 -07004530/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004531 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004532 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004533void
4534QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe,
4535 const uint8_t uTagRequirement,
4536 UsefulBufC *pBstr)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004537{
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004538 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004539 size_t uOffset;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004540
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004541 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004542 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4543 &Item,
4544 uTagRequirement,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004545 uOffset,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004546 pBstr);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004547}
4548
4549
Laurence Lundblade02625d42020-06-25 14:41:41 -07004550/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004551 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004552 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004553void
4554QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe,
4555 const int64_t nLabel,
4556 const uint8_t uTagRequirement,
4557 UsefulBufC *pBstr)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004558{
4559 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004560 size_t uOffset;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004561
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004562 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_BYTE_STRING, &Item, &uOffset);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004563 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4564 &Item,
4565 uTagRequirement,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004566 uOffset,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004567 pBstr);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004568}
4569
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004570
Laurence Lundblade02625d42020-06-25 14:41:41 -07004571/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004572 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004573 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004574void
4575QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe,
4576 const char *szLabel,
4577 const uint8_t uTagRequirement,
4578 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004579{
4580 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004581 size_t uOffset;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004582
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004583 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_BYTE_STRING, &Item, &uOffset);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004584 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4585 &Item,
4586 uTagRequirement,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004587 uOffset,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004588 pBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004589}
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004590
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004591
Laurence Lundblade02625d42020-06-25 14:41:41 -07004592/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004593 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004594 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004595void
4596QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004597{
Laurence Lundblade02625d42020-06-25 14:41:41 -07004598 if(pMe->uLastError != QCBOR_SUCCESS) {
4599 // Already in error state; do nothing.
4600 return;
4601 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004602
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004603 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004604 pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade02625d42020-06-25 14:41:41 -07004605 return;
4606 }
4607
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004608 const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
4609
Laurence Lundblade02625d42020-06-25 14:41:41 -07004610 /*
4611 Reset the length of the UsefulInputBuf to what it was before
4612 the bstr wrapped CBOR was entered.
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004613 */
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004614 UsefulInputBuf_SetBufferLength(&(pMe->InBuf),
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004615 DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004616
4617
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004618 QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004619 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004620}
4621
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004622
Laurence Lundbladee6430642020-03-14 21:15:44 -07004623
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004624/**
4625 * @brief Process simple type true and false, a boolean
4626 *
4627 * @param[in] pMe The decode context.
4628 * @param[in] pItem The item with either true or false.
4629 * @param[out] pBool The boolean value output.
4630 *
4631 * Sets the internal error if the item isn't a true or a false. Also
4632 * records any tag numbers as the tag numbers of the last item.
4633 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004634static void
4635QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe,
4636 const QCBORItem *pItem,
4637 bool *pBool)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004638{
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004639 if(pMe->uLastError != QCBOR_SUCCESS) {
4640 /* Already in error state, do nothing */
4641 return;
4642 }
4643
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004644 switch(pItem->uDataType) {
4645 case QCBOR_TYPE_TRUE:
4646 *pBool = true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004647 break;
4648
4649 case QCBOR_TYPE_FALSE:
4650 *pBool = false;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004651 break;
4652
4653 default:
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004654 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004655 break;
4656 }
4657}
Laurence Lundbladee6430642020-03-14 21:15:44 -07004658
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004659
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004660/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004661 * Public function, see header qcbor/qcbor_decode.h file
4662 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004663void
4664QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004665{
Laurence Lundbladec4537442020-04-14 18:53:22 -07004666 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07004667 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004668 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004669}
4670
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004671
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004672/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004673 * Public function, see header qcbor/qcbor_decode.h file
4674 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004675void
4676QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe,
4677 const int64_t nLabel,
4678 bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004679{
4680 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004681 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004682 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004683}
4684
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004685
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004686/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004687 * Public function, see header qcbor/qcbor_decode.h file
4688 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004689void
4690QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe,
4691 const char *szLabel,
4692 bool *pValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004693{
4694 QCBORItem Item;
4695 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004696 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004697}
4698
4699
Laurence Lundblade3888f002024-06-12 21:20:56 -07004700/**
4701 * @brief Process simple values.
4702 *
4703 * @param[in] pMe The decode context.
4704 * @param[in] pItem The item with the simple value.
4705 * @param[out] puSimple The simple value output.
4706 *
4707 * Sets the internal error if the item isn't a true or a false. Also
4708 * records any tag numbers as the tag numbers of the last item.
4709 */
4710static void
4711QCBORDecode_Private_ProcessSimple(QCBORDecodeContext *pMe,
4712 const QCBORItem *pItem,
4713 uint8_t *puSimple)
4714{
4715 if(pMe->uLastError != QCBOR_SUCCESS) {
4716 return;
4717 }
4718
4719 /* It's kind of lame to remap true...undef back to simple values, but
4720 * this function isn't used much and to not do it would require
4721 * changing GetNext() behavior in an incompatible way.
4722 */
4723 switch(pItem->uDataType) {
4724 case QCBOR_TYPE_UKNOWN_SIMPLE:
4725 *puSimple = pItem->val.uSimple;
4726 break;
4727
4728 case QCBOR_TYPE_TRUE:
4729 *puSimple = CBOR_SIMPLEV_TRUE;
4730 break;
4731
4732 case QCBOR_TYPE_FALSE:
4733 *puSimple = CBOR_SIMPLEV_FALSE;
4734 break;
4735
4736 case QCBOR_TYPE_NULL:
4737 *puSimple = CBOR_SIMPLEV_NULL;
4738 break;
4739
4740 case QCBOR_TYPE_UNDEF:
4741 *puSimple = CBOR_SIMPLEV_UNDEF;
4742 break;
4743
4744 default:
4745 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4746 return;
4747 }
Laurence Lundblade3888f002024-06-12 21:20:56 -07004748}
4749
4750/*
4751 * Public function, see header qcbor/qcbor_decode.h file
4752 */
4753void
4754QCBORDecode_GetSimple(QCBORDecodeContext *pMe, uint8_t *puSimple)
4755{
4756 QCBORItem Item;
Laurence Lundblade3888f002024-06-12 21:20:56 -07004757 QCBORDecode_VGetNext(pMe, &Item);
4758 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimple);
4759}
4760
4761/*
4762 * Public function, see header qcbor/qcbor_decode.h file
4763 */
4764void
4765QCBORDecode_GetSimpleInMapN(QCBORDecodeContext *pMe,
4766 int64_t nLabel,
4767 uint8_t *puSimpleValue)
4768{
4769 QCBORItem Item;
4770 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3888f002024-06-12 21:20:56 -07004771 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
4772}
4773
4774/*
4775 * Public function, see header qcbor/qcbor_decode.h file
4776 */
4777void
4778QCBORDecode_GetSimpleInMapSZ(QCBORDecodeContext *pMe,
4779 const char *szLabel,
4780 uint8_t *puSimpleValue)
4781{
4782 QCBORItem Item;
4783 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3888f002024-06-12 21:20:56 -07004784 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
4785}
4786
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004787
Laurence Lundbladec7114722020-08-13 05:11:40 -07004788
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004789
4790#ifndef QCBOR_DISABLE_TAGS
4791// TODO: uTagNumber might be better a list than calling this multiple times
4792static QCBORError
4793QCBORDecode_Private_Check1TagNumber(const QCBORDecodeContext *pMe,
4794 const QCBORItem *pItem,
4795 const uint64_t uTagNumber,
4796 const size_t uOffset)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004797{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004798 if(pItem->auTagNumbers[0] == CBOR_TAG_INVALID16) {
4799 /* There are no tag numbers at all, so no unprocessed */
4800 return QCBOR_SUCCESS;
4801 }
4802
4803 /* There are some tag numbers, so keep checking. This check passes
4804 * if there is one and only one tag number that matches uTagNumber
4805 */
4806
4807 // TODO: behave different in v1 and v2?
4808
4809 const uint64_t uInnerTag = QCBORDecode_GetNthTagNumber(pMe, pItem, 0);
4810
4811 if(uInnerTag == uTagNumber && pItem->auTagNumbers[1] == CBOR_TAG_INVALID16 ) {
4812 /* The only tag number is the one we are processing so no unprocessed */
4813 return QCBOR_SUCCESS;
4814 }
4815
4816 if(uOffset != pMe->uTagNumberCheckOffset) {
4817 /* processed tag numbers are for some other item, not us */
4818 return QCBOR_ERR_UNPROCESSED_TAG_NUMBER;
4819 }
4820
4821 if(pMe->uTagNumberIndex != 1) {
4822 return QCBOR_ERR_UNPROCESSED_TAG_NUMBER;
4823 }
4824
4825 return QCBOR_SUCCESS;
4826}
4827#endif
4828
4829
4830static QCBORError
4831QCBORDecode_Private_CheckTagNType(QCBORDecodeContext *pMe,
4832 const QCBORItem *pItem,
4833 const size_t uOffset,
4834 const uint8_t *uQCBORTypes,
4835 const uint64_t *uTagNumbers,
4836 const uint8_t uTagRequirement,
4837 bool *bTypeMatched)
4838{
4839 const int nTagReq = uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
4840
4841 *bTypeMatched = false;
4842 for(const uint8_t *pTNum = uQCBORTypes; *pTNum != QCBOR_TYPE_NONE; pTNum++) {
4843 if(pItem->uDataType == *pTNum) {
4844 *bTypeMatched = true;
4845 break;
4846 }
4847 }
4848
4849#ifndef QCBOR_DISABLE_TAGS
4850 bool bTagNumberMatched;
4851 QCBORError uErr;
4852 const uint64_t uInnerTag = QCBORDecode_GetNthTagNumber(pMe, pItem, 0);
4853
4854 bTagNumberMatched = false;
4855 for(const uint64_t *pQType = uTagNumbers; *pQType != CBOR_TAG_INVALID64; pQType++) {
4856 if(uInnerTag == *pQType) {
4857 bTagNumberMatched = true;
4858 break;
4859 }
4860 }
4861
4862
4863 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
4864 /* There must be a tag number */
4865 if(!bTagNumberMatched && !*bTypeMatched) {
4866 return QCBOR_ERR_UNEXPECTED_TYPE; // TODO: error code
4867 }
4868
4869 } else if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
4870 if(bTagNumberMatched || *bTypeMatched) {
4871 return QCBOR_ERR_UNEXPECTED_TYPE; // TODO: error code
4872 }
4873
4874 } else if(nTagReq == QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG) {
4875 /* No check necessary */
4876 }
4877
4878 /* Now check if there are extra tags and if there's an error in them */
4879 if(!(uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS)) {
4880 /* The flag to ignore extra is not set, so keep checking */
4881 for(const uint64_t *pTNum = uTagNumbers; *pTNum != CBOR_TAG_INVALID64; pTNum++) {
4882 uErr = QCBORDecode_Private_Check1TagNumber(pMe, pItem, *pTNum, uOffset);
4883 if(uErr != QCBOR_SUCCESS) {
4884 return uErr;
4885 }
4886 }
4887 }
4888
4889 return QCBOR_SUCCESS;
4890#else
4891 (void)pMe;
4892 (void)uOffset;
4893 (void)uTagNumbers;
4894
4895 if(nTagReq != QCBOR_TAG_REQUIREMENT_TAG && bTypeMatched) {
4896 return QCBOR_SUCCESS;
4897 } else {
4898 return QCBOR_ERR_UNEXPECTED_TYPE;
4899 }
4900
4901#endif
4902
4903}
4904
4905
4906void
4907QCBORDecode_Private_ProcessTagItemMulti(QCBORDecodeContext *pMe,
4908 QCBORItem *pItem,
4909 const uint8_t uTagRequirement,
4910 const uint8_t uQCBORTypes[],
4911 const uint64_t uTagNumbers[],
4912 QCBORTagContentCallBack *pfCB,
4913 size_t uOffset)
4914{
4915 QCBORError uErr;
4916 bool bTypeMatched;
4917
Laurence Lundbladec7114722020-08-13 05:11:40 -07004918 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec7114722020-08-13 05:11:40 -07004919 return;
4920 }
4921
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004922 uErr = QCBORDecode_Private_CheckTagNType(pMe,
4923 pItem,
4924 uOffset,
4925 uQCBORTypes,
4926 uTagNumbers,
4927 uTagRequirement,
4928 &bTypeMatched);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004929 if(uErr != QCBOR_SUCCESS) {
4930 goto Done;
4931 }
4932
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004933 if(!bTypeMatched) {
4934 /* Tag content wasn't previously processed, do it now */
4935 uErr = (*pfCB)(pMe, NULL, uTagNumbers[0], pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004936 if(uErr != QCBOR_SUCCESS) {
4937 goto Done;
4938 }
4939 }
4940
Laurence Lundbladec7114722020-08-13 05:11:40 -07004941Done:
4942 pMe->uLastError = (uint8_t)uErr;
4943}
4944
4945
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004946/*
4947 **/
4948 void
4949QCBORDecode_Private_ProcessTagItem(QCBORDecodeContext *pMe,
4950 QCBORItem *pItem,
4951 const uint8_t uTagRequirement,
4952 const uint8_t uQCBORTypes[],
4953 const uint64_t uTagNumber,
4954 QCBORTagContentCallBack *pfCB,
4955 size_t uOffset)
4956{
4957 uint64_t auTagNumbers[2];
4958
4959 auTagNumbers[0] = uTagNumber;
4960 auTagNumbers[1] = CBOR_TAG_INVALID64;
4961
4962 QCBORDecode_Private_ProcessTagItemMulti(pMe,
4963 pItem,
4964 uTagRequirement,
4965 uQCBORTypes,
4966 auTagNumbers,
4967 pfCB,
4968 uOffset);
4969}
4970
4971
4972static void
4973QCBORDecode_Private_ProcessTagOne(QCBORDecodeContext *pMe,
4974 QCBORItem *pItem,
4975 const uint8_t uTagRequirement,
4976 const uint8_t uQCBORType,
4977 const uint64_t uTagNumber,
4978 QCBORTagContentCallBack *pfCB,
4979 const size_t uOffset)
4980{
4981 uint8_t auQCBORType[2];
4982
4983 auQCBORType[0] = uQCBORType;
4984 auQCBORType[1] = QCBOR_TYPE_NONE;
4985
4986 QCBORDecode_Private_ProcessTagItem(pMe,
4987 pItem,
4988 uTagRequirement,
4989 auQCBORType,
4990 uTagNumber,
4991 pfCB,
4992 uOffset);
4993}
4994
4995
4996
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004997
4998/*
4999 * Public function, see header qcbor/qcbor_spiffy_decode.h file
5000 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005001void
5002QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
5003 uint8_t uTagRequirement,
5004 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07005005{
Laurence Lundbladec7114722020-08-13 05:11:40 -07005006 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005007 size_t uOffset;
5008
5009 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
5010 QCBORDecode_Private_ProcessTagOne(pMe,
5011 &Item,
5012 uTagRequirement,
5013 QCBOR_TYPE_DATE_EPOCH,
5014 CBOR_TAG_DATE_EPOCH,
5015 QCBORDecode_DateEpochTagCB,
5016 uOffset);
5017 *pnTime = Item.val.epochDate.nSeconds;
Laurence Lundbladec7114722020-08-13 05:11:40 -07005018}
5019
5020
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005021/*
5022 * Public function, see header qcbor/qcbor_spiffy_decode.h file
5023 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07005024void
5025QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
5026 int64_t nLabel,
5027 uint8_t uTagRequirement,
5028 int64_t *pnTime)
5029{
5030 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005031 size_t uOffset;
5032
5033 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
5034 QCBORDecode_Private_ProcessTagOne(pMe,
5035 &Item,
5036 uTagRequirement,
5037 QCBOR_TYPE_DATE_EPOCH,
5038 CBOR_TAG_DATE_EPOCH,
5039 QCBORDecode_DateEpochTagCB,
5040 uOffset);
5041 *pnTime = Item.val.epochDate.nSeconds;
Laurence Lundbladec7114722020-08-13 05:11:40 -07005042}
5043
5044
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005045/*
5046 * Public function, see header qcbor/qcbor_spiffy_decode.h file
5047 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07005048void
5049QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
5050 const char *szLabel,
5051 uint8_t uTagRequirement,
5052 int64_t *pnTime)
5053{
5054 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005055 size_t uOffset;
Laurence Lundbladec7114722020-08-13 05:11:40 -07005056
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005057 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
5058 QCBORDecode_Private_ProcessTagOne(pMe,
5059 &Item,
5060 uTagRequirement,
5061 QCBOR_TYPE_DATE_EPOCH,
5062 CBOR_TAG_DATE_EPOCH,
5063 QCBORDecode_DateEpochTagCB,
5064 uOffset);
5065 *pnTime = Item.val.epochDate.nSeconds;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005066}
5067
5068
5069/*
5070 * Public function, see header qcbor/qcbor_decode.h
5071 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005072void
5073QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe,
5074 uint8_t uTagRequirement,
5075 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005076{
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005077 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005078 size_t uOffset;
5079
5080 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
5081 QCBORDecode_Private_ProcessTagOne(pMe,
5082 &Item,
5083 uTagRequirement,
5084 QCBOR_TYPE_DAYS_EPOCH,
5085 CBOR_TAG_DAYS_EPOCH,
5086 QCBORDecode_DaysEpochTagCB,
5087 uOffset);
5088 *pnDays = Item.val.epochDays;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005089}
5090
5091
5092/*
5093 * Public function, see header qcbor/qcbor_decode.h
5094 */
5095void
5096QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe,
5097 int64_t nLabel,
5098 uint8_t uTagRequirement,
5099 int64_t *pnDays)
5100{
5101 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005102 size_t uOffset;
5103
5104 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
5105 QCBORDecode_Private_ProcessTagOne(pMe,
5106 &Item,
5107 uTagRequirement,
5108 QCBOR_TYPE_DAYS_EPOCH,
5109 CBOR_TAG_DAYS_EPOCH,
5110 QCBORDecode_DaysEpochTagCB,
5111 uOffset);
5112 *pnDays = Item.val.epochDays;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005113}
5114
5115
5116/*
5117 * Public function, see header qcbor/qcbor_decode.h
5118 */
5119void
5120QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe,
5121 const char *szLabel,
5122 uint8_t uTagRequirement,
5123 int64_t *pnDays)
5124{
5125 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005126 size_t uOffset;
5127
5128 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
5129 QCBORDecode_Private_ProcessTagOne(pMe,
5130 &Item,
5131 uTagRequirement,
5132 QCBOR_TYPE_DAYS_EPOCH,
5133 CBOR_TAG_DAYS_EPOCH,
5134 QCBORDecode_DaysEpochTagCB,
5135 uOffset);
5136 *pnDays = Item.val.epochDays;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005137}
5138
5139
5140
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005141
Laurence Lundblade37286c02022-09-03 10:05:02 -07005142void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005143QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
5144 const uint8_t uTagRequirement,
5145 const uint8_t uQCBOR_Type,
5146 const uint64_t uTagNumber,
5147 UsefulBufC *pStr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005148{
Laurence Lundbladec4537442020-04-14 18:53:22 -07005149 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005150 size_t uOffset;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005151
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005152 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
5153 QCBORDecode_Private_ProcessTagOne(pMe,
5154 &Item,
5155 uTagRequirement,
5156 uQCBOR_Type,
5157 uTagNumber,
5158 QCBORDecode_StringsTagCB,
5159 uOffset);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005160
5161 if(pMe->uLastError == QCBOR_SUCCESS) {
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005162 *pStr = Item.val.string;
Laurence Lundbladeab40c6f2020-08-28 11:24:58 -07005163 } else {
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005164 *pStr = NULLUsefulBufC;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005165 }
5166}
5167
Laurence Lundbladec4537442020-04-14 18:53:22 -07005168
5169
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005170
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005171/**
5172 * @brief Common processing for a big number tag.
5173 *
5174 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
5175 * @param[in] pItem The item with the date.
5176 * @param[out] pValue The returned big number
5177 * @param[out] pbIsNegative The returned sign of the big number.
5178 *
5179 * Common processing for the big number tag. Mostly make sure
5180 * the tag content is correct and copy forward any further other tag
5181 * numbers.
5182 */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005183static void
5184QCBOR_Private_ProcessBigNum(QCBORDecodeContext *pMe,
5185 const uint8_t uTagRequirement,
5186 QCBORItem *pItem,
5187 UsefulBufC *pValue,
5188 bool *pbIsNegative,
5189 size_t uOffset)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005190{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005191 QCBORError uErr;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005192
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005193 const uint8_t puTypes[] = {QCBOR_TYPE_POSBIGNUM,QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE};
5194
5195 const uint64_t puTNs[] = {CBOR_TAG_POS_BIGNUM, CBOR_TAG_NEG_BIGNUM, CBOR_TAG_INVALID64};
5196
5197 QCBORDecode_Private_ProcessTagItemMulti(pMe,
5198 pItem,
5199 uTagRequirement,
5200 puTypes,
5201 puTNs, QCBORDecode_StringsTagCB, uOffset);
5202 if(pMe->uLastError) {
5203 return;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005204 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005205
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005206
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005207 // TODO: is this right? Tests are passing. Fix after merges.
5208 // TODO: make this work for GetBigNum and GetBigNumber(). They are different.
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005209 if(pItem->uDataType == QCBOR_TYPE_POSBIGNUM) {
5210 *pbIsNegative = false;
5211 } else if(pItem->uDataType == QCBOR_TYPE_NEGBIGNUM) {
5212 *pbIsNegative = true;
5213 }
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005214 *pValue = pItem->val.bigNum;
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005215
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005216 uErr = QCBOR_SUCCESS;
5217
5218 pMe->uLastError = (uint8_t)uErr;
5219}
5220
5221
5222static void
5223QCBORDecode_Private_GetMIME(QCBORDecodeContext *pMe,
5224 const uint8_t uTagRequirement,
5225 QCBORItem *pItem,
5226 UsefulBufC *pValue,
5227 bool *pbIsTag257,
5228 size_t uOffset)
5229{
5230 QCBORError uErr;
5231
5232 const uint8_t puTypes[] = {QCBOR_TYPE_MIME, QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE};
5233
5234 const uint64_t puTNs[] = {CBOR_TAG_MIME, CBOR_TAG_BINARY_MIME, CBOR_TAG_INVALID64};
5235
5236 QCBORDecode_Private_ProcessTagItemMulti(pMe,
5237 pItem,
5238 uTagRequirement,
5239 puTypes,
5240 puTNs,
5241 QCBORDecode_MIMETagCB,
5242 uOffset);
5243 if(pMe->uLastError) {
5244 return;
5245 }
5246
5247 if(pItem->uDataType == QCBOR_TYPE_MIME) {
5248 *pbIsTag257 = false;
5249 } else if(pItem->uDataType == QCBOR_TYPE_BINARY_MIME) {
5250 *pbIsTag257 = true;
5251 }
5252 *pValue = pItem->val.string;
5253
5254
5255 uErr = QCBOR_SUCCESS;
5256
5257 pMe->uLastError = (uint8_t)uErr;
5258}
5259
5260
5261void
5262QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pMe,
5263 const uint8_t uTagRequirement,
5264 UsefulBufC *pMessage,
5265 bool *pbIsTag257)
5266{
5267 QCBORItem Item;
5268 size_t uOffset;
5269
5270 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
5271 QCBORDecode_Private_GetMIME(pMe,
5272 uTagRequirement,
5273 &Item,
5274 pMessage,
5275 pbIsTag257,
5276 uOffset);
5277}
5278
5279void
5280QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pMe,
5281 const int64_t nLabel,
5282 const uint8_t uTagRequirement,
5283 UsefulBufC *pMessage,
5284 bool *pbIsTag257)
5285{
5286 QCBORItem Item;
5287 size_t uOffset;
5288
5289 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
5290 QCBORDecode_Private_GetMIME(pMe,
5291 uTagRequirement,
5292 &Item,
5293 pMessage,
5294 pbIsTag257,
5295 uOffset);
5296}
5297
5298void
5299QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pMe,
5300 const char *szLabel,
5301 const uint8_t uTagRequirement,
5302 UsefulBufC *pMessage,
5303 bool *pbIsTag257)
5304{
5305 QCBORItem Item;
5306 size_t uOffset;
5307
5308 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
5309 QCBORDecode_Private_GetMIME(pMe,
5310 uTagRequirement,
5311 &Item,
5312 pMessage,
5313 pbIsTag257,
5314 uOffset);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005315}
5316
5317
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005318/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005319 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005320 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005321void
5322QCBORDecode_GetBignum(QCBORDecodeContext *pMe,
5323 const uint8_t uTagRequirement,
5324 UsefulBufC *pValue,
5325 bool *pbIsNegative)
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005326{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005327 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005328 size_t uOffset;
Laurence Lundblade14ce2282024-07-24 22:13:35 -07005329
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005330 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
5331 QCBOR_Private_ProcessBigNum(pMe,
5332 uTagRequirement,
5333 &Item,
5334 pValue,
5335 pbIsNegative,
5336 uOffset);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005337}
5338
Laurence Lundblade4e2da002020-06-13 23:08:31 -07005339/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005340 * Public function, see header qcbor/qcbor_spiffy_decode.h
5341 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005342void
5343QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe,
5344 const int64_t nLabel,
5345 const uint8_t uTagRequirement,
5346 UsefulBufC *pValue,
5347 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005348{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005349 QCBORItem Item;
5350 size_t uOffset;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005351
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005352 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
5353 QCBOR_Private_ProcessBigNum(pMe,
5354 uTagRequirement,
5355 &Item,
5356 pValue,
5357 pbIsNegative,
5358 uOffset);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005359}
5360
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005361/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005362 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005363 */
5364void
5365QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe,
5366 const char *szLabel,
5367 const uint8_t uTagRequirement,
5368 UsefulBufC *pValue,
5369 bool *pbIsNegative)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005370{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005371 QCBORItem Item;
5372 size_t uOffset;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005373
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005374 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
5375 QCBOR_Private_ProcessBigNum(pMe,
5376 uTagRequirement,
5377 &Item,
5378 pValue,
5379 pbIsNegative,
5380 uOffset);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005381}
5382
5383
5384
Laurence Lundblade93d89472020-10-03 22:30:50 -07005385// Improvement: add methods for wrapped CBOR, a simple alternate
5386// to EnterBstrWrapped
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005387
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005388
5389
5390
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005391#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundbladee6430642020-03-14 21:15:44 -07005392
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005393/**
5394 * @brief Prototype for conversion of exponent and mantissa to unsigned integer.
5395 *
5396 * @param[in] uMantissa The mantissa.
5397 * @param[in] nExponent The exponent.
5398 * @param[out] puResult The resulting integer.
5399 *
5400 * Concrete implementations of this are for exponent base 10 and 2 supporting
5401 * decimal fractions and big floats.
5402 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005403typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005404
5405
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005406/**
5407 * @brief Base 10 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5408 *
5409 * @param[in] uMantissa The unsigned integer mantissa.
5410 * @param[in] nExponent The signed integer exponent.
5411 * @param[out] puResult Place to return the unsigned integer result.
5412 *
5413 * This computes: mantissa * 10 ^^ exponent as for a decimal fraction. The output is a 64-bit
5414 * unsigned integer.
5415 *
5416 * There are many inputs for which the result will not fit in the
5417 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5418 * be returned.
5419 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005420static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005421QCBOR_Private_Exponentitate10(const uint64_t uMantissa,
5422 int64_t nExponent,
5423 uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005424{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005425 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005426
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005427 if(uResult != 0) {
5428 /* This loop will run a maximum of 19 times because
5429 * UINT64_MAX < 10 ^^ 19. More than that will cause
5430 * exit with the overflow error
5431 */
5432 for(; nExponent > 0; nExponent--) {
5433 if(uResult > UINT64_MAX / 10) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005434 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005435 }
5436 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005437 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005438
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005439 for(; nExponent < 0; nExponent++) {
5440 uResult = uResult / 10;
5441 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005442 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005443 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005444 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005445 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005446 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07005447
5448 *puResult = uResult;
5449
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005450 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005451}
5452
5453
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005454/**
5455 * @brief Base 2 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5456 *
5457 * @param[in] uMantissa The unsigned integer mantissa.
5458 * @param[in] nExponent The signed integer exponent.
5459 * @param[out] puResult Place to return the unsigned integer result.
5460 *
5461 * This computes: mantissa * 2 ^^ exponent as for a big float. The
5462 * output is a 64-bit unsigned integer.
5463 *
5464 * There are many inputs for which the result will not fit in the
5465 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5466 * be returned.
5467 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005468static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005469QCBOR_Private_Exponentitate2(const uint64_t uMantissa,
5470 int64_t nExponent,
5471 uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005472{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005473 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005474
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005475 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005476
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005477 /* This loop will run a maximum of 64 times because INT64_MAX <
5478 * 2^31. More than that will cause exit with the overflow error
Laurence Lundbladee6430642020-03-14 21:15:44 -07005479 */
5480 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005481 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005482 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005483 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005484 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005485 nExponent--;
5486 }
5487
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005488 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005489 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005490 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005491 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005492 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005493 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005494 }
5495
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005496 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005497
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005498 return QCBOR_SUCCESS;
5499}
5500
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005501
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005502/**
5503 * @brief Exponentiate a signed mantissa and signed exponent to produce a signed result.
5504 *
5505 * @param[in] nMantissa Signed integer mantissa.
5506 * @param[in] nExponent Signed integer exponent.
5507 * @param[out] pnResult Place to put the signed integer result.
5508 * @param[in] pfExp Exponentiation function.
5509 *
5510 * @returns Error code
5511 *
5512 * \c pfExp performs exponentiation on and unsigned mantissa and
5513 * produces an unsigned result. This converts the mantissa from signed
5514 * and converts the result to signed. The exponentiation function is
5515 * either for base 2 or base 10 (and could be other if needed).
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005516 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005517static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005518QCBOR_Private_ExponentiateNN(const int64_t nMantissa,
5519 const int64_t nExponent,
5520 int64_t *pnResult,
5521 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005522{
5523 uint64_t uResult;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005524 uint64_t uMantissa;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005525
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005526 /* Take the absolute value and put it into an unsigned. */
5527 if(nMantissa >= 0) {
5528 /* Positive case is straightforward */
5529 uMantissa = (uint64_t)nMantissa;
5530 } else if(nMantissa != INT64_MIN) {
5531 /* The common negative case. See next. */
5532 uMantissa = (uint64_t)-nMantissa;
5533 } else {
5534 /* int64_t and uint64_t are always two's complement per the
5535 * C standard (and since QCBOR uses these it only works with
5536 * two's complement, which is pretty much universal these
5537 * days). The range of a negative two's complement integer is
5538 * one more that than a positive, so the simple code above might
5539 * not work all the time because you can't simply negate the
5540 * value INT64_MIN because it can't be represented in an
5541 * int64_t. -INT64_MIN can however be represented in a
5542 * uint64_t. Some compilers seem to recognize this case for the
5543 * above code and put the correct value in uMantissa, however
5544 * they are not required to do this by the C standard. This next
5545 * line does however work for all compilers.
5546 *
5547 * This does assume two's complement where -INT64_MIN ==
5548 * INT64_MAX + 1 (which wouldn't be true for one's complement or
5549 * sign and magnitude (but we know we're using two's complement
5550 * because int64_t requires it)).
5551 *
5552 * See these, particularly the detailed commentary:
5553 * https://stackoverflow.com/questions/54915742/does-c99-mandate-a-int64-t-type-be-available-always
5554 * https://stackoverflow.com/questions/37301078/is-negating-int-min-undefined-behaviour
5555 */
5556 uMantissa = (uint64_t)INT64_MAX+1;
5557 }
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005558
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005559 /* Call the exponentiator passed for either base 2 or base 10.
5560 * Here is where most of the overflow errors are caught. */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005561 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
5562 if(uReturn) {
5563 return uReturn;
5564 }
5565
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005566 /* Convert back to the sign of the original mantissa */
5567 if(nMantissa >= 0) {
5568 if(uResult > INT64_MAX) {
5569 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5570 }
5571 *pnResult = (int64_t)uResult;
5572 } else {
5573 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
5574 * of INT64_MIN. This assumes two's compliment representation
5575 * where INT64_MIN is one increment farther from 0 than
5576 * INT64_MAX. Trying to write -INT64_MIN doesn't work to get
5577 * this because the compiler makes it an int64_t which can't
5578 * represent -INT64_MIN. Also see above.
5579 */
5580 if(uResult > (uint64_t)INT64_MAX+1) {
5581 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5582 }
5583 *pnResult = -(int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005584 }
5585
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005586 return QCBOR_SUCCESS;
5587}
5588
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005589
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005590/**
5591 * @brief Exponentiate an unsigned mantissa and signed exponent to produce an unsigned result.
5592 *
5593 * @param[in] nMantissa Signed integer mantissa.
5594 * @param[in] nExponent Signed integer exponent.
5595 * @param[out] puResult Place to put the signed integer result.
5596 * @param[in] pfExp Exponentiation function.
5597 *
5598 * @returns Error code
5599 *
5600 * \c pfExp performs exponentiation on and unsigned mantissa and
5601 * produces an unsigned result. This errors out if the mantissa
5602 * is negative because the output is unsigned.
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005603 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005604static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005605QCBOR_Private_ExponentitateNU(const int64_t nMantissa,
5606 const int64_t nExponent,
5607 uint64_t *puResult,
5608 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005609{
5610 if(nMantissa < 0) {
5611 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5612 }
5613
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005614 /* Cast to unsigned is OK because of check for negative.
5615 * Cast to unsigned is OK because UINT64_MAX > INT64_MAX.
5616 * Exponentiation is straight forward
5617 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005618 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
5619}
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005620
5621
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005622/**
5623 * @brief Exponentiate an usnigned mantissa and unsigned exponent to produce an unsigned result.
5624 *
5625 * @param[in] uMantissa Unsigned integer mantissa.
5626 * @param[in] nExponent Unsigned integer exponent.
5627 * @param[out] puResult Place to put the unsigned integer result.
5628 * @param[in] pfExp Exponentiation function.
5629 *
5630 * @returns Error code
5631 *
5632 * \c pfExp performs exponentiation on and unsigned mantissa and
5633 * produces an unsigned result so this is just a wrapper that does
5634 * nothing (and is likely inlined).
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005635 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005636static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005637QCBOR_Private_ExponentitateUU(const uint64_t uMantissa,
5638 const int64_t nExponent,
5639 uint64_t *puResult,
5640 fExponentiator pfExp)
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005641{
5642 return (*pfExp)(uMantissa, nExponent, puResult);
5643}
5644
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005645#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005646
5647
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005648
5649
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005650/**
5651 * @brief Convert a CBOR big number to a uint64_t.
5652 *
5653 * @param[in] BigNum Bytes of the big number to convert.
5654 * @param[in] uMax Maximum value allowed for the result.
5655 * @param[out] pResult Place to put the unsigned integer result.
5656 *
5657 * @returns Error code
5658 *
5659 * Many values will overflow because a big num can represent a much
5660 * larger range than uint64_t.
5661 */
5662static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005663QCBOR_Private_ConvertBigNumToUnsigned(const UsefulBufC BigNum,
5664 const uint64_t uMax,
5665 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005666{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005667 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005668
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005669 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005670 const uint8_t *pByte = BigNum.ptr;
5671 size_t uLen = BigNum.len;
5672 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07005673 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005674 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005675 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07005676 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005677 }
5678
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005679 *pResult = uResult;
5680 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005681}
5682
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005683
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005684/**
5685 * @brief Convert a CBOR postive big number to a uint64_t.
5686 *
5687 * @param[in] BigNum Bytes of the big number to convert.
5688 * @param[out] pResult Place to put the unsigned integer result.
5689 *
5690 * @returns Error code
5691 *
5692 * Many values will overflow because a big num can represent a much
5693 * larger range than uint64_t.
5694 */
5695static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005696QCBOR_Private_ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum,
5697 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005698{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005699 return QCBOR_Private_ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005700}
5701
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005702
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005703/**
5704 * @brief Convert a CBOR positive big number to an int64_t.
5705 *
5706 * @param[in] BigNum Bytes of the big number to convert.
5707 * @param[out] pResult Place to put the signed integer result.
5708 *
5709 * @returns Error code
5710 *
5711 * Many values will overflow because a big num can represent a much
5712 * larger range than int64_t.
5713 */
5714static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005715QCBOR_Private_ConvertPositiveBigNumToSigned(const UsefulBufC BigNum,
5716 int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005717{
5718 uint64_t uResult;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005719 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5720 INT64_MAX,
5721 &uResult);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005722 if(uError) {
5723 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005724 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005725 /* Cast is safe because ConvertBigNumToUnsigned limits to INT64_MAX */
Laurence Lundbladee6430642020-03-14 21:15:44 -07005726 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005727 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005728}
5729
5730
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005731/**
5732 * @brief Convert a CBOR negative big number to an int64_t.
5733 *
5734 * @param[in] BigNum Bytes of the big number to convert.
5735 * @param[out] pnResult Place to put the signed integer result.
5736 *
5737 * @returns Error code
5738 *
5739 * Many values will overflow because a big num can represent a much
5740 * larger range than int64_t.
5741 */
5742static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005743QCBOR_Private_ConvertNegativeBigNumToSigned(const UsefulBufC BigNum,
5744 int64_t *pnResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005745{
5746 uint64_t uResult;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005747 /* The negative integer furthest from zero for a C int64_t is
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005748 * INT64_MIN which is expressed as -INT64_MAX - 1. The value of a
5749 * negative number in CBOR is computed as -n - 1 where n is the
5750 * encoded integer, where n is what is in the variable BigNum. When
5751 * converting BigNum to a uint64_t, the maximum value is thus
5752 * INT64_MAX, so that when it -n - 1 is applied to it the result
5753 * will never be further from 0 than INT64_MIN.
5754 *
5755 * -n - 1 <= INT64_MIN.
5756 * -n - 1 <= -INT64_MAX - 1
5757 * n <= INT64_MAX.
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005758 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005759 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5760 INT64_MAX,
5761 &uResult);
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005762 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005763 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005764 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005765
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005766 /* Now apply -n - 1. The cast is safe because
5767 * ConvertBigNumToUnsigned() is limited to INT64_MAX which does fit
5768 * is the largest positive integer that an int64_t can
5769 * represent. */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005770 *pnResult = -(int64_t)uResult - 1;
5771
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005772 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005773}
5774
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005775
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005776
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005777
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005778/**
5779 * @brief Convert integers and floats to an int64_t.
5780 *
5781 * @param[in] pItem The item to convert.
5782 * @param[in] uConvertTypes Bit mask list of conversion options.
5783 * @param[out] pnValue The resulting converted value.
5784 *
5785 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5786 * in uConvertTypes.
5787 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5788 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5789 * or too small.
5790 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005791static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005792QCBOR_Private_ConvertInt64(const QCBORItem *pItem,
5793 const uint32_t uConvertTypes,
5794 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005795{
5796 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005797 case QCBOR_TYPE_FLOAT:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005798 case QCBOR_TYPE_DOUBLE:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005799#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005800 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005801 /* https://pubs.opengroup.org/onlinepubs/009695399/functions/llround.html
5802 http://www.cplusplus.com/reference/cmath/llround/
5803 */
5804 // Not interested in FE_INEXACT
5805 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005806 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5807 *pnValue = llround(pItem->val.dfnum);
5808 } else {
5809 *pnValue = lroundf(pItem->val.fnum);
5810 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005811 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5812 // llround() shouldn't result in divide by zero, but catch
5813 // it here in case it unexpectedly does. Don't try to
5814 // distinguish between the various exceptions because it seems
5815 // they vary by CPU, compiler and OS.
5816 return QCBOR_ERR_FLOAT_EXCEPTION;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005817 }
5818 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005819 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005820 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005821#else
5822 return QCBOR_ERR_HW_FLOAT_DISABLED;
5823#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005824 break;
5825
5826 case QCBOR_TYPE_INT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005827 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005828 *pnValue = pItem->val.int64;
5829 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005830 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005831 }
5832 break;
5833
5834 case QCBOR_TYPE_UINT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005835 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005836 if(pItem->val.uint64 < INT64_MAX) {
5837 *pnValue = pItem->val.int64;
5838 } else {
5839 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5840 }
5841 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005842 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005843 }
5844 break;
5845
Laurence Lundblade2d493002024-02-01 11:09:17 -07005846 case QCBOR_TYPE_65BIT_NEG_INT:
5847 /* This type occurs if the value won't fit into int64_t
5848 * so this is always an error. */
5849 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5850 break;
5851
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005852 default:
5853 return QCBOR_ERR_UNEXPECTED_TYPE;
5854 }
5855 return QCBOR_SUCCESS;
5856}
5857
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005858
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005859/**
5860 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5861 *
5862 * @param[in] pMe The decode context.
5863 * @param[in] uConvertTypes Bit mask list of conversion options.
5864 * @param[out] pnValue Result of the conversion.
5865 * @param[in,out] pItem Temporary space to store Item, returned item.
5866 *
5867 * See QCBORDecode_GetInt64Convert().
5868 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005869void
5870QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pMe,
5871 uint32_t uConvertTypes,
5872 int64_t *pnValue,
5873 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005874{
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07005875 QCBORDecode_VGetNext(pMe, pItem);
5876 if(pMe->uLastError) {
Laurence Lundbladee6430642020-03-14 21:15:44 -07005877 return;
5878 }
5879
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005880 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005881 uConvertTypes,
5882 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005883}
5884
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005885/**
5886 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5887 *
5888 * @param[in] pMe The decode context.
5889 * @param[in] nLabel Label to find in map.
5890 * @param[in] uConvertTypes Bit mask list of conversion options.
5891 * @param[out] pnValue Result of the conversion.
5892 * @param[in,out] pItem Temporary space to store Item, returned item.
5893 *
5894 * See QCBORDecode_GetInt64ConvertInMapN().
5895 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005896void
5897QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pMe,
5898 int64_t nLabel,
5899 uint32_t uConvertTypes,
5900 int64_t *pnValue,
5901 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005902{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005903 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005904 if(pMe->uLastError != QCBOR_SUCCESS) {
5905 return;
5906 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005907
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005908 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5909 uConvertTypes,
5910 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005911}
5912
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005913/**
5914 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5915 *
5916 * @param[in] pMe The decode context.
5917 * @param[in] szLabel Label to find in map.
5918 * @param[in] uConvertTypes Bit mask list of conversion options.
5919 * @param[out] pnValue Result of the conversion.
5920 * @param[in,out] pItem Temporary space to store Item, returned item.
5921 *
5922 * See QCBORDecode_GetInt64ConvertInMapSZ().
5923 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005924void
5925QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5926 const char * szLabel,
5927 uint32_t uConvertTypes,
5928 int64_t *pnValue,
5929 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005930{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005931 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005932 if(pMe->uLastError != QCBOR_SUCCESS) {
5933 return;
5934 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005935
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005936 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5937 uConvertTypes,
5938 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005939}
5940
5941
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005942/**
5943 * @brief Convert many number types to an int64_t.
5944 *
5945 * @param[in] pItem The item to convert.
5946 * @param[in] uConvertTypes Bit mask list of conversion options.
5947 * @param[out] pnValue The resulting converted value.
5948 *
5949 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5950 * in uConvertTypes.
5951 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5952 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5953 * or too small.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005954 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005955static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005956QCBOR_Private_Int64ConvertAll(const QCBORItem *pItem,
5957 const uint32_t uConvertTypes,
5958 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005959{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005960 switch(pItem->uDataType) {
5961
5962 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005963 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005964 return QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005965 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005966 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005967 }
5968 break;
5969
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005970 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005971 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005972 return QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005973 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005974 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005975 }
5976 break;
5977
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005978#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005979 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005980 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005981 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005982 pItem->val.expAndMantissa.nExponent,
5983 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005984 &QCBOR_Private_Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005985 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005986 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005987 }
5988 break;
5989
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005990 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005991 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005992 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005993 pItem->val.expAndMantissa.nExponent,
5994 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005995 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005996 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005997 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005998 }
5999 break;
6000
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006001 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006002 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006003 int64_t nMantissa;
6004 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006005 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006006 if(uErr) {
6007 return uErr;
6008 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006009 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006010 pItem->val.expAndMantissa.nExponent,
6011 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006012 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006013 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006014 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006015 }
6016 break;
6017
6018 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006019 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006020 int64_t nMantissa;
6021 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006022 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006023 if(uErr) {
6024 return uErr;
6025 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006026 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006027 pItem->val.expAndMantissa.nExponent,
6028 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006029 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006030 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006031 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006032 }
6033 break;
6034
6035 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006036 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006037 int64_t nMantissa;
6038 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006039 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006040 if(uErr) {
6041 return uErr;
6042 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006043 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006044 pItem->val.expAndMantissa.nExponent,
6045 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006046 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006047 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006048 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006049 }
6050 break;
6051
6052 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006053 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006054 int64_t nMantissa;
6055 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006056 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006057 if(uErr) {
6058 return uErr;
6059 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006060 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006061 pItem->val.expAndMantissa.nExponent,
6062 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006063 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006064 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006065 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07006066 }
6067 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006068#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006069
Laurence Lundbladee6430642020-03-14 21:15:44 -07006070
Laurence Lundbladec4537442020-04-14 18:53:22 -07006071 default:
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006072 return QCBOR_ERR_UNEXPECTED_TYPE; }
Laurence Lundbladec4537442020-04-14 18:53:22 -07006073}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006074
6075
Laurence Lundbladec4537442020-04-14 18:53:22 -07006076/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006077 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006078 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006079void
6080QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe,
6081 const uint32_t uConvertTypes,
6082 int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07006083{
6084 QCBORItem Item;
6085
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006086 QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07006087
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006088 if(pMe->uLastError == QCBOR_SUCCESS) {
6089 // The above conversion succeeded
6090 return;
6091 }
6092
Laurence Lundbladef6c86662020-05-12 02:08:00 -07006093 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006094 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07006095 return;
6096 }
6097
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006098 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
6099 uConvertTypes,
6100 pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006101}
6102
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006103
6104/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006105 * Public function, see header qcbor/qcbor_decode.h file
6106 */
6107void
6108QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
6109 const int64_t nLabel,
6110 const uint32_t uConvertTypes,
6111 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006112{
6113 QCBORItem Item;
6114
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006115 QCBORDecode_Private_GetInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006116 nLabel,
6117 uConvertTypes,
6118 pnValue,
6119 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006120
6121 if(pMe->uLastError == QCBOR_SUCCESS) {
6122 // The above conversion succeeded
6123 return;
6124 }
6125
6126 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6127 // The above conversion failed in a way that code below can't correct
6128 return;
6129 }
6130
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006131 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
6132 uConvertTypes,
6133 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006134}
6135
6136
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006137/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006138 * Public function, see header qcbor/qcbor_decode.h file
6139 */
6140void
6141QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
6142 const char *szLabel,
6143 const uint32_t uConvertTypes,
6144 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006145{
6146 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006147 QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006148 szLabel,
6149 uConvertTypes,
6150 pnValue,
6151 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006152
6153 if(pMe->uLastError == QCBOR_SUCCESS) {
6154 // The above conversion succeeded
6155 return;
6156 }
6157
6158 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6159 // The above conversion failed in a way that code below can't correct
6160 return;
6161 }
6162
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006163 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
6164 uConvertTypes,
6165 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006166}
6167
6168
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006169/**
6170 * @brief Convert many number types to an uint64_t.
6171 *
6172 * @param[in] pItem The item to convert.
6173 * @param[in] uConvertTypes Bit mask list of conversion options.
6174 * @param[out] puValue The resulting converted value.
6175 *
6176 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6177 * in uConvertTypes.
6178 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6179 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6180 * or too small.
6181 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006182static QCBORError
6183QCBOR_Private_ConvertUInt64(const QCBORItem *pItem,
6184 const uint32_t uConvertTypes,
6185 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006186{
6187 switch(pItem->uDataType) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006188 case QCBOR_TYPE_DOUBLE:
6189 case QCBOR_TYPE_FLOAT:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006190#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006191 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006192 // Can't use llround here because it will not convert values
6193 // greater than INT64_MAX and less than UINT64_MAX that
6194 // need to be converted so it is more complicated.
6195 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
6196 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
6197 if(isnan(pItem->val.dfnum)) {
6198 return QCBOR_ERR_FLOAT_EXCEPTION;
6199 } else if(pItem->val.dfnum < 0) {
6200 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6201 } else {
6202 double dRounded = round(pItem->val.dfnum);
6203 // See discussion in DecodeDateEpoch() for
6204 // explanation of - 0x7ff
6205 if(dRounded > (double)(UINT64_MAX- 0x7ff)) {
6206 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
6207 }
6208 *puValue = (uint64_t)dRounded;
6209 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006210 } else {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006211 if(isnan(pItem->val.fnum)) {
6212 return QCBOR_ERR_FLOAT_EXCEPTION;
6213 } else if(pItem->val.fnum < 0) {
6214 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6215 } else {
6216 float fRounded = roundf(pItem->val.fnum);
6217 // See discussion in DecodeDateEpoch() for
6218 // explanation of - 0x7ff
6219 if(fRounded > (float)(UINT64_MAX- 0x7ff)) {
6220 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
6221 }
6222 *puValue = (uint64_t)fRounded;
6223 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006224 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006225 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
6226 // round() and roundf() shouldn't result in exceptions here, but
6227 // catch them to be robust and thorough. Don't try to
6228 // distinguish between the various exceptions because it seems
6229 // they vary by CPU, compiler and OS.
6230 return QCBOR_ERR_FLOAT_EXCEPTION;
6231 }
6232
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006233 } else {
6234 return QCBOR_ERR_UNEXPECTED_TYPE;
6235 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006236#else
6237 return QCBOR_ERR_HW_FLOAT_DISABLED;
6238#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006239 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07006240
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006241 case QCBOR_TYPE_INT64:
6242 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
6243 if(pItem->val.int64 >= 0) {
6244 *puValue = (uint64_t)pItem->val.int64;
6245 } else {
6246 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6247 }
6248 } else {
6249 return QCBOR_ERR_UNEXPECTED_TYPE;
6250 }
6251 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006252
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006253 case QCBOR_TYPE_UINT64:
6254 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade2d493002024-02-01 11:09:17 -07006255 *puValue = pItem->val.uint64;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006256 } else {
6257 return QCBOR_ERR_UNEXPECTED_TYPE;
6258 }
6259 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006260
Laurence Lundblade2d493002024-02-01 11:09:17 -07006261 case QCBOR_TYPE_65BIT_NEG_INT:
6262 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6263
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006264 default:
6265 return QCBOR_ERR_UNEXPECTED_TYPE;
6266 }
6267
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006268 return QCBOR_SUCCESS;
6269}
Laurence Lundbladec4537442020-04-14 18:53:22 -07006270
6271
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006272/**
6273 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
6274 *
6275 * @param[in] pMe The decode context.
6276 * @param[in] uConvertTypes Bit mask list of conversion options.
6277 * @param[out] puValue Result of the conversion.
6278 * @param[in,out] pItem Temporary space to store Item, returned item.
6279 *
6280 * See QCBORDecode_GetUInt64Convert().
6281 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006282void
6283QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pMe,
6284 const uint32_t uConvertTypes,
6285 uint64_t *puValue,
6286 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07006287{
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07006288 QCBORDecode_VGetNext(pMe, pItem);
6289 if(pMe->uLastError) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006290 return;
6291 }
6292
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07006293 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006294 uConvertTypes,
6295 puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07006296}
6297
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006298
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006299/**
6300 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
6301 *
6302 * @param[in] pMe The decode context.
6303 * @param[in] nLabel Label to find in map.
6304 * @param[in] uConvertTypes Bit mask list of conversion options.
6305 * @param[out] puValue Result of the conversion.
6306 * @param[in,out] pItem Temporary space to store Item, returned item.
6307 *
6308 * See QCBORDecode_GetUInt64ConvertInMapN().
6309 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006310void
6311QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe,
6312 const int64_t nLabel,
6313 const uint32_t uConvertTypes,
6314 uint64_t *puValue,
6315 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006316{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006317 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006318 if(pMe->uLastError != QCBOR_SUCCESS) {
6319 return;
6320 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006321
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006322 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
6323 uConvertTypes,
6324 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006325}
6326
6327
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006328/**
6329 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
6330 *
6331 * @param[in] pMe The decode context.
6332 * @param[in] szLabel Label to find in map.
6333 * @param[in] uConvertTypes Bit mask list of conversion options.
6334 * @param[out] puValue Result of the conversion.
6335 * @param[in,out] pItem Temporary space to store Item, returned item.
6336 *
6337 * See QCBORDecode_GetUInt64ConvertInMapSZ().
6338 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006339void
6340QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
6341 const char *szLabel,
6342 const uint32_t uConvertTypes,
6343 uint64_t *puValue,
6344 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006345{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006346 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006347 if(pMe->uLastError != QCBOR_SUCCESS) {
6348 return;
6349 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006350
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006351 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
6352 uConvertTypes,
6353 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006354}
6355
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006356
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006357/**
6358 * @brief Convert many number types to an unt64_t.
6359 *
6360 * @param[in] pItem The item to convert.
6361 * @param[in] uConvertTypes Bit mask list of conversion options.
6362 * @param[out] puValue The resulting converted value.
6363 *
6364 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6365 * in uConvertTypes.
6366 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6367 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6368 * or too small.
6369 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006370static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006371QCBOR_Private_UInt64ConvertAll(const QCBORItem *pItem,
6372 const uint32_t uConvertTypes,
6373 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006374{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08006375 switch(pItem->uDataType) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006376
6377 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006378 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006379 return QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006380 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006381 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006382 }
6383 break;
6384
6385 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006386 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006387 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6388 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006389 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006390 }
6391 break;
6392
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006393#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006394
6395 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006396 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006397 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006398 pItem->val.expAndMantissa.nExponent,
6399 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006400 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006401 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006402 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006403 }
6404 break;
6405
6406 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006407 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006408 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006409 pItem->val.expAndMantissa.nExponent,
6410 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006411 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006412 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006413 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006414 }
6415 break;
6416
6417 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006418 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006419 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006420 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006421 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006422 if(uErr != QCBOR_SUCCESS) {
6423 return uErr;
6424 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006425 return QCBOR_Private_ExponentitateUU(uMantissa,
6426 pItem->val.expAndMantissa.nExponent,
6427 puValue,
6428 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006429 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006430 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006431 }
6432 break;
6433
6434 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006435 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006436 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6437 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006438 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006439 }
6440 break;
6441
6442 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006443 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006444 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006445 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006446 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum,
6447 &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006448 if(uErr != QCBOR_SUCCESS) {
6449 return uErr;
6450 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006451 return QCBOR_Private_ExponentitateUU(uMantissa,
6452 pItem->val.expAndMantissa.nExponent,
6453 puValue,
6454 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006455 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006456 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006457 }
6458 break;
6459
6460 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006461 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006462 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6463 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006464 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006465 }
6466 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006467#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006468 default:
6469 return QCBOR_ERR_UNEXPECTED_TYPE;
6470 }
6471}
6472
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006473
Laurence Lundblade4e2da002020-06-13 23:08:31 -07006474/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006475 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006476 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006477void
6478QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe,
6479 const uint32_t uConvertTypes,
6480 uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006481{
6482 QCBORItem Item;
6483
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006484 QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006485
Laurence Lundbladef6c86662020-05-12 02:08:00 -07006486 if(pMe->uLastError == QCBOR_SUCCESS) {
6487 // The above conversion succeeded
6488 return;
6489 }
6490
6491 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6492 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07006493 return;
6494 }
6495
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006496 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6497 uConvertTypes,
6498 puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006499}
6500
Laurence Lundbladec4537442020-04-14 18:53:22 -07006501
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006502/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006503 * Public function, see header qcbor/qcbor_decode.h file
6504 */
6505void
6506QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
6507 const int64_t nLabel,
6508 const uint32_t uConvertTypes,
6509 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006510{
6511 QCBORItem Item;
6512
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006513 QCBORDecode_Private_GetUInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006514 nLabel,
6515 uConvertTypes,
6516 puValue,
6517 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006518
6519 if(pMe->uLastError == QCBOR_SUCCESS) {
6520 // The above conversion succeeded
6521 return;
6522 }
6523
6524 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6525 // The above conversion failed in a way that code below can't correct
6526 return;
6527 }
6528
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006529 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6530 uConvertTypes,
6531 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006532}
6533
6534
6535/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006536 * Public function, see header qcbor/qcbor_decode.h file
6537 */
6538void
6539QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
6540 const char *szLabel,
6541 const uint32_t uConvertTypes,
6542 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006543{
6544 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006545 QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006546 szLabel,
6547 uConvertTypes,
6548 puValue,
6549 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006550
6551 if(pMe->uLastError == QCBOR_SUCCESS) {
6552 // The above conversion succeeded
6553 return;
6554 }
6555
6556 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6557 // The above conversion failed in a way that code below can't correct
6558 return;
6559 }
6560
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006561 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6562 uConvertTypes,
6563 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006564}
6565
6566
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006567
6568
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006569#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006570/**
6571 * @brief Basic conversions to a double.
6572 *
6573 * @param[in] pItem The item to convert
6574 * @param[in] uConvertTypes Bit flags indicating source types for conversion
6575 * @param[out] pdValue The value converted to a double
6576 *
6577 * This does the conversions that don't need much object code,
6578 * the conversions from int, uint and float to double.
6579 *
6580 * See QCBOR_Private_DoubleConvertAll() for the full set
6581 * of conversions.
6582 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006583static QCBORError
6584QCBOR_Private_ConvertDouble(const QCBORItem *pItem,
6585 const uint32_t uConvertTypes,
6586 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006587{
6588 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006589 case QCBOR_TYPE_FLOAT:
6590#ifndef QCBOR_DISABLE_FLOAT_HW_USE
6591 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6592 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006593 // Simple cast does the job.
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006594 *pdValue = (double)pItem->val.fnum;
6595 } else {
6596 return QCBOR_ERR_UNEXPECTED_TYPE;
6597 }
6598 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006599#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006600 return QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006601#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006602 break;
6603
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006604 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006605 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6606 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006607 *pdValue = pItem->val.dfnum;
6608 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006609 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006610 }
6611 }
6612 break;
6613
6614 case QCBOR_TYPE_INT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006615#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006616 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006617 // A simple cast seems to do the job with no worry of exceptions.
6618 // There will be precision loss for some values.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006619 *pdValue = (double)pItem->val.int64;
6620
6621 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006622 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006623 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006624#else
6625 return QCBOR_ERR_HW_FLOAT_DISABLED;
6626#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006627 break;
6628
6629 case QCBOR_TYPE_UINT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006630#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006631 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006632 // A simple cast seems to do the job with no worry of exceptions.
6633 // There will be precision loss for some values.
6634 *pdValue = (double)pItem->val.uint64;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006635 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006636 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006637 }
6638 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006639#else
6640 return QCBOR_ERR_HW_FLOAT_DISABLED;
6641#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006642
Laurence Lundblade2d493002024-02-01 11:09:17 -07006643 case QCBOR_TYPE_65BIT_NEG_INT:
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -08006644#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade14ce2282024-07-24 22:13:35 -07006645 // TODO: don't use float HW. We have the function to do it.
Laurence Lundblade2d493002024-02-01 11:09:17 -07006646 *pdValue = -(double)pItem->val.uint64 - 1;
6647 break;
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -08006648#else
6649 return QCBOR_ERR_HW_FLOAT_DISABLED;
6650#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade2d493002024-02-01 11:09:17 -07006651
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006652 default:
6653 return QCBOR_ERR_UNEXPECTED_TYPE;
6654 }
6655
6656 return QCBOR_SUCCESS;
6657}
6658
6659
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006660/**
6661 * @brief Almost-public method to decode a number and convert to double (semi-private).
6662 *
6663 * @param[in] pMe The decode context.
6664 * @param[in] uConvertTypes Bit mask list of conversion options
6665 * @param[out] pdValue The output of the conversion.
6666 * @param[in,out] pItem Temporary space to store Item, returned item.
6667 *
6668 * See QCBORDecode_GetDoubleConvert().
6669 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006670void
6671QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pMe,
6672 const uint32_t uConvertTypes,
6673 double *pdValue,
6674 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07006675{
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07006676 QCBORDecode_VGetNext(pMe, pItem);
6677 if(pMe->uLastError) {
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006678 return;
6679 }
6680
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006681 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006682 uConvertTypes,
6683 pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006684}
Laurence Lundbladec4537442020-04-14 18:53:22 -07006685
Laurence Lundbladec4537442020-04-14 18:53:22 -07006686
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006687/**
6688 * @brief Almost-public method to decode a number and convert to double (semi-private).
6689 *
6690 * @param[in] pMe The decode context.
6691 * @param[in] nLabel Label to find in map.
6692 * @param[in] uConvertTypes Bit mask list of conversion options
6693 * @param[out] pdValue The output of the conversion.
6694 * @param[in,out] pItem Temporary space to store Item, returned item.
6695 *
6696 * See QCBORDecode_GetDoubleConvertInMapN().
6697 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006698void
6699QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pMe,
6700 const int64_t nLabel,
6701 const uint32_t uConvertTypes,
6702 double *pdValue,
6703 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006704{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006705 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006706 if(pMe->uLastError != QCBOR_SUCCESS) {
6707 return;
6708 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006709
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006710 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6711 uConvertTypes,
6712 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006713}
6714
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006715
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006716/**
6717 * @brief Almost-public method to decode a number and convert to double (semi-private).
6718 *
6719 * @param[in] pMe The decode context.
6720 * @param[in] szLabel Label to find in map.
6721 * @param[in] uConvertTypes Bit mask list of conversion options
6722 * @param[out] pdValue The output of the conversion.
6723 * @param[in,out] pItem Temporary space to store Item, returned item.
6724 *
6725 * See QCBORDecode_GetDoubleConvertInMapSZ().
6726 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006727void
6728QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe,
6729 const char *szLabel,
6730 const uint32_t uConvertTypes,
6731 double *pdValue,
6732 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006733{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006734 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006735 if(pMe->uLastError != QCBOR_SUCCESS) {
6736 return;
6737 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006738
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006739 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6740 uConvertTypes,
6741 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006742}
6743
6744
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006745#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006746/**
6747 * @brief Convert a big number to double-precision float.
6748 *
6749 * @param[in] BigNum The big number to convert
6750 *
6751 * @returns The double value.
6752 *
6753 * This will always succeed. It will lose precision for larger
6754 * numbers. If the big number is too large to fit (more than
6755 * 1.7976931348623157E+308) infinity will be returned. NaN is never
6756 * returned.
6757 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006758static double
6759QCBOR_Private_ConvertBigNumToDouble(const UsefulBufC BigNum)
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006760{
6761 double dResult;
6762
6763 dResult = 0.0;
6764 const uint8_t *pByte = BigNum.ptr;
6765 size_t uLen = BigNum.len;
6766 /* This will overflow and become the float value INFINITY if the number
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006767 * is too large to fit. */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006768 while(uLen--) {
6769 dResult = (dResult * 256.0) + (double)*pByte++;
6770 }
6771
6772 return dResult;
6773}
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006774#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6775
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006776
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006777
6778
6779/**
6780 * @brief Convert many number types to a double.
6781 *
6782 * @param[in] pItem The item to convert.
6783 * @param[in] uConvertTypes Bit mask list of conversion options.
6784 * @param[out] pdValue The resulting converted value.
6785 *
6786 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6787 * in uConvertTypes.
6788 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6789 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6790 * or too small.
6791 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006792static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006793QCBOR_Private_DoubleConvertAll(const QCBORItem *pItem,
6794 const uint32_t uConvertTypes,
6795 double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006796{
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006797#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07006798 /*
Laurence Lundblade16a207a2021-09-18 17:22:46 -07006799 * What Every Computer Scientist Should Know About Floating-Point Arithmetic
6800 * https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
6801 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006802 switch(pItem->uDataType) {
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006803
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006804#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006805 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006806 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006807 // Underflow gives 0, overflow gives infinity
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006808 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6809 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
6810 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006811 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006812 }
6813 break;
6814
6815 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006816 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006817 // Underflow gives 0, overflow gives infinity
6818 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6819 exp2((double)pItem->val.expAndMantissa.nExponent);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006820 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006821 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006822 }
6823 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006824#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006825
6826 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006827 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006828 *pdValue = QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006829 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006830 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006831 }
6832 break;
6833
6834 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006835 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006836 *pdValue = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006837 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006838 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006839 }
6840 break;
6841
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006842#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006843 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006844 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006845 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006846 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6847 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006848 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006849 }
6850 break;
6851
6852 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006853 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006854 double dMantissa = -QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006855 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6856 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006857 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006858 }
6859 break;
6860
6861 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006862 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006863 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006864 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6865 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006866 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006867 }
6868 break;
6869
6870 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006871 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006872 double dMantissa = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006873 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6874 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006875 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006876 }
6877 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006878#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006879
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006880 default:
6881 return QCBOR_ERR_UNEXPECTED_TYPE;
6882 }
6883
6884 return QCBOR_SUCCESS;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006885
6886#else
6887 (void)pItem;
6888 (void)uConvertTypes;
6889 (void)pdValue;
6890 return QCBOR_ERR_HW_FLOAT_DISABLED;
6891#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6892
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006893}
6894
6895
6896/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006897 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006898 */
6899void
6900QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe,
6901 const uint32_t uConvertTypes,
6902 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006903{
6904
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006905 QCBORItem Item;
6906
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006907 QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006908
6909 if(pMe->uLastError == QCBOR_SUCCESS) {
6910 // The above conversion succeeded
6911 return;
6912 }
6913
6914 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6915 // The above conversion failed in a way that code below can't correct
6916 return;
6917 }
6918
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006919 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6920 uConvertTypes,
6921 pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006922}
6923
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006924
6925/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006926 * Public function, see header qcbor/qcbor_decode.h file
6927 */
6928void
6929QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe,
6930 const int64_t nLabel,
6931 const uint32_t uConvertTypes,
6932 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006933{
6934 QCBORItem Item;
6935
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006936 QCBORDecode_Private_GetDoubleConvertInMapN(pMe,
6937 nLabel,
6938 uConvertTypes,
6939 pdValue,
6940 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006941
6942 if(pMe->uLastError == QCBOR_SUCCESS) {
6943 // The above conversion succeeded
6944 return;
6945 }
6946
6947 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6948 // The above conversion failed in a way that code below can't correct
6949 return;
6950 }
6951
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006952 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6953 uConvertTypes,
6954 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006955}
6956
6957
6958/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006959 * Public function, see header qcbor/qcbor_decode.h file
6960 */
6961void
6962QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe,
6963 const char *szLabel,
6964 const uint32_t uConvertTypes,
6965 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006966{
6967 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006968 QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe,
6969 szLabel,
6970 uConvertTypes,
6971 pdValue,
6972 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006973
6974 if(pMe->uLastError == QCBOR_SUCCESS) {
6975 // The above conversion succeeded
6976 return;
6977 }
6978
6979 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6980 // The above conversion failed in a way that code below can't correct
6981 return;
6982 }
6983
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006984 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6985 uConvertTypes,
6986 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006987}
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006988#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006989
6990
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006991
6992
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006993#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006994/**
6995 * @brief Convert an integer to a big number
6996 *
6997 * @param[in] uInt The integer to convert.
6998 * @param[in] Buffer The buffer to output the big number to.
6999 *
7000 * @returns The big number or NULLUsefulBufC is the buffer is to small.
7001 *
7002 * This always succeeds unless the buffer is too small.
7003 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007004static UsefulBufC
7005QCBOR_Private_ConvertIntToBigNum(uint64_t uInt, const UsefulBuf Buffer)
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07007006{
7007 while((uInt & 0xff00000000000000UL) == 0) {
7008 uInt = uInt << 8;
7009 };
7010
7011 UsefulOutBuf UOB;
7012
7013 UsefulOutBuf_Init(&UOB, Buffer);
7014
7015 while(uInt) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07007016 UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff00000000000000UL) >> 56));
7017 uInt = uInt << 8;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07007018 }
7019
7020 return UsefulOutBuf_OutUBuf(&UOB);
7021}
7022
7023
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007024
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007025
Laurence Lundblade37286c02022-09-03 10:05:02 -07007026/* Some notes from the work to disable tags.
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007027 * Some are out of date since tag refactoring.
Laurence Lundblade37286c02022-09-03 10:05:02 -07007028 *
7029 * The API for big floats and decimal fractions seems good.
7030 * If there's any issue with it it's that the code size to
7031 * implement is a bit large because of the conversion
7032 * to/from int and bignum that is required. There is no API
7033 * that doesn't do the conversion so dead stripping will never
7034 * leave that code out.
7035 *
7036 * The implementation itself seems correct, but not as clean
7037 * and neat as it could be. It could probably be smaller too.
7038 *
7039 * The implementation has three main parts / functions
7040 * - The decoding of the array of two
7041 * - All the tag and type checking for the various API functions
7042 * - Conversion to/from bignum and int
7043 *
7044 * The type checking seems like it wastes the most code for
7045 * what it needs to do.
7046 *
7047 * The inlining for the conversion is probably making the
7048 * overall code base larger.
7049 *
7050 * The tests cases could be organized a lot better and be
7051 * more thorough.
7052 *
7053 * Seems also like there could be more common code in the
7054 * first tier part of the public API. Some functions only
7055 * vary by a TagSpec.
7056 */
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007057
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007058
7059static const uint8_t QCBORDecode_Private_DecimalFractionTypes[] = {
7060 QCBOR_TYPE_DECIMAL_FRACTION,
7061 QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7062 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM,
7063 QCBOR_TYPE_NONE};
7064
7065static const uint8_t QCBORDecode_Private_BigFloatTypes[] = {
7066 QCBOR_TYPE_BIGFLOAT,
7067 QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7068 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM,
7069 QCBOR_TYPE_NONE};
7070
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007071/**
7072 * @brief Common processor for exponent and mantissa.
7073 *
7074 * @param[in] pMe The decode context.
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007075 * @param[in] uTagRequirement Whether tag number must be present or not.
7076 * @param[in] uTagNumber The tag number for which content is expected.
7077 * @param[in] uOffset Cursor offset for tag number consumption checking.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007078 * @param[in] pItem The data item to process.
7079 * @param[out] pnMantissa The returned mantissa as an int64_t.
7080 * @param[out] pnExponent The returned exponent as an int64_t.
7081 *
7082 * This handles exponent and mantissa for base 2 and 10. This
7083 * is limited to a mantissa that is an int64_t. See also
7084 * QCBORDecode_Private_ProcessExpMantissaBig().
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007085 *
7086 * On output, the item is always a fully decoded decimal fraction or
7087 * big float.
7088 *
7089 * This errors out if the input type does not meet the TagSpec.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007090 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007091static void
7092QCBOR_Private_ProcessExpMantissa(QCBORDecodeContext *pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007093 const uint8_t uTagRequirement,
7094 const uint64_t uTagNumber,
7095 const size_t uOffset,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007096 QCBORItem *pItem,
7097 int64_t *pnMantissa,
7098 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007099{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007100 QCBORError uErr = QCBOR_SUCCESS;
7101 const uint8_t *qTypes;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007102
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07007103 if(pMe->uLastError) {
7104 return;
7105 }
7106
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007107 if(uTagNumber == CBOR_TAG_BIGFLOAT) {
7108 qTypes = QCBORDecode_Private_BigFloatTypes;
7109 } else {
7110 qTypes = QCBORDecode_Private_DecimalFractionTypes;
7111 }
7112
7113 QCBORDecode_Private_ProcessTagItem(pMe,
7114 pItem,
7115 uTagRequirement,
7116 qTypes,
7117 uTagNumber,
7118 QCBORDecode_ExpMantissaTagCB,
7119 uOffset);
7120
7121 if(pMe->uLastError != QCBOR_SUCCESS) {
7122 return;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007123 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007124
Laurence Lundblade9b334962020-08-27 10:55:53 -07007125 switch (pItem->uDataType) {
7126
7127 case QCBOR_TYPE_DECIMAL_FRACTION:
7128 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade9b334962020-08-27 10:55:53 -07007129 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade37286c02022-09-03 10:05:02 -07007130 *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
Laurence Lundblade9b334962020-08-27 10:55:53 -07007131 break;
7132
Laurence Lundblade37286c02022-09-03 10:05:02 -07007133#ifndef QCBOR_DISABLE_TAGS
7134 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundblade9b334962020-08-27 10:55:53 -07007135 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
7136 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
7137 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007138 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07007139 break;
7140
7141 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
7142 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
7143 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007144 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07007145 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07007146#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07007147
7148 default:
7149 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
7150 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007151
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007152 // Done:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007153 pMe->uLastError = (uint8_t)uErr;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007154}
7155
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007156
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007157/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007158 * @brief Decode exponent and mantissa into a big number.
7159 *
7160 * @param[in] pMe The decode context.
7161 * @param[in] TagSpec The expected/allowed tags.
7162 * @param[in] pItem Item to decode and convert.
7163 * @param[in] BufferForMantissa Buffer to output mantissa into.
7164 * @param[out] pMantissa The output mantissa.
7165 * @param[out] pbIsNegative The sign of the output.
7166 * @param[out] pnExponent The mantissa of the output.
7167 *
7168 * This is the common processing of a decimal fraction or a big float
7169 * into a big number. This will decode and consume all the CBOR items
7170 * that make up the decimal fraction or big float.
7171 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007172static void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007173QCBORDecode_Private_ProcessExpMantissaBig(QCBORDecodeContext *pMe,
7174 const uint8_t uTagRequirement,
7175 const uint64_t uTagNumber,
7176 const size_t uOffset,
7177 QCBORItem *pItem,
7178 const UsefulBuf BufferForMantissa,
7179 UsefulBufC *pMantissa,
7180 bool *pbIsNegative,
7181 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007182{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007183 QCBORError uErr = QCBOR_SUCCESS;
7184 const uint8_t *qTypes;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007185
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007186 if(pMe->uLastError) {
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07007187 return;
7188 }
7189
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007190 if(uTagNumber == CBOR_TAG_BIGFLOAT) {
7191 qTypes = QCBORDecode_Private_BigFloatTypes;
7192 } else {
7193 qTypes = QCBORDecode_Private_DecimalFractionTypes;
7194 }
7195
7196 QCBORDecode_Private_ProcessTagItem(pMe,
7197 pItem,
7198 uTagRequirement,
7199 qTypes,
7200 uTagNumber,
7201 QCBORDecode_ExpMantissaTagCB,
7202 uOffset);
7203
7204 if(pMe->uLastError != QCBOR_SUCCESS) {
7205 return;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007206 }
7207
7208 uint64_t uMantissa;
7209
7210 switch (pItem->uDataType) {
7211
7212 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007213 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07007214 /* See comments in ExponentiateNN() on handling INT64_MIN */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007215 if(pItem->val.expAndMantissa.Mantissa.nInt >= 0) {
7216 uMantissa = (uint64_t)pItem->val.expAndMantissa.Mantissa.nInt;
7217 *pbIsNegative = false;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07007218 } else if(pItem->val.expAndMantissa.Mantissa.nInt != INT64_MIN) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007219 uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt;
7220 *pbIsNegative = true;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07007221 } else {
7222 uMantissa = (uint64_t)INT64_MAX+1;
7223 *pbIsNegative = true;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007224 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007225 *pMantissa = QCBOR_Private_ConvertIntToBigNum(uMantissa,
7226 BufferForMantissa);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007227 *pnExponent = pItem->val.expAndMantissa.nExponent;
7228 break;
7229
Laurence Lundblade37286c02022-09-03 10:05:02 -07007230#ifndef QCBOR_DISABLE_TAGS
7231 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007232 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007233 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007234 *pnExponent = pItem->val.expAndMantissa.nExponent;
7235 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
7236 *pbIsNegative = false;
7237 break;
7238
7239 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007240 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007241 *pnExponent = pItem->val.expAndMantissa.nExponent;
7242 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
7243 *pbIsNegative = true;
7244 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07007245#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007246
7247 default:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007248 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007249 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007250
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007251 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007252}
7253
7254
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007255/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007256 * Public function, see header qcbor/qcbor_decode.h file
7257 */
7258void
7259QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe,
7260 const uint8_t uTagRequirement,
7261 int64_t *pnMantissa,
7262 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007263{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007264 QCBORItem Item;
7265 size_t uOffset;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007266
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007267 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007268 QCBOR_Private_ProcessExpMantissa(pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007269 uTagRequirement,
7270 CBOR_TAG_DECIMAL_FRACTION,
7271 uOffset,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007272 &Item,
7273 pnMantissa,
7274 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007275}
7276
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007277
7278/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007279 * Public function, see header qcbor/qcbor_decode.h file
7280 */
7281void
7282QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe,
7283 const int64_t nLabel,
7284 const uint8_t uTagRequirement,
7285 int64_t *pnMantissa,
7286 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007287{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007288 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007289 size_t uOffset;
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007290
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007291 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007292 QCBOR_Private_ProcessExpMantissa(pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007293 uTagRequirement,
7294 CBOR_TAG_DECIMAL_FRACTION,
7295 uOffset,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007296 &Item,
7297 pnMantissa,
7298 pnExponent);
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007299
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007300}
7301
7302
7303/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007304 * Public function, see header qcbor/qcbor_decode.h file
7305 */
7306void
7307QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
7308 const char *szLabel,
7309 const uint8_t uTagRequirement,
7310 int64_t *pnMantissa,
7311 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007312{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007313 QCBORItem Item;
7314 size_t uOffset;
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007315
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007316 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007317 QCBOR_Private_ProcessExpMantissa(pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007318 uTagRequirement,
7319 CBOR_TAG_DECIMAL_FRACTION,
7320 uOffset,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007321 &Item,
7322 pnMantissa,
7323 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007324}
7325
7326
7327/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007328 * Public function, see header qcbor/qcbor_decode.h file
7329 */
7330void
7331QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe,
7332 const uint8_t uTagRequirement,
7333 const UsefulBuf MantissaBuffer,
7334 UsefulBufC *pMantissa,
7335 bool *pbMantissaIsNegative,
7336 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007337{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007338 QCBORItem Item;
7339 size_t uOffset;
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007340
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007341 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007342 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007343 uTagRequirement,
7344 CBOR_TAG_DECIMAL_FRACTION,
7345 uOffset,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007346 &Item,
7347 MantissaBuffer,
7348 pMantissa,
7349 pbMantissaIsNegative,
7350 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007351}
7352
7353
7354/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007355 * Public function, see header qcbor/qcbor_decode.h file
7356 */
7357void
7358QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe,
7359 const int64_t nLabel,
7360 const uint8_t uTagRequirement,
7361 const UsefulBuf BufferForMantissa,
7362 UsefulBufC *pMantissa,
7363 bool *pbIsNegative,
7364 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007365{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007366 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007367 size_t uOffset;
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007368
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007369 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007370 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007371 uTagRequirement,
7372 CBOR_TAG_DECIMAL_FRACTION,
7373 uOffset,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007374 &Item,
7375 BufferForMantissa,
7376 pMantissa,
7377 pbIsNegative,
7378 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007379}
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007380
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007381
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007382/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007383 * Public function, see header qcbor/qcbor_decode.h file
7384 */
7385void
7386QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe,
7387 const char *szLabel,
7388 const uint8_t uTagRequirement,
7389 const UsefulBuf BufferForMantissa,
7390 UsefulBufC *pMantissa,
7391 bool *pbIsNegative,
7392 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007393{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007394 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007395 size_t uOffset;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007396
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007397 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007398 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007399 uTagRequirement,
7400 CBOR_TAG_DECIMAL_FRACTION,
7401 uOffset,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007402 &Item,
7403 BufferForMantissa,
7404 pMantissa,
7405 pbIsNegative,
7406 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007407}
7408
7409
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007410/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007411 * Public function, see header qcbor/qcbor_decode.h file
7412 */
7413void
7414QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe,
7415 const uint8_t uTagRequirement,
7416 int64_t *pnMantissa,
7417 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007418{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007419 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007420 size_t uOffset;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07007421
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007422 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007423 QCBOR_Private_ProcessExpMantissa(pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007424 uTagRequirement,
7425 CBOR_TAG_BIGFLOAT,
7426 uOffset,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007427 &Item,
7428 pnMantissa,
7429 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007430}
7431
7432
7433/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007434 * Public function, see header qcbor/qcbor_decode.h file
7435 */
7436void
7437QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe,
7438 const int64_t nLabel,
7439 const uint8_t uTagRequirement,
7440 int64_t *pnMantissa,
7441 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007442{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007443 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007444 size_t uOffset;
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007445
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007446 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007447 QCBOR_Private_ProcessExpMantissa(pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007448 uTagRequirement,
7449 CBOR_TAG_BIGFLOAT,
7450 uOffset,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007451 &Item,
7452 pnMantissa,
7453 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007454}
7455
7456
7457/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007458 * Public function, see header qcbor/qcbor_decode.h file
7459 */
7460void
7461QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe,
7462 const char *szLabel,
7463 const uint8_t uTagRequirement,
7464 int64_t *pnMantissa,
7465 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007466{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007467 QCBORItem Item;
7468 size_t uOffset;
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007469
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007470 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007471 QCBOR_Private_ProcessExpMantissa(pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007472 uTagRequirement,
7473 CBOR_TAG_BIGFLOAT,
7474 uOffset,
7475 &Item,
7476 pnMantissa,
7477 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007478}
7479
7480
7481/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007482 * Public function, see header qcbor/qcbor_decode.h file
7483 */
7484void
7485QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe,
7486 const uint8_t uTagRequirement,
7487 const UsefulBuf MantissaBuffer,
7488 UsefulBufC *pMantissa,
7489 bool *pbMantissaIsNegative,
7490 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007491{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007492 QCBORItem Item;
7493 size_t uOffset;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007494
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007495 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007496 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007497 uTagRequirement,
7498 CBOR_TAG_BIGFLOAT,
7499 uOffset,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007500 &Item,
7501 MantissaBuffer,
7502 pMantissa,
7503 pbMantissaIsNegative,
7504 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007505}
7506
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007507
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007508/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007509 * Public function, see header qcbor/qcbor_decode.h file
7510 */
7511void
7512QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe,
7513 const int64_t nLabel,
7514 const uint8_t uTagRequirement,
7515 const UsefulBuf BufferForMantissa,
7516 UsefulBufC *pMantissa,
7517 bool *pbIsNegative,
7518 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007519{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007520 QCBORItem Item;
7521 size_t uOffset;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007522
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007523 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007524 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007525 uTagRequirement,
7526 CBOR_TAG_BIGFLOAT,
7527 uOffset,
7528 &Item,
7529 BufferForMantissa,
7530 pMantissa,
7531 pbIsNegative,
7532 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007533}
7534
7535
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007536/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007537 * Public function, see header qcbor/qcbor_decode.h file
7538 */
7539void
7540QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe,
7541 const char *szLabel,
7542 const uint8_t uTagRequirement,
7543 const UsefulBuf BufferForMantissa,
7544 UsefulBufC *pMantissa,
7545 bool *pbIsNegative,
7546 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007547{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007548 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007549 size_t uOffset;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007550
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007551 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007552 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007553 uTagRequirement,
7554 CBOR_TAG_BIGFLOAT,
7555 uOffset,
7556 &Item,
7557 BufferForMantissa,
7558 pMantissa,
7559 pbIsNegative,
7560 pnExponent);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007561}
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007562
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07007563#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007564
7565
7566#if !defined(USEFULBUF_DISABLE_ALL_FLOAT) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
7567/*
7568 * Public function, see header qcbor/qcbor_spiffy_decode.h file
7569 */
7570void
7571QCBORDecode_GetNumberConvertPrecisely(QCBORDecodeContext *pMe,
7572 QCBORItem *pNumber)
7573{
7574 QCBORItem Item;
7575 struct IEEE754_ToInt ToInt;
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007576 double dNum;
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007577 QCBORError uError;
7578
7579 if(pMe->uLastError != QCBOR_SUCCESS) {
7580 return;
7581 }
7582
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007583 // TODO:VGetNext?
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007584 uError = QCBORDecode_GetNext(pMe, &Item);
7585 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007586 *pNumber = Item;
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007587 pMe->uLastError = (uint8_t)uError;
7588 return;
7589 }
7590
7591 switch(Item.uDataType) {
7592 case QCBOR_TYPE_INT64:
7593 case QCBOR_TYPE_UINT64:
7594 *pNumber = Item;
7595 break;
7596
7597 case QCBOR_TYPE_DOUBLE:
7598 ToInt = IEEE754_DoubleToInt(Item.val.dfnum);
7599 if(ToInt.type == IEEE754_ToInt_IS_INT) {
7600 pNumber->uDataType = QCBOR_TYPE_INT64;
7601 pNumber->val.int64 = ToInt.integer.is_signed;
7602 } else if(ToInt.type == IEEE754_ToInt_IS_UINT) {
7603 if(ToInt.integer.un_signed <= INT64_MAX) {
7604 /* Do the same as base QCBOR integer decoding */
7605 pNumber->uDataType = QCBOR_TYPE_INT64;
7606 pNumber->val.int64 = (int64_t)ToInt.integer.un_signed;
7607 } else {
7608 pNumber->uDataType = QCBOR_TYPE_UINT64;
7609 pNumber->val.uint64 = ToInt.integer.un_signed;
7610 }
7611 } else {
7612 *pNumber = Item;
7613 }
7614 break;
7615
7616 case QCBOR_TYPE_FLOAT:
7617 ToInt = IEEE754_SingleToInt(Item.val.fnum);
7618 if(ToInt.type == IEEE754_ToInt_IS_INT) {
7619 pNumber->uDataType = QCBOR_TYPE_INT64;
7620 pNumber->val.int64 = ToInt.integer.is_signed;
7621 } else if(ToInt.type == IEEE754_ToInt_IS_UINT) {
7622 if(ToInt.integer.un_signed <= INT64_MAX) {
7623 /* Do the same as base QCBOR integer decoding */
7624 pNumber->uDataType = QCBOR_TYPE_INT64;
7625 pNumber->val.int64 = (int64_t)ToInt.integer.un_signed;
7626 } else {
7627 pNumber->uDataType = QCBOR_TYPE_UINT64;
7628 pNumber->val.uint64 = ToInt.integer.un_signed;
7629 }
7630 } else {
7631 *pNumber = Item;
7632 }
7633 break;
7634
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007635 case QCBOR_TYPE_65BIT_NEG_INT:
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007636 if(Item.val.uint64 == UINT64_MAX) {
7637 /* The value -18446744073709551616 is encoded as an
7638 * unsigned 18446744073709551615. It's a whole number that
7639 * needs to be returned as a double. It can't be handled
7640 * by IEEE754_UintToDouble because 18446744073709551616
7641 * doesn't fit into a uint64_t. You can't get it by adding
7642 * 1 to 18446744073709551615.
7643 */
7644 pNumber->val.dfnum = -18446744073709551616.0;
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007645 pNumber->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007646 } else {
7647 dNum = IEEE754_UintToDouble(Item.val.uint64 + 1, 1);
7648 if(dNum == IEEE754_UINT_TO_DOUBLE_OOB) {
7649 *pNumber = Item;
7650 } else {
7651 pNumber->val.dfnum = dNum;
7652 pNumber->uDataType = QCBOR_TYPE_DOUBLE;
7653 }
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007654 }
7655 break;
7656
7657 default:
7658 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
7659 pNumber->uDataType = QCBOR_TYPE_NONE;
7660 break;
7661 }
7662}
7663
7664#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT && ! QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007665
7666
7667static UsefulBufC
7668QCBORDecode_IntToBigNum(uint64_t uNum,
7669 const UsefulBuf BigNumBuf)
7670{
7671 UsefulOutBuf OB;
7672
7673 /* With a UsefulOutBuf, there's no pointer math here. */
7674 UsefulOutBuf_Init(&OB, BigNumBuf);
7675
7676 /* Must copy one byte even if zero. The loop, mask and shift
7677 * algorithm provides endian conversion.
7678 */
7679 do {
7680 UsefulOutBuf_InsertByte(&OB, uNum & 0xff, 0);
7681 uNum >>= 8;
7682 } while(uNum);
7683
7684 return UsefulOutBuf_OutUBuf(&OB);
7685}
7686
7687
7688static UsefulBufC
7689QCBORDecode_Private_RemoveLeadingZeros(UsefulBufC String)
7690{
7691 while(String.len > 1) {
7692 if(*(const uint8_t *)String.ptr) {
7693 break;
7694 }
7695 String.len--;
7696 String.ptr = (const uint8_t *)String.ptr + 1;
7697 }
7698
7699 return String;
7700}
7701
7702
7703/* Add one to the big number and put the result in a new UsefulBufC
7704 * from storage in UsefulBuf.
7705 *
7706 * Leading zeros must be removed before calling this.
7707 *
7708 * Code Reviewers: THIS FUNCTION DOES POINTER MATH
7709 */
7710static UsefulBufC
7711QCBORDecode_BigNumCopyPlusOne(UsefulBufC BigNum,
7712 UsefulBuf BigNumBuf)
7713{
7714 uint8_t uCarry;
7715 uint8_t uSourceValue;
7716 const uint8_t *pSource;
7717 uint8_t *pDest;
7718 ptrdiff_t uDestBytesLeft;
7719
7720 /* Start adding at the LSB */
7721 pSource = &((const uint8_t *)BigNum.ptr)[BigNum.len-1];
7722 pDest = &((uint8_t *)BigNumBuf.ptr)[BigNumBuf.len-1];
7723
7724 uCarry = 1; /* Gets set back to zero if add the next line doesn't wrap */
7725 *pDest = *pSource + 1;
7726 while(1) {
7727 /* Wrap around from 0xff to 0 is a defined operation for
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007728 * unsigned addition in C.*/
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007729 if(*pDest != 0) {
7730 /* The add operation didn't wrap so no more carry. This
7731 * funciton only adds one, so when there is no more carry,
7732 * carrying is over to the end.
7733 */
7734 uCarry = 0;
7735 }
7736
7737 uDestBytesLeft = pDest - (uint8_t *)BigNumBuf.ptr;
7738 if(pSource <= (const uint8_t *)BigNum.ptr && uCarry == 0) {
7739 break; /* Successful exit */
7740 }
7741 if(pSource > (const uint8_t *)BigNum.ptr) {
7742 uSourceValue = *--pSource;
7743 } else {
7744 /* All source bytes processed, but not the last carry */
7745 uSourceValue = 0;
7746 }
7747
7748 pDest--;
7749 if(uDestBytesLeft < 0) {
7750 return NULLUsefulBufC; /* Not enough space in destination buffer */
7751 }
7752
7753 *pDest = uSourceValue + uCarry;
7754 }
7755
7756 return (UsefulBufC){pDest, BigNumBuf.len - (size_t)uDestBytesLeft};
7757}
7758
7759
7760/* This returns 1 when uNum is 0 */
7761static size_t
7762QCBORDecode_Private_CountNonZeroBytes(uint64_t uNum)
7763{
7764 size_t uCount = 0;
7765 do {
7766 uCount++;
7767 uNum >>= 8;
7768 } while(uNum);
7769
7770 return uCount;
7771}
7772
7773
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007774
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007775/*
7776 * Public function, see header qcbor/qcbor_decode.h
7777 */
7778QCBORError
7779QCBORDecode_BignumPreferred(const QCBORItem Item,
7780 UsefulBuf BigNumBuf,
7781 UsefulBufC *pBigNum,
7782 bool *pbIsNegative)
7783{
7784 QCBORError uResult;
7785 size_t uLen;
7786 UsefulBufC BigNum;
7787 int uType;
7788
7789 uType = Item.uDataType;
7790 if(uType == QCBOR_TYPE_BYTE_STRING) {
7791 uType = *pbIsNegative ? QCBOR_TYPE_POSBIGNUM : QCBOR_TYPE_NEGBIGNUM;
7792 }
7793
7794 static const uint8_t Zero[] = {0x00};
7795 BigNum = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(Zero);
7796 if((uType == QCBOR_TYPE_POSBIGNUM || uType == QCBOR_TYPE_NEGBIGNUM) &&
7797 Item.val.bigNum.len) {
7798 BigNum = QCBORDecode_Private_RemoveLeadingZeros(Item.val.bigNum);
7799 }
7800
7801 /* Compute required length so it can be returned if buffer is too small */
7802 switch(uType) {
7803 case QCBOR_TYPE_INT64:
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007804 uLen = QCBORDecode_Private_CountNonZeroBytes((uint64_t)ABSOLUTE_VALUE(Item.val.int64));
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007805 break;
7806
7807 case QCBOR_TYPE_UINT64:
7808 uLen = QCBORDecode_Private_CountNonZeroBytes(Item.val.uint64);
7809 break;
7810
7811 case QCBOR_TYPE_65BIT_NEG_INT:
7812 uLen = Item.val.uint64 == UINT64_MAX ? 9 : QCBORDecode_Private_CountNonZeroBytes(Item.val.uint64);
7813 break;
7814
7815 case QCBOR_TYPE_POSBIGNUM:
7816 uLen = BigNum.len;
7817 break;
7818
7819 case QCBOR_TYPE_NEGBIGNUM:
7820 uLen = BigNum.len;
7821 if(UsefulBuf_IsValue(BigNum, 0xff) == SIZE_MAX) {
7822 uLen++;
7823 }
7824 break;
7825
7826 default:
7827 uLen = 0;
7828 }
7829
7830 *pBigNum = (UsefulBufC){NULL, uLen};
7831
7832 if(BigNumBuf.len < uLen || uLen == 0 || BigNumBuf.ptr == NULL) {
7833 return BigNumBuf.ptr == NULL ? QCBOR_SUCCESS : QCBOR_ERR_BUFFER_TOO_SMALL;
7834 /* Buffer is too short or type is wrong */
7835 }
7836
7837 uResult = QCBOR_SUCCESS;
7838
7839 if(uType == QCBOR_TYPE_POSBIGNUM) {
7840 *pBigNum = UsefulBuf_Copy(BigNumBuf, BigNum);
7841 *pbIsNegative = false;
7842 } else if(uType == QCBOR_TYPE_UINT64) {
7843 *pBigNum = QCBORDecode_IntToBigNum(Item.val.uint64, BigNumBuf);
7844 *pbIsNegative = false;
7845 } else if(uType == QCBOR_TYPE_INT64) {
7846 *pbIsNegative = Item.val.int64 < 0;
7847 *pBigNum = QCBORDecode_IntToBigNum((uint64_t)(*pbIsNegative ? -Item.val.int64 : Item.val.int64), BigNumBuf);
7848 } else if(uType == QCBOR_TYPE_65BIT_NEG_INT) {
7849 *pbIsNegative = true;
7850 if(Item.val.uint64 == UINT64_MAX) {
7851 /* The one value that can't be done with a computation
7852 * because it would overflow a uint64_t*/
7853 static const uint8_t TwoToThe64[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
7854 *pBigNum = UsefulBuf_Copy(BigNumBuf, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(TwoToThe64));
7855 } else {
7856 *pBigNum = QCBORDecode_IntToBigNum(Item.val.uint64 + 1, BigNumBuf);
7857 }
7858 } else if(uType == QCBOR_TYPE_NEGBIGNUM) {
7859 /* The messy one. Take the stuff in the buffer and copy it to
7860 * the new buffer, adding one to it. This might be one byte
7861 * bigger than the original because of the carry from adding
7862 * one.*/
7863 *pbIsNegative = true;
7864 *pBigNum = QCBORDecode_BigNumCopyPlusOne(BigNum, BigNumBuf);
7865
7866 } else {
7867 uResult = QCBOR_ERR_UNEXPECTED_TYPE;
7868 }
7869
7870 return uResult;
7871}
7872
7873
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007874
7875
7876static void
7877QCBOR_Private_ProcessPreferredBigNum(QCBORDecodeContext *pMe,
7878 const uint8_t uTagRequirement,
7879 QCBORItem *pItem,
7880 const size_t uOffset,
7881 UsefulBuf BigNumBuf,
7882 UsefulBufC *pValue,
7883 bool *pbIsNegative)
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007884{
7885 if(pItem->uDataType != QCBOR_TYPE_INT64 &&
7886 pItem->uDataType != QCBOR_TYPE_UINT64 &&
7887 pItem->uDataType != QCBOR_TYPE_65BIT_NEG_INT) {
7888
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007889 /* Two stage processing because big numbers are handled like that */
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007890
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007891 const uint8_t puTypes[] = {QCBOR_TYPE_POSBIGNUM,QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE};
7892 const uint64_t puTNs[] = {CBOR_TAG_POS_BIGNUM, CBOR_TAG_NEG_BIGNUM, CBOR_TAG_INVALID64};
7893
7894 QCBORDecode_Private_ProcessTagItemMulti(pMe,
7895 pItem,
7896 uTagRequirement,
7897 puTypes,
7898 puTNs,
7899 QCBORDecode_StringsTagCB,
7900 uOffset);
7901
7902 if(pMe->uLastError) {
7903 return;
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007904 }
7905 }
7906
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007907 pMe->uLastError = (uint8_t)QCBORDecode_BignumPreferred(*pItem, BigNumBuf, pValue, pbIsNegative);
7908}
7909
7910
7911static void
7912QCBOR_Private_ProcessBigNumber(QCBORDecodeContext *pMe,
7913 const uint8_t uTagRequirement,
7914 QCBORItem *pItem,
7915 const size_t uOffset,
7916 UsefulBuf BigNumBuf,
7917 UsefulBufC *pValue,
7918 bool *pbIsNegative)
7919{
7920 /* Two stage processing because big numbers are handled like that */
7921
7922 const uint8_t puTypes[] = {QCBOR_TYPE_POSBIGNUM,QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE};
7923 const uint64_t puTNs[] = {CBOR_TAG_POS_BIGNUM, CBOR_TAG_NEG_BIGNUM, CBOR_TAG_INVALID64};
7924
7925 QCBORDecode_Private_ProcessTagItemMulti(pMe,
7926 pItem,
7927 uTagRequirement,
7928 puTypes,
7929 puTNs,
7930 QCBORDecode_StringsTagCB,
7931 uOffset);
7932
7933 if(pMe->uLastError) {
7934 return;
7935 }
7936
7937 pMe->uLastError = (uint8_t)QCBORDecode_BignumPreferred(*pItem, BigNumBuf, pValue, pbIsNegative);
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007938}
7939
7940
7941/*
7942 * Public function, see header qcbor/qcbor_decode.h
7943 */
7944void
7945QCBORDecode_GetBigNumPreferred(QCBORDecodeContext *pMe,
7946 const uint8_t uTagRequirement,
7947 UsefulBuf BigNumBuf,
7948 UsefulBufC *pValue,
7949 bool *pbIsNegative)
7950{
7951 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007952 size_t uOffset;
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007953
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007954 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
7955 QCBOR_Private_ProcessPreferredBigNum(pMe, uTagRequirement, &Item, uOffset, BigNumBuf, pValue, pbIsNegative);
7956}
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007957
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007958
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007959
7960void
7961QCBORDecode_GetBigNumber(QCBORDecodeContext *pMe,
7962 const uint8_t uTagRequirement,
7963 UsefulBuf BigNumberBuf,
7964 UsefulBufC *pBigNumber,
7965 bool *pbIsNegative)
7966{
7967 QCBORItem Item;
7968 size_t uOffset;
7969
7970 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
7971 QCBOR_Private_ProcessBigNumber(pMe,
7972 uTagRequirement,
7973 &Item,
7974 uOffset,
7975 BigNumberBuf,
7976 pBigNumber,
7977 pbIsNegative);
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007978}
7979
7980
7981/*
7982 * Public function, see header qcbor/qcbor_decode.h
7983 */
7984void
7985QCBORDecode_GetPreferredBignumInMapN(QCBORDecodeContext *pMe,
7986 const int64_t nLabel,
7987 const uint8_t uTagRequirement,
7988 UsefulBuf BigNumBuf,
7989 UsefulBufC *pValue,
7990 bool *pbIsNegative)
7991{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007992 QCBORItem Item;
7993 size_t uOffset;
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007994
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007995 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
7996 QCBOR_Private_ProcessPreferredBigNum(pMe,
7997 uTagRequirement,
7998 &Item,
7999 uOffset,
8000 BigNumBuf,
8001 pValue,
8002 pbIsNegative);
Laurence Lundblade14ce2282024-07-24 22:13:35 -07008003}
8004
8005/*
8006 * Public function, see header qcbor/qcbor_decode.h
8007 */
8008void
8009QCBORDecode_GetPreferredBignumInMapSZ(QCBORDecodeContext *pMe,
8010 const char * szLabel,
8011 const uint8_t uTagRequirement,
8012 UsefulBuf BigNumBuf,
8013 UsefulBufC *pValue,
8014 bool *pbIsNegative)
8015{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07008016 QCBORItem Item;
8017 size_t uOffset;
Laurence Lundblade14ce2282024-07-24 22:13:35 -07008018
Laurence Lundblade721b56e2024-10-22 03:02:04 -07008019 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
8020 QCBOR_Private_ProcessPreferredBigNum(pMe,
8021 uTagRequirement,
8022 &Item,
8023 uOffset,
8024 BigNumBuf,
8025 pValue,
8026 pbIsNegative);
Laurence Lundblade14ce2282024-07-24 22:13:35 -07008027}
8028
Laurence Lundblade721b56e2024-10-22 03:02:04 -07008029// TODO: re order above functions in tag number order