blob: 282efdde5edf291083154df99354a03a1c1b6afd [file] [log] [blame]
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001/*==============================================================================
Laurence Lundbladed92a6162018-11-01 11:38:35 +07002 Copyright (c) 2016-2018, The Linux Foundation.
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003 Copyright (c) 2018-2024, Laurence Lundblade.
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02004 Copyright (c) 2021, Arm Limited.
Laurence Lundbladed92a6162018-11-01 11:38:35 +07005 All rights reserved.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08006
Laurence Lundblade0dbc9172018-11-01 14:17:21 +07007Redistribution and use in source and binary forms, with or without
8modification, are permitted provided that the following conditions are
9met:
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above
13 copyright notice, this list of conditions and the following
14 disclaimer in the documentation and/or other materials provided
15 with the distribution.
16 * Neither the name of The Linux Foundation nor the names of its
17 contributors, nor the name "Laurence Lundblade" may be used to
18 endorse or promote products derived from this software without
19 specific prior written permission.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080020
Laurence Lundblade0dbc9172018-11-01 14:17:21 +070021THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
22WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
24ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
25BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
30OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Laurence Lundbladeee851742020-01-08 08:37:05 -080032 =============================================================================*/
Laurence Lundblade624405d2018-09-18 20:10:47 -070033
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080034
Laurence Lundblade844bb5c2020-03-01 17:27:25 -080035#include "qcbor/qcbor_decode.h"
Laurence Lundblade67257dc2020-07-27 03:33:37 -070036#include "qcbor/qcbor_spiffy_decode.h"
Laurence Lundblade3f1318a2021-01-04 18:26:44 -080037#include "ieee754.h" /* Does not use math.h */
Laurence Lundbladec7114722020-08-13 05:11:40 -070038
39#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade3f1318a2021-01-04 18:26:44 -080040
41#include <math.h> /* For isnan(), llround(), llroudf(), round(), roundf(),
42 * pow(), exp2()
43 */
44#include <fenv.h> /* feclearexcept(), fetestexcept() */
45
Laurence Lundbladee2c893c2020-12-26 17:41:53 -080046#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070047
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070048
Laurence Lundblade68cb61c2023-02-12 13:21:44 -080049#if (defined(__GNUC__) && !defined(__clang__))
Laurence Lundblade8e36f812024-01-26 10:59:29 -070050/*
Laurence Lundblade68cb61c2023-02-12 13:21:44 -080051 * This is how the -Wmaybe-uninitialized compiler warning is
52 * handled. It can’t be ignored because some version of gcc enable it
53 * with -Wall which is a common and useful gcc warning option. It also
54 * can’t be ignored because it is the goal of QCBOR to compile clean
55 * out of the box in all environments.
56 *
57 * The big problem with -Wmaybe-uninitialized is that it generates
58 * false positives. It complains things are uninitialized when they
59 * are not. This is because it is not a thorough static analyzer. This
60 * is why “maybe” is in its name. The problem is it is just not
61 * thorough enough to understand all the code (and someone saw fit to
62 * put it in gcc and worse to enable it with -Wall).
63 *
64 * One solution would be to change the code so -Wmaybe-uninitialized
65 * doesn’t get confused, for example adding an unnecessary extra
66 * initialization to zero. (If variables were truly uninitialized, the
67 * correct path is to understand the code thoroughly and set them to
68 * the correct value at the correct time; in essence this is already
69 * done; -Wmaybe-uninitialized just can’t tell). This path is not
70 * taken because it makes the code bigger and is kind of the tail
71 * wagging the dog.
72 *
73 * The solution here is to just use a pragma to disable it for the
74 * whole file. Disabling it for each line makes the code fairly ugly
75 * requiring #pragma to push, pop and ignore. Another reason is the
76 * warnings issues vary by version of gcc and which optimization
77 * optimizations are selected. Another reason is that compilers other
78 * than gcc don’t have -Wmaybe-uninitialized.
79 *
80 * One may ask how to be sure these warnings are false positives and
81 * not real issues. 1) The code has been read carefully to check. 2)
82 * Testing is pretty thorough. 3) This code has been run through
83 * thorough high-quality static analyzers.
84 *
85 * In particularly, most of the warnings are about
86 * Item.Item->uDataType being uninitialized. QCBORDecode_GetNext()
87 * *always* sets this value and test case confirm
88 * this. -Wmaybe-uninitialized just can't tell.
89 *
90 * https://stackoverflow.com/questions/5080848/disable-gcc-may-be-used-uninitialized-on-a-particular-variable
91 */
92#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
Laurence Lundblade8e36f812024-01-26 10:59:29 -070093#endif
Laurence Lundblade68cb61c2023-02-12 13:21:44 -080094
95
96
Laurence Lundblade3f1318a2021-01-04 18:26:44 -080097
Laurence Lundbladea9489f82020-09-12 13:50:56 -070098#define SIZEOF_C_ARRAY(array,type) (sizeof(array)/sizeof(type))
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070099
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700100
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800101
102
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700103static bool
104QCBORItem_IsMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700105{
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700106 const uint8_t uDataType = Item.uDataType;
Laurence Lundblade02625d42020-06-25 14:41:41 -0700107 return uDataType == QCBOR_TYPE_MAP ||
108 uDataType == QCBOR_TYPE_ARRAY ||
109 uDataType == QCBOR_TYPE_MAP_AS_ARRAY;
110}
111
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700112static bool
113QCBORItem_IsEmptyDefiniteLengthMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700114{
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700115 if(!QCBORItem_IsMapOrArray(Item)){
Laurence Lundblade02625d42020-06-25 14:41:41 -0700116 return false;
117 }
118
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700119 if(Item.val.uCount != 0) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700120 return false;
121 }
122 return true;
123}
124
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700125static bool
126QCBORItem_IsIndefiniteLengthMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700127{
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800128#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700129 if(!QCBORItem_IsMapOrArray(Item)){
Laurence Lundblade02625d42020-06-25 14:41:41 -0700130 return false;
131 }
132
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700133 if(Item.val.uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700134 return false;
135 }
136 return true;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800137#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700138 (void)Item;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800139 return false;
140#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700141}
142
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700143/* Return true if the labels in Item1 and Item2 are the same.
144 Works only for integer and string labels. Returns false
145 for any other type. */
146static bool
147QCBORItem_MatchLabel(const QCBORItem Item1, const QCBORItem Item2)
148{
149 if(Item1.uLabelType == QCBOR_TYPE_INT64) {
150 if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
151 return true;
152 }
153 } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
154 if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
155 return true;
156 }
157 } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
158 if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
159 return true;
160 }
161 } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
162 if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
163 return true;
164 }
165 }
166
167 /* Other label types are never matched */
168 return false;
169}
170
171
172/*
173 Returns true if Item1 and Item2 are the same type
174 or if either are of QCBOR_TYPE_ANY.
175 */
176static bool
177QCBORItem_MatchType(const QCBORItem Item1, const QCBORItem Item2)
178{
179 if(Item1.uDataType == Item2.uDataType) {
180 return true;
181 } else if(Item1.uDataType == QCBOR_TYPE_ANY) {
182 return true;
183 } else if(Item2.uDataType == QCBOR_TYPE_ANY) {
184 return true;
185 }
186 return false;
187}
188
Laurence Lundblade02625d42020-06-25 14:41:41 -0700189
Laurence Lundbladeee851742020-01-08 08:37:05 -0800190/*===========================================================================
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700191 DecodeNesting -- Tracking array/map/sequence/bstr-wrapped nesting
Laurence Lundbladeee851742020-01-08 08:37:05 -0800192 ===========================================================================*/
193
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700194/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800195 * See comments about and typedef of QCBORDecodeNesting in qcbor_private.h,
196 * the data structure all these functions work on.
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700197 */
198
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700199
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700200static uint8_t
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700201DecodeNesting_GetCurrentLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700202{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700203 const ptrdiff_t nLevel = pNesting->pCurrent - &(pNesting->pLevels[0]);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800204 /* Limit in DecodeNesting_Descend against more than
205 * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
Laurence Lundblade02625d42020-06-25 14:41:41 -0700206 */
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700207 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700208}
209
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700210
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700211static uint8_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700212DecodeNesting_GetBoundedModeLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700213{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700214 const ptrdiff_t nLevel = pNesting->pCurrentBounded - &(pNesting->pLevels[0]);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800215 /* Limit in DecodeNesting_Descend against more than
216 * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
Laurence Lundblade02625d42020-06-25 14:41:41 -0700217 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700218 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700219}
220
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700221
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700222static uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700223DecodeNesting_GetMapOrArrayStart(const QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700224{
225 return pNesting->pCurrentBounded->u.ma.uStartOffset;
226}
227
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700228
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700229static bool
Laurence Lundblade085d7952020-07-24 10:26:30 -0700230DecodeNesting_IsBoundedEmpty(const QCBORDecodeNesting *pNesting)
231{
232 if(pNesting->pCurrentBounded->u.ma.uCountCursor == QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
233 return true;
234 } else {
235 return false;
236 }
237}
238
239
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700240static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700241DecodeNesting_IsCurrentAtTop(const QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700242{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700243 if(pNesting->pCurrent == &(pNesting->pLevels[0])) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700244 return true;
245 } else {
246 return false;
247 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700248}
249
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700250
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700251static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700252DecodeNesting_IsCurrentDefiniteLength(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700253{
254 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800255 /* Not a map or array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700256 return false;
257 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800258
259#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700260 if(pNesting->pCurrent->u.ma.uCountTotal == QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800261 /* Is indefinite */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700262 return false;
263 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800264
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800265#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
266
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800267 /* All checks passed; is a definte length map or array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700268 return true;
269}
270
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700271static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700272DecodeNesting_IsCurrentBstrWrapped(const QCBORDecodeNesting *pNesting)
Laurence Lundblade642282a2020-06-23 12:00:33 -0700273{
274 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800275 /* is a byte string */
Laurence Lundblade642282a2020-06-23 12:00:33 -0700276 return true;
277 }
278 return false;
279}
280
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700281
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700282static bool
283DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700284{
285 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
286 return true;
287 }
Laurence Lundblade02625d42020-06-25 14:41:41 -0700288 if(pNesting->pCurrent->u.ma.uStartOffset != QCBOR_NON_BOUNDED_OFFSET) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700289 return true;
290 }
291 return false;
292}
293
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700294
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700295static void
296DecodeNesting_SetMapOrArrayBoundedMode(QCBORDecodeNesting *pNesting, bool bIsEmpty, size_t uStart)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700297{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800298 /* Should be only called on maps and arrays */
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700299 /*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800300 * DecodeNesting_EnterBoundedMode() checks to be sure uStart is not
301 * larger than DecodeNesting_EnterBoundedMode which keeps it less than
302 * uin32_t so the cast is safe.
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700303 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700304 pNesting->pCurrent->u.ma.uStartOffset = (uint32_t)uStart;
Laurence Lundblade085d7952020-07-24 10:26:30 -0700305
306 if(bIsEmpty) {
307 pNesting->pCurrent->u.ma.uCountCursor = QCBOR_COUNT_INDICATES_ZERO_LENGTH;
308 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700309}
310
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700311
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700312static void
313DecodeNesting_ClearBoundedMode(QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700314{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700315 pNesting->pCurrent->u.ma.uStartOffset = QCBOR_NON_BOUNDED_OFFSET;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700316}
317
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700318
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700319static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700320DecodeNesting_IsAtEndOfBoundedLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700321{
322 if(pNesting->pCurrentBounded == NULL) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800323 /* No bounded map or array set up */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700324 return false;
325 }
326 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800327 /* Not a map or array; end of those is by byte count */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700328 return false;
329 }
Laurence Lundblade6ab01fb2020-10-01 13:04:49 -0700330 if(!DecodeNesting_IsCurrentBounded(pNesting)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800331 /* In a traveral at a level deeper than the bounded level */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700332 return false;
333 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800334 /* Works for both definite- and indefinitelength maps/arrays */
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800335 if(pNesting->pCurrentBounded->u.ma.uCountCursor != 0 &&
336 pNesting->pCurrentBounded->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800337 /* Count is not zero, still unconsumed item */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700338 return false;
339 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800340 /* All checks passed, got to the end of an array or map*/
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700341 return true;
342}
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700343
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700344
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700345static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700346DecodeNesting_IsEndOfDefiniteLengthMapOrArray(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700347{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800348 /* Must only be called on map / array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700349 if(pNesting->pCurrent->u.ma.uCountCursor == 0) {
350 return true;
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700351 } else {
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700352 return false;
353 }
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700354}
355
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700356
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700357static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700358DecodeNesting_IsCurrentTypeMap(const QCBORDecodeNesting *pNesting)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700359{
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700360 if(pNesting->pCurrent->uLevelType == CBOR_MAJOR_TYPE_MAP) {
361 return true;
362 } else {
363 return false;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700364 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700365}
366
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700367
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700368static bool
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700369DecodeNesting_IsBoundedType(const QCBORDecodeNesting *pNesting, uint8_t uType)
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700370{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700371 if(pNesting->pCurrentBounded == NULL) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700372 return false;
373 }
Laurence Lundblade02625d42020-06-25 14:41:41 -0700374
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700375 uint8_t uItemDataType = pNesting->pCurrentBounded->uLevelType;
376 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
377 uItemDataType = QCBOR_TYPE_ARRAY;
378 }
379
380 if(uItemDataType != uType) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700381 return false;
382 }
383
384 return true;
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700385}
386
Laurence Lundblade02625d42020-06-25 14:41:41 -0700387
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700388static void
Laurence Lundblade6c8a4442020-06-22 22:16:11 -0700389DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700390{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800391 /* Only call on a definite-length array / map */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700392 pNesting->pCurrent->u.ma.uCountCursor--;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700393}
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700394
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700395
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700396static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700397DecodeNesting_ReverseDecrement(QCBORDecodeNesting *pNesting)
398{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800399 /* Only call on a definite-length array / map */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700400 pNesting->pCurrent->u.ma.uCountCursor++;
401}
402
403
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700404static void
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700405DecodeNesting_Ascend(QCBORDecodeNesting *pNesting)
406{
407 pNesting->pCurrent--;
408}
409
Laurence Lundblade02625d42020-06-25 14:41:41 -0700410
411static QCBORError
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700412DecodeNesting_Descend(QCBORDecodeNesting *pNesting, uint8_t uType)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700413{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800414 /* Error out if nesting is too deep */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700415 if(pNesting->pCurrent >= &(pNesting->pLevels[QCBOR_MAX_ARRAY_NESTING])) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700416 return QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP;
Laurence Lundblade02625d42020-06-25 14:41:41 -0700417 }
418
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800419 /* The actual descend */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700420 pNesting->pCurrent++;
421
422 pNesting->pCurrent->uLevelType = uType;
423
424 return QCBOR_SUCCESS;
425}
426
427
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700428static QCBORError
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800429DecodeNesting_EnterBoundedMapOrArray(QCBORDecodeNesting *pNesting,
430 bool bIsEmpty,
431 size_t uOffset)
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700432{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700433 /*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800434 * Should only be called on map/array.
435 *
436 * Have descended into this before this is called. The job here is
437 * just to mark it in bounded mode.
438 *
439 * Check against QCBOR_MAX_DECODE_INPUT_SIZE make sure that
440 * uOffset doesn't collide with QCBOR_NON_BOUNDED_OFFSET.
441 *
442 * Cast of uOffset to uint32_t for cases where SIZE_MAX < UINT32_MAX.
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700443 */
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -0800444 if((uint32_t)uOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700445 return QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700446 }
447
Laurence Lundblade0750fc42020-06-20 21:02:34 -0700448 pNesting->pCurrentBounded = pNesting->pCurrent;
Laurence Lundblade085d7952020-07-24 10:26:30 -0700449
450 DecodeNesting_SetMapOrArrayBoundedMode(pNesting, bIsEmpty, uOffset);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700451
452 return QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700453}
454
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700455
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700456static QCBORError
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700457DecodeNesting_DescendMapOrArray(QCBORDecodeNesting *pNesting,
Laurence Lundblade02625d42020-06-25 14:41:41 -0700458 uint8_t uQCBORType,
459 uint64_t uCount)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700460{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700461 QCBORError uError = QCBOR_SUCCESS;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700462
463 if(uCount == 0) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800464 /* Nothing to do for empty definite-length arrays. They are just are
465 * effectively the same as an item that is not a map or array.
466 */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700467 goto Done;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800468 /* Empty indefinite-length maps and arrays are handled elsewhere */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700469 }
470
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800471 /* Error out if arrays is too long to handle */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700472 if(uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH &&
473 uCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700474 uError = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700475 goto Done;
476 }
477
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700478 uError = DecodeNesting_Descend(pNesting, uQCBORType);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700479 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700480 goto Done;
481 }
482
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800483 /* Fill in the new map/array level. Check above makes casts OK. */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -0700484 pNesting->pCurrent->u.ma.uCountCursor = (uint16_t)uCount;
485 pNesting->pCurrent->u.ma.uCountTotal = (uint16_t)uCount;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700486
487 DecodeNesting_ClearBoundedMode(pNesting);
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700488
489Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700490 return uError;;
491}
492
493
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700494static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700495DecodeNesting_LevelUpCurrent(QCBORDecodeNesting *pNesting)
496{
497 pNesting->pCurrent = pNesting->pCurrentBounded - 1;
498}
499
500
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700501static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700502DecodeNesting_LevelUpBounded(QCBORDecodeNesting *pNesting)
503{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700504 while(pNesting->pCurrentBounded != &(pNesting->pLevels[0])) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700505 pNesting->pCurrentBounded--;
506 if(DecodeNesting_IsCurrentBounded(pNesting)) {
507 break;
508 }
509 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700510}
511
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800512
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700513static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700514DecodeNesting_SetCurrentToBoundedLevel(QCBORDecodeNesting *pNesting)
515{
516 pNesting->pCurrent = pNesting->pCurrentBounded;
517}
518
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700519
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700520static QCBORError
Laurence Lundblade02625d42020-06-25 14:41:41 -0700521DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting,
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700522 uint32_t uEndOffset,
523 uint32_t uStartOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700524{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700525 QCBORError uError;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700526
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700527 uError = DecodeNesting_Descend(pNesting, QCBOR_TYPE_BYTE_STRING);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700528 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700529 goto Done;
530 }
531
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800532 /* Fill in the new byte string level */
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700533 pNesting->pCurrent->u.bs.uSavedEndOffset = uEndOffset;
534 pNesting->pCurrent->u.bs.uBstrStartOffset = uStartOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700535
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800536 /* Bstr wrapped levels are always bounded */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700537 pNesting->pCurrentBounded = pNesting->pCurrent;
538
539Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700540 return uError;;
541}
542
Laurence Lundbladed0304932020-06-27 10:59:38 -0700543
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700544static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700545DecodeNesting_ZeroMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700546{
547 pNesting->pCurrent->u.ma.uCountCursor = 0;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700548}
549
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700550
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700551static void
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800552DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting)
553{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700554 if(pNesting->pCurrent->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
555 pNesting->pCurrentBounded->u.ma.uCountCursor = pNesting->pCurrentBounded->u.ma.uCountTotal;
556 }
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800557}
558
559
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700560static void
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700561DecodeNesting_Init(QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700562{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700563 /* Assumes that *pNesting has been zero'd before this call. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700564 pNesting->pLevels[0].uLevelType = QCBOR_TYPE_BYTE_STRING;
565 pNesting->pCurrent = &(pNesting->pLevels[0]);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700566}
567
568
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700569static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800570DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting,
571 QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700572{
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700573 *pSave = *pNesting;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700574}
575
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700576
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700577static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800578DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting,
579 const QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700580{
581 *pNesting = *pSave;
582}
583
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700584
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700585static uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700586DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700587{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700588 return pMe->pCurrentBounded->u.bs.uSavedEndOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700589}
590
591
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800592
593
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800594#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladeee851742020-01-08 08:37:05 -0800595/*===========================================================================
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800596 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
597
598 The following four functions are pretty wrappers for invocation of
599 the string allocator supplied by the caller.
600
Laurence Lundbladeee851742020-01-08 08:37:05 -0800601 ===========================================================================*/
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800602
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700603static void
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800604StringAllocator_Free(const QCBORInternalAllocator *pMe, const void *pMem)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800605{
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300606 /* This cast to uintptr_t suppresses the "-Wcast-qual" warnings.
607 * This is the one place where the const needs to be cast away so const can
608 * be use in the rest of the code.
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800609 */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300610 (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, 0);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800611}
612
Laurence Lundbladeee851742020-01-08 08:37:05 -0800613// StringAllocator_Reallocate called with pMem NULL is
614// equal to StringAllocator_Allocate()
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700615static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800616StringAllocator_Reallocate(const QCBORInternalAllocator *pMe,
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800617 const void *pMem,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800618 size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800619{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800620 /* See comment in StringAllocator_Free() */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300621 return (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, uSize);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800622}
623
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700624static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800625StringAllocator_Allocate(const QCBORInternalAllocator *pMe, size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800626{
627 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
628}
629
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700630static void
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800631StringAllocator_Destruct(const QCBORInternalAllocator *pMe)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800632{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800633 /* See comment in StringAllocator_Free() */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800634 if(pMe->pfAllocator) {
635 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
636 }
637}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800638#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800639
640
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800641
642
Laurence Lundbladeee851742020-01-08 08:37:05 -0800643/*===========================================================================
644 QCBORDecode -- The main implementation of CBOR decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700645
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800646 See qcbor/qcbor_decode.h for definition of the object
647 used here: QCBORDecodeContext
Laurence Lundbladeee851742020-01-08 08:37:05 -0800648 ===========================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700649/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800650 * Public function, see header file
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700651 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700652void
653QCBORDecode_Init(QCBORDecodeContext *pMe,
654 UsefulBufC EncodedCBOR,
655 QCBORDecodeMode nDecodeMode)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700656{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800657 memset(pMe, 0, sizeof(QCBORDecodeContext));
658 UsefulInputBuf_Init(&(pMe->InBuf), EncodedCBOR);
659 /* Don't bother with error check on decode mode. If a bad value is
660 * passed it will just act as if the default normal mode of 0 was set.
661 */
662 pMe->uDecodeMode = (uint8_t)nDecodeMode;
663 DecodeNesting_Init(&(pMe->nesting));
664
665 /* Inialize me->auMappedTags to CBOR_TAG_INVALID16. See
666 * GetNext_TaggedItem() and MapTagNumber(). */
667 memset(pMe->auMappedTags, 0xff, sizeof(pMe->auMappedTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700668}
669
670
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800671#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
672
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700673/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800674 * Public function, see header file
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700675 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700676void
677QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
678 QCBORStringAllocate pfAllocateFunction,
679 void *pAllocateContext,
680 bool bAllStrings)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700681{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800682 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
683 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
684 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700685}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800686#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700687
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800688
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800689
690
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800691/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800692 * Deprecated public function, see header file
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800693 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700694void
695QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pMe,
696 const QCBORTagListIn *pTagList)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700697{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800698 /* This does nothing now. It is retained for backwards compatibility */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700699 (void)pMe;
700 (void)pTagList;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700701}
702
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700703
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800704
705
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700706/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800707 * Decoding items is done in six layers, one calling the next one
708 * down. If a layer has no work to do for a particular item, it
709 * returns quickly.
710 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700711 * 1. QCBORDecode_Private_GetNextTagContent - The top layer processes
712 * tagged data items, turning them into the local C representation.
713 * For the most simple it is just associating a QCBOR_TYPE with the
714 * data. For the complex ones that an aggregate of data items, there
715 * is some further decoding and some limited recursion.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800716 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700717 * 2. QCBORDecode_Private_GetNextMapOrArray - This manages the
718 * beginnings and ends of maps and arrays. It tracks descending into
719 * and ascending out of maps/arrays. It processes breaks that
720 * terminate indefinite-length maps and arrays.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800721 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700722 * 3. QCBORDecode_Private_GetNextMapEntry - This handles the combining
723 * of two items, the label and the data, that make up a map entry. It
724 * only does work on maps. It combines the label and data items into
725 * one labeled item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800726 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700727 * 4. QCBORDecode_Private_GetNextTagNumber - This decodes type 6 tag
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800728 * numbers. It turns the tag numbers into bit flags associated with
729 * the data item. No actual decoding of the contents of the tag is
730 * performed here.
731 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700732 * 5. QCBORDecode_Private_GetNextFullString - This assembles the
733 * sub-items that make up an indefinite-length string into one string
734 * item. It uses the string allocator to create contiguous space for
735 * the item. It processes all breaks that are part of
736 * indefinite-length strings.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800737 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700738 * 6. QCBOR_Private_DecodeAtomicDataItem - This decodes the atomic
739 * data items in CBOR. Each atomic data item has a "major type", an
740 * integer "argument" and optionally some content. For text and byte
741 * strings, the content is the bytes that make up the string. These
742 * are the smallest data items that are considered to be well-formed.
743 * The content may also be other data items in the case of aggregate
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800744 * types. They are not handled in this layer.
745 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700746 * This uses about 350 bytes of stack. This number comes from
747 * instrumenting (printf address of stack variables) the code on x86
748 * compiled for size optimization.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700749 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800750
751
752/*
753 * Note about use of int and unsigned variables.
754 *
755 * See http://www.unix.org/whitepapers/64bit.html for reasons int is
756 * used carefully here, and in particular why it isn't used in the
757 * public interface. Also see
758 * https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers
759 *
760 * Int is used for values that need less than 16-bits and would be
761 * subject to integer promotion and result in complaining from static
762 * analyzers.
763 */
764
765
766/**
767 * @brief Decode the CBOR head, the type and argument.
768 *
769 * @param[in] pUInBuf The input buffer to read from.
770 * @param[out] pnMajorType The decoded major type.
771 * @param[out] puArgument The decoded argument.
772 * @param[out] pnAdditionalInfo The decoded Lower 5 bits of initial byte.
773 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -0700774 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved features
775 * @retval QCBOR_ERR_HIT_END Unexpected end of input
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800776 *
777 * This decodes the CBOR "head" that every CBOR data item has. See
778 * longer explaination of the head in documentation for
779 * QCBOREncode_EncodeHead().
780 *
781 * This does the network->host byte order conversion. The conversion
782 * here also results in the conversion for floats in addition to that
783 * for lengths, tags and integer values.
784 *
785 * The int type is preferred to uint8_t for some variables as this
786 * avoids integer promotions, can reduce code size and makes static
787 * analyzers happier.
788 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700789static QCBORError
790QCBOR_Private_DecodeHead(UsefulInputBuf *pUInBuf,
791 int *pnMajorType,
792 uint64_t *puArgument,
793 int *pnAdditionalInfo)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700794{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800795 QCBORError uReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800796
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800797 /* Get the initial byte that every CBOR data item has and break it
798 * down. */
799 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800800 const int nTmpMajorType = nInitialByte >> 5;
801 const int nAdditionalInfo = nInitialByte & 0x1f;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800802
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800803 /* Where the argument accumulates */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800804 uint64_t uArgument;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800805
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800806 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800807 /* Need to get 1,2,4 or 8 additional argument bytes. Map
808 * LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length.
809 */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800810 static const uint8_t aIterate[] = {1,2,4,8};
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800811
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800812 /* Loop getting all the bytes in the argument */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800813 uArgument = 0;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800814 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800815 /* This shift and add gives the endian conversion. */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800816 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
817 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800818 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800819 /* The reserved and thus-far unused additional info values */
820 uReturn = QCBOR_ERR_UNSUPPORTED;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800821 goto Done;
822 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800823 /* Less than 24, additional info is argument or 31, an
824 * indefinite-length. No more bytes to get.
825 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800826 uArgument = (uint64_t)nAdditionalInfo;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700827 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800828
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700829 if(UsefulInputBuf_GetError(pUInBuf)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800830 uReturn = QCBOR_ERR_HIT_END;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700831 goto Done;
832 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800833
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800834 /* All successful if arrived here. */
835 uReturn = QCBOR_SUCCESS;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800836 *pnMajorType = nTmpMajorType;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800837 *puArgument = uArgument;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800838 *pnAdditionalInfo = nAdditionalInfo;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800839
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700840Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800841 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700842}
843
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800844
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800845/**
846 * @brief Decode integer types, major types 0 and 1.
847 *
848 * @param[in] nMajorType The CBOR major type (0 or 1).
849 * @param[in] uArgument The argument from the head.
850 * @param[out] pDecodedItem The filled in decoded item.
851 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -0700852 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800853 *
854 * Must only be called when major type is 0 or 1.
855 *
856 * CBOR doesn't explicitly specify two's compliment for integers but
857 * all CPUs use it these days and the test vectors in the RFC are
858 * so. All integers in the CBOR structure are positive and the major
859 * type indicates positive or negative. CBOR can express positive
860 * integers up to 2^x - 1 where x is the number of bits and negative
861 * integers down to 2^x. Note that negative numbers can be one more
862 * away from zero than positive. Stdint, as far as I can tell, uses
863 * two's compliment to represent negative integers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700864 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700865static QCBORError
866QCBOR_Private_DecodeInteger(const int nMajorType,
867 const uint64_t uArgument,
868 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700869{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800870 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800871
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700872 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800873 if (uArgument <= INT64_MAX) {
874 pDecodedItem->val.int64 = (int64_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700875 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800876
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700877 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800878 pDecodedItem->val.uint64 = uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700879 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700880 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800881
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700882 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800883 if(uArgument <= INT64_MAX) {
884 /* CBOR's representation of negative numbers lines up with
885 * the two-compliment representation. A negative integer has
886 * one more in range than a positive integer. INT64_MIN is
887 * equal to (-INT64_MAX) - 1.
888 */
889 pDecodedItem->val.int64 = (-(int64_t)uArgument) - 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700890 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800891
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700892 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800893 /* C can't represent a negative integer in this range so it
894 * is an error.
895 */
896 uReturn = QCBOR_ERR_INT_OVERFLOW;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700897 }
898 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800899
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800900 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700901}
902
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800903
904/* Make sure #define value line up as DecodeSimple counts on this. */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700905#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
906#error QCBOR_TYPE_FALSE macro value wrong
907#endif
908
909#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
910#error QCBOR_TYPE_TRUE macro value wrong
911#endif
912
913#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
914#error QCBOR_TYPE_NULL macro value wrong
915#endif
916
917#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
918#error QCBOR_TYPE_UNDEF macro value wrong
919#endif
920
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700921#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
922#error QCBOR_TYPE_BREAK macro value wrong
923#endif
924
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700925#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
926#error QCBOR_TYPE_DOUBLE macro value wrong
927#endif
928
929#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
930#error QCBOR_TYPE_FLOAT macro value wrong
931#endif
932
Laurence Lundblade9b334962020-08-27 10:55:53 -0700933
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800934/**
935 * @brief Decode major type 7 -- true, false, floating-point, break...
936 *
937 * @param[in] nAdditionalInfo The lower five bits from the initial byte.
938 * @param[in] uArgument The argument from the head.
939 * @param[out] pDecodedItem The filled in decoded item.
940 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -0700941 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
942 * of half-precision disabled
943 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all float
944 * decode is disabled.
945 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of simple
946 * type in input.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700947 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700948static QCBORError
949QCBOR_Private_DecodeType7(const int nAdditionalInfo,
950 const uint64_t uArgument,
951 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800952{
953 QCBORError uReturn = QCBOR_SUCCESS;
954
955 /* uAdditionalInfo is 5 bits from the initial byte. Compile time
956 * checks above make sure uAdditionalInfo values line up with
957 * uDataType values. DecodeHead() never returns an AdditionalInfo
958 * > 0x1f so cast is safe.
959 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800960 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800961
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800962 switch(nAdditionalInfo) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800963 /* No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they
964 * are caught before this is called.
965 */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800966
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800967 case HALF_PREC_FLOAT: /* 25 */
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700968#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800969 /* Half-precision is returned as a double. The cast to
970 * uint16_t is safe because the encoded value was 16 bits. It
971 * was widened to 64 bits to be passed in here.
972 */
973 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uArgument);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700974 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800975#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200976 uReturn = FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700977 break;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800978 case SINGLE_PREC_FLOAT: /* 26 */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200979#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800980 /* Single precision is normally returned as a double since
981 * double is widely supported, there is no loss of precision,
982 * it makes it easy for the caller in most cases and it can
983 * be converted back to single with no loss of precision
984 *
985 * The cast to uint32_t is safe because the encoded value was
986 * 32 bits. It was widened to 64 bits to be passed in here.
987 */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700988 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800989 const float f = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uArgument);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700990#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800991 /* In the normal case, use HW to convert float to
992 * double. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700993 pDecodedItem->val.dfnum = (double)f;
994 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800995#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800996 /* Use of float HW is disabled, return as a float. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700997 pDecodedItem->val.fnum = f;
998 pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
999
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001000 /* IEEE754_FloatToDouble() could be used here to return as
1001 * a double, but it adds object code and most likely
1002 * anyone disabling FLOAT HW use doesn't care about floats
1003 * and wants to save object code.
1004 */
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001005#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001006 }
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001007#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1008 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001009 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001010
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001011 case DOUBLE_PREC_FLOAT: /* 27 */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001012#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001013 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uArgument);
Laurence Lundblade67bd5512018-11-02 21:44:06 +07001014 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001015#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1016 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001017 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001018
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001019 case CBOR_SIMPLEV_FALSE: /* 20 */
1020 case CBOR_SIMPLEV_TRUE: /* 21 */
1021 case CBOR_SIMPLEV_NULL: /* 22 */
1022 case CBOR_SIMPLEV_UNDEF: /* 23 */
1023 case CBOR_SIMPLE_BREAK: /* 31 */
1024 break; /* nothing to do */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001025
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001026 case CBOR_SIMPLEV_ONEBYTE: /* 24 */
1027 if(uArgument <= CBOR_SIMPLE_BREAK) {
1028 /* This takes out f8 00 ... f8 1f which should be encoded
1029 * as e0 … f7
1030 */
1031 uReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001032 goto Done;
1033 }
Laurence Lundblade5e390822019-01-06 12:35:01 -08001034 /* FALLTHROUGH */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001035
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001036 default: /* 0-19 */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001037 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001038 /* DecodeHead() will make uArgument equal to
1039 * nAdditionalInfo when nAdditionalInfo is < 24. This cast is
1040 * safe because the 2, 4 and 8 byte lengths of uNumber are in
1041 * the double/float cases above
Laurence Lundbladeee851742020-01-08 08:37:05 -08001042 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001043 pDecodedItem->val.uSimple = (uint8_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001044 break;
1045 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001046
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001047Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001048 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001049}
1050
1051
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001052/**
1053 * @brief Decode text and byte strings
1054 *
1055 * @param[in] pAllocator The string allocator or NULL.
1056 * @param[in] uStrLen The length of the string.
1057 * @param[in] pUInBuf The surce from which to read the string's bytes.
1058 * @param[out] pDecodedItem The filled in decoded item.
1059 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001060 * @retval QCBOR_ERR_HIT_END Unexpected end of input.
1061 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1062 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001063 *
1064 * The reads @c uStrlen bytes from @c pUInBuf and fills in @c
1065 * pDecodedItem. If @c pAllocator is not NULL then memory for the
1066 * string is allocated.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001067 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001068static QCBORError
1069QCBOR_Private_DecodeBytes(const QCBORInternalAllocator *pAllocator,
1070 const uint64_t uStrLen,
1071 UsefulInputBuf *pUInBuf,
1072 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001073{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001074 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001075
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001076 /* CBOR lengths can be 64 bits, but size_t is not 64 bits on all
1077 * CPUs. This check makes the casts to size_t below safe.
1078 *
1079 * The max is 4 bytes less than the largest sizeof() so this can be
1080 * tested by putting a SIZE_MAX length in the CBOR test input (no
1081 * one will care the limit on strings is 4 bytes shorter).
1082 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001083 if(uStrLen > SIZE_MAX-4) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001084 uReturn = QCBOR_ERR_STRING_TOO_LONG;
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001085 goto Done;
1086 }
1087
1088 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, (size_t)uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +05301089 if(UsefulBuf_IsNULLC(Bytes)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001090 /* Failed to get the bytes for this string item */
1091 uReturn = QCBOR_ERR_HIT_END;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +05301092 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001093 }
Laurence Lundblade471a3fd2018-10-18 21:27:45 +05301094
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001095#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001096 /* Note that this is not where allocation to coalesce
1097 * indefinite-length strings is done. This is for when the caller
1098 * has requested all strings be allocated. Disabling indefinite
1099 * length strings also disables this allocate-all option.
1100 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001101 if(pAllocator) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001102 /* request to use the string allocator to make a copy */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001103 UsefulBuf NewMem = StringAllocator_Allocate(pAllocator, (size_t)uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +05301104 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001105 uReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +05301106 goto Done;
1107 }
1108 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001109 pDecodedItem->uDataAlloc = 1;
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001110 goto Done;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +05301111 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001112#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1113 (void)pAllocator;
1114#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1115
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001116 /* Normal case with no string allocator */
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001117 pDecodedItem->val.string = Bytes;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001118
Laurence Lundblade471a3fd2018-10-18 21:27:45 +05301119Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001120 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001121}
1122
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001123
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001124/**
1125 * @brief Map the CBOR major types for strings to the QCBOR types.
1126 *
1127 * @param[in] nCBORMajorType The CBOR major type to convert.
1128 * @retturns QCBOR type number.
1129 *
1130 * This only works for the two string types.
1131 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001132static uint8_t
1133QCBOR_Private_ConvertStringMajorTypes(int nCBORMajorType)
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001134{
1135 #if CBOR_MAJOR_TYPE_BYTE_STRING + 4 != QCBOR_TYPE_BYTE_STRING
1136 #error QCBOR_TYPE_BYTE_STRING no lined up with major type
1137 #endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001138
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001139 #if CBOR_MAJOR_TYPE_TEXT_STRING + 4 != QCBOR_TYPE_TEXT_STRING
1140 #error QCBOR_TYPE_TEXT_STRING no lined up with major type
1141 #endif
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001142
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001143 return (uint8_t)(nCBORMajorType + 4);
1144}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001145
1146
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001147/**
1148 * @brief Map the CBOR major types for arrays/maps to the QCBOR types.
1149 *
1150 * @param[in] nCBORMajorType The CBOR major type to convert.
1151 * @retturns QCBOR type number.
1152 *
1153 * This only works for the two aggregate types.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001154 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001155static uint8_t
1156QCBORDecode_Private_ConvertArrayOrMapType(int nCBORMajorType)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001157{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001158 #if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
1159 #error QCBOR_TYPE_ARRAY value not lined up with major type
1160 #endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001161
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001162 #if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
1163 #error QCBOR_TYPE_MAP value not lined up with major type
1164 #endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001165
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001166 return (uint8_t)(nCBORMajorType);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001167}
1168
1169
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001170/**
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001171 * @brief Decode a single primitive data item (decode layer 6).
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001172 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001173 * @param[in] pUInBuf Input buffer to read data item from.
1174 * @param[out] pDecodedItem The filled-in decoded item.
1175 * @param[in] pAllocator The allocator to use for strings or NULL.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001176 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001177 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1178 * features
1179 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1180 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1181 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1182 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1183 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1184 * of half-precision disabled
1185 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1186 * float decode is disabled.
1187 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1188 * simple type in input.
1189 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1190 * in input, but indefinite
1191 * lengths disabled.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001192 *
1193 * This decodes the most primitive / atomic data item. It does
1194 * no combing of data items.
1195 */
1196static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001197QCBOR_Private_DecodeAtomicDataItem(UsefulInputBuf *pUInBuf,
1198 QCBORItem *pDecodedItem,
1199 const QCBORInternalAllocator *pAllocator)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001200{
1201 QCBORError uReturn;
1202
1203 /* Get the major type and the argument. The argument could be
1204 * length of more bytes or the value depending on the major
1205 * type. nAdditionalInfo is an encoding of the length of the
1206 * uNumber and is needed to decode floats and doubles.
1207 */
1208 int nMajorType = 0;
1209 uint64_t uArgument = 0;
1210 int nAdditionalInfo = 0;
1211
1212 memset(pDecodedItem, 0, sizeof(QCBORItem));
1213
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001214 uReturn = QCBOR_Private_DecodeHead(pUInBuf, &nMajorType, &uArgument, &nAdditionalInfo);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001215 if(uReturn) {
1216 goto Done;
1217 }
1218
1219 /* At this point the major type and the argument are valid. We've
1220 * got the type and the argument that starts every CBOR data item.
1221 */
1222 switch (nMajorType) {
1223 case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
1224 case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
1225 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1226 uReturn = QCBOR_ERR_BAD_INT;
1227 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001228 uReturn = QCBOR_Private_DecodeInteger(nMajorType, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001229 }
1230 break;
1231
1232 case CBOR_MAJOR_TYPE_BYTE_STRING: /* Major type 2 */
1233 case CBOR_MAJOR_TYPE_TEXT_STRING: /* Major type 3 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001234 pDecodedItem->uDataType = QCBOR_Private_ConvertStringMajorTypes(nMajorType);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001235 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1236 pDecodedItem->val.string = (UsefulBufC){NULL, QCBOR_STRING_LENGTH_INDEFINITE};
1237 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001238 uReturn = QCBOR_Private_DecodeBytes(pAllocator, uArgument, pUInBuf, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001239 }
1240 break;
1241
1242 case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */
1243 case CBOR_MAJOR_TYPE_MAP: /* Major type 5 */
1244 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1245 /* Indefinite-length string. */
1246#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
1247 pDecodedItem->val.uCount = QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH;
1248#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1249 uReturn = QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED;
1250 break;
1251#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1252 } else {
1253 /* Definite-length string. */
1254 if(uArgument > QCBOR_MAX_ITEMS_IN_ARRAY) {
1255 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
1256 goto Done;
1257 }
1258 /* cast OK because of check above */
1259 pDecodedItem->val.uCount = (uint16_t)uArgument;
1260 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001261 pDecodedItem->uDataType = QCBORDecode_Private_ConvertArrayOrMapType(nMajorType);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001262 break;
1263
1264 case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */
Laurence Lundblade37286c02022-09-03 10:05:02 -07001265#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001266 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1267 uReturn = QCBOR_ERR_BAD_INT;
1268 } else {
1269 pDecodedItem->val.uTagV = uArgument;
1270 pDecodedItem->uDataType = QCBOR_TYPE_TAG;
1271 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07001272#else /* QCBOR_DISABLE_TAGS */
1273 uReturn = QCBOR_ERR_TAGS_DISABLED;
1274#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001275 break;
1276
1277 case CBOR_MAJOR_TYPE_SIMPLE:
1278 /* Major type 7: float, double, true, false, null... */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001279 uReturn = QCBOR_Private_DecodeType7(nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001280 break;
1281
1282 default:
1283 /* Never happens because DecodeHead() should never return > 7 */
1284 uReturn = QCBOR_ERR_UNSUPPORTED;
1285 break;
1286 }
1287
1288Done:
1289 return uReturn;
1290}
1291
1292
1293/**
1294 * @brief Process indefinite-length strings (decode layer 5).
1295 *
1296 * @param[in] pMe Decoder context
1297 * @param[out] pDecodedItem The decoded item that work is done on.
1298 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001299 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1300 * features
1301 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1302 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1303 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1304 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1305 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1306 * of half-precision disabled
1307 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1308 * float decode is disabled.
1309 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1310 * simple type in input.
1311 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1312 * in input, but indefinite
1313 * lengths disabled.
1314 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1315 * but no string allocator.
1316 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1317 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1318 * input, but indefinite-length
1319 * strings are disabled.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001320 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001321 * If @c pDecodedItem is not an indefinite-length string, this does nothing.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001322 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001323 * If it is, this loops getting the subsequent chunk data items that
1324 * make up the string. The string allocator is used to make a
1325 * contiguous buffer for the chunks. When this completes @c
1326 * pDecodedItem contains the put-together string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001327 *
1328 * Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001329 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001330static QCBORError
1331QCBORDecode_Private_GetNextFullString(QCBORDecodeContext *pMe,
1332 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001333{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001334 /* Aproximate stack usage
1335 * 64-bit 32-bit
1336 * local vars 32 16
1337 * 2 UsefulBufs 32 16
1338 * QCBORItem 56 52
1339 * TOTAL 120 74
1340 */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001341
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001342 /* The string allocator is used here for two purposes: 1)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001343 * coalescing the chunks of an indefinite-length string, 2)
1344 * allocating storage for every string returned when requested.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001345 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001346 * The first use is below in this function. Indefinite-length
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001347 * strings cannot be processed at all without a string allocator.
1348 *
1349 * The second used is in DecodeBytes() which is called by
1350 * GetNext_Item() below. This second use unneccessary for most use
1351 * and only happens when requested in the call to
1352 * QCBORDecode_SetMemPool(). If the second use not requested then
1353 * NULL is passed for the string allocator to GetNext_Item().
1354 *
1355 * QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS disables the string
1356 * allocator altogether and thus both of these uses. It reduced the
1357 * decoder object code by about 400 bytes.
1358 */
Laurence Lundblade3a691a02020-12-28 04:15:16 -08001359 const QCBORInternalAllocator *pAllocatorForGetNext = NULL;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001360
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001361#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3a691a02020-12-28 04:15:16 -08001362 const QCBORInternalAllocator *pAllocator = NULL;
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001363
1364 if(pMe->StringAllocator.pfAllocator) {
1365 pAllocator = &(pMe->StringAllocator);
1366 if(pMe->bStringAllocateAll) {
1367 pAllocatorForGetNext = pAllocator;
1368 }
1369 }
1370#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1371
1372 QCBORError uReturn;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001373 uReturn = QCBOR_Private_DecodeAtomicDataItem(&(pMe->InBuf), pDecodedItem, pAllocatorForGetNext);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001374 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001375 goto Done;
1376 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001377
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001378 /* Only do indefinite-length processing on strings */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001379 const uint8_t uStringType = pDecodedItem->uDataType;
1380 if(uStringType!= QCBOR_TYPE_BYTE_STRING && uStringType != QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001381 goto Done;
1382 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001383
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001384 /* Is this a string with an indefinite length? */
1385 if(pDecodedItem->val.string.len != QCBOR_STRING_LENGTH_INDEFINITE) {
1386 goto Done;
1387 }
1388
1389#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001390 /* Can't decode indefinite-length strings without a string allocator */
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001391 if(pAllocator == NULL) {
1392 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1393 goto Done;
1394 }
1395
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001396 /* Loop getting chunks of the indefinite-length string */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001397 UsefulBufC FullString = NULLUsefulBufC;
1398
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001399 for(;;) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001400 /* Get QCBORItem for next chunk */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001401 QCBORItem StringChunkItem;
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001402 /* Pass a NULL string allocator to GetNext_Item() because the
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001403 * individual string chunks in an indefinite-length should not
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001404 * be allocated. They are always copied in the the contiguous
1405 * buffer allocated here.
1406 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001407 uReturn = QCBOR_Private_DecodeAtomicDataItem(&(pMe->InBuf), &StringChunkItem, NULL);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001408 if(uReturn) {
1409 break;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001410 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001411
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001412 /* Is item is the marker for end of the indefinite-length string? */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001413 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001414 /* String is complete */
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001415 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301416 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001417 break;
1418 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001419
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001420 /* All chunks must be of the same type, the type of the item
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001421 * that introduces the indefinite-length string. This also
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001422 * catches errors where the chunk is not a string at all and an
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001423 * indefinite-length string inside an indefinite-length string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001424 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001425 if(StringChunkItem.uDataType != uStringType ||
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001426 StringChunkItem.val.string.len == QCBOR_STRING_LENGTH_INDEFINITE) {
1427 uReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001428 break;
1429 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001430
David Navarro9123e5b2022-03-28 16:04:03 +02001431 if (StringChunkItem.val.string.len > 0) {
1432 /* The first time throurgh FullString.ptr is NULL and this is
1433 * equivalent to StringAllocator_Allocate(). Subsequently it is
1434 * not NULL and a reallocation happens.
1435 */
1436 UsefulBuf NewMem = StringAllocator_Reallocate(pAllocator,
1437 FullString.ptr,
1438 FullString.len + StringChunkItem.val.string.len);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001439
David Navarro9123e5b2022-03-28 16:04:03 +02001440 if(UsefulBuf_IsNULL(NewMem)) {
1441 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1442 break;
1443 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001444
David Navarro9123e5b2022-03-28 16:04:03 +02001445 /* Copy new string chunk to the end of accumulated string */
1446 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001447 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001448 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001449
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001450 if(uReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
1451 /* Getting the item failed, clean up the allocated memory */
Laurence Lundbladeb9702452021-03-08 21:02:57 -08001452 StringAllocator_Free(pAllocator, FullString.ptr);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001453 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001454#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1455 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1456#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001457
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001458Done:
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001459 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001460}
1461
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001462
Laurence Lundblade37286c02022-09-03 10:05:02 -07001463#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001464/**
1465 * @brief This converts a tag number to a shorter mapped value for storage.
1466 *
1467 * @param[in] pMe The decode context.
1468 * @param[in] uUnMappedTag The tag number to map
1469 * @param[out] puMappedTagNumer The stored tag number.
1470 *
1471 * @return error code.
1472 *
1473 * The main point of mapping tag numbers is make QCBORItem
1474 * smaller. With this mapping storage of 4 tags takes up 8
1475 * bytes. Without, it would take up 32 bytes.
1476 *
1477 * This maps tag numbers greater than QCBOR_LAST_UNMAPPED_TAG.
1478 * QCBOR_LAST_UNMAPPED_TAG is a little smaller than MAX_UINT16.
1479 *
1480 * See also UnMapTagNumber() and @ref QCBORItem.
1481 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001482static QCBORError
1483QCBORDecode_Private_MapTagNumber(QCBORDecodeContext *pMe,
1484 const uint64_t uUnMappedTag,
1485 uint16_t *puMappedTagNumer)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001486{
1487 if(uUnMappedTag > QCBOR_LAST_UNMAPPED_TAG) {
1488 unsigned uTagMapIndex;
1489 /* Is there room in the tag map, or is it in it already? */
1490 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
1491 if(pMe->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID64) {
1492 break;
1493 }
1494 if(pMe->auMappedTags[uTagMapIndex] == uUnMappedTag) {
1495 break;
1496 }
1497 }
1498 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
1499 return QCBOR_ERR_TOO_MANY_TAGS;
1500 }
1501
1502 /* Covers the cases where tag is new and were it is already in the map */
1503 pMe->auMappedTags[uTagMapIndex] = uUnMappedTag;
1504 *puMappedTagNumer = (uint16_t)(uTagMapIndex + QCBOR_LAST_UNMAPPED_TAG + 1);
1505
1506 } else {
1507 *puMappedTagNumer = (uint16_t)uUnMappedTag;
1508 }
1509
1510 return QCBOR_SUCCESS;
1511}
1512
1513
1514/**
1515 * @brief This converts a mapped tag number to the actual tag number.
1516 *
1517 * @param[in] pMe The decode context.
1518 * @param[in] uMappedTagNumber The stored tag number.
1519 *
1520 * @return The actual tag number is returned or
1521 * @ref CBOR_TAG_INVALID64 on error.
1522 *
1523 * This is the reverse of MapTagNumber()
1524 */
1525static uint64_t
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001526QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe,
1527 const uint16_t uMappedTagNumber)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001528{
1529 if(uMappedTagNumber <= QCBOR_LAST_UNMAPPED_TAG) {
1530 return uMappedTagNumber;
1531 } else if(uMappedTagNumber == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07001532 return CBOR_TAG_INVALID64;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001533 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001534 /* This won't be negative because of code below in
1535 * MapTagNumber()
1536 */
1537 const unsigned uIndex = uMappedTagNumber - (QCBOR_LAST_UNMAPPED_TAG + 1);
1538 return pMe->auMappedTags[uIndex];
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001539 }
1540}
Laurence Lundblade37286c02022-09-03 10:05:02 -07001541#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001542
Laurence Lundblade9b334962020-08-27 10:55:53 -07001543
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001544/**
1545 * @brief Aggregate all tags wrapping a data item (decode layer 4).
1546 *
1547 * @param[in] pMe Decoder context
1548 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001549 *
1550 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1551 * features
1552 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1553 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1554 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1555 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1556 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1557 * of half-precision disabled
1558 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1559 * float decode is disabled.
1560 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1561 * simple type in input.
1562 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1563 * in input, but indefinite
1564 * lengths disabled.
1565 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1566 * but no string allocator.
1567 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1568 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1569 * input, but indefinite-length
1570 * strings are disabled.
1571 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001572 *
1573 * This loops getting atomic data items until one is not a tag
1574 * number. Usually this is largely pass-through because most
1575 * item are not tag numbers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001576 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001577static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001578QCBORDecode_Private_GetNextTagNumber(QCBORDecodeContext *pMe,
1579 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001580{
Laurence Lundblade37286c02022-09-03 10:05:02 -07001581#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001582 /* Accummulate the tags from multiple items here and then copy them
1583 * into the last item, the non-tag item.
1584 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001585 uint16_t auItemsTags[QCBOR_MAX_TAGS_PER_ITEM];
1586
1587 /* Initialize to CBOR_TAG_INVALID16 */
1588 #if CBOR_TAG_INVALID16 != 0xffff
1589 /* Be sure the memset does the right thing. */
1590 #err CBOR_TAG_INVALID16 tag not defined as expected
1591 #endif
1592 memset(auItemsTags, 0xff, sizeof(auItemsTags));
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001593
Laurence Lundblade9b334962020-08-27 10:55:53 -07001594 QCBORError uReturn = QCBOR_SUCCESS;
1595
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001596 /* Loop fetching data items until the item fetched is not a tag */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001597 for(;;) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001598 QCBORError uErr = QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07001599 if(uErr != QCBOR_SUCCESS) {
1600 uReturn = uErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001601 goto Done;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001602 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001603
Laurence Lundblade9b334962020-08-27 10:55:53 -07001604 if(pDecodedItem->uDataType != QCBOR_TYPE_TAG) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001605 /* Successful exit from loop; maybe got some tags, maybe not */
1606 memcpy(pDecodedItem->uTags, auItemsTags, sizeof(auItemsTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001607 break;
1608 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001609
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001610 if(auItemsTags[QCBOR_MAX_TAGS_PER_ITEM - 1] != CBOR_TAG_INVALID16) {
1611 /* No room in the tag list */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001612 uReturn = QCBOR_ERR_TOO_MANY_TAGS;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001613 /* Continue on to get all tags wrapping this item even though
1614 * it is erroring out in the end. This allows decoding to
1615 * continue. This is a resource limit error, not a problem
1616 * with being well-formed CBOR.
1617 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001618 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001619 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001620 /* Slide tags over one in the array to make room at index 0.
1621 * Must use memmove because the move source and destination
1622 * overlap.
1623 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001624 memmove(&auItemsTags[1],
1625 auItemsTags,
1626 sizeof(auItemsTags) - sizeof(auItemsTags[0]));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001627
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001628 /* Map the tag */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001629 uint16_t uMappedTagNumber = 0;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001630 uReturn = QCBORDecode_Private_MapTagNumber(pMe, pDecodedItem->val.uTagV, &uMappedTagNumber);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001631 /* Continue even on error so as to consume all tags wrapping
1632 * this data item so decoding can go on. If MapTagNumber()
1633 * errors once it will continue to error.
1634 */
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001635 auItemsTags[0] = uMappedTagNumber;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001636 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001637
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001638Done:
Laurence Lundblade9b334962020-08-27 10:55:53 -07001639 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001640
Laurence Lundblade37286c02022-09-03 10:05:02 -07001641#else /* QCBOR_DISABLE_TAGS */
1642
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07001643 return QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07001644
1645#endif /* QCBOR_DISABLE_TAGS */
1646}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001647
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001648
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001649/**
1650 * @brief Combine a map entry label and value into one item (decode layer 3).
1651 *
1652 * @param[in] pMe Decoder context
1653 * @param[out] pDecodedItem The decoded item that work is done on.
1654 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001655 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1656 * features
1657 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1658 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1659 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1660 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1661 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1662 * of half-precision disabled
1663 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1664 * float decode is disabled.
1665 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1666 * simple type in input.
1667 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1668 * in input, but indefinite
1669 * lengths disabled.
1670 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1671 * but no string allocator.
1672 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1673 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1674 * input, but indefinite-length
1675 * strings are disabled.
1676 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1677 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1678 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001679 *
1680 * If a the current nesting level is a map, then this
1681 * combines pairs of items into one data item with a label
1682 * and value.
1683 *
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07001684 * This is passthrough if the current nesting level is
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001685 * not a map.
1686 *
1687 * This also implements maps-as-array mode where a map
1688 * is treated like an array to allow caller to do their
1689 * own label processing.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001690 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001691static QCBORError
1692QCBORDecode_Private_GetNextMapEntry(QCBORDecodeContext *pMe,
1693 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001694{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001695 QCBORError uReturn = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001696 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001697 goto Done;
1698 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001699
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001700 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
1701 /* Break can't be a map entry */
1702 goto Done;
1703 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001704
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001705 if(pMe->uDecodeMode != QCBOR_DECODE_MODE_MAP_AS_ARRAY) {
1706 /* Normal decoding of maps -- combine label and value into one item. */
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001707
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001708 if(DecodeNesting_IsCurrentTypeMap(&(pMe->nesting))) {
1709 /* Save label in pDecodedItem and get the next which will
1710 * be the real data item.
1711 */
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001712 QCBORItem LabelItem = *pDecodedItem;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001713 uReturn = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001714 if(QCBORDecode_IsUnrecoverableError(uReturn)) {
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001715 goto Done;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07001716 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001717
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301718 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001719
1720 if(LabelItem.uDataType == QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001721 /* strings are always good labels */
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001722 pDecodedItem->label.string = LabelItem.val.string;
1723 pDecodedItem->uLabelType = QCBOR_TYPE_TEXT_STRING;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001724 } else if (QCBOR_DECODE_MODE_MAP_STRINGS_ONLY == pMe->uDecodeMode) {
1725 /* It's not a string and we only want strings */
1726 uReturn = QCBOR_ERR_MAP_LABEL_TYPE;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001727 goto Done;
1728 } else if(LabelItem.uDataType == QCBOR_TYPE_INT64) {
1729 pDecodedItem->label.int64 = LabelItem.val.int64;
1730 pDecodedItem->uLabelType = QCBOR_TYPE_INT64;
1731 } else if(LabelItem.uDataType == QCBOR_TYPE_UINT64) {
1732 pDecodedItem->label.uint64 = LabelItem.val.uint64;
1733 pDecodedItem->uLabelType = QCBOR_TYPE_UINT64;
1734 } else if(LabelItem.uDataType == QCBOR_TYPE_BYTE_STRING) {
1735 pDecodedItem->label.string = LabelItem.val.string;
1736 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
1737 pDecodedItem->uLabelType = QCBOR_TYPE_BYTE_STRING;
1738 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001739 /* label is not an int or a string. It is an arrray
1740 * or a float or such and this implementation doesn't handle that.
1741 * Also, tags on labels are ignored.
1742 */
1743 uReturn = QCBOR_ERR_MAP_LABEL_TYPE;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001744 goto Done;
1745 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001746 }
1747 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001748 /* Decoding of maps as arrays to let the caller decide what to do
1749 * about labels, particularly lables that are not integers or
1750 * strings.
1751 */
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001752 if(pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001753 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
Laurence Lundblade5db34da2024-05-30 03:14:35 -07001754 if(pDecodedItem->val.uCount != UINT16_MAX) {
1755 /* Adjust definite-length map item count */
1756 if(pDecodedItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
1757 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
1758 goto Done;
1759 }
1760 /* Cast is safe because of check against QCBOR_MAX_ITEMS_IN_ARRAY/2.
1761 * Cast is needed because of integer promotion.
1762 */
1763 pDecodedItem->val.uCount = (uint16_t)(pDecodedItem->val.uCount * 2);
1764 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001765 }
1766 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001767
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001768Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001769 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001770}
1771
1772
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001773#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001774/**
1775 * @brief Peek and see if next data item is a break;
1776 *
1777 * @param[in] pUIB UsefulInputBuf to read from.
1778 * @param[out] pbNextIsBreak Indicate if next was a break or not.
1779 *
1780 * @return Any decoding error.
1781 *
1782 * See if next item is a CBOR break. If it is, it is consumed,
1783 * if not it is not consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07001784*/
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001785static QCBORError
1786QCBOR_Private_NextIsBreak(UsefulInputBuf *pUIB, bool *pbNextIsBreak)
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001787{
1788 *pbNextIsBreak = false;
1789 if(UsefulInputBuf_BytesUnconsumed(pUIB) != 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001790 QCBORItem Peek;
1791 size_t uPeek = UsefulInputBuf_Tell(pUIB);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001792 QCBORError uReturn = QCBOR_Private_DecodeAtomicDataItem(pUIB, &Peek, NULL);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001793 if(uReturn != QCBOR_SUCCESS) {
1794 return uReturn;
1795 }
1796 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001797 /* It is not a break, rewind so it can be processed normally. */
Laurence Lundblade02625d42020-06-25 14:41:41 -07001798 UsefulInputBuf_Seek(pUIB, uPeek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001799 } else {
1800 *pbNextIsBreak = true;
1801 }
1802 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001803
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001804 return QCBOR_SUCCESS;
1805}
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001806#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001807
1808
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001809/**
1810 * @brief Ascend up nesting levels if all items in them have been consumed.
1811 *
1812 * @param[in] pMe The decode context.
1813 * @param[in] bMarkEnd If true mark end of maps/arrays with count of zero.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001814 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001815 *
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001816 * An item was just consumed, now figure out if it was the
1817 * end of an array/map map that can be closed out. That
1818 * may in turn close out the above array/map...
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001819 *
1820 * When ascending indefinite-length arrays and maps, this will correctly
1821 * consume the break for the level above. This is a problem for the
1822 * implementation of QCBORDecode_GetArray() that must not return
1823 * that break. @c pbBreak is set to true to indicate that one
1824 * byte should be removed.
1825 *
1826 * Improvement: this could reduced further if indef is disabled
1827 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001828static QCBORError
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001829QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd, bool *pbBreak)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001830{
1831 QCBORError uReturn;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001832
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001833 /* Loop ascending nesting levels as long as there is ascending to do */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001834 while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001835 if(pbBreak) {
1836 *pbBreak = false;
1837 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001838
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001839 if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) {
1840 /* Nesting level is bstr-wrapped CBOR */
1841
1842 /* Ascent for bstr-wrapped CBOR is always by explicit call
1843 * so no further ascending can happen.
1844 */
1845 break;
1846
1847 } else if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
1848 /* Level is a definite-length array/map */
1849
1850 /* Decrement the item count the definite-length array/map */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001851 DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(&(pMe->nesting));
1852 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001853 /* Didn't close out array/map, so all work here is done */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001854 break;
1855 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001856 /* All items in a definite-length array were consumed so it
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001857 * is time to ascend one level. This happens below.
1858 */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001859
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001860#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001861 } else {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001862 /* Level is an indefinite-length array/map. */
1863
1864 /* Check for a break which is what ends indefinite-length arrays/maps */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001865 bool bIsBreak = false;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001866 uReturn = QCBOR_Private_NextIsBreak(&(pMe->InBuf), &bIsBreak);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001867 if(uReturn != QCBOR_SUCCESS) {
1868 goto Done;
1869 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001870
1871 if(!bIsBreak) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001872 /* Not a break so array/map does not close out. All work is done */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001873 break;
1874 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001875
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001876 /* It was a break in an indefinitelength map / array so
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001877 * it is time to ascend one level.
1878 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001879 if(pbBreak) {
1880 *pbBreak = true;
1881 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001882
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001883#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001884 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001885
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001886
1887 /* All items in the array/map have been consumed. */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001888
Laurence Lundblade93d89472020-10-03 22:30:50 -07001889 /* But ascent in bounded mode is only by explicit call to
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001890 * QCBORDecode_ExitBoundedMode().
1891 */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07001892 if(DecodeNesting_IsCurrentBounded(&(pMe->nesting))) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001893 /* Set the count to zero for definite-length arrays to indicate
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001894 * cursor is at end of bounded array/map */
Laurence Lundbladed0304932020-06-27 10:59:38 -07001895 if(bMarkEnd) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001896 /* Used for definite and indefinite to signal end */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07001897 DecodeNesting_ZeroMapOrArrayCount(&(pMe->nesting));
Laurence Lundbladed0304932020-06-27 10:59:38 -07001898
Laurence Lundblade2c1faf92020-06-26 22:43:56 -07001899 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001900 break;
1901 }
1902
1903 /* Finally, actually ascend one level. */
1904 DecodeNesting_Ascend(&(pMe->nesting));
1905 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001906
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001907 uReturn = QCBOR_SUCCESS;
1908
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001909#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001910Done:
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001911#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1912
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001913 return uReturn;
1914}
1915
1916
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001917/**
1918 * @brief Ascending & Descending out of nesting levels (decode layer 2).
1919 *
1920 * @param[in] pMe Decoder context
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001921 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001922 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001923
1924 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1925 * features
1926 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1927 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1928 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1929 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1930 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1931 * of half-precision disabled
1932 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1933 * float decode is disabled.
1934 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1935 * simple type in input.
1936 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1937 * in input, but indefinite
1938 * lengths disabled.
1939 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1940 * but no string allocator.
1941 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1942 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1943 * input, but indefinite-length
1944 * strings are disabled.
1945 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1946 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1947 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
1948 * @retval QCBOR_ERR_NO_MORE_ITEMS Need more items for map or array.
1949 * @retval QCBOR_ERR_BAD_BREAK Indefinite-length break in wrong
1950 * place.
1951 * @retval QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP Nesting deeper than QCBOR
1952 * can handle.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001953 *
1954 * This handles the traversal descending into and asecnding out of
1955 * maps, arrays and bstr-wrapped CBOR. It figures out the ends of
1956 * definite- and indefinte-length maps and arrays by looking at the
1957 * item count or finding CBOR breaks. It detects the ends of the
1958 * top-level sequence and of bstr-wrapped CBOR by byte count.
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001959 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001960static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001961QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07001962 bool *pbBreak,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001963 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001964{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001965 QCBORError uReturn;
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07001966 /* ==== First: figure out if at the end of a traversal ==== */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001967
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001968 /* If out of bytes to consume, it is either the end of the
1969 * top-level sequence of some bstr-wrapped CBOR that was entered.
1970 *
1971 * In the case of bstr-wrapped CBOR, the length of the
1972 * UsefulInputBuf was set to that of the bstr-wrapped CBOR. When
1973 * the bstr-wrapped CBOR is exited, the length is set back to the
1974 * top-level's length or to the next highest bstr-wrapped CBOR.
Laurence Lundblade642282a2020-06-23 12:00:33 -07001975 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001976 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) == 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001977 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001978 goto Done;
1979 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07001980
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001981 /* Check to see if at the end of a bounded definite-length map or
1982 * array. The check for a break ending indefinite-length array is
1983 * later in QCBORDecode_NestLevelAscender().
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001984 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001985 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001986 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07001987 goto Done;
1988 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001989
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001990 /* ==== Next: not at the end, so get another item ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001991 uReturn = QCBORDecode_Private_GetNextMapEntry(pMe, pDecodedItem);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07001992 if(QCBORDecode_IsUnrecoverableError(uReturn)) {
1993 /* Error is so bad that traversal is not possible. */
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001994 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001995 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301996
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001997 /* Breaks ending arrays/maps are processed later in the call to
1998 * QCBORDecode_NestLevelAscender(). They should never show up here.
Laurence Lundblade642282a2020-06-23 12:00:33 -07001999 */
Laurence Lundblade6de37062018-10-15 12:22:42 +05302000 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002001 uReturn = QCBOR_ERR_BAD_BREAK;
Laurence Lundblade6de37062018-10-15 12:22:42 +05302002 goto Done;
Laurence Lundblade5b8c5852018-10-14 21:11:42 +05302003 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002004
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002005 /* Record the nesting level for this data item before processing
2006 * any of decrementing and descending.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002007 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002008 pDecodedItem->uNestingLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002009
Laurence Lundblade642282a2020-06-23 12:00:33 -07002010
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002011 /* ==== Next: Process the item for descent, ascent, decrement... ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002012 if(QCBORItem_IsMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002013 /* If the new item is a map or array, descend.
2014 *
2015 * Empty indefinite-length maps and arrays are descended into,
2016 * but then ascended out of in the next chunk of code.
2017 *
2018 * Maps and arrays do count as items in the map/array that
2019 * encloses them so a decrement needs to be done for them too,
2020 * but that is done only when all the items in them have been
2021 * processed, not when they are opened with the exception of an
2022 * empty map or array.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002023 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002024 QCBORError uDescendErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002025 uDescendErr = DecodeNesting_DescendMapOrArray(&(pMe->nesting),
Laurence Lundblade642282a2020-06-23 12:00:33 -07002026 pDecodedItem->uDataType,
2027 pDecodedItem->val.uCount);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002028 if(uDescendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002029 /* This error is probably a traversal error and it overrides
2030 * the non-traversal error.
2031 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002032 uReturn = uDescendErr;
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002033 goto Done;
2034 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002035 }
2036
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002037 if(!QCBORItem_IsMapOrArray(*pDecodedItem) ||
2038 QCBORItem_IsEmptyDefiniteLengthMapOrArray(*pDecodedItem) ||
2039 QCBORItem_IsIndefiniteLengthMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002040 /* The following cases are handled here:
2041 * - A non-aggregate item like an integer or string
2042 * - An empty definite-length map or array
2043 * - An indefinite-length map or array that might be empty or might not.
2044 *
2045 * QCBORDecode_NestLevelAscender() does the work of decrementing the count
2046 * for an definite-length map/array and break detection for an
2047 * indefinite-0length map/array. If the end of the map/array was
2048 * reached, then it ascends nesting levels, possibly all the way
2049 * to the top level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002050 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002051 QCBORError uAscendErr;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002052 uAscendErr = QCBORDecode_Private_NestLevelAscender(pMe, true, pbBreak);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002053 if(uAscendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002054 /* This error is probably a traversal error and it overrides
2055 * the non-traversal error.
2056 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002057 uReturn = uAscendErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002058 goto Done;
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002059 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05302060 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002061
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002062 /* ==== Last: tell the caller the nest level of the next item ==== */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002063 /* Tell the caller what level is next. This tells them what
2064 * maps/arrays were closed out and makes it possible for them to
2065 * reconstruct the tree with just the information returned in a
2066 * QCBORItem.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002067 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002068 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07002069 /* At end of a bounded map/array; uNextNestLevel 0 to indicate this */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002070 pDecodedItem->uNextNestLevel = 0;
2071 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002072 pDecodedItem->uNextNestLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002073 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002074
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002075Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002076 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002077}
2078
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002079
Laurence Lundblade37286c02022-09-03 10:05:02 -07002080#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002081/**
2082 * @brief Shift 0th tag out of the tag list.
2083 *
2084 * pDecodedItem[in,out] The data item to convert.
2085 *
2086 * The 0th tag is discarded. \ref CBOR_TAG_INVALID16 is
2087 * shifted into empty slot at the end of the tag list.
2088 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002089static void
2090QCBOR_Private_ShiftTags(QCBORItem *pDecodedItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002091{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002092 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM-1; i++) {
2093 pDecodedItem->uTags[i] = pDecodedItem->uTags[i+1];
2094 }
2095 pDecodedItem->uTags[QCBOR_MAX_TAGS_PER_ITEM-1] = CBOR_TAG_INVALID16;
Laurence Lundblade9b334962020-08-27 10:55:53 -07002096}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002097#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002098
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002099
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002100/**
2101 * @brief Convert different epoch date formats in to the QCBOR epoch date format
2102 *
2103 * pDecodedItem[in,out] The data item to convert.
2104 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002105 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2106 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2107 * floating-point date disabled.
2108 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2109 * all floating-point disabled.
2110 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2111 * error decoding date.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002112 *
2113 * The epoch date tag defined in QCBOR allows for floating-point
2114 * dates. It even allows a protocol to flop between date formats when
2115 * ever it wants. Floating-point dates aren't that useful as they are
2116 * only needed for dates beyond the age of the earth.
2117 *
2118 * This converts all the date formats into one format of an unsigned
2119 * integer plus a floating-point fraction.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002120 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002121static QCBORError
2122QCBOR_Private_DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002123{
Laurence Lundbladec7114722020-08-13 05:11:40 -07002124 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002125
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002126#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade59289e52019-12-30 13:44:37 -08002127 pDecodedItem->val.epochDate.fSecondsFraction = 0;
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02002128#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002129
2130 switch (pDecodedItem->uDataType) {
2131
2132 case QCBOR_TYPE_INT64:
2133 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
2134 break;
2135
2136 case QCBOR_TYPE_UINT64:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002137 /* This only happens for CBOR type 0 > INT64_MAX so it is
2138 * always an overflow.
2139 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07002140 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2141 goto Done;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002142 break;
2143
2144 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade9682a532020-06-06 18:33:04 -07002145 case QCBOR_TYPE_FLOAT:
2146#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade59289e52019-12-30 13:44:37 -08002147 {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002148 /* Convert working value to double if input was a float */
Laurence Lundblade3ed0bca2020-07-14 22:50:10 -07002149 const double d = pDecodedItem->uDataType == QCBOR_TYPE_DOUBLE ?
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002150 pDecodedItem->val.dfnum :
2151 (double)pDecodedItem->val.fnum;
2152
2153 /* The conversion from float to integer requires overflow
2154 * detection since floats can be much larger than integers.
2155 * This implementation errors out on these large float values
2156 * since they are beyond the age of the earth.
2157 *
2158 * These constants for the overflow check are computed by the
2159 * compiler. They are not computed at run time.
2160 *
2161 * The factor of 0x7ff is added/subtracted to avoid a
2162 * rounding error in the wrong direction when the compiler
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002163 * computes these constants. There is rounding because a
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002164 * 64-bit integer has 63 bits of precision where a double
2165 * only has 53 bits. Without the 0x7ff factor, the compiler
2166 * may round up and produce a double for the bounds check
2167 * that is larger than can be stored in a 64-bit integer. The
2168 * amount of 0x7ff is picked because it has 11 bits set.
2169 *
2170 * Without the 0x7ff there is a ~30 minute range of time
2171 * values 10 billion years in the past and in the future
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002172 * where this code could go wrong. Some compilers
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002173 * generate a warning or error without the 0x7ff.
2174 */
2175 const double dDateMax = (double)(INT64_MAX - 0x7ff);
2176 const double dDateMin = (double)(INT64_MIN + 0x7ff);
2177
2178 if(isnan(d) || d > dDateMax || d < dDateMin) {
Laurence Lundbladec7114722020-08-13 05:11:40 -07002179 uReturn = QCBOR_ERR_DATE_OVERFLOW;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002180 goto Done;
2181 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002182
2183 /* The actual conversion */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002184 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
Laurence Lundblade2feb1e12020-07-15 03:50:45 -07002185 pDecodedItem->val.epochDate.fSecondsFraction =
2186 d - (double)pDecodedItem->val.epochDate.nSeconds;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002187 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002188#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade4b270642020-08-14 12:53:07 -07002189
Laurence Lundblade16a207a2021-09-18 17:22:46 -07002190 uReturn = QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundblade4b270642020-08-14 12:53:07 -07002191 goto Done;
2192
Laurence Lundblade9682a532020-06-06 18:33:04 -07002193#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002194 break;
2195
2196 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002197 /* It's the arrays and maps that are unrecoverable because
2198 * they are not consumed here. Since this is just an error
2199 * condition, no extra code is added here to make the error
2200 * recoverable for non-arrays and maps like strings. */
2201 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002202 goto Done;
2203 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002204
Laurence Lundblade59289e52019-12-30 13:44:37 -08002205 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
2206
2207Done:
Laurence Lundbladec7114722020-08-13 05:11:40 -07002208 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002209}
2210
2211
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002212/**
2213 * @brief Convert the days epoch date.
2214 *
2215 * pDecodedItem[in,out] The data item to convert.
2216 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002217 * @retval QCBOR_ERR_DATE_OVERFLOW 65-bit negative integer.
2218 * @retval QCBOR_ERR_FLOAT_DATE_DISABLED Float-point date in input,
2219 * floating-point date disabled.
2220 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point date in input,
2221 * all floating-point disabled.
2222 * @retval QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT Unexpected and unrecoverable
2223 * error decoding date.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002224 *
2225 * This is much simpler than the other epoch date format because
2226 * floating-porint is not allowed. This is mostly a simple type check.
2227 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002228static QCBORError
2229QCBOR_Private_DecodeDaysEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002230{
2231 QCBORError uReturn = QCBOR_SUCCESS;
2232
2233 switch (pDecodedItem->uDataType) {
2234
2235 case QCBOR_TYPE_INT64:
2236 pDecodedItem->val.epochDays = pDecodedItem->val.int64;
2237 break;
2238
2239 case QCBOR_TYPE_UINT64:
2240 /* This only happens for CBOR type 0 > INT64_MAX so it is
2241 * always an overflow.
2242 */
2243 uReturn = QCBOR_ERR_DATE_OVERFLOW;
2244 goto Done;
2245 break;
2246
2247 default:
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002248 /* It's the arrays and maps that are unrecoverable because
2249 * they are not consumed here. Since this is just an error
2250 * condition, no extra code is added here to make the error
2251 * recoverable for non-arrays and maps like strings. */
2252 uReturn = QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002253 goto Done;
2254 break;
2255 }
2256
2257 pDecodedItem->uDataType = QCBOR_TYPE_DAYS_EPOCH;
2258
2259Done:
2260 return uReturn;
2261}
2262
2263
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002264#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade37286c02022-09-03 10:05:02 -07002265
2266/* Forward declaration is necessary for
2267 * QCBORDecode_MantissaAndExponent(). to be able to decode bignum
2268 * tags in the mantissa. If the mantissa is a decimal fraction or big
2269 * float in error, this will result in a recurive call to
2270 * QCBORDecode_MantissaAndExponent(), but the recursion will unwined
2271 * correctly and the correct error is returned.
2272 */
2273static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002274QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2275 QCBORItem *pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002276
2277
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002278/**
2279 * @brief Decode decimal fractions and big floats.
2280 *
2281 * @param[in] pMe The decode context.
2282 * @param[in,out] pDecodedItem On input the array data item that
2283 * holds the mantissa and exponent. On
2284 * output the decoded mantissa and
2285 * exponent.
2286 *
2287 * @returns Decoding errors from getting primitive data items or
2288 * \ref QCBOR_ERR_BAD_EXP_AND_MANTISSA.
2289 *
Laurence Lundblade37286c02022-09-03 10:05:02 -07002290 * When called pDecodedItem must be the array with two members, the
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002291 * exponent and mantissa.
2292 *
2293 * This will fetch and decode the exponent and mantissa and put the
2294 * result back into pDecodedItem.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002295 *
2296 * This does no checking or processing of tag numbers. That is to be
2297 * done by the code that calls this.
2298 *
2299 * This stuffs the type of the mantissa into pDecodedItem with the expectation
2300 * the caller will process it.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002301 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002302static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002303QCBORDecode_Private_ExpMantissa(QCBORDecodeContext *pMe,
2304 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002305{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002306 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002307
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002308 /* --- Make sure it is an array; track nesting level of members --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002309 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002310 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002311 goto Done;
2312 }
2313
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002314 /* A check for pDecodedItem->val.uCount == 2 would work for
Laurence Lundblade37286c02022-09-03 10:05:02 -07002315 * definite-length arrays, but not for indefinite. Instead remember
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002316 * the nesting level the two integers must be at, which is one
2317 * deeper than that of the array.
2318 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002319 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
2320
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002321 /* --- Get the exponent --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002322 QCBORItem exponentItem;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002323 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, &exponentItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002324 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002325 goto Done;
2326 }
2327 if(exponentItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002328 /* Array is empty or a map/array encountered when expecting an int */
2329 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002330 goto Done;
2331 }
2332 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002333 /* Data arriving as an unsigned int < INT64_MAX has been
2334 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2335 * also means that the only data arriving here of type
2336 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2337 * and thus an error that will get handled in the next else.
2338 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002339 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
2340 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002341 /* Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX */
2342 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002343 goto Done;
2344 }
2345
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002346 /* --- Get the mantissa --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002347 QCBORItem mantissaItem;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002348 uReturn = QCBORDecode_Private_GetNextTagContent(pMe, &mantissaItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002349 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002350 goto Done;
2351 }
2352 if(mantissaItem.uNestingLevel != nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002353 /* Mantissa missing or map/array encountered when expecting number */
2354 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002355 goto Done;
2356 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002357 /* Stuff the mantissa data type into the item to send it up to the
2358 * the next level. */
2359 pDecodedItem->uDataType = mantissaItem.uDataType;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002360 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002361 /* Data arriving as an unsigned int < INT64_MAX has been
2362 * converted to QCBOR_TYPE_INT64 and thus handled here. This is
2363 * also means that the only data arriving here of type
2364 * QCBOR_TYPE_UINT64 data will be too large for this to handle
2365 * and thus an error that will get handled in an else below.
2366 */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002367 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002368#ifndef QCBOR_DISABLE_TAGS
2369 /* With tags fully disabled a big number mantissa will error out
2370 * in the call to QCBORDecode_GetNextWithTags() because it has
2371 * a tag number.
2372 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07002373 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM ||
2374 mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002375 /* Got a good big num mantissa */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002376 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002377#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002378 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002379 /* Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX */
2380 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002381 goto Done;
2382 }
2383
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002384 /* --- Check that array only has the two numbers --- */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002385 if(mantissaItem.uNextNestLevel == nNestLevel) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002386 /* Extra items in the decimal fraction / big float */
Laurence Lundblade37286c02022-09-03 10:05:02 -07002387 /* Improvement: this should probably be an unrecoverable error. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002388 uReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002389 goto Done;
2390 }
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002391 pDecodedItem->uNextNestLevel = mantissaItem.uNextNestLevel;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002392
2393Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002394 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002395}
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002396#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002397
2398
Laurence Lundblade37286c02022-09-03 10:05:02 -07002399#ifndef QCBOR_DISABLE_TAGS
2400
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002401#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002402/**
2403 * @brief Decode the MIME type tag
2404 *
2405 * @param[in,out] pDecodedItem The item to decode.
2406 *
2407 * Handle the text and binary MIME type tags. Slightly too complicated
2408 * f or ProcessTaggedString() because the RFC 7049 MIME type was
2409 * incorreclty text-only.
2410 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002411static QCBORError
2412QCBOR_Private_DecodeMIME(QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002413{
2414 if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) {
2415 pDecodedItem->uDataType = QCBOR_TYPE_MIME;
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07002416 } else if(pDecodedItem->uDataType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002417 pDecodedItem->uDataType = QCBOR_TYPE_BINARY_MIME;
2418 } else {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002419 /* It's the arrays and maps that are unrecoverable because
2420 * they are not consumed here. Since this is just an error
2421 * condition, no extra code is added here to make the error
2422 * recoverable for non-arrays and maps like strings. */
2423 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002424 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002425
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002426 return QCBOR_SUCCESS;
2427}
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002428#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002429
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002430/**
Laurence Lundblade99615302020-11-29 11:19:47 -08002431 * Table of CBOR tags whose content is either a text string or a byte
2432 * string. The table maps the CBOR tag to the QCBOR type. The high-bit
2433 * of uQCBORtype indicates the content should be a byte string rather
2434 * than a text string
2435 */
2436struct StringTagMapEntry {
2437 uint16_t uTagNumber;
2438 uint8_t uQCBORtype;
2439};
2440
2441#define IS_BYTE_STRING_BIT 0x80
2442#define QCBOR_TYPE_MASK ~IS_BYTE_STRING_BIT
2443
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002444static const struct StringTagMapEntry QCBOR_Private_StringTagMap[] = {
Laurence Lundblade99615302020-11-29 11:19:47 -08002445 {CBOR_TAG_DATE_STRING, QCBOR_TYPE_DATE_STRING},
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002446 {CBOR_TAG_DAYS_STRING, QCBOR_TYPE_DAYS_STRING},
Laurence Lundblade99615302020-11-29 11:19:47 -08002447 {CBOR_TAG_POS_BIGNUM, QCBOR_TYPE_POSBIGNUM | IS_BYTE_STRING_BIT},
2448 {CBOR_TAG_NEG_BIGNUM, QCBOR_TYPE_NEGBIGNUM | IS_BYTE_STRING_BIT},
2449 {CBOR_TAG_CBOR, QBCOR_TYPE_WRAPPED_CBOR | IS_BYTE_STRING_BIT},
2450 {CBOR_TAG_URI, QCBOR_TYPE_URI},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002451#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002452 {CBOR_TAG_B64URL, QCBOR_TYPE_BASE64URL},
2453 {CBOR_TAG_B64, QCBOR_TYPE_BASE64},
2454 {CBOR_TAG_REGEX, QCBOR_TYPE_REGEX},
2455 {CBOR_TAG_BIN_UUID, QCBOR_TYPE_UUID | IS_BYTE_STRING_BIT},
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002456#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade99615302020-11-29 11:19:47 -08002457 {CBOR_TAG_CBOR_SEQUENCE, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE | IS_BYTE_STRING_BIT},
2458 {CBOR_TAG_INVALID16, QCBOR_TYPE_NONE}
2459};
2460
2461
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002462/**
2463 * @brief Process standard CBOR tags whose content is a string
2464 *
2465 * @param[in] uTag The tag.
2466 * @param[in,out] pDecodedItem The data item.
2467 *
2468 * @returns This returns QCBOR_SUCCESS if the tag was procssed,
2469 * \ref QCBOR_ERR_UNSUPPORTED if the tag was not processed and
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002470 * \ref QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT if the content type was wrong for the tag.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002471 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002472 * Process the CBOR tags that whose content is a byte string or a text
2473 * string and for which the string is just passed on to the caller.
2474 *
2475 * This maps the CBOR tag to the QCBOR type and checks the content
2476 * type. Nothing more. It may not be the most important
Laurence Lundbladec02e13e2020-12-06 05:45:41 -08002477 * functionality, but it part of implementing as much of RFC 8949 as
Laurence Lundblade99615302020-11-29 11:19:47 -08002478 * possible.
Laurence Lundblade99615302020-11-29 11:19:47 -08002479 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002480static QCBORError
2481QCBOR_Private_ProcessTaggedString(uint16_t uTag, QCBORItem *pDecodedItem)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002482{
Laurence Lundblade99615302020-11-29 11:19:47 -08002483 /* This only works on tags that were not mapped; no need for other yet */
2484 if(uTag > QCBOR_LAST_UNMAPPED_TAG) {
2485 return QCBOR_ERR_UNSUPPORTED;
2486 }
2487
2488 unsigned uIndex;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002489 for(uIndex = 0; QCBOR_Private_StringTagMap[uIndex].uTagNumber != CBOR_TAG_INVALID16; uIndex++) {
2490 if(QCBOR_Private_StringTagMap[uIndex].uTagNumber == uTag) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002491 break;
2492 }
2493 }
2494
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002495 const uint8_t uQCBORType = QCBOR_Private_StringTagMap[uIndex].uQCBORtype;
Laurence Lundblade99615302020-11-29 11:19:47 -08002496 if(uQCBORType == QCBOR_TYPE_NONE) {
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002497 /* repurpose this error to mean not handled here */
Laurence Lundblade99615302020-11-29 11:19:47 -08002498 return QCBOR_ERR_UNSUPPORTED;
2499 }
2500
2501 uint8_t uExpectedType = QCBOR_TYPE_TEXT_STRING;
2502 if(uQCBORType & IS_BYTE_STRING_BIT) {
2503 uExpectedType = QCBOR_TYPE_BYTE_STRING;
2504 }
2505
2506 if(pDecodedItem->uDataType != uExpectedType) {
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07002507 /* It's the arrays and maps that are unrecoverable because
2508 * they are not consumed here. Since this is just an error
2509 * condition, no extra code is added here to make the error
2510 * recoverable for non-arrays and maps like strings. */
2511 return QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002512 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002513
Laurence Lundblade99615302020-11-29 11:19:47 -08002514 pDecodedItem->uDataType = (uint8_t)(uQCBORType & QCBOR_TYPE_MASK);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002515 return QCBOR_SUCCESS;
2516}
Laurence Lundblade37286c02022-09-03 10:05:02 -07002517#endif /* QCBOR_DISABLE_TAGS */
2518
2519
2520#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002521/**
2522 * @brief Figures out data type for exponent mantissa tags.
2523 *
2524 * @param[in] uTagToProcess Either @ref CBOR_TAG_DECIMAL_FRACTION or
2525 * @ref CBOR_TAG_BIG_FLOAT.
2526 * @param[in] pDecodedItem Item being decoded.
2527 *
2528 * @returns One of the 6 values between \ref QCBOR_TYPE_DECIMAL_FRACTION
2529 * and @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM.
2530 *
2531 * Does mapping between a CBOR tag number and a QCBOR type. with a
2532 * little bit of logic and arithmatic.
2533 *
2534 * Used in serveral contexts. Does the work where sometimes the data
2535 * item is explicitly tagged and sometimes not.
Laurence Lundblade37286c02022-09-03 10:05:02 -07002536 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002537static uint8_t
2538QCBOR_Private_ExpMantissaDataType(const uint16_t uTagToProcess,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002539 const QCBORItem *pDecodedItem)
Laurence Lundblade37286c02022-09-03 10:05:02 -07002540{
2541 uint8_t uBase = uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ?
2542 QCBOR_TYPE_DECIMAL_FRACTION :
2543 QCBOR_TYPE_BIGFLOAT;
2544 if(pDecodedItem->uDataType != QCBOR_TYPE_INT64) {
2545 uBase = (uint8_t)(uBase + pDecodedItem->uDataType - QCBOR_TYPE_POSBIGNUM + 1);
2546 }
2547 return uBase;
2548}
2549#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002550
2551
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002552/**
2553 * @brief Decode tag content for select tags (decoding layer 1).
2554 *
2555 * @param[in] pMe The decode context.
2556 * @param[out] pDecodedItem The decoded item.
2557 *
2558 * @return Decoding error code.
2559 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002560 * CBOR tag numbers for the item were decoded in GetNext_TaggedItem(),
2561 * but the whole tag was not decoded. Here, the whole tags (tag number
2562 * and tag content) that are supported by QCBOR are decoded. This is a
2563 * quick pass through for items that are not tags.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002564 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002565static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002566QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2567 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002568{
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002569 QCBORError uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002570
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002571 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pDecodedItem);
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002572 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002573 goto Done;
2574 }
2575
Laurence Lundblade37286c02022-09-03 10:05:02 -07002576#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002577 /* When there are no tag numbers for the item, this exits first
2578 * thing and effectively does nothing.
2579 *
2580 * This loops over all the tag numbers accumulated for this item
2581 * trying to decode and interpret them. This stops at the end of
2582 * the list or at the first tag number that can't be interpreted by
2583 * this code. This is effectively a recursive processing of the
2584 * tags number list that handles nested tags.
2585 */
2586 while(1) {
2587 /* Don't bother to unmap tags via QCBORITem.uTags since this
2588 * code only works on tags less than QCBOR_LAST_UNMAPPED_TAG.
2589 */
2590 const uint16_t uTagToProcess = pDecodedItem->uTags[0];
Laurence Lundblade59289e52019-12-30 13:44:37 -08002591
Laurence Lundblade99615302020-11-29 11:19:47 -08002592 if(uTagToProcess == CBOR_TAG_INVALID16) {
2593 /* Hit the end of the tag list. A successful exit. */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002594 break;
2595
Laurence Lundblade99615302020-11-29 11:19:47 -08002596 } else if(uTagToProcess == CBOR_TAG_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002597 uReturn = QCBOR_Private_DecodeDateEpoch(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002598
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002599 } else if(uTagToProcess == CBOR_TAG_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002600 uReturn = QCBOR_Private_DecodeDaysEpoch(pDecodedItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07002601
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002602#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade99615302020-11-29 11:19:47 -08002603 } else if(uTagToProcess == CBOR_TAG_DECIMAL_FRACTION ||
2604 uTagToProcess == CBOR_TAG_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002605 uReturn = QCBORDecode_Private_ExpMantissa(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002606 /* --- Which is it, decimal fraction or a bigfloat? --- */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002607 pDecodedItem->uDataType = QCBOR_Private_ExpMantissaDataType(uTagToProcess, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07002608
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07002609#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002610#ifndef QCBOR_DISABLE_UNCOMMON_TAGS
Laurence Lundblade99615302020-11-29 11:19:47 -08002611 } else if(uTagToProcess == CBOR_TAG_MIME ||
2612 uTagToProcess == CBOR_TAG_BINARY_MIME) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002613 uReturn = QCBOR_Private_DecodeMIME(pDecodedItem);
Laurence Lundblade24bd7e12021-01-09 00:05:11 -08002614#endif /* QCBOR_DISABLE_UNCOMMON_TAGS */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002615
Laurence Lundblade99615302020-11-29 11:19:47 -08002616 } else {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002617 /* See if it is a passthrough byte/text string tag; process if so */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002618 uReturn = QCBOR_Private_ProcessTaggedString(pDecodedItem->uTags[0], pDecodedItem);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002619
Laurence Lundblade99615302020-11-29 11:19:47 -08002620 if(uReturn == QCBOR_ERR_UNSUPPORTED) {
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01002621 /* It wasn't a passthrough byte/text string tag so it is
Laurence Lundblade99615302020-11-29 11:19:47 -08002622 * an unknown tag. This is the exit from the loop on the
2623 * first unknown tag. It is a successful exit.
2624 */
2625 uReturn = QCBOR_SUCCESS;
2626 break;
2627 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002628 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002629
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002630 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade99615302020-11-29 11:19:47 -08002631 /* Error exit from the loop */
2632 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002633 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002634
2635 /* A tag was successfully processed, shift it out of the list of
2636 * tags returned. This is the loop increment.
2637 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002638 QCBOR_Private_ShiftTags(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002639 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002640#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002641
2642Done:
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002643 return uReturn;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002644}
2645
2646
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002647/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002648 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002649 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002650QCBORError
2651QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2652{
2653 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002654 uErr = QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002655 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002656 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2657 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
2658 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002659 return uErr;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002660}
2661
2662
2663/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002664 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08002665 */
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002666QCBORError
2667QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2668{
2669 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2670 const UsefulInputBuf Save = pMe->InBuf;
2671
2672 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
2673
2674 pMe->nesting = SaveNesting;
2675 pMe->InBuf = Save;
2676
2677 return uErr;
2678}
2679
2680
2681/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002682 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002683 */
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002684void
2685QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2686{
2687 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002688 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2689 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002690 return;
2691 }
2692
2693 pMe->uLastError = (uint8_t)QCBORDecode_PeekNext(pMe, pDecodedItem);
2694}
2695
2696
2697/*
2698 * Public function, see header qcbor/qcbor_decode.h file
2699 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002700void
2701QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002702{
2703 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002704 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2705 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002706 return;
2707 }
2708
2709 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem);
2710}
2711
2712
2713/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002714 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002715 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002716QCBORError
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002717QCBORDecode_GetNextWithTags(QCBORDecodeContext *pMe,
2718 QCBORItem *pDecodedItem,
2719 QCBORTagListOut *pTags)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002720{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002721#ifndef QCBOR_DISABLE_TAGS
2722
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002723 QCBORError uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002724
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002725 uReturn = QCBORDecode_GetNext(pMe, pDecodedItem);
2726 if(uReturn != QCBOR_SUCCESS) {
2727 return uReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002728 }
2729
2730 if(pTags != NULL) {
2731 pTags->uNumUsed = 0;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002732 /* Reverse the order because pTags is reverse of QCBORItem.uTags. */
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002733 for(int nTagIndex = QCBOR_MAX_TAGS_PER_ITEM-1; nTagIndex >=0; nTagIndex--) {
2734 if(pDecodedItem->uTags[nTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07002735 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002736 }
2737 if(pTags->uNumUsed >= pTags->uNumAllocated) {
2738 return QCBOR_ERR_TOO_MANY_TAGS;
2739 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002740 pTags->puTags[pTags->uNumUsed] = QCBORDecode_Private_UnMapTagNumber(pMe,pDecodedItem->uTags[nTagIndex]);
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002741 pTags->uNumUsed++;
2742 }
2743 }
2744
2745 return QCBOR_SUCCESS;
Laurence Lundblade37286c02022-09-03 10:05:02 -07002746
2747#else /* QCBOR_DISABLE_TAGS */
2748 (void)pMe;
2749 (void)pDecodedItem;
2750 (void)pTags;
2751 return QCBOR_ERR_TAGS_DISABLED;
2752#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002753}
2754
2755
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002756/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002757 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05302758 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002759bool
2760QCBORDecode_IsTagged(QCBORDecodeContext *pMe,
2761 const QCBORItem *pItem,
2762 uint64_t uTag)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002763{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002764#ifndef QCBOR_DISABLE_TAGS
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07002765 for(unsigned uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) {
2766 if(pItem->uTags[uTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002767 break;
2768 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002769 if(QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uTagIndex]) == uTag) {
Laurence Lundbladef71e1622020-08-06 18:52:13 -07002770 return true;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002771 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002772 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002773#else /* QCBOR_TAGS_DISABLED */
2774 (void)pMe;
2775 (void)pItem;
2776 (void)uTag;
2777#endif /* QCBOR_TAGS_DISABLED */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002778
Laurence Lundbladef71e1622020-08-06 18:52:13 -07002779 return false;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002780}
2781
2782
2783/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002784 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002785 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002786QCBORError
2787QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002788{
Laurence Lundblade87495732021-02-26 10:05:55 -07002789 if(puConsumed != NULL) {
2790 *puConsumed = pMe->InBuf.cursor;
2791 }
2792
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002793 QCBORError uReturn = pMe->uLastError;
Laurence Lundblade085d7952020-07-24 10:26:30 -07002794
2795 if(uReturn != QCBOR_SUCCESS) {
2796 goto Done;
2797 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002798
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002799 /* Error out if all the maps/arrays are not closed out */
2800 if(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002801 uReturn = QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002802 goto Done;
2803 }
2804
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002805 /* Error out if not all the bytes are consumed */
2806 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf))) {
Laurence Lundblade085d7952020-07-24 10:26:30 -07002807 uReturn = QCBOR_ERR_EXTRA_BYTES;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002808 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002809
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002810Done:
Laurence Lundblade87495732021-02-26 10:05:55 -07002811 return uReturn;
2812}
2813
2814
2815/*
2816 * Public function, see header qcbor/qcbor_decode.h file
2817 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002818QCBORError
2819QCBORDecode_Finish(QCBORDecodeContext *pMe)
Laurence Lundblade87495732021-02-26 10:05:55 -07002820{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002821#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002822 /* Call the destructor for the string allocator if there is one.
2823 * Always called, even if there are errors; always have to clean up.
2824 */
2825 StringAllocator_Destruct(&(pMe->StringAllocator));
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002826#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002827
Laurence Lundblade87495732021-02-26 10:05:55 -07002828 return QCBORDecode_PartialFinish(pMe, NULL);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002829}
2830
2831
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002832/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002833 * Public function, see header qcbor/qcbor_decode.h file
2834 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002835uint64_t
2836QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
2837 const QCBORItem *pItem,
2838 uint32_t uIndex)
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002839{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002840#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002841 if(pItem->uDataType == QCBOR_TYPE_NONE) {
2842 return CBOR_TAG_INVALID64;
2843 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002844 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2845 return CBOR_TAG_INVALID64;
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002846 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002847 return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->uTags[uIndex]);
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002848 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002849#else /* QCBOR_DISABLE_TAGS */
2850 (void)pMe;
2851 (void)pItem;
2852 (void)uIndex;
2853
2854 return CBOR_TAG_INVALID64;
2855#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002856}
2857
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002858
Laurence Lundblade9b334962020-08-27 10:55:53 -07002859/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002860 * Public function, see header qcbor/qcbor_decode.h file
2861 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002862uint64_t
2863QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe,
2864 uint32_t uIndex)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002865{
Laurence Lundblade37286c02022-09-03 10:05:02 -07002866#ifndef QCBOR_DISABLE_TAGS
2867
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002868 if(pMe->uLastError != QCBOR_SUCCESS) {
2869 return CBOR_TAG_INVALID64;
2870 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002871 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2872 return CBOR_TAG_INVALID64;
2873 } else {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002874 return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->uLastTags[uIndex]);
Laurence Lundblade9b334962020-08-27 10:55:53 -07002875 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002876#else /* QCBOR_DISABLE_TAGS */
2877 (void)pMe;
2878 (void)uIndex;
2879
2880 return CBOR_TAG_INVALID64;
2881#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07002882}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002883
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002884
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002885
2886
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002887#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladef6531662018-12-04 10:42:22 +09002888
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002889/* ===========================================================================
2890 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002891
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002892 This implements a simple sting allocator for indefinite-length
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002893 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
2894 implements the function type QCBORStringAllocate and allows easy
2895 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09002896
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002897 This particular allocator is built-in for convenience. The caller
2898 can implement their own. All of this following code will get
2899 dead-stripped if QCBORDecode_SetMemPool() is not called.
2900
2901 This is a very primitive memory allocator. It does not track
2902 individual allocations, only a high-water mark. A free or
2903 reallocation must be of the last chunk allocated.
2904
2905 The size of the pool and offset to free memory are packed into the
2906 first 8 bytes of the memory pool so we don't have to keep them in
2907 the decode context. Since the address of the pool may not be
2908 aligned, they have to be packed and unpacked as if they were
2909 serialized data of the wire or such.
2910
2911 The sizes packed in are uint32_t to be the same on all CPU types
2912 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08002913 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002914
2915
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002916static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08002917MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002918{
2919 // Use of UsefulInputBuf is overkill, but it is convenient.
2920 UsefulInputBuf UIB;
2921
Laurence Lundbladeee851742020-01-08 08:37:05 -08002922 // Just assume the size here. It was checked during SetUp so
2923 // the assumption is safe.
Laurence Lundblade93d89472020-10-03 22:30:50 -07002924 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem,QCBOR_DECODE_MIN_MEM_POOL_SIZE});
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002925 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
2926 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
2927 return UsefulInputBuf_GetError(&UIB);
2928}
2929
2930
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002931static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08002932MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002933{
2934 // Use of UsefulOutBuf is overkill, but convenient. The
2935 // length check performed here is useful.
2936 UsefulOutBuf UOB;
2937
2938 UsefulOutBuf_Init(&UOB, Pool);
2939 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
2940 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
2941 return UsefulOutBuf_GetError(&UOB);
2942}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002943
2944
2945/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002946 Internal function for an allocation, reallocation free and destuct.
2947
2948 Having only one function rather than one each per mode saves space in
2949 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002950
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002951 Code Reviewers: THIS FUNCTION DOES POINTER MATH
2952 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08002953static UsefulBuf
2954MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002955{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002956 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002957
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002958 uint32_t uPoolSize;
2959 uint32_t uFreeOffset;
2960
2961 if(uNewSize > UINT32_MAX) {
2962 // This allocator is only good up to 4GB. This check should
2963 // optimize out if sizeof(size_t) == sizeof(uint32_t)
2964 goto Done;
2965 }
2966 const uint32_t uNewSize32 = (uint32_t)uNewSize;
2967
2968 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
2969 goto Done;
2970 }
2971
2972 if(uNewSize) {
2973 if(pMem) {
2974 // REALLOCATION MODE
2975 // Calculate pointer to the end of the memory pool. It is
2976 // assumed that pPool + uPoolSize won't wrap around by
2977 // assuming the caller won't pass a pool buffer in that is
2978 // not in legitimate memory space.
2979 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
2980
2981 // Check that the pointer for reallocation is in the range of the
2982 // pool. This also makes sure that pointer math further down
2983 // doesn't wrap under or over.
2984 if(pMem >= pPool && pMem < pPoolEnd) {
2985 // Offset to start of chunk for reallocation. This won't
2986 // wrap under because of check that pMem >= pPool. Cast
2987 // is safe because the pool is always less than UINT32_MAX
2988 // because of check in QCBORDecode_SetMemPool().
2989 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
2990
2991 // Check to see if the allocation will fit. uPoolSize -
2992 // uMemOffset will not wrap under because of check that
2993 // pMem is in the range of the uPoolSize by check above.
2994 if(uNewSize <= uPoolSize - uMemOffset) {
2995 ReturnValue.ptr = pMem;
2996 ReturnValue.len = uNewSize;
2997
2998 // Addition won't wrap around over because uNewSize was
2999 // checked to be sure it is less than the pool size.
3000 uFreeOffset = uMemOffset + uNewSize32;
3001 }
3002 }
3003 } else {
3004 // ALLOCATION MODE
3005 // uPoolSize - uFreeOffset will not underflow because this
3006 // pool implementation makes sure uFreeOffset is always
3007 // smaller than uPoolSize through this check here and
3008 // reallocation case.
3009 if(uNewSize <= uPoolSize - uFreeOffset) {
3010 ReturnValue.len = uNewSize;
3011 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08003012 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003013 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003014 }
3015 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003016 if(pMem) {
3017 // FREE MODE
3018 // Cast is safe because of limit on pool size in
3019 // QCBORDecode_SetMemPool()
3020 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3021 } else {
3022 // DESTRUCT MODE
3023 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003024 }
3025 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003026
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003027 UsefulBuf Pool = {pPool, uPoolSize};
3028 MemPool_Pack(Pool, uFreeOffset);
3029
3030Done:
3031 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003032}
3033
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003034
Laurence Lundbladef6531662018-12-04 10:42:22 +09003035/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003036 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09003037 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003038QCBORError
3039QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
3040 UsefulBuf Pool,
3041 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003042{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003043 // The pool size and free mem offset are packed into the beginning
Dave Thaler93c01182022-08-06 15:08:35 -04003044 // of the pool memory. This compile time check makes sure the
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003045 // constant in the header is correct. This check should optimize
3046 // down to nothing.
Dave Thaler93c01182022-08-06 15:08:35 -04003047#ifdef _MSC_VER
3048#pragma warning(push)
3049#pragma warning(disable:4127) // conditional expression is constant
3050#endif
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003051 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003052 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003053 }
Dave Thaler93c01182022-08-06 15:08:35 -04003054#ifdef _MSC_VER
3055#pragma warning(pop)
3056#endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003057
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003058 // The pool size and free offset packed in to the beginning of pool
3059 // memory are only 32-bits. This check will optimize out on 32-bit
3060 // machines.
3061 if(Pool.len > UINT32_MAX) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003062 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003063 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003064
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003065 // This checks that the pool buffer given is big enough.
3066 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003067 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003068 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003069
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003070 QCBORDecode_SetUpAllocator(pMe, MemPool_Function, Pool.ptr, bAllStrings);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003071
Laurence Lundblade30816f22018-11-10 13:40:22 +07003072 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003073}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003074#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003075
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003076
3077
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003078static void
3079QCBORDecode_Private_CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07003080{
Laurence Lundblade37286c02022-09-03 10:05:02 -07003081#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade9b334962020-08-27 10:55:53 -07003082 memcpy(pMe->uLastTags, pItem->uTags, sizeof(pItem->uTags));
Laurence Lundblade37286c02022-09-03 10:05:02 -07003083#else
3084 (void)pMe;
3085 (void)pItem;
3086#endif
Laurence Lundblade9b334962020-08-27 10:55:53 -07003087}
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003088
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003089
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003090/**
3091 * @brief Consume an entire map or array including its contents.
3092 *
3093 * @param[in] pMe The decoder context.
3094 * @param[in] pItemToConsume The array/map whose contents are to be
3095 * consumed.
3096 * @param[out] puNextNestLevel The next nesting level after the item was
3097 * fully consumed.
3098 *
3099 * This may be called when @c pItemToConsume is not an array or
3100 * map. In that case, this is just a pass through for @c puNextNestLevel
3101 * since there is nothing to do.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003102 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003103static QCBORError
3104QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
3105 const QCBORItem *pItemToConsume,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003106 bool *pbBreak,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003107 uint8_t *puNextNestLevel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003108{
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003109 QCBORError uReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003110 QCBORItem Item;
Laurence Lundblade9b334962020-08-27 10:55:53 -07003111
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003112 /* If it is a map or array, this will tell if it is empty. */
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003113 const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel);
3114
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003115 if(QCBORItem_IsMapOrArray(*pItemToConsume) && !bIsEmpty) {
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003116 /* There is only real work to do for non-empty maps and arrays */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003117
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003118 /* This works for definite- and indefinite-length maps and
3119 * arrays by using the nesting level
Laurence Lundblade1341c592020-04-11 14:19:05 -07003120 */
3121 do {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003122 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pbBreak, &Item);
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003123 if(QCBORDecode_IsUnrecoverableError(uReturn) ||
3124 uReturn == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003125 goto Done;
3126 }
3127 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003128
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003129 *puNextNestLevel = Item.uNextNestLevel;
3130
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003131 uReturn = QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003132
Laurence Lundblade1341c592020-04-11 14:19:05 -07003133 } else {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003134 /* pItemToConsume is not a map or array. Just pass the nesting
Laurence Lundbladeaf5921e2022-07-15 09:06:30 -07003135 * level through. */
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07003136 *puNextNestLevel = pItemToConsume->uNextNestLevel;
3137
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003138 uReturn = QCBOR_SUCCESS;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003139 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003140
3141Done:
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003142 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003143}
3144
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003145
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003146/*
3147 * Public function, see header qcbor/qcbor_decode.h file
3148 */
3149void
3150QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003151{
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003152 QCBORDecode_VGetNext(pMe, pDecodedItem);
3153
3154 if(pMe->uLastError == QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003155 pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL,
Máté Tóth-Pálc6d59682021-05-26 18:55:30 +02003156 &pDecodedItem->uNextNestLevel);
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003157 }
3158}
3159
3160
Laurence Lundblade11654912024-05-09 11:49:24 -07003161/*
3162 * Public function, see header qcbor/qcbor_decode.h file
3163 */
3164uint32_t
3165QCBORDecode_Tell(QCBORDecodeContext *pMe)
3166{
3167 size_t uCursorOffset;
3168
3169 if(pMe->uLastError != QCBOR_SUCCESS) {
3170 return UINT32_MAX;
3171 }
3172
3173 uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
3174
3175 if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
3176 return UINT32_MAX;
3177 } else {
3178 /* Cast is safe because decoder input size is restricted. */
3179 return (uint32_t)uCursorOffset;
3180 }
3181}
3182
3183
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003184/**
3185 * @brief Rewind cursor to start as if map or array were just entered.
3186 *
3187 * @param[in] pMe The decoding context
3188 *
3189 * This affects the nesting tracking and the UsefulInputBuf.
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003190 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003191static void
3192QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003193{
3194 /* Reset nesting tracking to the deepest bounded level */
3195 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3196
3197 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3198
3199 /* Reposition traversal cursor to the start of the map/array */
3200 UsefulInputBuf_Seek(&(pMe->InBuf),
3201 DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
3202}
3203
3204
3205/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003206 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003207 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003208void
3209QCBORDecode_Rewind(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003210{
3211 if(pMe->nesting.pCurrentBounded != NULL) {
3212 /* In a bounded map, array or bstr-wrapped CBOR */
3213
3214 if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
3215 /* In bstr-wrapped CBOR. */
3216
3217 /* Reposition traversal cursor to start of wrapping byte string */
3218 UsefulInputBuf_Seek(&(pMe->InBuf),
3219 pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
3220 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3221
3222 } else {
3223 /* In a map or array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003224 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003225 }
3226
3227 } else {
3228 /* Not in anything bounded */
3229
3230 /* Reposition traversal cursor to the start of input CBOR */
3231 UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
3232
3233 /* Reset nesting tracking to beginning of input. */
3234 DecodeNesting_Init(&(pMe->nesting));
3235 }
3236
3237 pMe->uLastError = QCBOR_SUCCESS;
3238}
3239
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003240
Laurence Lundblade9b334962020-08-27 10:55:53 -07003241
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003242
3243
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003244typedef struct {
3245 void *pCBContext;
3246 QCBORItemCallback pfCallback;
3247} MapSearchCallBack;
3248
3249typedef struct {
3250 size_t uStartOffset;
3251 uint16_t uItemCount;
3252} MapSearchInfo;
3253
3254
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003255/**
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003256 * @brief Search a map for a set of items.
3257 *
3258 * @param[in] pMe The decode context to search.
3259 * @param[in,out] pItemArray The items to search for and the items found.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003260 * @param[out] pInfo Several bits of meta-info returned by search.
3261 * @param[in] pCallBack Callback object or @c NULL.
3262 * TODO: fix params
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003263 *
3264 * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map.
3265 *
3266 * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label)
3267 * were found for one of the labels being
3268 * search for. This duplicate detection is
3269 * only performed for items in pItemArray,
3270 * not every item in the map.
3271 *
3272 * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was
3273 * wrong for the matchd label.
3274 *
3275 * @retval Also errors returned by QCBORDecode_GetNext().
3276 *
3277 * On input, \c pItemArray contains a list of labels and data types of
3278 * items to be found.
3279 *
3280 * On output, the fully retrieved items are filled in with values and
3281 * such. The label was matched, so it never changes.
3282 *
3283 * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE.
3284 *
3285 * This also finds the ends of maps and arrays when they are exited.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003286 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003287static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003288QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
3289 QCBORItem *pItemArray,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003290 MapSearchInfo *pInfo,
3291 MapSearchCallBack *pCallBack)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003292{
Laurence Lundbladee6f15112020-07-23 18:44:16 -07003293 QCBORError uReturn;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003294 uint64_t uFoundItemBitMap = 0;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07003295
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003296 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003297 uReturn = pMe->uLastError;
3298 goto Done2;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003299 }
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003300
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003301 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) &&
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003302 pItemArray->uLabelType != QCBOR_TYPE_NONE) {
3303 /* QCBOR_TYPE_NONE as first item indicates just looking
3304 for the end of an array, so don't give error. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003305 uReturn = QCBOR_ERR_MAP_NOT_ENTERED;
3306 goto Done2;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003307 }
3308
Laurence Lundblade085d7952020-07-24 10:26:30 -07003309 if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) {
3310 // It is an empty bounded array or map
3311 if(pItemArray->uLabelType == QCBOR_TYPE_NONE) {
3312 // Just trying to find the end of the map or array
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003313 pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003314 uReturn = QCBOR_SUCCESS;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003315 } else {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003316 // Nothing is ever found in an empty array or map. All items
3317 // are marked as not found below.
Laurence Lundblade085d7952020-07-24 10:26:30 -07003318 uReturn = QCBOR_SUCCESS;
3319 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003320 goto Done2;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003321 }
3322
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003323 QCBORDecodeNesting SaveNesting;
Laurence Lundblade11654912024-05-09 11:49:24 -07003324 size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003325 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3326
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003327 /* Reposition to search from the start of the map / array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003328 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundblade1341c592020-04-11 14:19:05 -07003329
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003330 /*
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003331 Loop over all the items in the map or array. Each item
3332 could be a map or array, but label matching is only at
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003333 the main level. This handles definite- and indefinite-
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003334 length maps and arrays. The only reason this is ever
3335 called on arrays is to find their end position.
3336
3337 This will always run over all items in order to do
3338 duplicate detection.
3339
3340 This will exit with failure if it encounters an
3341 unrecoverable error, but continue on for recoverable
3342 errors.
3343
3344 If a recoverable error occurs on a matched item, then
3345 that error code is returned.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003346 */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07003347 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003348 if(pInfo) {
3349 pInfo->uItemCount = 0;
3350 }
Máté Tóth-Pál2f2aa5f2021-05-17 21:35:09 +02003351 uint8_t uNextNestLevel;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003352 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003353 /* Remember offset of the item because sometimes it has to be returned */
Laurence Lundblade1341c592020-04-11 14:19:05 -07003354 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003355
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003356 /* Get the item */
3357 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003358 QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003359 if(QCBORDecode_IsUnrecoverableError(uResult)) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003360 /* The map/array can't be decoded when unrecoverable errors occur */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003361 uReturn = uResult;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003362 goto Done;
3363 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003364 if(uResult == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003365 /* Unexpected end of map or array. */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003366 uReturn = uResult;
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003367 goto Done;
3368 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003369
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003370 /* See if item has one of the labels that are of interest */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003371 bool bMatched = false;
3372 for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003373 if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003374 /* A label match has been found */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003375 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
3376 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003377 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003378 }
Laurence Lundblade63926052021-03-29 16:05:51 -07003379 if(uResult != QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003380 /* The label matches, but the data item is in error.
3381 * It is OK to have recoverable errors on items that are not
3382 * matched. */
Laurence Lundblade63926052021-03-29 16:05:51 -07003383 uReturn = uResult;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003384 goto Done;
3385 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003386 if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) {
Laurence Lundblade63926052021-03-29 16:05:51 -07003387 /* The data item is not of the type(s) requested */
3388 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003389 goto Done;
3390 }
3391
Laurence Lundblade1341c592020-04-11 14:19:05 -07003392 /* Successful match. Return the item. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003393 pItemArray[nIndex] = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003394 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003395 if(pInfo) {
3396 pInfo->uStartOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003397 }
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003398 bMatched = true;
3399 }
3400 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003401
3402
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003403 if(!bMatched && pCallBack != NULL) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003404 /*
3405 Call the callback on unmatched labels.
3406 (It is tempting to do duplicate detection here, but that would
3407 require dynamic memory allocation because the number of labels
3408 that might be encountered is unbounded.)
3409 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003410 uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item);
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003411 if(uReturn != QCBOR_SUCCESS) {
3412 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003413 }
3414 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003415
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003416 /*
3417 Consume the item whether matched or not. This
3418 does the work of traversing maps and array and
3419 everything in them. In this loop only the
3420 items at the current nesting level are examined
3421 to match the labels.
3422 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003423 uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel);
Laurence Lundbladec7114722020-08-13 05:11:40 -07003424 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003425 goto Done;
3426 }
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003427
3428 if(pInfo) {
3429 pInfo->uItemCount++;
3430 }
3431
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003432 } while (uNextNestLevel >= uMapNestLevel);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003433
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003434 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003435
3436 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003437
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003438 // Check here makes sure that this won't accidentally be
3439 // QCBOR_MAP_OFFSET_CACHE_INVALID which is larger than
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003440 // QCBOR_MAX_DECODE_INPUT_SIZE.
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -08003441 // Cast to uint32_t to possibly address cases where SIZE_MAX < UINT32_MAX
3442 if((uint32_t)uEndOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003443 uReturn = QCBOR_ERR_INPUT_TOO_LARGE;
3444 goto Done;
3445 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003446 /* Cast OK because encoded CBOR is limited to UINT32_MAX */
3447 pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003448
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003449 Done:
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003450 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade11654912024-05-09 11:49:24 -07003451 UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos);
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003452
3453 Done2:
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003454 /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */
Laurence Lundbladec7114722020-08-13 05:11:40 -07003455 for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003456 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003457 pItemArray[i].uDataType = QCBOR_TYPE_NONE;
3458 pItemArray[i].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003459 }
3460 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003461
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003462 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003463}
3464
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003465
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003466/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003467 * Public function, see header qcbor/qcbor_decode.h file
3468 */
3469void
3470QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
3471 int64_t nLabel,
3472 uint8_t uQcborType,
3473 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003474{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003475 if(pMe->uLastError != QCBOR_SUCCESS) {
3476 return;
3477 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003478
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003479 QCBORItem OneItemSeach[2];
3480 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3481 OneItemSeach[0].label.int64 = nLabel;
3482 OneItemSeach[0].uDataType = uQcborType;
3483 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003484
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003485 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003486
3487 *pItem = OneItemSeach[0];
3488
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003489 if(uReturn != QCBOR_SUCCESS) {
3490 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003491 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003492 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003493 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003494 }
3495
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003496 Done:
3497 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003498}
3499
3500
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003501/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003502 * Public function, see header qcbor/qcbor_decode.h file
3503 */
3504void
3505QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
3506 const char *szLabel,
3507 uint8_t uQcborType,
3508 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003509{
Laurence Lundbladeda095972020-06-06 18:35:33 -07003510 if(pMe->uLastError != QCBOR_SUCCESS) {
3511 return;
3512 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003513
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003514 QCBORItem OneItemSeach[2];
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003515 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3516 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3517 OneItemSeach[0].uDataType = uQcborType;
3518 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003519
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003520 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, NULL, NULL);
3521
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003522 if(uReturn != QCBOR_SUCCESS) {
3523 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003524 }
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003525 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003526 uReturn = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003527 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003528 }
3529
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003530 *pItem = OneItemSeach[0];
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003531
3532Done:
3533 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003534}
3535
3536
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003537
3538/**
3539 * @brief Semi-private. Get pointer, length and item for an array or map.
3540 *
3541 * @param[in] pMe The decode context.
3542 * @param[in] uType CBOR major type, either array/map.
3543 * @param[out] pItem The item for the array/map.
3544 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3545 *
3546 * The next item to be decoded must be a map or array as specified by \c uType.
3547 *
3548 * \c pItem will be filled in with the label and tags of the array or map
3549 * in addition to \c pEncodedCBOR giving the pointer and length of the
3550 * encoded CBOR.
3551 *
3552 * When this is complete, the traversal cursor is at the end of the array or
3553 * map that was retrieved.
3554 */
3555void
3556QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe,
3557 const uint8_t uType,
3558 QCBORItem *pItem,
3559 UsefulBufC *pEncodedCBOR)
3560{
3561 QCBORError uErr;
3562 uint8_t uNestLevel;
3563 size_t uStartingCursor;
3564 size_t uStartOfReturned;
3565 size_t uEndOfReturned;
3566 size_t uTempSaveCursor;
3567 bool bInMap;
3568 QCBORItem LabelItem;
3569 bool EndedByBreak;
3570
3571 uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3572 bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting));
3573
3574 /* Could call GetNext here, but don't need to because this
3575 * is only interested in arrays and maps. */
3576 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem);
3577 if(uErr != QCBOR_SUCCESS) {
3578 pMe->uLastError = (uint8_t)uErr;
3579 return;
3580 }
3581
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003582 uint8_t uItemDataType = pItem->uDataType;
3583 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
3584 uItemDataType = QCBOR_TYPE_ARRAY;
3585 }
3586
3587 if(uItemDataType != uType) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003588 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
3589 return;
3590 }
3591
3592 if(bInMap) {
3593 /* If the item is in a map, the start of the array/map
3594 * itself, not the label, must be found. Do this by
3595 * rewinding to the starting position and fetching
3596 * just the label data item. QCBORDecode_Private_GetNextTagNumber()
3597 * doesn't do any of the array/map item counting or nesting
3598 * level tracking. Used here it will just fetech the label
3599 * data item.
3600 *
3601 * Have to save the cursor and put it back to the position
3602 * after the full item once the label as been fetched by
3603 * itself.
3604 */
3605 uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3606 UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor);
3607
3608 /* Item has been fetched once so safe to ignore error */
3609 (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem);
3610
3611 uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3612 UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor);
3613 } else {
3614 uStartOfReturned = uStartingCursor;
3615 }
3616
3617 /* Consume the entire array/map to find the end */
3618 uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel);
3619 if(uErr != QCBOR_SUCCESS) {
3620 pMe->uLastError = (uint8_t)uErr;
3621 goto Done;
3622 }
3623
3624 /* Fill in returned values */
3625 uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3626 if(EndedByBreak) {
3627 /* When ascending nesting levels, a break for the level above
3628 * was consumed. That break is not a part of what is consumed here. */
3629 uEndOfReturned--;
3630 }
3631 pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned);
3632 pEncodedCBOR->len = uEndOfReturned - uStartOfReturned;
3633
3634Done:
3635 return;
3636}
3637
3638
3639/**
3640 * @brief Semi-private. Get pointer, length and item count of an array or map.
3641 *
3642 * @param[in] pMe The decode context.
3643 * @param[in] pTarget The label and type of the array or map to retrieve.
3644 * @param[out] pItem The item for the array/map.
3645 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3646 *
3647 * The next item to be decoded must be a map or array as specified by \c uType.
3648 *
3649 * When this is complete, the traversal cursor is unchanged.
3650 */void
3651QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe,
3652 QCBORItem *pTarget,
3653 QCBORItem *pItem,
3654 UsefulBufC *pEncodedCBOR)
3655{
3656 MapSearchInfo Info;
3657 QCBORDecodeNesting SaveNesting;
3658 size_t uSaveCursor;
3659
3660 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL);
3661 if(pMe->uLastError != QCBOR_SUCCESS) {
3662 return;
3663 }
3664
3665 /* Save the whole position of things so they can be restored.
3666 * so the cursor position is unchanged by this operation, like
3667 * all the other GetXxxxInMap() operations. */
3668 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3669 uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3670
3671 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3672 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
3673 QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR);
3674
3675 UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor);
3676 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
3677}
3678
3679
3680
3681
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003682/**
3683 * @brief Is a QCBOR_TYPE in the type list?
3684 *
3685 * @param[in] uDataType Type to check for.
3686 * @param[in] puTypeList List to check.
3687 *
3688 * @retval QCBOR_SUCCESS If in the list.
3689 * @retval QCBOR_ERR_UNEXPECTED_TYPE Not in the list.
3690 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07003691static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003692QCBOR_Private_CheckTypeList(const int uDataType,
3693 const uint8_t puTypeList[QCBOR_TAGSPEC_NUM_TYPES])
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003694{
3695 for(size_t i = 0; i < QCBOR_TAGSPEC_NUM_TYPES; i++) {
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003696 if(uDataType == puTypeList[i]) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003697 return QCBOR_SUCCESS;
3698 }
3699 }
3700 return QCBOR_ERR_UNEXPECTED_TYPE;
3701}
3702
Laurence Lundblade67257dc2020-07-27 03:33:37 -07003703
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003704/**
Laurence Lundblade37286c02022-09-03 10:05:02 -07003705 * Match a tag/type specification against the type of the item.
3706 *
3707 * @param[in] TagSpec Specification for matching tags.
3708 * @param[in] pItem The item to check.
3709 *
3710 * @retval QCBOR_SUCCESS \c uDataType is allowed by @c TagSpec
3711 * @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec
3712 *
3713 * This checks the item data type of untagged items as well as of
3714 * tagged items against a specification to see if decoding should
3715 * proceed.
3716 *
3717 * This relies on the automatic tag decoding done by QCBOR that turns
3718 * tag numbers into particular QCBOR_TYPEs so there is no actual
3719 * comparsion of tag numbers, just of QCBOR_TYPEs.
3720 *
3721 * This checks the data item type as possibly representing the tag
3722 * number or as the tag content type.
3723 *
3724 * If QCBOR_DISABLE_TAGS is #defined, this primarily checks the item
3725 * data type against the allowed tag content types. It will also error out
3726 * if the caller tries to require a tag because there is no way that can
3727 * ever be fulfilled.
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003728 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07003729static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003730QCBOR_Private_CheckTagRequirement(const QCBOR_Private_TagSpec TagSpec,
3731 const QCBORItem *pItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07003732{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003733 const int nItemType = pItem->uDataType; /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade37286c02022-09-03 10:05:02 -07003734 const int nTagReq = TagSpec.uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
3735
3736#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08003737 /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003738 if(!(TagSpec.uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS) &&
3739 pItem->uTags[0] != CBOR_TAG_INVALID16) {
3740 /* There are tags that QCBOR couldn't process on this item and
Laurence Lundblade37286c02022-09-03 10:05:02 -07003741 * the caller has told us there should not be.
3742 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003743 return QCBOR_ERR_UNEXPECTED_TYPE;
3744 }
3745
Laurence Lundblade9b334962020-08-27 10:55:53 -07003746 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
Laurence Lundblade37286c02022-09-03 10:05:02 -07003747 /* Must match the tag number and only the tag */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003748 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003749 }
3750
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003751 QCBORError uReturn = QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003752 if(uReturn == QCBOR_SUCCESS) {
3753 return QCBOR_SUCCESS;
3754 }
3755
3756 if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
3757 /* Must match the content type and only the content type.
Laurence Lundblade37286c02022-09-03 10:05:02 -07003758 * There was no match just above so it is a fail. */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003759 return QCBOR_ERR_UNEXPECTED_TYPE;
3760 }
3761
Laurence Lundblade37286c02022-09-03 10:05:02 -07003762 /* QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG: If here it can match either the tag or the content
3763 * and it hasn't matched the content, so the end
3764 * result is whether it matches the tag. This is
3765 * the tag optional case that the CBOR standard discourages.
3766 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07003767
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003768 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uTaggedTypes);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003769
Laurence Lundblade37286c02022-09-03 10:05:02 -07003770#else /* QCBOR_DISABLE_TAGS */
3771 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
3772 return QCBOR_ERR_UNEXPECTED_TYPE;
3773 }
3774
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07003775 return QCBOR_Private_CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
Laurence Lundblade37286c02022-09-03 10:05:02 -07003776
3777#endif /* QCBOR_DISABLE_TAGS */
3778}
Laurence Lundblade9b334962020-08-27 10:55:53 -07003779
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003780
3781/**
3782 * @brief Get an item by label to match a tag specification.
3783 *
3784 * @param[in] pMe The decode context.
3785 * @param[in] nLabel The label to search map for.
3786 * @param[in] TagSpec The tag number specification to match.
3787 * @param[out] pItem The item found.
3788 *
3789 * This finds the item with the given label in currently open
3790 * map. Then checks that its tag number and types matches the tag
3791 * specification. If not, an error is set in the decode context.
3792 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003793static void
3794QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
3795 const int64_t nLabel,
3796 const QCBOR_Private_TagSpec TagSpec,
3797 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003798{
3799 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
3800 if(pMe->uLastError != QCBOR_SUCCESS) {
3801 return;
3802 }
3803
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003804 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003805}
3806
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07003807
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003808/**
3809 * @brief Get an item by label to match a tag specification.
3810 *
3811 * @param[in] pMe The decode context.
3812 * @param[in] szLabel The label to search map for.
3813 * @param[in] TagSpec The tag number specification to match.
3814 * @param[out] pItem The item found.
3815 *
3816 * This finds the item with the given label in currently open
3817 * map. Then checks that its tag number and types matches the tag
3818 * specification. If not, an error is set in the decode context.
3819 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003820static void
3821QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
3822 const char *szLabel,
3823 const QCBOR_Private_TagSpec TagSpec,
3824 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003825{
3826 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
3827 if(pMe->uLastError != QCBOR_SUCCESS) {
3828 return;
3829 }
3830
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003831 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003832}
3833
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003834
3835/**
3836 * @brief Semi-private to get an string by label to match a tag specification.
3837 *
3838 * @param[in] pMe The decode context.
3839 * @param[in] nLabel The label to search map for.
3840 * @param[in] TagSpec The tag number specification to match.
3841 * @param[out] pString The string found.
3842 *
3843 * This finds the string with the given label in currently open
3844 * map. Then checks that its tag number and types matches the tag
3845 * specification. If not, an error is set in the decode context.
3846 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003847void
3848QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
3849 const int64_t nLabel,
3850 const QCBOR_Private_TagSpec TagSpec,
3851 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003852{
3853 QCBORItem Item;
3854 QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
3855 if(pMe->uLastError == QCBOR_SUCCESS) {
3856 *pString = Item.val.string;
3857 }
3858}
3859
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003860
3861/**
3862 * @brief Semi-private to get an string by label to match a tag specification.
3863 *
3864 * @param[in] pMe The decode context.
3865 * @param[in] szLabel The label to search map for.
3866 * @param[in] TagSpec The tag number specification to match.
3867 * @param[out] pString The string found.
3868 *
3869 * This finds the string with the given label in currently open
3870 * map. Then checks that its tag number and types matches the tag
3871 * specification. If not, an error is set in the decode context.
3872 */void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003873QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
3874 const char * szLabel,
3875 const QCBOR_Private_TagSpec TagSpec,
3876 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003877{
3878 QCBORItem Item;
3879 QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
3880 if(pMe->uLastError == QCBOR_SUCCESS) {
3881 *pString = Item.val.string;
3882 }
3883}
Laurence Lundblade1341c592020-04-11 14:19:05 -07003884
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003885
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003886/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003887 * Public function, see header qcbor/qcbor_decode.h file
3888 */
3889void
3890QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003891{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003892 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL);
Laurence Lundblade5f53f832020-09-03 12:00:14 -07003893 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003894}
3895
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003896/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003897 * Public function, see header qcbor/qcbor_decode.h file
3898 */
3899void
3900QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe,
3901 QCBORItem *pItemList,
3902 void *pCallbackCtx,
3903 QCBORItemCallback pfCB)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003904{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003905 MapSearchCallBack CallBack;
3906 CallBack.pCBContext = pCallbackCtx;
3907 CallBack.pfCallback = pfCB;
3908
3909 QCBORError uErr = QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack);
3910
Laurence Lundblade5f53f832020-09-03 12:00:14 -07003911 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003912}
3913
3914
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08003915/**
3916 * @brief Search for a map/array by label and enter it
3917 *
3918 * @param[in] pMe The decode context.
3919 * @param[in] pSearch The map/array to search for.
3920 *
3921 * @c pSearch is expected to contain one item of type map or array
3922 * with the label specified. The current bounded map will be searched for
3923 * this and if found will be entered.
3924 *
3925 * If the label is not found, or the item found is not a map or array,
3926 * the error state is set.
3927 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003928static void
3929QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07003930{
Laurence Lundblade323f8a92020-09-06 19:43:09 -07003931 // The first item in pSearch is the one that is to be
3932 // entered. It should be the only one filled in. Any other
3933 // will be ignored unless it causes an error.
Laurence Lundblade34691b92020-05-18 22:25:25 -07003934 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07003935 return;
3936 }
3937
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003938 MapSearchInfo Info;
3939 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pSearch, &Info, NULL);
Laurence Lundblade34691b92020-05-18 22:25:25 -07003940 if(pMe->uLastError != QCBOR_SUCCESS) {
3941 return;
3942 }
3943
Laurence Lundblade9b334962020-08-27 10:55:53 -07003944 if(pSearch->uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003945 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade9b334962020-08-27 10:55:53 -07003946 return;
3947 }
3948
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003949
3950 /* The map or array was found. Now enter it.
3951 *
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08003952 * QCBORDecode_EnterBoundedMapOrArray() used here, requires the
3953 * next item for the pre-order traversal cursor to be the map/array
3954 * found by MapSearch(). The next few lines of code force the
3955 * cursor to that.
3956 *
3957 * There is no need to retain the old cursor because
3958 * QCBORDecode_EnterBoundedMapOrArray() will set it to the
3959 * beginning of the map/array being entered.
3960 *
3961 * The cursor is forced by: 1) setting the input buffer position to
3962 * the item offset found by MapSearch(), 2) setting the map/array
3963 * counter to the total in the map/array, 3) setting the nesting
3964 * level. Setting the map/array counter to the total is not
3965 * strictly correct, but this is OK because this cursor only needs
3966 * to be used to get one item and MapSearch() has already found it
3967 * confirming it exists.
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003968 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003969 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07003970
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08003971 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3972
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07003973 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003974
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003975 QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003976}
3977
3978
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003979/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003980 * Public function, see header qcbor/qcbor_decode.h file
3981 */
3982void
3983QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003984{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003985 QCBORItem OneItemSeach[2];
3986 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3987 OneItemSeach[0].label.int64 = nLabel;
3988 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
3989 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003990
Laurence Lundblade9b334962020-08-27 10:55:53 -07003991 /* The map to enter was found, now finish off entering it. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003992 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003993}
3994
3995
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003996/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003997 * Public function, see header qcbor/qcbor_decode.h file
3998 */
3999void
4000QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004001{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004002 QCBORItem OneItemSeach[2];
4003 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4004 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4005 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4006 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004007
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004008 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004009}
4010
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004011/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004012 * Public function, see header qcbor/qcbor_decode.h file
4013 */
4014void
4015QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07004016{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004017 QCBORItem OneItemSeach[2];
4018 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4019 OneItemSeach[0].label.int64 = nLabel;
4020 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4021 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004022
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004023 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07004024}
4025
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004026/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004027 * Public function, see header qcbor/qcbor_decode.h file
4028 */
4029void
4030QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundblade34691b92020-05-18 22:25:25 -07004031{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004032 QCBORItem OneItemSeach[2];
4033 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4034 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4035 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4036 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004037
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004038 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade1341c592020-04-11 14:19:05 -07004039}
4040
4041
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004042/**
4043 * @brief Semi-private to do the the work for EnterMap() and EnterArray().
4044 *
4045 * @param[in] pMe The decode context
4046 * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY.
4047 * @param[out] pItem The data item for the map or array entered.
4048 *
4049 * The next item in the traversal must be a map or array. This
4050 * consumes that item and does the book keeping to enter the map or
4051 * array.
4052 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004053void
4054QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe,
4055 const uint8_t uType,
4056 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004057{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004058 QCBORError uErr;
4059
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004060 /* Must only be called on maps and arrays. */
Laurence Lundblade34691b92020-05-18 22:25:25 -07004061 if(pMe->uLastError != QCBOR_SUCCESS) {
4062 // Already in error state; do nothing.
4063 return;
4064 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07004065
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004066 /* Get the data item that is the map or array being entered. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004067 QCBORItem Item;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004068 uErr = QCBORDecode_GetNext(pMe, &Item);
4069 if(uErr != QCBOR_SUCCESS) {
4070 goto Done;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07004071 }
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004072
4073 uint8_t uItemDataType = Item.uDataType;
4074 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) {
4075 uItemDataType = QCBOR_TYPE_ARRAY;
4076 }
4077 if(uItemDataType != uType) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004078 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
4079 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004080 }
4081
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004082 QCBORDecode_Private_CopyTags(pMe, &Item);
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004083
4084
Laurence Lundbladef0499502020-08-01 11:55:57 -07004085 const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
Laurence Lundblade085d7952020-07-24 10:26:30 -07004086 if(bIsEmpty) {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004087 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
4088 // Undo decrement done by QCBORDecode_GetNext() so the the
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004089 // the decrement when exiting the map/array works correctly
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004090 pMe->nesting.pCurrent->u.ma.uCountCursor++;
4091 }
Laurence Lundblade93d89472020-10-03 22:30:50 -07004092 // Special case to increment nesting level for zero-length maps
4093 // and arrays entered in bounded mode.
Laurence Lundbladee6f15112020-07-23 18:44:16 -07004094 DecodeNesting_Descend(&(pMe->nesting), uType);
4095 }
4096
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004097 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004098
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004099 uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty,
4100 UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004101
Laurence Lundblade6545d1b2020-10-14 11:13:13 -07004102 if(pItem != NULL) {
4103 *pItem = Item;
4104 }
4105
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004106Done:
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004107 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004108}
4109
Laurence Lundblade02625d42020-06-25 14:41:41 -07004110
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004111/**
4112 * @brief Exit a bounded map, array or bstr (semi-private).
4113 *
4114 * @param[in] pMe Decode context.
4115 * @param[in] uEndOffset The input buffer offset of the end of item exited.
4116 *
4117 * @returns QCBOR_SUCCESS or an error code.
4118 *
4119 * This is the common work for exiting a level that is a bounded map,
4120 * array or bstr wrapped CBOR.
4121 *
4122 * One chunk of work is to set up the pre-order traversal so it is at
4123 * the item just after the bounded map, array or bstr that is being
4124 * exited. This is somewhat complex.
4125 *
4126 * The other work is to level-up the bounded mode to next higest
4127 * bounded mode or the top level if there isn't one.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004128 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004129static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004130QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
4131 const uint32_t uEndOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004132{
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004133 QCBORError uErr;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004134
Laurence Lundblade02625d42020-06-25 14:41:41 -07004135 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004136 * First the pre-order-traversal byte offset is positioned to the
4137 * item just after the bounded mode item that was just consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004138 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004139 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
4140
Laurence Lundblade02625d42020-06-25 14:41:41 -07004141 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004142 * Next, set the current nesting level to one above the bounded
4143 * level that was just exited.
4144 *
4145 * DecodeNesting_CheckBoundedType() is always called before this
4146 * and makes sure pCurrentBounded is valid.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004147 */
4148 DecodeNesting_LevelUpCurrent(&(pMe->nesting));
4149
4150 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004151 * This does the complex work of leveling up the pre-order
4152 * traversal when the end of a map or array or another bounded
4153 * level is reached. It may do nothing, or ascend all the way to
4154 * the top level.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004155 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004156 uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004157 if(uErr != QCBOR_SUCCESS) {
4158 goto Done;
4159 }
4160
Laurence Lundblade02625d42020-06-25 14:41:41 -07004161 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004162 * This makes the next highest bounded level the current bounded
4163 * level. If there is no next highest level, then no bounded mode
4164 * is in effect.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004165 */
4166 DecodeNesting_LevelUpBounded(&(pMe->nesting));
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004167
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004168 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004169
4170Done:
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004171 return uErr;
4172}
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004173
Laurence Lundblade02625d42020-06-25 14:41:41 -07004174
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004175/**
4176 * @brief Get started exiting a map or array (semi-private)
4177 *
4178 * @param[in] pMe The decode context
4179 * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP
4180 *
4181 * This does some work for map and array exiting (but not
4182 * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel()
4183 * is called to do the rest.
4184 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004185void
4186QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe,
4187 const uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004188{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004189 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07004190 /* Already in error state; do nothing. */
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004191 return;
4192 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004193
Laurence Lundblade02625d42020-06-25 14:41:41 -07004194 QCBORError uErr;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004195
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004196 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004197 uErr = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004198 goto Done;
4199 }
4200
Laurence Lundblade02625d42020-06-25 14:41:41 -07004201 /*
4202 Have to set the offset to the end of the map/array
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004203 that is being exited. If there is no cached value,
Laurence Lundblade02625d42020-06-25 14:41:41 -07004204 from previous map search, then do a dummy search.
4205 */
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004206 if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004207 QCBORItem Dummy;
4208 Dummy.uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004209 uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL);
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004210 if(uErr != QCBOR_SUCCESS) {
4211 goto Done;
4212 }
4213 }
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004214
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004215 uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004216
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004217Done:
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004218 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004219}
4220
4221
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004222/**
4223 * @brief The main work of entering some byte-string wrapped CBOR.
4224 *
4225 * @param[in] pMe The decode context.
4226 * @param[in] pItem The byte string item.
4227 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX
4228 * @param[out] pBstr Pointer and length of byte string entered.
4229 *
4230 * This is called once the byte string item has been decoded to do all
4231 * the book keeping work for descending a nesting level into the
4232 * nested CBOR.
4233 *
4234 * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement.
4235 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004236static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004237QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe,
4238 const QCBORItem *pItem,
4239 const uint8_t uTagRequirement,
4240 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004241{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004242 if(pBstr) {
4243 *pBstr = NULLUsefulBufC;
4244 }
4245
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004246 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004247 /* Already in error state; do nothing. */
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004248 return pMe->uLastError;
4249 }
4250
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004251 QCBORError uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004252
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004253 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004254 {
4255 uTagRequirement,
4256 {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE},
4257 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4258 };
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004259
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004260 uError = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004261 if(uError != QCBOR_SUCCESS) {
4262 goto Done;
4263 }
4264
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004265 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004266 /* Reverse the decrement done by GetNext() for the bstr so the
4267 * increment in QCBORDecode_NestLevelAscender() called by
4268 * ExitBoundedLevel() will work right.
4269 */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004270 DecodeNesting_ReverseDecrement(&(pMe->nesting));
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07004271 }
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004272
4273 if(pBstr) {
4274 *pBstr = pItem->val.string;
4275 }
4276
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004277 /* This saves the current length of the UsefulInputBuf and then
4278 * narrows the UsefulInputBuf to start and length of the wrapped
4279 * CBOR that is being entered.
4280 *
4281 * Most of these calls are simple inline accessors so this doesn't
4282 * amount to much code.
4283 */
4284
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004285 const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004286 /* This check makes the cast of uPreviousLength to uint32_t below safe. */
4287 if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004288 uError = QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladef76a2622020-08-06 19:51:03 -07004289 goto Done;
4290 }
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004291
4292 const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
4293 pItem->val.string.ptr);
4294 /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
4295 if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
4296 /* This should never happen because pItem->val.string.ptr should
4297 * always be valid since it was just returned.
4298 */
4299 uError = QCBOR_ERR_INPUT_TOO_LARGE;
4300 goto Done;
4301 }
4302
4303 const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
4304
4305 UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004306 UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004307
Laurence Lundblade02625d42020-06-25 14:41:41 -07004308 uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004309 (uint32_t)uPreviousLength,
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004310 (uint32_t)uStartOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004311Done:
4312 return uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004313}
4314
4315
Laurence Lundblade02625d42020-06-25 14:41:41 -07004316/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004317 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004318 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004319void
4320QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe,
4321 const uint8_t uTagRequirement,
4322 UsefulBufC *pBstr)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004323{
4324 if(pMe->uLastError != QCBOR_SUCCESS) {
4325 // Already in error state; do nothing.
4326 return;
4327 }
4328
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004329 /* Get the data item that is the byte string being entered */
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004330 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004331 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4332 if(pMe->uLastError != QCBOR_SUCCESS) {
4333 return;
4334 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004335
Laurence Lundblade31fddb72024-05-13 13:03:35 -07004336 if(Item.uDataAlloc) {
4337 pMe->uLastError = QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
4338 return;
4339 }
4340
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004341 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4342 &Item,
4343 uTagRequirement,
4344 pBstr);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004345}
4346
4347
Laurence Lundblade02625d42020-06-25 14:41:41 -07004348/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004349 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004350 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004351void
4352QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe,
4353 const int64_t nLabel,
4354 const uint8_t uTagRequirement,
4355 UsefulBufC *pBstr)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004356{
4357 QCBORItem Item;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004358 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004359
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004360 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4361 &Item,
4362 uTagRequirement,
4363 pBstr);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004364}
4365
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004366
Laurence Lundblade02625d42020-06-25 14:41:41 -07004367/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004368 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004369 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004370void
4371QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe,
4372 const char *szLabel,
4373 const uint8_t uTagRequirement,
4374 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004375{
4376 QCBORItem Item;
4377 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4378
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004379 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4380 &Item,
4381 uTagRequirement,
4382 pBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004383}
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004384
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004385
Laurence Lundblade02625d42020-06-25 14:41:41 -07004386/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004387 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004388 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004389void
4390QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004391{
Laurence Lundblade02625d42020-06-25 14:41:41 -07004392 if(pMe->uLastError != QCBOR_SUCCESS) {
4393 // Already in error state; do nothing.
4394 return;
4395 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004396
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004397 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004398 pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade02625d42020-06-25 14:41:41 -07004399 return;
4400 }
4401
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004402 const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
4403
Laurence Lundblade02625d42020-06-25 14:41:41 -07004404 /*
4405 Reset the length of the UsefulInputBuf to what it was before
4406 the bstr wrapped CBOR was entered.
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004407 */
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004408 UsefulInputBuf_SetBufferLength(&(pMe->InBuf),
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004409 DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004410
4411
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004412 QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004413 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004414}
4415
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004416
Laurence Lundbladee6430642020-03-14 21:15:44 -07004417
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004418/**
4419 * @brief Process simple type true and false, a boolean
4420 *
4421 * @param[in] pMe The decode context.
4422 * @param[in] pItem The item with either true or false.
4423 * @param[out] pBool The boolean value output.
4424 *
4425 * Sets the internal error if the item isn't a true or a false. Also
4426 * records any tag numbers as the tag numbers of the last item.
4427 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004428static void
4429QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe,
4430 const QCBORItem *pItem,
4431 bool *pBool)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004432{
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004433 if(pMe->uLastError != QCBOR_SUCCESS) {
4434 /* Already in error state, do nothing */
4435 return;
4436 }
4437
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004438 switch(pItem->uDataType) {
4439 case QCBOR_TYPE_TRUE:
4440 *pBool = true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004441 break;
4442
4443 case QCBOR_TYPE_FALSE:
4444 *pBool = false;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004445 break;
4446
4447 default:
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004448 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004449 break;
4450 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004451 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004452}
Laurence Lundbladee6430642020-03-14 21:15:44 -07004453
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004454
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004455/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004456 * Public function, see header qcbor/qcbor_decode.h file
4457 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004458void
4459QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004460{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004461 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004462 /* Already in error state, do nothing */
Laurence Lundbladee6430642020-03-14 21:15:44 -07004463 return;
4464 }
4465
Laurence Lundbladec4537442020-04-14 18:53:22 -07004466 QCBORItem Item;
4467
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004468 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4469
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004470 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004471}
4472
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004473
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004474/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004475 * Public function, see header qcbor/qcbor_decode.h file
4476 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004477void
4478QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe,
4479 const int64_t nLabel,
4480 bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004481{
4482 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004483 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004484
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004485 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004486}
4487
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004488
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004489/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004490 * Public function, see header qcbor/qcbor_decode.h file
4491 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004492void
4493QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe,
4494 const char *szLabel,
4495 bool *pValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004496{
4497 QCBORItem Item;
4498 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4499
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004500 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004501}
4502
4503
4504
Laurence Lundbladec7114722020-08-13 05:11:40 -07004505
Laurence Lundbladea66c72c2024-06-11 20:30:19 -07004506void
4507QCBORDecode_GetSimple(QCBORDecodeContext *pMe, uint8_t *puSimple)
4508{
4509 QCBORItem Item;
4510
4511 QCBORDecode_VGetNext(pMe, &Item);
4512 if(pMe->uLastError != QCBOR_SUCCESS) {
4513 return;
4514 }
4515
4516 /* It's kind of lame to remap true...undef back to simple values, but
4517 * this function isn't used much.
4518 */
4519 switch(Item.uDataType) {
4520 case QCBOR_TYPE_UKNOWN_SIMPLE:
4521 *puSimple = Item.val.uSimple;
4522 break;
4523
4524 case QCBOR_TYPE_TRUE:
4525 *puSimple = CBOR_SIMPLEV_TRUE;
4526 break;
4527
4528 case QCBOR_TYPE_FALSE:
4529 *puSimple = CBOR_SIMPLEV_FALSE;
4530 break;
4531
4532 case QCBOR_TYPE_NULL:
4533 *puSimple = CBOR_SIMPLEV_NULL;
4534 break;
4535
4536 case QCBOR_TYPE_UNDEF:
4537 *puSimple = CBOR_SIMPLEV_UNDEF;
4538 break;
4539
4540 default:
4541 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4542 return;
4543 }
4544}
4545
4546
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004547/**
4548 * @brief Common processing for an epoch date.
4549 *
4550 * @param[in] pMe The decode context.
4551 * @param[in] pItem The item with the date.
4552 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4553 * @param[out] pnTime The returned date.
4554 *
4555 * Common processing for the date tag. Mostly make sure the tag
4556 * content is correct and copy forward any further other tag numbers.
4557 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004558static void
4559QCBORDecode_Private_ProcessEpochDate(QCBORDecodeContext *pMe,
4560 QCBORItem *pItem,
4561 const uint8_t uTagRequirement,
4562 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004563{
4564 if(pMe->uLastError != QCBOR_SUCCESS) {
4565 // Already in error state, do nothing
4566 return;
4567 }
4568
4569 QCBORError uErr;
4570
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004571 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladec7114722020-08-13 05:11:40 -07004572 {
4573 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004574 {QCBOR_TYPE_DATE_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4575 {QCBOR_TYPE_INT64, QCBOR_TYPE_DOUBLE, QCBOR_TYPE_FLOAT, QCBOR_TYPE_UINT64}
Laurence Lundbladec7114722020-08-13 05:11:40 -07004576 };
4577
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004578 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004579 if(uErr != QCBOR_SUCCESS) {
4580 goto Done;
4581 }
4582
4583 if(pItem->uDataType != QCBOR_TYPE_DATE_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004584 uErr = QCBOR_Private_DecodeDateEpoch(pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004585 if(uErr != QCBOR_SUCCESS) {
4586 goto Done;
4587 }
4588 }
4589
Laurence Lundblade9b334962020-08-27 10:55:53 -07004590 // Save the tags in the last item's tags in the decode context
4591 // for QCBORDecode_GetNthTagOfLast()
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004592 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07004593
Laurence Lundbladec7114722020-08-13 05:11:40 -07004594 *pnTime = pItem->val.epochDate.nSeconds;
4595
4596Done:
4597 pMe->uLastError = (uint8_t)uErr;
4598}
4599
4600
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004601
4602/*
4603 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4604 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004605void
4606QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
4607 uint8_t uTagRequirement,
4608 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004609{
4610 if(pMe->uLastError != QCBOR_SUCCESS) {
4611 // Already in error state, do nothing
4612 return;
4613 }
4614
4615 QCBORItem Item;
4616 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4617
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004618 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004619}
4620
4621
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004622/*
4623 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4624 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07004625void
4626QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
4627 int64_t nLabel,
4628 uint8_t uTagRequirement,
4629 int64_t *pnTime)
4630{
4631 QCBORItem Item;
4632 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004633 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004634}
4635
4636
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004637/*
4638 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4639 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07004640void
4641QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
4642 const char *szLabel,
4643 uint8_t uTagRequirement,
4644 int64_t *pnTime)
4645{
4646 QCBORItem Item;
4647 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004648 QCBORDecode_Private_ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004649}
4650
4651
4652
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004653/**
4654 * @brief Common processing for an epoch date.
4655 *
4656 * @param[in] pMe The decode context.
4657 * @param[in] pItem The item with the date.
4658 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4659 * @param[out] pnDays The returned day count.
4660 *
4661 * Common processing for the RFC 8943 day-count tag. Mostly make sure
4662 * the tag content is correct and copy forward any further other tag
4663 * numbers.
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004664 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004665static void
4666QCBORDecode_Private_ProcessEpochDays(QCBORDecodeContext *pMe,
4667 QCBORItem *pItem,
4668 uint8_t uTagRequirement,
4669 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004670{
4671 if(pMe->uLastError != QCBOR_SUCCESS) {
4672 /* Already in error state, do nothing */
4673 return;
4674 }
4675
4676 QCBORError uErr;
4677
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004678 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004679 {
4680 uTagRequirement,
4681 {QCBOR_TYPE_DAYS_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4682 {QCBOR_TYPE_INT64, QCBOR_TYPE_UINT64, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
4683 };
4684
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004685 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004686 if(uErr != QCBOR_SUCCESS) {
4687 goto Done;
4688 }
4689
4690 if(pItem->uDataType != QCBOR_TYPE_DAYS_EPOCH) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004691 uErr = QCBOR_Private_DecodeDaysEpoch(pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004692 if(uErr != QCBOR_SUCCESS) {
4693 goto Done;
4694 }
4695 }
4696
4697 /* Save the tags in the last item's tags in the decode context
4698 * for QCBORDecode_GetNthTagOfLast()
4699 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004700 QCBORDecode_Private_CopyTags(pMe, pItem);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004701
4702 *pnDays = pItem->val.epochDays;
4703
4704Done:
4705 pMe->uLastError = (uint8_t)uErr;
4706}
4707
4708
4709/*
4710 * Public function, see header qcbor/qcbor_decode.h
4711 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004712void
4713QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe,
4714 uint8_t uTagRequirement,
4715 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004716{
4717 if(pMe->uLastError != QCBOR_SUCCESS) {
4718 /* Already in error state, do nothing */
4719 return;
4720 }
4721
4722 QCBORItem Item;
4723 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
4724
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004725 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004726}
4727
4728
4729/*
4730 * Public function, see header qcbor/qcbor_decode.h
4731 */
4732void
4733QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe,
4734 int64_t nLabel,
4735 uint8_t uTagRequirement,
4736 int64_t *pnDays)
4737{
4738 QCBORItem Item;
4739 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004740 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004741}
4742
4743
4744/*
4745 * Public function, see header qcbor/qcbor_decode.h
4746 */
4747void
4748QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe,
4749 const char *szLabel,
4750 uint8_t uTagRequirement,
4751 int64_t *pnDays)
4752{
4753 QCBORItem Item;
4754 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004755 QCBORDecode_Private_ProcessEpochDays(pMe, &Item, uTagRequirement, pnDays);
Laurence Lundblade46d63e92021-05-13 11:37:10 -07004756}
4757
4758
4759
Laurence Lundblade37286c02022-09-03 10:05:02 -07004760/*
4761 * @brief Get a string that matches the type/tag specification.
4762 */
4763void
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004764QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
4765 const QCBOR_Private_TagSpec TagSpec,
4766 UsefulBufC *pBstr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004767{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004768 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade37286c02022-09-03 10:05:02 -07004769 /* Already in error state, do nothing */
Laurence Lundbladec4537442020-04-14 18:53:22 -07004770 return;
4771 }
4772
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004773 QCBORError uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004774 QCBORItem Item;
4775
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004776 uError = QCBORDecode_GetNext(pMe, &Item);
4777 if(uError != QCBOR_SUCCESS) {
4778 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004779 return;
4780 }
4781
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004782 pMe->uLastError = (uint8_t)QCBOR_Private_CheckTagRequirement(TagSpec, &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004783
4784 if(pMe->uLastError == QCBOR_SUCCESS) {
4785 *pBstr = Item.val.string;
Laurence Lundbladeab40c6f2020-08-28 11:24:58 -07004786 } else {
4787 *pBstr = NULLUsefulBufC;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004788 }
4789}
4790
Laurence Lundbladec4537442020-04-14 18:53:22 -07004791
4792
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004793
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004794/**
4795 * @brief Common processing for a big number tag.
4796 *
4797 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4798 * @param[in] pItem The item with the date.
4799 * @param[out] pValue The returned big number
4800 * @param[out] pbIsNegative The returned sign of the big number.
4801 *
4802 * Common processing for the big number tag. Mostly make sure
4803 * the tag content is correct and copy forward any further other tag
4804 * numbers.
4805 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004806static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004807QCBOR_Private_ProcessBigNum(const uint8_t uTagRequirement,
4808 const QCBORItem *pItem,
4809 UsefulBufC *pValue,
4810 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004811{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004812 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004813 {
4814 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004815 {QCBOR_TYPE_POSBIGNUM, QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4816 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004817 };
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004818
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004819 QCBORError uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004820 if(uErr != QCBOR_SUCCESS) {
4821 return uErr;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004822 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004823
4824 *pValue = pItem->val.string;
4825
4826 if(pItem->uDataType == QCBOR_TYPE_POSBIGNUM) {
4827 *pbIsNegative = false;
4828 } else if(pItem->uDataType == QCBOR_TYPE_NEGBIGNUM) {
4829 *pbIsNegative = true;
4830 }
4831
4832 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004833}
4834
4835
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004836/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004837 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004838 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004839void
4840QCBORDecode_GetBignum(QCBORDecodeContext *pMe,
4841 const uint8_t uTagRequirement,
4842 UsefulBufC *pValue,
4843 bool *pbIsNegative)
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004844{
4845 if(pMe->uLastError != QCBOR_SUCCESS) {
4846 // Already in error state, do nothing
4847 return;
4848 }
4849
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004850 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004851 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
4852 if(uError != QCBOR_SUCCESS) {
4853 pMe->uLastError = (uint8_t)uError;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004854 return;
4855 }
4856
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004857 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4858 &Item,
4859 pValue,
4860 pbIsNegative);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004861}
4862
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004863
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004864/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004865 * Public function, see header qcbor/qcbor_spiffy_decode.h
4866 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004867void
4868QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe,
4869 const int64_t nLabel,
4870 const uint8_t uTagRequirement,
4871 UsefulBufC *pValue,
4872 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004873{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004874 QCBORItem Item;
4875 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004876 if(pMe->uLastError != QCBOR_SUCCESS) {
4877 return;
4878 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004879
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004880 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4881 &Item,
4882 pValue,
4883 pbIsNegative);
Laurence Lundbladec4537442020-04-14 18:53:22 -07004884}
4885
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004886
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004887/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004888 * Public function, see header qcbor/qcbor_spiffy_decode.h
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004889 */
4890void
4891QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe,
4892 const char *szLabel,
4893 const uint8_t uTagRequirement,
4894 UsefulBufC *pValue,
4895 bool *pbIsNegative)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004896{
4897 QCBORItem Item;
4898 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07004899 if(pMe->uLastError != QCBOR_SUCCESS) {
4900 return;
4901 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004902
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004903 pMe->uLastError = (uint8_t)QCBOR_Private_ProcessBigNum(uTagRequirement,
4904 &Item,
4905 pValue,
4906 pbIsNegative);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004907}
4908
4909
4910
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004911/**
4912 * @brief Common processing for MIME tag (semi-private).
4913 *
4914 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
4915 * @param[in] pItem The item with the date.
4916 * @param[out] pMessage The returned MIME message.
4917 * @param[out] pbIsTag257 If true, binary MIME, if not, text MIME.
4918 *
4919 * Common processing for the MIME tag. Mostly make sure the tag
4920 * content is correct and copy forward any further other tag
4921 * numbers. See QCBORDecode_GetMIMEMessage().
4922 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004923QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004924QCBORDecode_Private_GetMIME(const uint8_t uTagRequirement,
Laurence Lundblade37286c02022-09-03 10:05:02 -07004925 const QCBORItem *pItem,
4926 UsefulBufC *pMessage,
4927 bool *pbIsTag257)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004928{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004929 const QCBOR_Private_TagSpec TagSpecText =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004930 {
4931 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004932 {QCBOR_TYPE_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4933 {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004934 };
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004935 const QCBOR_Private_TagSpec TagSpecBinary =
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004936 {
4937 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07004938 {QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
4939 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004940 };
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004941
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004942 QCBORError uReturn;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004943
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004944 if(QCBOR_Private_CheckTagRequirement(TagSpecText, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004945 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07004946 if(pbIsTag257 != NULL) {
4947 *pbIsTag257 = false;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004948 }
4949 uReturn = QCBOR_SUCCESS;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004950 } else if(QCBOR_Private_CheckTagRequirement(TagSpecBinary, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004951 *pMessage = pItem->val.string;
Laurence Lundblade4982f412020-09-18 23:02:18 -07004952 if(pbIsTag257 != NULL) {
4953 *pbIsTag257 = true;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004954 }
4955 uReturn = QCBOR_SUCCESS;
4956
4957 } else {
4958 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
4959 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07004960
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004961 return uReturn;
4962}
4963
Laurence Lundblade93d89472020-10-03 22:30:50 -07004964// Improvement: add methods for wrapped CBOR, a simple alternate
4965// to EnterBstrWrapped
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004966
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004967
4968
4969
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07004970#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundbladee6430642020-03-14 21:15:44 -07004971
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004972/**
4973 * @brief Prototype for conversion of exponent and mantissa to unsigned integer.
4974 *
4975 * @param[in] uMantissa The mantissa.
4976 * @param[in] nExponent The exponent.
4977 * @param[out] puResult The resulting integer.
4978 *
4979 * Concrete implementations of this are for exponent base 10 and 2 supporting
4980 * decimal fractions and big floats.
4981 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004982typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004983
4984
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07004985/**
4986 * @brief Base 10 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
4987 *
4988 * @param[in] uMantissa The unsigned integer mantissa.
4989 * @param[in] nExponent The signed integer exponent.
4990 * @param[out] puResult Place to return the unsigned integer result.
4991 *
4992 * This computes: mantissa * 10 ^^ exponent as for a decimal fraction. The output is a 64-bit
4993 * unsigned integer.
4994 *
4995 * There are many inputs for which the result will not fit in the
4996 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
4997 * be returned.
4998 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07004999static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005000QCBOR_Private_Exponentitate10(const uint64_t uMantissa,
5001 int64_t nExponent,
5002 uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005003{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005004 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005005
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005006 if(uResult != 0) {
5007 /* This loop will run a maximum of 19 times because
5008 * UINT64_MAX < 10 ^^ 19. More than that will cause
5009 * exit with the overflow error
5010 */
5011 for(; nExponent > 0; nExponent--) {
5012 if(uResult > UINT64_MAX / 10) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005013 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005014 }
5015 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005016 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005017
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005018 for(; nExponent < 0; nExponent++) {
5019 uResult = uResult / 10;
5020 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005021 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005022 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005023 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005024 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005025 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07005026
5027 *puResult = uResult;
5028
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005029 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005030}
5031
5032
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005033/**
5034 * @brief Base 2 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5035 *
5036 * @param[in] uMantissa The unsigned integer mantissa.
5037 * @param[in] nExponent The signed integer exponent.
5038 * @param[out] puResult Place to return the unsigned integer result.
5039 *
5040 * This computes: mantissa * 2 ^^ exponent as for a big float. The
5041 * output is a 64-bit unsigned integer.
5042 *
5043 * There are many inputs for which the result will not fit in the
5044 * 64-bit integer and \ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
5045 * be returned.
5046 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005047static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005048QCBOR_Private_Exponentitate2(const uint64_t uMantissa,
5049 int64_t nExponent,
5050 uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005051{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005052 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005053
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005054 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005055
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005056 /* This loop will run a maximum of 64 times because INT64_MAX <
5057 * 2^31. More than that will cause exit with the overflow error
Laurence Lundbladee6430642020-03-14 21:15:44 -07005058 */
5059 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005060 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005061 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005062 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005063 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005064 nExponent--;
5065 }
5066
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005067 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005068 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005069 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005070 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005071 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005072 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005073 }
5074
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005075 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005076
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005077 return QCBOR_SUCCESS;
5078}
5079
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005080
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005081/**
5082 * @brief Exponentiate a signed mantissa and signed exponent to produce a signed result.
5083 *
5084 * @param[in] nMantissa Signed integer mantissa.
5085 * @param[in] nExponent Signed integer exponent.
5086 * @param[out] pnResult Place to put the signed integer result.
5087 * @param[in] pfExp Exponentiation function.
5088 *
5089 * @returns Error code
5090 *
5091 * \c pfExp performs exponentiation on and unsigned mantissa and
5092 * produces an unsigned result. This converts the mantissa from signed
5093 * and converts the result to signed. The exponentiation function is
5094 * either for base 2 or base 10 (and could be other if needed).
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005095 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005096static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005097QCBOR_Private_ExponentiateNN(const int64_t nMantissa,
5098 const int64_t nExponent,
5099 int64_t *pnResult,
5100 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005101{
5102 uint64_t uResult;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005103 uint64_t uMantissa;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005104
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005105 /* Take the absolute value and put it into an unsigned. */
5106 if(nMantissa >= 0) {
5107 /* Positive case is straightforward */
5108 uMantissa = (uint64_t)nMantissa;
5109 } else if(nMantissa != INT64_MIN) {
5110 /* The common negative case. See next. */
5111 uMantissa = (uint64_t)-nMantissa;
5112 } else {
5113 /* int64_t and uint64_t are always two's complement per the
5114 * C standard (and since QCBOR uses these it only works with
5115 * two's complement, which is pretty much universal these
5116 * days). The range of a negative two's complement integer is
5117 * one more that than a positive, so the simple code above might
5118 * not work all the time because you can't simply negate the
5119 * value INT64_MIN because it can't be represented in an
5120 * int64_t. -INT64_MIN can however be represented in a
5121 * uint64_t. Some compilers seem to recognize this case for the
5122 * above code and put the correct value in uMantissa, however
5123 * they are not required to do this by the C standard. This next
5124 * line does however work for all compilers.
5125 *
5126 * This does assume two's complement where -INT64_MIN ==
5127 * INT64_MAX + 1 (which wouldn't be true for one's complement or
5128 * sign and magnitude (but we know we're using two's complement
5129 * because int64_t requires it)).
5130 *
5131 * See these, particularly the detailed commentary:
5132 * https://stackoverflow.com/questions/54915742/does-c99-mandate-a-int64-t-type-be-available-always
5133 * https://stackoverflow.com/questions/37301078/is-negating-int-min-undefined-behaviour
5134 */
5135 uMantissa = (uint64_t)INT64_MAX+1;
5136 }
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005137
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005138 /* Call the exponentiator passed for either base 2 or base 10.
5139 * Here is where most of the overflow errors are caught. */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005140 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
5141 if(uReturn) {
5142 return uReturn;
5143 }
5144
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005145 /* Convert back to the sign of the original mantissa */
5146 if(nMantissa >= 0) {
5147 if(uResult > INT64_MAX) {
5148 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5149 }
5150 *pnResult = (int64_t)uResult;
5151 } else {
5152 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
5153 * of INT64_MIN. This assumes two's compliment representation
5154 * where INT64_MIN is one increment farther from 0 than
5155 * INT64_MAX. Trying to write -INT64_MIN doesn't work to get
5156 * this because the compiler makes it an int64_t which can't
5157 * represent -INT64_MIN. Also see above.
5158 */
5159 if(uResult > (uint64_t)INT64_MAX+1) {
5160 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5161 }
5162 *pnResult = -(int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005163 }
5164
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005165 return QCBOR_SUCCESS;
5166}
5167
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005168
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005169/**
5170 * @brief Exponentiate an unsigned mantissa and signed exponent to produce an unsigned result.
5171 *
5172 * @param[in] nMantissa Signed integer mantissa.
5173 * @param[in] nExponent Signed integer exponent.
5174 * @param[out] puResult Place to put the signed integer result.
5175 * @param[in] pfExp Exponentiation function.
5176 *
5177 * @returns Error code
5178 *
5179 * \c pfExp performs exponentiation on and unsigned mantissa and
5180 * produces an unsigned result. This errors out if the mantissa
5181 * is negative because the output is unsigned.
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005182 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005183static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005184QCBOR_Private_ExponentitateNU(const int64_t nMantissa,
5185 const int64_t nExponent,
5186 uint64_t *puResult,
5187 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005188{
5189 if(nMantissa < 0) {
5190 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5191 }
5192
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005193 /* Cast to unsigned is OK because of check for negative.
5194 * Cast to unsigned is OK because UINT64_MAX > INT64_MAX.
5195 * Exponentiation is straight forward
5196 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005197 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
5198}
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005199
5200
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005201/**
5202 * @brief Exponentiate an usnigned mantissa and unsigned exponent to produce an unsigned result.
5203 *
5204 * @param[in] uMantissa Unsigned integer mantissa.
5205 * @param[in] nExponent Unsigned integer exponent.
5206 * @param[out] puResult Place to put the unsigned integer result.
5207 * @param[in] pfExp Exponentiation function.
5208 *
5209 * @returns Error code
5210 *
5211 * \c pfExp performs exponentiation on and unsigned mantissa and
5212 * produces an unsigned result so this is just a wrapper that does
5213 * nothing (and is likely inlined).
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005214 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005215static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005216QCBOR_Private_ExponentitateUU(const uint64_t uMantissa,
5217 const int64_t nExponent,
5218 uint64_t *puResult,
5219 fExponentiator pfExp)
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005220{
5221 return (*pfExp)(uMantissa, nExponent, puResult);
5222}
5223
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005224#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005225
5226
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005227
5228
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005229/**
5230 * @brief Convert a CBOR big number to a uint64_t.
5231 *
5232 * @param[in] BigNum Bytes of the big number to convert.
5233 * @param[in] uMax Maximum value allowed for the result.
5234 * @param[out] pResult Place to put the unsigned integer result.
5235 *
5236 * @returns Error code
5237 *
5238 * Many values will overflow because a big num can represent a much
5239 * larger range than uint64_t.
5240 */
5241static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005242QCBOR_Private_ConvertBigNumToUnsigned(const UsefulBufC BigNum,
5243 const uint64_t uMax,
5244 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005245{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005246 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005247
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005248 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005249 const uint8_t *pByte = BigNum.ptr;
5250 size_t uLen = BigNum.len;
5251 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07005252 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005253 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005254 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07005255 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005256 }
5257
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005258 *pResult = uResult;
5259 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005260}
5261
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005262
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005263/**
5264 * @brief Convert a CBOR postive big number to a uint64_t.
5265 *
5266 * @param[in] BigNum Bytes of the big number to convert.
5267 * @param[out] pResult Place to put the unsigned integer result.
5268 *
5269 * @returns Error code
5270 *
5271 * Many values will overflow because a big num can represent a much
5272 * larger range than uint64_t.
5273 */
5274static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005275QCBOR_Private_ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum,
5276 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005277{
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005278 return QCBOR_Private_ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005279}
5280
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005281
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005282/**
5283 * @brief Convert a CBOR positive big number to an int64_t.
5284 *
5285 * @param[in] BigNum Bytes of the big number to convert.
5286 * @param[out] pResult Place to put the signed integer result.
5287 *
5288 * @returns Error code
5289 *
5290 * Many values will overflow because a big num can represent a much
5291 * larger range than int64_t.
5292 */
5293static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005294QCBOR_Private_ConvertPositiveBigNumToSigned(const UsefulBufC BigNum,
5295 int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005296{
5297 uint64_t uResult;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005298 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5299 INT64_MAX,
5300 &uResult);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005301 if(uError) {
5302 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005303 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005304 /* Cast is safe because ConvertBigNumToUnsigned limits to INT64_MAX */
Laurence Lundbladee6430642020-03-14 21:15:44 -07005305 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005306 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005307}
5308
5309
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005310/**
5311 * @brief Convert a CBOR negative big number to an int64_t.
5312 *
5313 * @param[in] BigNum Bytes of the big number to convert.
5314 * @param[out] pnResult Place to put the signed integer result.
5315 *
5316 * @returns Error code
5317 *
5318 * Many values will overflow because a big num can represent a much
5319 * larger range than int64_t.
5320 */
5321static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005322QCBOR_Private_ConvertNegativeBigNumToSigned(const UsefulBufC BigNum,
5323 int64_t *pnResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005324{
5325 uint64_t uResult;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005326 /* The negative integer furthest from zero for a C int64_t is
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005327 * INT64_MIN which is expressed as -INT64_MAX - 1. The value of a
5328 * negative number in CBOR is computed as -n - 1 where n is the
5329 * encoded integer, where n is what is in the variable BigNum. When
5330 * converting BigNum to a uint64_t, the maximum value is thus
5331 * INT64_MAX, so that when it -n - 1 is applied to it the result
5332 * will never be further from 0 than INT64_MIN.
5333 *
5334 * -n - 1 <= INT64_MIN.
5335 * -n - 1 <= -INT64_MAX - 1
5336 * n <= INT64_MAX.
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005337 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005338 QCBORError uError = QCBOR_Private_ConvertBigNumToUnsigned(BigNum,
5339 INT64_MAX,
5340 &uResult);
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005341 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005342 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005343 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005344
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005345 /* Now apply -n - 1. The cast is safe because
5346 * ConvertBigNumToUnsigned() is limited to INT64_MAX which does fit
5347 * is the largest positive integer that an int64_t can
5348 * represent. */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005349 *pnResult = -(int64_t)uResult - 1;
5350
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005351 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005352}
5353
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005354
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005355
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005356
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005357/**
5358 * @brief Convert integers and floats to an int64_t.
5359 *
5360 * @param[in] pItem The item to convert.
5361 * @param[in] uConvertTypes Bit mask list of conversion options.
5362 * @param[out] pnValue The resulting converted value.
5363 *
5364 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5365 * in uConvertTypes.
5366 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5367 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5368 * or too small.
5369 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005370static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005371QCBOR_Private_ConvertInt64(const QCBORItem *pItem,
5372 const uint32_t uConvertTypes,
5373 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005374{
5375 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005376 case QCBOR_TYPE_FLOAT:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005377 case QCBOR_TYPE_DOUBLE:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005378#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005379 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005380 /* https://pubs.opengroup.org/onlinepubs/009695399/functions/llround.html
5381 http://www.cplusplus.com/reference/cmath/llround/
5382 */
5383 // Not interested in FE_INEXACT
5384 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005385 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5386 *pnValue = llround(pItem->val.dfnum);
5387 } else {
5388 *pnValue = lroundf(pItem->val.fnum);
5389 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005390 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5391 // llround() shouldn't result in divide by zero, but catch
5392 // it here in case it unexpectedly does. Don't try to
5393 // distinguish between the various exceptions because it seems
5394 // they vary by CPU, compiler and OS.
5395 return QCBOR_ERR_FLOAT_EXCEPTION;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005396 }
5397 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005398 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005399 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005400#else
5401 return QCBOR_ERR_HW_FLOAT_DISABLED;
5402#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005403 break;
5404
5405 case QCBOR_TYPE_INT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005406 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005407 *pnValue = pItem->val.int64;
5408 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005409 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005410 }
5411 break;
5412
5413 case QCBOR_TYPE_UINT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005414 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005415 if(pItem->val.uint64 < INT64_MAX) {
5416 *pnValue = pItem->val.int64;
5417 } else {
5418 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5419 }
5420 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005421 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005422 }
5423 break;
5424
5425 default:
5426 return QCBOR_ERR_UNEXPECTED_TYPE;
5427 }
5428 return QCBOR_SUCCESS;
5429}
5430
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005431
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005432/**
5433 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5434 *
5435 * @param[in] pMe The decode context.
5436 * @param[in] uConvertTypes Bit mask list of conversion options.
5437 * @param[out] pnValue Result of the conversion.
5438 * @param[in,out] pItem Temporary space to store Item, returned item.
5439 *
5440 * See QCBORDecode_GetInt64Convert().
5441 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005442void
5443QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pMe,
5444 uint32_t uConvertTypes,
5445 int64_t *pnValue,
5446 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005447{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07005448 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005449 return;
5450 }
5451
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005452 QCBORError uError = QCBORDecode_GetNext(pMe, pItem);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005453 if(uError) {
5454 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005455 return;
5456 }
5457
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005458 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005459 uConvertTypes,
5460 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005461}
5462
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005463/**
5464 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5465 *
5466 * @param[in] pMe The decode context.
5467 * @param[in] nLabel Label to find in map.
5468 * @param[in] uConvertTypes Bit mask list of conversion options.
5469 * @param[out] pnValue Result of the conversion.
5470 * @param[in,out] pItem Temporary space to store Item, returned item.
5471 *
5472 * See QCBORDecode_GetInt64ConvertInMapN().
5473 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005474void
5475QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pMe,
5476 int64_t nLabel,
5477 uint32_t uConvertTypes,
5478 int64_t *pnValue,
5479 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005480{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005481 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005482 if(pMe->uLastError != QCBOR_SUCCESS) {
5483 return;
5484 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005485
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005486 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5487 uConvertTypes,
5488 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005489}
5490
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005491/**
5492 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
5493 *
5494 * @param[in] pMe The decode context.
5495 * @param[in] szLabel Label to find in map.
5496 * @param[in] uConvertTypes Bit mask list of conversion options.
5497 * @param[out] pnValue Result of the conversion.
5498 * @param[in,out] pItem Temporary space to store Item, returned item.
5499 *
5500 * See QCBORDecode_GetInt64ConvertInMapSZ().
5501 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005502void
5503QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5504 const char * szLabel,
5505 uint32_t uConvertTypes,
5506 int64_t *pnValue,
5507 QCBORItem *pItem)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005508{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005509 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005510 if(pMe->uLastError != QCBOR_SUCCESS) {
5511 return;
5512 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005513
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005514 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
5515 uConvertTypes,
5516 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005517}
5518
5519
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005520/**
5521 * @brief Convert many number types to an int64_t.
5522 *
5523 * @param[in] pItem The item to convert.
5524 * @param[in] uConvertTypes Bit mask list of conversion options.
5525 * @param[out] pnValue The resulting converted value.
5526 *
5527 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5528 * in uConvertTypes.
5529 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5530 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5531 * or too small.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005532 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005533static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005534QCBOR_Private_Int64ConvertAll(const QCBORItem *pItem,
5535 const uint32_t uConvertTypes,
5536 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005537{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005538 switch(pItem->uDataType) {
5539
5540 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005541 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005542 return QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005543 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005544 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005545 }
5546 break;
5547
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005548 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005549 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005550 return QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005551 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005552 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005553 }
5554 break;
5555
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005556#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005557 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005558 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005559 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005560 pItem->val.expAndMantissa.nExponent,
5561 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005562 &QCBOR_Private_Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005563 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005564 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005565 }
5566 break;
5567
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005568 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005569 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005570 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005571 pItem->val.expAndMantissa.nExponent,
5572 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005573 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005574 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005575 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005576 }
5577 break;
5578
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005579 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005580 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005581 int64_t nMantissa;
5582 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005583 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005584 if(uErr) {
5585 return uErr;
5586 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005587 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005588 pItem->val.expAndMantissa.nExponent,
5589 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005590 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005591 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005592 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005593 }
5594 break;
5595
5596 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005597 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005598 int64_t nMantissa;
5599 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005600 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005601 if(uErr) {
5602 return uErr;
5603 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005604 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005605 pItem->val.expAndMantissa.nExponent,
5606 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005607 QCBOR_Private_Exponentitate10);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005608 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005609 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005610 }
5611 break;
5612
5613 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005614 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005615 int64_t nMantissa;
5616 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005617 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005618 if(uErr) {
5619 return uErr;
5620 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005621 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005622 pItem->val.expAndMantissa.nExponent,
5623 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005624 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005625 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005626 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005627 }
5628 break;
5629
5630 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005631 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005632 int64_t nMantissa;
5633 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005634 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005635 if(uErr) {
5636 return uErr;
5637 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005638 return QCBOR_Private_ExponentiateNN(nMantissa,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005639 pItem->val.expAndMantissa.nExponent,
5640 pnValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005641 QCBOR_Private_Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005642 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005643 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005644 }
5645 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005646#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005647
Laurence Lundbladee6430642020-03-14 21:15:44 -07005648
Laurence Lundbladec4537442020-04-14 18:53:22 -07005649 default:
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005650 return QCBOR_ERR_UNEXPECTED_TYPE; }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005651}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005652
5653
Laurence Lundbladec4537442020-04-14 18:53:22 -07005654/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005655 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005656 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005657void
5658QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe,
5659 const uint32_t uConvertTypes,
5660 int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005661{
5662 QCBORItem Item;
5663
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005664 QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005665
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005666 if(pMe->uLastError == QCBOR_SUCCESS) {
5667 // The above conversion succeeded
5668 return;
5669 }
5670
Laurence Lundbladef6c86662020-05-12 02:08:00 -07005671 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005672 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07005673 return;
5674 }
5675
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005676 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5677 uConvertTypes,
5678 pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005679}
5680
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005681
5682/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005683 * Public function, see header qcbor/qcbor_decode.h file
5684 */
5685void
5686QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
5687 const int64_t nLabel,
5688 const uint32_t uConvertTypes,
5689 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005690{
5691 QCBORItem Item;
5692
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005693 QCBORDecode_Private_GetInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07005694 nLabel,
5695 uConvertTypes,
5696 pnValue,
5697 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005698
5699 if(pMe->uLastError == QCBOR_SUCCESS) {
5700 // The above conversion succeeded
5701 return;
5702 }
5703
5704 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5705 // The above conversion failed in a way that code below can't correct
5706 return;
5707 }
5708
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005709 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5710 uConvertTypes,
5711 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005712}
5713
5714
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005715/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005716 * Public function, see header qcbor/qcbor_decode.h file
5717 */
5718void
5719QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
5720 const char *szLabel,
5721 const uint32_t uConvertTypes,
5722 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005723{
5724 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005725 QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07005726 szLabel,
5727 uConvertTypes,
5728 pnValue,
5729 &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005730
5731 if(pMe->uLastError == QCBOR_SUCCESS) {
5732 // The above conversion succeeded
5733 return;
5734 }
5735
5736 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
5737 // The above conversion failed in a way that code below can't correct
5738 return;
5739 }
5740
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005741 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
5742 uConvertTypes,
5743 pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005744}
5745
5746
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005747/**
5748 * @brief Convert many number types to an uint64_t.
5749 *
5750 * @param[in] pItem The item to convert.
5751 * @param[in] uConvertTypes Bit mask list of conversion options.
5752 * @param[out] puValue The resulting converted value.
5753 *
5754 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5755 * in uConvertTypes.
5756 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5757 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5758 * or too small.
5759 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005760static QCBORError
5761QCBOR_Private_ConvertUInt64(const QCBORItem *pItem,
5762 const uint32_t uConvertTypes,
5763 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005764{
5765 switch(pItem->uDataType) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005766 case QCBOR_TYPE_DOUBLE:
5767 case QCBOR_TYPE_FLOAT:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005768#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005769 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005770 // Can't use llround here because it will not convert values
5771 // greater than INT64_MAX and less than UINT64_MAX that
5772 // need to be converted so it is more complicated.
5773 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
5774 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5775 if(isnan(pItem->val.dfnum)) {
5776 return QCBOR_ERR_FLOAT_EXCEPTION;
5777 } else if(pItem->val.dfnum < 0) {
5778 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5779 } else {
5780 double dRounded = round(pItem->val.dfnum);
5781 // See discussion in DecodeDateEpoch() for
5782 // explanation of - 0x7ff
5783 if(dRounded > (double)(UINT64_MAX- 0x7ff)) {
5784 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5785 }
5786 *puValue = (uint64_t)dRounded;
5787 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005788 } else {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005789 if(isnan(pItem->val.fnum)) {
5790 return QCBOR_ERR_FLOAT_EXCEPTION;
5791 } else if(pItem->val.fnum < 0) {
5792 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5793 } else {
5794 float fRounded = roundf(pItem->val.fnum);
5795 // See discussion in DecodeDateEpoch() for
5796 // explanation of - 0x7ff
5797 if(fRounded > (float)(UINT64_MAX- 0x7ff)) {
5798 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5799 }
5800 *puValue = (uint64_t)fRounded;
5801 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005802 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005803 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5804 // round() and roundf() shouldn't result in exceptions here, but
5805 // catch them to be robust and thorough. Don't try to
5806 // distinguish between the various exceptions because it seems
5807 // they vary by CPU, compiler and OS.
5808 return QCBOR_ERR_FLOAT_EXCEPTION;
5809 }
5810
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005811 } else {
5812 return QCBOR_ERR_UNEXPECTED_TYPE;
5813 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005814#else
5815 return QCBOR_ERR_HW_FLOAT_DISABLED;
5816#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005817 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005818
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005819 case QCBOR_TYPE_INT64:
5820 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
5821 if(pItem->val.int64 >= 0) {
5822 *puValue = (uint64_t)pItem->val.int64;
5823 } else {
5824 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5825 }
5826 } else {
5827 return QCBOR_ERR_UNEXPECTED_TYPE;
5828 }
5829 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005830
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005831 case QCBOR_TYPE_UINT64:
5832 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
5833 *puValue = pItem->val.uint64;
5834 } else {
5835 return QCBOR_ERR_UNEXPECTED_TYPE;
5836 }
5837 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005838
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005839 default:
5840 return QCBOR_ERR_UNEXPECTED_TYPE;
5841 }
5842
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005843 return QCBOR_SUCCESS;
5844}
Laurence Lundbladec4537442020-04-14 18:53:22 -07005845
5846
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005847/**
5848 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5849 *
5850 * @param[in] pMe The decode context.
5851 * @param[in] uConvertTypes Bit mask list of conversion options.
5852 * @param[out] puValue Result of the conversion.
5853 * @param[in,out] pItem Temporary space to store Item, returned item.
5854 *
5855 * See QCBORDecode_GetUInt64Convert().
5856 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005857void
5858QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pMe,
5859 const uint32_t uConvertTypes,
5860 uint64_t *puValue,
5861 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005862{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005863 if(pMe->uLastError != QCBOR_SUCCESS) {
5864 return;
5865 }
5866
Laurence Lundbladec4537442020-04-14 18:53:22 -07005867 QCBORItem Item;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005868
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005869 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
5870 if(uError) {
5871 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005872 return;
5873 }
5874
Laurence Lundbladea826c502020-05-10 21:07:00 -07005875 if(pItem) {
5876 *pItem = Item;
5877 }
5878
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005879 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(&Item,
5880 uConvertTypes,
5881 puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005882}
5883
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005884
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005885/**
5886 * @brief Almost-public method to decode a number and convert to uint64_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] puValue Result of the conversion.
5892 * @param[in,out] pItem Temporary space to store Item, returned item.
5893 *
5894 * See QCBORDecode_GetUInt64ConvertInMapN().
5895 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005896void
5897QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe,
5898 const int64_t nLabel,
5899 const uint32_t uConvertTypes,
5900 uint64_t *puValue,
5901 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -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 Lundblade7e5be1d2020-05-24 21:17:28 -07005907
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005908 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
5909 uConvertTypes,
5910 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005911}
5912
5913
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005914/**
5915 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
5916 *
5917 * @param[in] pMe The decode context.
5918 * @param[in] szLabel Label to find in map.
5919 * @param[in] uConvertTypes Bit mask list of conversion options.
5920 * @param[out] puValue Result of the conversion.
5921 * @param[in,out] pItem Temporary space to store Item, returned item.
5922 *
5923 * See QCBORDecode_GetUInt64ConvertInMapSZ().
5924 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005925void
5926QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
5927 const char *szLabel,
5928 const uint32_t uConvertTypes,
5929 uint64_t *puValue,
5930 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005931{
5932 if(pMe->uLastError != QCBOR_SUCCESS) {
5933 return;
5934 }
5935
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005936 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005937 if(pMe->uLastError != QCBOR_SUCCESS) {
5938 return;
5939 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005940
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005941 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
5942 uConvertTypes,
5943 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005944}
5945
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005946
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005947/**
5948 * @brief Convert many number types to an unt64_t.
5949 *
5950 * @param[in] pItem The item to convert.
5951 * @param[in] uConvertTypes Bit mask list of conversion options.
5952 * @param[out] puValue The resulting converted value.
5953 *
5954 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5955 * in uConvertTypes.
5956 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5957 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5958 * or too small.
5959 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005960static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005961QCBOR_Private_UInt64ConvertAll(const QCBORItem *pItem,
5962 const uint32_t uConvertTypes,
5963 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005964{
Laurence Lundblade68cb61c2023-02-12 13:21:44 -08005965 switch(pItem->uDataType) { /* -Wmaybe-uninitialized falsly warns here */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005966
5967 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005968 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005969 return QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005970 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005971 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005972 }
5973 break;
5974
5975 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005976 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005977 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5978 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005979 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005980 }
5981 break;
5982
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005983#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005984
5985 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005986 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005987 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005988 pItem->val.expAndMantissa.nExponent,
5989 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005990 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005991 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005992 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005993 }
5994 break;
5995
5996 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005997 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005998 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005999 pItem->val.expAndMantissa.nExponent,
6000 puValue,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006001 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006002 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006003 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006004 }
6005 break;
6006
6007 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006008 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006009 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006010 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006011 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006012 if(uErr != QCBOR_SUCCESS) {
6013 return uErr;
6014 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006015 return QCBOR_Private_ExponentitateUU(uMantissa,
6016 pItem->val.expAndMantissa.nExponent,
6017 puValue,
6018 QCBOR_Private_Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006019 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006020 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006021 }
6022 break;
6023
6024 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006025 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006026 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6027 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006028 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006029 }
6030 break;
6031
6032 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006033 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006034 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006035 QCBORError uErr;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006036 uErr = QCBOR_Private_ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum,
6037 &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006038 if(uErr != QCBOR_SUCCESS) {
6039 return uErr;
6040 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006041 return QCBOR_Private_ExponentitateUU(uMantissa,
6042 pItem->val.expAndMantissa.nExponent,
6043 puValue,
6044 QCBOR_Private_Exponentitate2);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006045 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006046 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006047 }
6048 break;
6049
6050 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006051 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006052 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
6053 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006054 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006055 }
6056 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006057#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006058 default:
6059 return QCBOR_ERR_UNEXPECTED_TYPE;
6060 }
6061}
6062
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006063
Laurence Lundblade4e2da002020-06-13 23:08:31 -07006064/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006065 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006066 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006067void
6068QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe,
6069 const uint32_t uConvertTypes,
6070 uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006071{
6072 QCBORItem Item;
6073
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006074 QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07006075
Laurence Lundbladef6c86662020-05-12 02:08:00 -07006076 if(pMe->uLastError == QCBOR_SUCCESS) {
6077 // The above conversion succeeded
6078 return;
6079 }
6080
6081 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6082 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07006083 return;
6084 }
6085
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006086 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6087 uConvertTypes,
6088 puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006089}
6090
Laurence Lundbladec4537442020-04-14 18:53:22 -07006091
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006092/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006093 * Public function, see header qcbor/qcbor_decode.h file
6094 */
6095void
6096QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
6097 const int64_t nLabel,
6098 const uint32_t uConvertTypes,
6099 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006100{
6101 QCBORItem Item;
6102
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006103 QCBORDecode_Private_GetUInt64ConvertInMapN(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006104 nLabel,
6105 uConvertTypes,
6106 puValue,
6107 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006108
6109 if(pMe->uLastError == QCBOR_SUCCESS) {
6110 // The above conversion succeeded
6111 return;
6112 }
6113
6114 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6115 // The above conversion failed in a way that code below can't correct
6116 return;
6117 }
6118
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006119 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6120 uConvertTypes,
6121 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006122}
6123
6124
6125/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006126 * Public function, see header qcbor/qcbor_decode.h file
6127 */
6128void
6129QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
6130 const char *szLabel,
6131 const uint32_t uConvertTypes,
6132 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006133{
6134 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006135 QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe,
Laurence Lundblade93d89472020-10-03 22:30:50 -07006136 szLabel,
6137 uConvertTypes,
6138 puValue,
6139 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006140
6141 if(pMe->uLastError == QCBOR_SUCCESS) {
6142 // The above conversion succeeded
6143 return;
6144 }
6145
6146 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6147 // The above conversion failed in a way that code below can't correct
6148 return;
6149 }
6150
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006151 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
6152 uConvertTypes,
6153 puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006154}
6155
6156
Laurence Lundbladef7a70bc2020-10-24 12:23:25 -07006157
6158
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006159#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006160/**
6161 * @brief Basic conversions to a double.
6162 *
6163 * @param[in] pItem The item to convert
6164 * @param[in] uConvertTypes Bit flags indicating source types for conversion
6165 * @param[out] pdValue The value converted to a double
6166 *
6167 * This does the conversions that don't need much object code,
6168 * the conversions from int, uint and float to double.
6169 *
6170 * See QCBOR_Private_DoubleConvertAll() for the full set
6171 * of conversions.
6172 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006173static QCBORError
6174QCBOR_Private_ConvertDouble(const QCBORItem *pItem,
6175 const uint32_t uConvertTypes,
6176 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006177{
6178 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006179 case QCBOR_TYPE_FLOAT:
6180#ifndef QCBOR_DISABLE_FLOAT_HW_USE
6181 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6182 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006183 // Simple cast does the job.
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006184 *pdValue = (double)pItem->val.fnum;
6185 } else {
6186 return QCBOR_ERR_UNEXPECTED_TYPE;
6187 }
6188 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006189#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006190 return QCBOR_ERR_HW_FLOAT_DISABLED;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08006191#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006192 break;
6193
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006194 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006195 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
6196 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006197 *pdValue = pItem->val.dfnum;
6198 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006199 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006200 }
6201 }
6202 break;
6203
6204 case QCBOR_TYPE_INT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006205#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006206 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006207 // A simple cast seems to do the job with no worry of exceptions.
6208 // There will be precision loss for some values.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006209 *pdValue = (double)pItem->val.int64;
6210
6211 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006212 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006213 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006214#else
6215 return QCBOR_ERR_HW_FLOAT_DISABLED;
6216#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006217 break;
6218
6219 case QCBOR_TYPE_UINT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006220#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006221 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07006222 // A simple cast seems to do the job with no worry of exceptions.
6223 // There will be precision loss for some values.
6224 *pdValue = (double)pItem->val.uint64;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006225 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006226 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006227 }
6228 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006229#else
6230 return QCBOR_ERR_HW_FLOAT_DISABLED;
6231#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006232
6233 default:
6234 return QCBOR_ERR_UNEXPECTED_TYPE;
6235 }
6236
6237 return QCBOR_SUCCESS;
6238}
6239
6240
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006241/**
6242 * @brief Almost-public method to decode a number and convert to double (semi-private).
6243 *
6244 * @param[in] pMe The decode context.
6245 * @param[in] uConvertTypes Bit mask list of conversion options
6246 * @param[out] pdValue The output of the conversion.
6247 * @param[in,out] pItem Temporary space to store Item, returned item.
6248 *
6249 * See QCBORDecode_GetDoubleConvert().
6250 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006251void
6252QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pMe,
6253 const uint32_t uConvertTypes,
6254 double *pdValue,
6255 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07006256{
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006257 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07006258 return;
6259 }
6260
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006261 QCBORError uError = QCBORDecode_GetNext(pMe, pItem);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006262 if(uError) {
6263 pMe->uLastError = (uint8_t)uError;
6264 return;
6265 }
6266
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006267 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006268 uConvertTypes,
6269 pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006270}
Laurence Lundbladec4537442020-04-14 18:53:22 -07006271
Laurence Lundbladec4537442020-04-14 18:53:22 -07006272
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006273/**
6274 * @brief Almost-public method to decode a number and convert to double (semi-private).
6275 *
6276 * @param[in] pMe The decode context.
6277 * @param[in] nLabel Label to find in map.
6278 * @param[in] uConvertTypes Bit mask list of conversion options
6279 * @param[out] pdValue The output of the conversion.
6280 * @param[in,out] pItem Temporary space to store Item, returned item.
6281 *
6282 * See QCBORDecode_GetDoubleConvertInMapN().
6283 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006284void
6285QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pMe,
6286 const int64_t nLabel,
6287 const uint32_t uConvertTypes,
6288 double *pdValue,
6289 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006290{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006291 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006292 if(pMe->uLastError != QCBOR_SUCCESS) {
6293 return;
6294 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006295
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006296 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6297 uConvertTypes,
6298 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006299}
6300
Laurence Lundblade784b54b2020-08-10 01:24:52 -07006301
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006302/**
6303 * @brief Almost-public method to decode a number and convert to double (semi-private).
6304 *
6305 * @param[in] pMe The decode context.
6306 * @param[in] szLabel Label to find in map.
6307 * @param[in] uConvertTypes Bit mask list of conversion options
6308 * @param[out] pdValue The output of the conversion.
6309 * @param[in,out] pItem Temporary space to store Item, returned item.
6310 *
6311 * See QCBORDecode_GetDoubleConvertInMapSZ().
6312 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006313void
6314QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe,
6315 const char *szLabel,
6316 const uint32_t uConvertTypes,
6317 double *pdValue,
6318 QCBORItem *pItem)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006319{
6320 if(pMe->uLastError != QCBOR_SUCCESS) {
6321 return;
6322 }
6323
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006324 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07006325 if(pMe->uLastError != QCBOR_SUCCESS) {
6326 return;
6327 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006328
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006329 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
6330 uConvertTypes,
6331 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006332}
6333
6334
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006335#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006336/**
6337 * @brief Convert a big number to double-precision float.
6338 *
6339 * @param[in] BigNum The big number to convert
6340 *
6341 * @returns The double value.
6342 *
6343 * This will always succeed. It will lose precision for larger
6344 * numbers. If the big number is too large to fit (more than
6345 * 1.7976931348623157E+308) infinity will be returned. NaN is never
6346 * returned.
6347 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006348static double
6349QCBOR_Private_ConvertBigNumToDouble(const UsefulBufC BigNum)
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006350{
6351 double dResult;
6352
6353 dResult = 0.0;
6354 const uint8_t *pByte = BigNum.ptr;
6355 size_t uLen = BigNum.len;
6356 /* This will overflow and become the float value INFINITY if the number
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006357 * is too large to fit. */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006358 while(uLen--) {
6359 dResult = (dResult * 256.0) + (double)*pByte++;
6360 }
6361
6362 return dResult;
6363}
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006364#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6365
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07006366
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006367
6368
6369/**
6370 * @brief Convert many number types to a double.
6371 *
6372 * @param[in] pItem The item to convert.
6373 * @param[in] uConvertTypes Bit mask list of conversion options.
6374 * @param[out] pdValue The resulting converted value.
6375 *
6376 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
6377 * in uConvertTypes.
6378 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
6379 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
6380 * or too small.
6381 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07006382static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006383QCBOR_Private_DoubleConvertAll(const QCBORItem *pItem,
6384 const uint32_t uConvertTypes,
6385 double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006386{
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006387#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07006388 /*
Laurence Lundblade16a207a2021-09-18 17:22:46 -07006389 * What Every Computer Scientist Should Know About Floating-Point Arithmetic
6390 * https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
6391 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006392 switch(pItem->uDataType) {
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006393
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006394#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006395 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006396 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006397 // Underflow gives 0, overflow gives infinity
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006398 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6399 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
6400 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006401 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006402 }
6403 break;
6404
6405 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006406 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07006407 // Underflow gives 0, overflow gives infinity
6408 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
6409 exp2((double)pItem->val.expAndMantissa.nExponent);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006410 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006411 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006412 }
6413 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006414#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006415
6416 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006417 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006418 *pdValue = QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006419 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006420 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006421 }
6422 break;
6423
6424 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006425 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006426 *pdValue = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006427 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006428 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006429 }
6430 break;
6431
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006432#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006433 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006434 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006435 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006436 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
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_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006443 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006444 double dMantissa = -QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006445 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
6446 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006447 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006448 }
6449 break;
6450
6451 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006452 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006453 double dMantissa = QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006454 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6455 } 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_BIGFLOAT) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006462 double dMantissa = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006463 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
6464 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07006465 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006466 }
6467 break;
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006468#endif /* ndef QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade410c7e02020-06-25 23:35:29 -07006469
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006470 default:
6471 return QCBOR_ERR_UNEXPECTED_TYPE;
6472 }
6473
6474 return QCBOR_SUCCESS;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006475
6476#else
6477 (void)pItem;
6478 (void)uConvertTypes;
6479 (void)pdValue;
6480 return QCBOR_ERR_HW_FLOAT_DISABLED;
6481#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
6482
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006483}
6484
6485
6486/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006487 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006488 */
6489void
6490QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe,
6491 const uint32_t uConvertTypes,
6492 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006493{
6494
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006495 QCBORItem Item;
6496
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006497 QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07006498
6499 if(pMe->uLastError == QCBOR_SUCCESS) {
6500 // The above conversion succeeded
6501 return;
6502 }
6503
6504 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6505 // The above conversion failed in a way that code below can't correct
6506 return;
6507 }
6508
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006509 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6510 uConvertTypes,
6511 pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07006512}
6513
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006514
6515/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006516 * Public function, see header qcbor/qcbor_decode.h file
6517 */
6518void
6519QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe,
6520 const int64_t nLabel,
6521 const uint32_t uConvertTypes,
6522 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006523{
6524 QCBORItem Item;
6525
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006526 QCBORDecode_Private_GetDoubleConvertInMapN(pMe,
6527 nLabel,
6528 uConvertTypes,
6529 pdValue,
6530 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006531
6532 if(pMe->uLastError == QCBOR_SUCCESS) {
6533 // The above conversion succeeded
6534 return;
6535 }
6536
6537 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6538 // The above conversion failed in a way that code below can't correct
6539 return;
6540 }
6541
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006542 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6543 uConvertTypes,
6544 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006545}
6546
6547
6548/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006549 * Public function, see header qcbor/qcbor_decode.h file
6550 */
6551void
6552QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe,
6553 const char *szLabel,
6554 const uint32_t uConvertTypes,
6555 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006556{
6557 QCBORItem Item;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006558 QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe,
6559 szLabel,
6560 uConvertTypes,
6561 pdValue,
6562 &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006563
6564 if(pMe->uLastError == QCBOR_SUCCESS) {
6565 // The above conversion succeeded
6566 return;
6567 }
6568
6569 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
6570 // The above conversion failed in a way that code below can't correct
6571 return;
6572 }
6573
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006574 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
6575 uConvertTypes,
6576 pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07006577}
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02006578#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006579
6580
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006581
6582
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07006583#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006584/**
6585 * @brief Convert an integer to a big number
6586 *
6587 * @param[in] uInt The integer to convert.
6588 * @param[in] Buffer The buffer to output the big number to.
6589 *
6590 * @returns The big number or NULLUsefulBufC is the buffer is to small.
6591 *
6592 * This always succeeds unless the buffer is too small.
6593 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006594static UsefulBufC
6595QCBOR_Private_ConvertIntToBigNum(uint64_t uInt, const UsefulBuf Buffer)
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006596{
6597 while((uInt & 0xff00000000000000UL) == 0) {
6598 uInt = uInt << 8;
6599 };
6600
6601 UsefulOutBuf UOB;
6602
6603 UsefulOutBuf_Init(&UOB, Buffer);
6604
6605 while(uInt) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006606 UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff00000000000000UL) >> 56));
6607 uInt = uInt << 8;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07006608 }
6609
6610 return UsefulOutBuf_OutUBuf(&UOB);
6611}
6612
6613
Laurence Lundblade37286c02022-09-03 10:05:02 -07006614/**
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006615 * @brief Check and/or complete exponent and mantissa item.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006616 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006617 * @param[in] pMe The decoder context.
6618 * @param[in] TagSpec Expected type(s).
6619 * @param[in,out] pItem See below.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006620 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006621 * This is for decimal fractions and big floats, both of which are an
6622 * exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006623 *
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006624 * If the item item had a tag number indicating it was a
6625 * decimal fraction or big float, then the input @c pItem will
6626 * have been decoded as exponent and mantissa. If there was
6627 * no tag number, the caller is asking this be decoded as a
6628 * big float or decimal fraction and @c pItem just has the
6629 * first item in an exponent and mantissa.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006630 *
6631 * On output, the item is always a fully decoded decimal fraction or
6632 * big float.
6633 *
6634 * This errors out if the input type does not meet the TagSpec.
6635 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07006636static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006637QCBOR_Private_ExpMantissaTypeHandler(QCBORDecodeContext *pMe,
6638 const QCBOR_Private_TagSpec TagSpec,
6639 QCBORItem *pItem)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006640{
6641 QCBORError uErr;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006642
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006643 /* pItem could either be a decoded exponent and mantissa or
6644 * the opening array of an undecoded exponent and mantissa. This
Laurence Lundblade37286c02022-09-03 10:05:02 -07006645 * check will succeed on either, but doesn't say which it was.
6646 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006647 uErr = QCBOR_Private_CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07006648 if(uErr != QCBOR_SUCCESS) {
6649 goto Done;
6650 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006651
Laurence Lundblade37286c02022-09-03 10:05:02 -07006652 if(pItem->uDataType == QCBOR_TYPE_ARRAY) {
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006653 /* The item is an array, which means is is an undecoded exponent
6654 * and mantissa. This call consumes the items in the array and
6655 * results in a decoded exponent and mantissa in pItem. This is
Laurence Lundblade37286c02022-09-03 10:05:02 -07006656 * the case where there was no tag.
6657 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006658 uErr = QCBORDecode_Private_ExpMantissa(pMe, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006659 if(uErr != QCBOR_SUCCESS) {
6660 goto Done;
6661 }
6662
Laurence Lundblade37286c02022-09-03 10:05:02 -07006663 /* The above decode didn't determine whether it is a decimal
6664 * fraction or big num. Which of these two depends on what the
6665 * caller wants it decoded as since there is no tag, so fish the
6666 * type out of the TagSpec. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006667 pItem->uDataType = QCBOR_Private_ExpMantissaDataType(TagSpec.uTaggedTypes[0], pItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07006668
6669 /* No need to check the type again. All that we need to know was
Laurence Lundblade23b4ce82024-02-18 21:28:30 -07006670 * that it decoded correctly as a exponent and mantissa. The
Laurence Lundblade37286c02022-09-03 10:05:02 -07006671 * QCBOR type is set out by what was requested.
6672 */
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006673 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07006674
6675 /* If the item was not an array and the check passed, then
6676 * it is a fully decoded big float or decimal fraction and
6677 * matches what is requested.
6678 */
6679
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006680Done:
6681 return uErr;
6682}
6683
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006684
Laurence Lundblade37286c02022-09-03 10:05:02 -07006685/* Some notes from the work to disable tags.
6686 *
6687 * The API for big floats and decimal fractions seems good.
6688 * If there's any issue with it it's that the code size to
6689 * implement is a bit large because of the conversion
6690 * to/from int and bignum that is required. There is no API
6691 * that doesn't do the conversion so dead stripping will never
6692 * leave that code out.
6693 *
6694 * The implementation itself seems correct, but not as clean
6695 * and neat as it could be. It could probably be smaller too.
6696 *
6697 * The implementation has three main parts / functions
6698 * - The decoding of the array of two
6699 * - All the tag and type checking for the various API functions
6700 * - Conversion to/from bignum and int
6701 *
6702 * The type checking seems like it wastes the most code for
6703 * what it needs to do.
6704 *
6705 * The inlining for the conversion is probably making the
6706 * overall code base larger.
6707 *
6708 * The tests cases could be organized a lot better and be
6709 * more thorough.
6710 *
6711 * Seems also like there could be more common code in the
6712 * first tier part of the public API. Some functions only
6713 * vary by a TagSpec.
6714 */
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006715
6716/**
6717 * @brief Common processor for exponent and mantissa.
6718 *
6719 * @param[in] pMe The decode context.
6720 * @param[in] TagSpec The expected/allowed tags.
6721 * @param[in] pItem The data item to process.
6722 * @param[out] pnMantissa The returned mantissa as an int64_t.
6723 * @param[out] pnExponent The returned exponent as an int64_t.
6724 *
6725 * This handles exponent and mantissa for base 2 and 10. This
6726 * is limited to a mantissa that is an int64_t. See also
6727 * QCBORDecode_Private_ProcessExpMantissaBig().
6728 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006729static void
6730QCBOR_Private_ProcessExpMantissa(QCBORDecodeContext *pMe,
6731 const QCBOR_Private_TagSpec TagSpec,
6732 QCBORItem *pItem,
6733 int64_t *pnMantissa,
6734 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006735{
6736 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006737
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006738 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006739 if(uErr != QCBOR_SUCCESS) {
6740 goto Done;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006741 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006742
Laurence Lundblade9b334962020-08-27 10:55:53 -07006743 switch (pItem->uDataType) {
6744
6745 case QCBOR_TYPE_DECIMAL_FRACTION:
6746 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade9b334962020-08-27 10:55:53 -07006747 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006748 *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
Laurence Lundblade9b334962020-08-27 10:55:53 -07006749 break;
6750
Laurence Lundblade37286c02022-09-03 10:05:02 -07006751#ifndef QCBOR_DISABLE_TAGS
6752 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006753 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
6754 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
6755 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006756 uErr = QCBOR_Private_ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006757 break;
6758
6759 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
6760 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
6761 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006762 uErr = QCBOR_Private_ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006763 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006764#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006765
6766 default:
6767 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
6768 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006769
6770 Done:
6771 pMe->uLastError = (uint8_t)uErr;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006772}
6773
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006774
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006775/**
6776 * @brief Decode exponent and mantissa into a big number.
6777 *
6778 * @param[in] pMe The decode context.
6779 * @param[in] TagSpec The expected/allowed tags.
6780 * @param[in] pItem Item to decode and convert.
6781 * @param[in] BufferForMantissa Buffer to output mantissa into.
6782 * @param[out] pMantissa The output mantissa.
6783 * @param[out] pbIsNegative The sign of the output.
6784 * @param[out] pnExponent The mantissa of the output.
6785 *
6786 * This is the common processing of a decimal fraction or a big float
6787 * into a big number. This will decode and consume all the CBOR items
6788 * that make up the decimal fraction or big float.
6789 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006790static void
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006791QCBORDecode_Private_ProcessExpMantissaBig(QCBORDecodeContext *pMe,
6792 const QCBOR_Private_TagSpec TagSpec,
6793 QCBORItem *pItem,
6794 const UsefulBuf BufferForMantissa,
6795 UsefulBufC *pMantissa,
6796 bool *pbIsNegative,
6797 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006798{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006799 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006800
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006801 uErr = QCBOR_Private_ExpMantissaTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006802 if(uErr != QCBOR_SUCCESS) {
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006803 goto Done;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006804 }
6805
6806 uint64_t uMantissa;
6807
6808 switch (pItem->uDataType) {
6809
6810 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006811 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006812 /* See comments in ExponentiateNN() on handling INT64_MIN */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006813 if(pItem->val.expAndMantissa.Mantissa.nInt >= 0) {
6814 uMantissa = (uint64_t)pItem->val.expAndMantissa.Mantissa.nInt;
6815 *pbIsNegative = false;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006816 } else if(pItem->val.expAndMantissa.Mantissa.nInt != INT64_MIN) {
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006817 uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt;
6818 *pbIsNegative = true;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006819 } else {
6820 uMantissa = (uint64_t)INT64_MAX+1;
6821 *pbIsNegative = true;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006822 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006823 *pMantissa = QCBOR_Private_ConvertIntToBigNum(uMantissa,
6824 BufferForMantissa);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006825 *pnExponent = pItem->val.expAndMantissa.nExponent;
6826 break;
6827
Laurence Lundblade37286c02022-09-03 10:05:02 -07006828#ifndef QCBOR_DISABLE_TAGS
6829 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006830 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006831 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006832 *pnExponent = pItem->val.expAndMantissa.nExponent;
6833 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6834 *pbIsNegative = false;
6835 break;
6836
6837 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006838 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006839 *pnExponent = pItem->val.expAndMantissa.nExponent;
6840 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6841 *pbIsNegative = true;
6842 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006843#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006844
6845 default:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006846 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006847 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006848
6849Done:
6850 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006851}
6852
6853
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006854/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006855 * Public function, see header qcbor/qcbor_decode.h file
6856 */
6857void
6858QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe,
6859 const uint8_t uTagRequirement,
6860 int64_t *pnMantissa,
6861 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006862{
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006863 if(pMe->uLastError != QCBOR_SUCCESS) {
6864 return;
6865 }
6866
6867 QCBORItem Item;
6868 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
6869 if(uError) {
6870 pMe->uLastError = (uint8_t)uError;
6871 return;
6872 }
6873
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006874 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006875 {
6876 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006877 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6878 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6879 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006880 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006881
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006882 QCBOR_Private_ProcessExpMantissa(pMe,
6883 TagSpec,
6884 &Item,
6885 pnMantissa,
6886 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006887}
6888
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006889
6890/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006891 * Public function, see header qcbor/qcbor_decode.h file
6892 */
6893void
6894QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe,
6895 const int64_t nLabel,
6896 const uint8_t uTagRequirement,
6897 int64_t *pnMantissa,
6898 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006899{
6900 if(pMe->uLastError != QCBOR_SUCCESS) {
6901 return;
6902 }
6903
6904 QCBORItem Item;
6905 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
6906
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006907 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006908 {
6909 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006910 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6911 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6912 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006913 };
6914
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006915 QCBOR_Private_ProcessExpMantissa(pMe,
6916 TagSpec,
6917 &Item,
6918 pnMantissa,
6919 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006920}
6921
6922
6923/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006924 * Public function, see header qcbor/qcbor_decode.h file
6925 */
6926void
6927QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
6928 const char *szLabel,
6929 const uint8_t uTagRequirement,
6930 int64_t *pnMantissa,
6931 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006932{
6933 if(pMe->uLastError != QCBOR_SUCCESS) {
6934 return;
6935 }
6936
6937 QCBORItem Item;
6938 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
6939
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006940 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006941 {
6942 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006943 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6944 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6945 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006946 };
Laurence Lundblade9b334962020-08-27 10:55:53 -07006947
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006948 QCBOR_Private_ProcessExpMantissa(pMe,
6949 TagSpec,
6950 &Item,
6951 pnMantissa,
6952 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006953}
6954
6955
6956/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006957 * Public function, see header qcbor/qcbor_decode.h file
6958 */
6959void
6960QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe,
6961 const uint8_t uTagRequirement,
6962 const UsefulBuf MantissaBuffer,
6963 UsefulBufC *pMantissa,
6964 bool *pbMantissaIsNegative,
6965 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006966{
6967 if(pMe->uLastError != QCBOR_SUCCESS) {
6968 return;
6969 }
6970
6971 QCBORItem Item;
6972 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
6973 if(uError) {
6974 pMe->uLastError = (uint8_t)uError;
6975 return;
6976 }
6977
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006978 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006979 {
6980 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07006981 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6982 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
6983 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006984 };
6985
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006986 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
6987 TagSpec,
6988 &Item,
6989 MantissaBuffer,
6990 pMantissa,
6991 pbMantissaIsNegative,
6992 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006993}
6994
6995
6996/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006997 * Public function, see header qcbor/qcbor_decode.h file
6998 */
6999void
7000QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe,
7001 const int64_t nLabel,
7002 const uint8_t uTagRequirement,
7003 const UsefulBuf BufferForMantissa,
7004 UsefulBufC *pMantissa,
7005 bool *pbIsNegative,
7006 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007007{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007008 if(pMe->uLastError != QCBOR_SUCCESS) {
7009 return;
7010 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007011
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007012 QCBORItem Item;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007013 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007014 if(pMe->uLastError != QCBOR_SUCCESS) {
7015 return;
7016 }
7017
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007018 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007019 {
7020 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007021 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7022 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7023 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007024 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007025
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007026 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7027 TagSpec,
7028 &Item,
7029 BufferForMantissa,
7030 pMantissa,
7031 pbIsNegative,
7032 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007033}
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007034
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007035
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007036/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007037 * Public function, see header qcbor/qcbor_decode.h file
7038 */
7039void
7040QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe,
7041 const char *szLabel,
7042 const uint8_t uTagRequirement,
7043 const UsefulBuf BufferForMantissa,
7044 UsefulBufC *pMantissa,
7045 bool *pbIsNegative,
7046 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007047{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007048 if(pMe->uLastError != QCBOR_SUCCESS) {
7049 return;
7050 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007051
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007052 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007053 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7054 if(pMe->uLastError != QCBOR_SUCCESS) {
7055 return;
7056 }
7057
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007058 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007059 {
7060 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007061 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
7062 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM, QCBOR_TYPE_NONE},
7063 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007064 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007065
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007066 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7067 TagSpec,
7068 &Item,
7069 BufferForMantissa,
7070 pMantissa,
7071 pbIsNegative,
7072 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007073}
7074
7075
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007076/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007077 * Public function, see header qcbor/qcbor_decode.h file
7078 */
7079void
7080QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe,
7081 const uint8_t uTagRequirement,
7082 int64_t *pnMantissa,
7083 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007084{
7085 if(pMe->uLastError != QCBOR_SUCCESS) {
7086 return;
7087 }
7088
7089 QCBORItem Item;
7090 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
7091 if(uError) {
7092 pMe->uLastError = (uint8_t)uError;
7093 return;
7094 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007095 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007096 {
7097 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007098 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7099 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7100 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007101 };
7102
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007103 QCBOR_Private_ProcessExpMantissa(pMe,
7104 TagSpec,
7105 &Item,
7106 pnMantissa,
7107 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007108}
7109
7110
7111/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007112 * Public function, see header qcbor/qcbor_decode.h file
7113 */
7114void
7115QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe,
7116 const int64_t nLabel,
7117 const uint8_t uTagRequirement,
7118 int64_t *pnMantissa,
7119 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007120{
7121 if(pMe->uLastError != QCBOR_SUCCESS) {
7122 return;
7123 }
7124
7125 QCBORItem Item;
7126 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7127 if(pMe->uLastError != QCBOR_SUCCESS) {
7128 return;
7129 }
7130
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007131 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007132 {
7133 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007134 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7135 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7136 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007137 };
7138
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007139 QCBOR_Private_ProcessExpMantissa(pMe,
7140 TagSpec,
7141 &Item,
7142 pnMantissa,
7143 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007144}
7145
7146
7147/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007148 * Public function, see header qcbor/qcbor_decode.h file
7149 */
7150void
7151QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe,
7152 const char *szLabel,
7153 const uint8_t uTagRequirement,
7154 int64_t *pnMantissa,
7155 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007156{
7157 if(pMe->uLastError != QCBOR_SUCCESS) {
7158 return;
7159 }
7160
7161 QCBORItem Item;
7162 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7163 if(pMe->uLastError != QCBOR_SUCCESS) {
7164 return;
7165 }
7166
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007167 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007168 {
7169 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007170 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7171 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7172 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007173 };
7174
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007175 QCBOR_Private_ProcessExpMantissa(pMe,
7176 TagSpec,
7177 &Item,
7178 pnMantissa,
7179 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007180}
7181
7182
7183/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007184 * Public function, see header qcbor/qcbor_decode.h file
7185 */
7186void
7187QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe,
7188 const uint8_t uTagRequirement,
7189 const UsefulBuf MantissaBuffer,
7190 UsefulBufC *pMantissa,
7191 bool *pbMantissaIsNegative,
7192 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007193{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007194 if(pMe->uLastError != QCBOR_SUCCESS) {
7195 return;
7196 }
7197
7198 QCBORItem Item;
7199 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
7200 if(uError) {
7201 pMe->uLastError = (uint8_t)uError;
7202 return;
7203 }
7204
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007205 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007206 {
7207 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007208 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7209 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7210 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007211 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007212
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007213 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7214 TagSpec,
7215 &Item,
7216 MantissaBuffer,
7217 pMantissa,
7218 pbMantissaIsNegative,
7219 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007220}
7221
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007222
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007223/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007224 * Public function, see header qcbor/qcbor_decode.h file
7225 */
7226void
7227QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe,
7228 const int64_t nLabel,
7229 const uint8_t uTagRequirement,
7230 const UsefulBuf BufferForMantissa,
7231 UsefulBufC *pMantissa,
7232 bool *pbIsNegative,
7233 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007234{
7235 if(pMe->uLastError != QCBOR_SUCCESS) {
7236 return;
7237 }
7238
7239 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007240 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
7241 if(pMe->uLastError != QCBOR_SUCCESS) {
7242 return;
7243 }
7244
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007245 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007246 {
7247 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007248 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7249 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7250 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007251 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007252
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007253 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7254 TagSpec,
7255 &Item,
7256 BufferForMantissa,
7257 pMantissa,
7258 pbIsNegative,
7259 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007260}
7261
7262
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007263/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007264 * Public function, see header qcbor/qcbor_decode.h file
7265 */
7266void
7267QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe,
7268 const char *szLabel,
7269 const uint8_t uTagRequirement,
7270 const UsefulBuf BufferForMantissa,
7271 UsefulBufC *pMantissa,
7272 bool *pbIsNegative,
7273 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007274{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007275 if(pMe->uLastError != QCBOR_SUCCESS) {
7276 return;
7277 }
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007278
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007279 QCBORItem Item;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007280 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
7281 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07007282 return;
7283 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007284
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007285 const QCBOR_Private_TagSpec TagSpec =
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007286 {
7287 uTagRequirement,
Laurence Lundbladec384d4e2020-10-07 09:46:10 -07007288 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
7289 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM, QCBOR_TYPE_NONE},
7290 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007291 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007292
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007293 QCBORDecode_Private_ProcessExpMantissaBig(pMe,
7294 TagSpec,
7295 &Item,
7296 BufferForMantissa,
7297 pMantissa,
7298 pbIsNegative,
7299 pnExponent);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007300}
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007301
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07007302#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */