blob: aa331b691b53e4a0e4043fd4ed1fd037ad463173 [file] [log] [blame]
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001/*==============================================================================
Laurence Lundbladed92a6162018-11-01 11:38:35 +07002 Copyright (c) 2016-2018, The Linux Foundation.
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003 Copyright (c) 2018-2024, Laurence Lundblade.
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02004 Copyright (c) 2021, Arm Limited.
Laurence Lundbladed92a6162018-11-01 11:38:35 +07005 All rights reserved.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08006
Laurence Lundblade0dbc9172018-11-01 14:17:21 +07007Redistribution and use in source and binary forms, with or without
8modification, are permitted provided that the following conditions are
9met:
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above
13 copyright notice, this list of conditions and the following
14 disclaimer in the documentation and/or other materials provided
15 with the distribution.
16 * Neither the name of The Linux Foundation nor the names of its
17 contributors, nor the name "Laurence Lundblade" may be used to
18 endorse or promote products derived from this software without
19 specific prior written permission.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080020
Laurence Lundblade0dbc9172018-11-01 14:17:21 +070021THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
22WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
24ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
25BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
30OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
31IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Laurence Lundbladeee851742020-01-08 08:37:05 -080032 =============================================================================*/
Laurence Lundblade624405d2018-09-18 20:10:47 -070033
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080034
Laurence Lundblade844bb5c2020-03-01 17:27:25 -080035#include "qcbor/qcbor_decode.h"
Laurence Lundblade67257dc2020-07-27 03:33:37 -070036#include "qcbor/qcbor_spiffy_decode.h"
Laurence Lundblade721b56e2024-10-22 03:02:04 -070037#include "qcbor/qcbor_tag_decode.h"
Laurence Lundblade3f1318a2021-01-04 18:26:44 -080038#include "ieee754.h" /* Does not use math.h */
Laurence Lundbladec7114722020-08-13 05:11:40 -070039
40#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade3f1318a2021-01-04 18:26:44 -080041
42#include <math.h> /* For isnan(), llround(), llroudf(), round(), roundf(),
43 * pow(), exp2()
44 */
45#include <fenv.h> /* feclearexcept(), fetestexcept() */
46
Laurence Lundbladee2c893c2020-12-26 17:41:53 -080047#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070048
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070049
Laurence Lundblade68cb61c2023-02-12 13:21:44 -080050#if (defined(__GNUC__) && !defined(__clang__))
Laurence Lundblade8e36f812024-01-26 10:59:29 -070051/*
Laurence Lundblade68cb61c2023-02-12 13:21:44 -080052 * This is how the -Wmaybe-uninitialized compiler warning is
53 * handled. It can’t be ignored because some version of gcc enable it
54 * with -Wall which is a common and useful gcc warning option. It also
55 * can’t be ignored because it is the goal of QCBOR to compile clean
56 * out of the box in all environments.
57 *
58 * The big problem with -Wmaybe-uninitialized is that it generates
59 * false positives. It complains things are uninitialized when they
60 * are not. This is because it is not a thorough static analyzer. This
61 * is why “maybe” is in its name. The problem is it is just not
62 * thorough enough to understand all the code (and someone saw fit to
63 * put it in gcc and worse to enable it with -Wall).
64 *
65 * One solution would be to change the code so -Wmaybe-uninitialized
66 * doesn’t get confused, for example adding an unnecessary extra
67 * initialization to zero. (If variables were truly uninitialized, the
68 * correct path is to understand the code thoroughly and set them to
69 * the correct value at the correct time; in essence this is already
70 * done; -Wmaybe-uninitialized just can’t tell). This path is not
71 * taken because it makes the code bigger and is kind of the tail
72 * wagging the dog.
73 *
74 * The solution here is to just use a pragma to disable it for the
75 * whole file. Disabling it for each line makes the code fairly ugly
76 * requiring #pragma to push, pop and ignore. Another reason is the
77 * warnings issues vary by version of gcc and which optimization
78 * optimizations are selected. Another reason is that compilers other
79 * than gcc don’t have -Wmaybe-uninitialized.
80 *
81 * One may ask how to be sure these warnings are false positives and
82 * not real issues. 1) The code has been read carefully to check. 2)
83 * Testing is pretty thorough. 3) This code has been run through
84 * thorough high-quality static analyzers.
85 *
86 * In particularly, most of the warnings are about
87 * Item.Item->uDataType being uninitialized. QCBORDecode_GetNext()
88 * *always* sets this value and test case confirm
89 * this. -Wmaybe-uninitialized just can't tell.
90 *
91 * https://stackoverflow.com/questions/5080848/disable-gcc-may-be-used-uninitialized-on-a-particular-variable
92 */
93#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
Laurence Lundblade8e36f812024-01-26 10:59:29 -070094#endif
Laurence Lundblade68cb61c2023-02-12 13:21:44 -080095
96
Laurence Lundblade8e36f812024-01-26 10:59:29 -070097static bool
98QCBORItem_IsMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -070099{
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700100 const uint8_t uDataType = Item.uDataType;
Laurence Lundblade02625d42020-06-25 14:41:41 -0700101 return uDataType == QCBOR_TYPE_MAP ||
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700102#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
103 uDataType == QCBOR_TYPE_MAP_AS_ARRAY ||
104#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
105 uDataType == QCBOR_TYPE_ARRAY;
Laurence Lundblade02625d42020-06-25 14:41:41 -0700106}
107
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700108static bool
109QCBORItem_IsEmptyDefiniteLengthMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700110{
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700111 if(!QCBORItem_IsMapOrArray(Item)){
Laurence Lundblade02625d42020-06-25 14:41:41 -0700112 return false;
113 }
114
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700115 if(Item.val.uCount != 0) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700116 return false;
117 }
118 return true;
119}
120
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700121static bool
122QCBORItem_IsIndefiniteLengthMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700123{
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800124#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700125 if(!QCBORItem_IsMapOrArray(Item)){
Laurence Lundblade02625d42020-06-25 14:41:41 -0700126 return false;
127 }
128
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700129 if(Item.val.uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700130 return false;
131 }
132 return true;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800133#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700134 (void)Item;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800135 return false;
136#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700137}
138
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700139/* Return true if the labels in Item1 and Item2 are the same.
140 Works only for integer and string labels. Returns false
141 for any other type. */
142static bool
143QCBORItem_MatchLabel(const QCBORItem Item1, const QCBORItem Item2)
144{
145 if(Item1.uLabelType == QCBOR_TYPE_INT64) {
146 if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
147 return true;
148 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700149#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700150 } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
151 if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
152 return true;
153 }
154 } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
155 if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
156 return true;
157 }
158 } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
159 if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
160 return true;
161 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700162#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700163 }
164
165 /* Other label types are never matched */
166 return false;
167}
168
169
170/*
171 Returns true if Item1 and Item2 are the same type
172 or if either are of QCBOR_TYPE_ANY.
173 */
174static bool
175QCBORItem_MatchType(const QCBORItem Item1, const QCBORItem Item2)
176{
177 if(Item1.uDataType == Item2.uDataType) {
178 return true;
179 } else if(Item1.uDataType == QCBOR_TYPE_ANY) {
180 return true;
181 } else if(Item2.uDataType == QCBOR_TYPE_ANY) {
182 return true;
183 }
184 return false;
185}
186
Laurence Lundblade02625d42020-06-25 14:41:41 -0700187
Laurence Lundbladeee851742020-01-08 08:37:05 -0800188/*===========================================================================
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700189 DecodeNesting -- Tracking array/map/sequence/bstr-wrapped nesting
Laurence Lundbladeee851742020-01-08 08:37:05 -0800190 ===========================================================================*/
191
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700192/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800193 * See comments about and typedef of QCBORDecodeNesting in qcbor_private.h,
194 * the data structure all these functions work on.
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700195 */
196
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700197
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700198static uint8_t
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700199DecodeNesting_GetCurrentLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700200{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700201 const ptrdiff_t nLevel = pNesting->pCurrent - &(pNesting->pLevels[0]);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800202 /* Limit in DecodeNesting_Descend against more than
203 * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
Laurence Lundblade02625d42020-06-25 14:41:41 -0700204 */
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700205 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700206}
207
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700208
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700209static uint8_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700210DecodeNesting_GetBoundedModeLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700211{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700212 const ptrdiff_t nLevel = pNesting->pCurrentBounded - &(pNesting->pLevels[0]);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800213 /* Limit in DecodeNesting_Descend against more than
214 * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
Laurence Lundblade02625d42020-06-25 14:41:41 -0700215 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700216 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700217}
218
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700219
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700220static uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700221DecodeNesting_GetMapOrArrayStart(const QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700222{
223 return pNesting->pCurrentBounded->u.ma.uStartOffset;
224}
225
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700226
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700227static bool
Laurence Lundblade085d7952020-07-24 10:26:30 -0700228DecodeNesting_IsBoundedEmpty(const QCBORDecodeNesting *pNesting)
229{
230 if(pNesting->pCurrentBounded->u.ma.uCountCursor == QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
231 return true;
232 } else {
233 return false;
234 }
235}
236
237
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700238static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700239DecodeNesting_IsCurrentAtTop(const QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700240{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700241 if(pNesting->pCurrent == &(pNesting->pLevels[0])) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700242 return true;
243 } else {
244 return false;
245 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700246}
247
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700248
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700249static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700250DecodeNesting_IsCurrentDefiniteLength(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700251{
252 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800253 /* Not a map or array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700254 return false;
255 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800256
257#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700258 if(pNesting->pCurrent->u.ma.uCountTotal == QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800259 /* Is indefinite */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700260 return false;
261 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800262
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800263#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
264
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800265 /* All checks passed; is a definte length map or array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700266 return true;
267}
268
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700269static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700270DecodeNesting_IsCurrentBstrWrapped(const QCBORDecodeNesting *pNesting)
Laurence Lundblade642282a2020-06-23 12:00:33 -0700271{
272 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800273 /* is a byte string */
Laurence Lundblade642282a2020-06-23 12:00:33 -0700274 return true;
275 }
276 return false;
277}
278
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700279
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700280static bool
281DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700282{
283 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
284 return true;
285 }
Laurence Lundblade02625d42020-06-25 14:41:41 -0700286 if(pNesting->pCurrent->u.ma.uStartOffset != QCBOR_NON_BOUNDED_OFFSET) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700287 return true;
288 }
289 return false;
290}
291
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700292
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700293static void
294DecodeNesting_SetMapOrArrayBoundedMode(QCBORDecodeNesting *pNesting, bool bIsEmpty, size_t uStart)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700295{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800296 /* Should be only called on maps and arrays */
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700297 /*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800298 * DecodeNesting_EnterBoundedMode() checks to be sure uStart is not
299 * larger than DecodeNesting_EnterBoundedMode which keeps it less than
300 * uin32_t so the cast is safe.
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700301 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700302 pNesting->pCurrent->u.ma.uStartOffset = (uint32_t)uStart;
Laurence Lundblade085d7952020-07-24 10:26:30 -0700303
304 if(bIsEmpty) {
305 pNesting->pCurrent->u.ma.uCountCursor = QCBOR_COUNT_INDICATES_ZERO_LENGTH;
306 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700307}
308
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700309
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700310static void
311DecodeNesting_ClearBoundedMode(QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700312{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700313 pNesting->pCurrent->u.ma.uStartOffset = QCBOR_NON_BOUNDED_OFFSET;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700314}
315
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700316
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700317static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700318DecodeNesting_IsAtEndOfBoundedLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700319{
320 if(pNesting->pCurrentBounded == NULL) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800321 /* No bounded map or array set up */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700322 return false;
323 }
324 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800325 /* Not a map or array; end of those is by byte count */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700326 return false;
327 }
Laurence Lundblade6ab01fb2020-10-01 13:04:49 -0700328 if(!DecodeNesting_IsCurrentBounded(pNesting)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800329 /* In a traveral at a level deeper than the bounded level */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700330 return false;
331 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800332 /* Works for both definite- and indefinitelength maps/arrays */
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800333 if(pNesting->pCurrentBounded->u.ma.uCountCursor != 0 &&
334 pNesting->pCurrentBounded->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800335 /* Count is not zero, still unconsumed item */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700336 return false;
337 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800338 /* All checks passed, got to the end of an array or map*/
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700339 return true;
340}
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700341
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700342
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700343static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700344DecodeNesting_IsEndOfDefiniteLengthMapOrArray(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700345{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800346 /* Must only be called on map / array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700347 if(pNesting->pCurrent->u.ma.uCountCursor == 0) {
348 return true;
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700349 } else {
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700350 return false;
351 }
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700352}
353
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700354
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700355static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700356DecodeNesting_IsCurrentTypeMap(const QCBORDecodeNesting *pNesting)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700357{
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700358 if(pNesting->pCurrent->uLevelType == CBOR_MAJOR_TYPE_MAP) {
359 return true;
360 } else {
361 return false;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700362 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700363}
364
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700365
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700366static bool
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700367DecodeNesting_IsBoundedType(const QCBORDecodeNesting *pNesting, uint8_t uType)
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700368{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700369 if(pNesting->pCurrentBounded == NULL) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700370 return false;
371 }
Laurence Lundblade02625d42020-06-25 14:41:41 -0700372
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700373 uint8_t uItemDataType = pNesting->pCurrentBounded->uLevelType;
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700374#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700375 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
376 uItemDataType = QCBOR_TYPE_ARRAY;
377 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700378#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700379
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 Lundbladeb95afec2024-08-26 10:51:28 -0700458 const uint8_t uQCBORType,
459 const uint16_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 Lundbladeb95afec2024-08-26 10:51:28 -0700471 /* Rely on check in QCBOR_Private_DecodeArrayOrMap() for definite-length
472 * arrays and maps that are too long */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700473
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700474 uError = DecodeNesting_Descend(pNesting, uQCBORType);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700475 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700476 goto Done;
477 }
478
Laurence Lundbladeb95afec2024-08-26 10:51:28 -0700479 pNesting->pCurrent->u.ma.uCountCursor = uCount;
480 pNesting->pCurrent->u.ma.uCountTotal = uCount;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700481
482 DecodeNesting_ClearBoundedMode(pNesting);
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700483
484Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700485 return uError;;
486}
487
488
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700489static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700490DecodeNesting_LevelUpCurrent(QCBORDecodeNesting *pNesting)
491{
492 pNesting->pCurrent = pNesting->pCurrentBounded - 1;
493}
494
495
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700496static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700497DecodeNesting_LevelUpBounded(QCBORDecodeNesting *pNesting)
498{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700499 while(pNesting->pCurrentBounded != &(pNesting->pLevels[0])) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700500 pNesting->pCurrentBounded--;
501 if(DecodeNesting_IsCurrentBounded(pNesting)) {
502 break;
503 }
504 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700505}
506
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800507
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700508static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700509DecodeNesting_SetCurrentToBoundedLevel(QCBORDecodeNesting *pNesting)
510{
511 pNesting->pCurrent = pNesting->pCurrentBounded;
512}
513
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700514
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700515static QCBORError
Laurence Lundblade02625d42020-06-25 14:41:41 -0700516DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting,
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700517 uint32_t uEndOffset,
518 uint32_t uStartOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700519{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700520 QCBORError uError;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700521
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700522 uError = DecodeNesting_Descend(pNesting, QCBOR_TYPE_BYTE_STRING);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700523 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700524 goto Done;
525 }
526
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800527 /* Fill in the new byte string level */
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700528 pNesting->pCurrent->u.bs.uSavedEndOffset = uEndOffset;
529 pNesting->pCurrent->u.bs.uBstrStartOffset = uStartOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700530
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800531 /* Bstr wrapped levels are always bounded */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700532 pNesting->pCurrentBounded = pNesting->pCurrent;
533
534Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700535 return uError;;
536}
537
Laurence Lundbladed0304932020-06-27 10:59:38 -0700538
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700539static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700540DecodeNesting_ZeroMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700541{
542 pNesting->pCurrent->u.ma.uCountCursor = 0;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700543}
544
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700545
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700546static void
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800547DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting)
548{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700549 if(pNesting->pCurrent->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
550 pNesting->pCurrentBounded->u.ma.uCountCursor = pNesting->pCurrentBounded->u.ma.uCountTotal;
551 }
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800552}
553
554
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700555static void
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700556DecodeNesting_Init(QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700557{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700558 /* Assumes that *pNesting has been zero'd before this call. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700559 pNesting->pLevels[0].uLevelType = QCBOR_TYPE_BYTE_STRING;
560 pNesting->pCurrent = &(pNesting->pLevels[0]);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700561}
562
563
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700564static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800565DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting,
566 QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700567{
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700568 *pSave = *pNesting;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700569}
570
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700571
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700572static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800573DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting,
574 const QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700575{
576 *pNesting = *pSave;
577}
578
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700579
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700580static uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700581DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700582{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700583 return pMe->pCurrentBounded->u.bs.uSavedEndOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700584}
585
586
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800587
588
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800589#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladeee851742020-01-08 08:37:05 -0800590/*===========================================================================
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800591 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
592
593 The following four functions are pretty wrappers for invocation of
594 the string allocator supplied by the caller.
595
Laurence Lundbladeee851742020-01-08 08:37:05 -0800596 ===========================================================================*/
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800597
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700598static void
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800599StringAllocator_Free(const QCBORInternalAllocator *pMe, const void *pMem)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800600{
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300601 /* This cast to uintptr_t suppresses the "-Wcast-qual" warnings.
602 * This is the one place where the const needs to be cast away so const can
603 * be use in the rest of the code.
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800604 */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300605 (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, 0);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800606}
607
Laurence Lundbladeee851742020-01-08 08:37:05 -0800608// StringAllocator_Reallocate called with pMem NULL is
609// equal to StringAllocator_Allocate()
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700610static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800611StringAllocator_Reallocate(const QCBORInternalAllocator *pMe,
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800612 const void *pMem,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800613 size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800614{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800615 /* See comment in StringAllocator_Free() */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300616 return (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, uSize);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800617}
618
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700619static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800620StringAllocator_Allocate(const QCBORInternalAllocator *pMe, size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800621{
622 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
623}
624
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700625static void
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800626StringAllocator_Destruct(const QCBORInternalAllocator *pMe)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800627{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800628 /* See comment in StringAllocator_Free() */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800629 if(pMe->pfAllocator) {
630 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
631 }
632}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800633#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800634
635
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800636
637
Laurence Lundbladeee851742020-01-08 08:37:05 -0800638/*===========================================================================
639 QCBORDecode -- The main implementation of CBOR decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700640
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800641 See qcbor/qcbor_decode.h for definition of the object
642 used here: QCBORDecodeContext
Laurence Lundbladeee851742020-01-08 08:37:05 -0800643 ===========================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700644/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800645 * Public function, see header file
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700646 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700647void
648QCBORDecode_Init(QCBORDecodeContext *pMe,
649 UsefulBufC EncodedCBOR,
Laurence Lundblade36b28f92024-11-19 21:47:28 -0800650 QCBORDecodeMode uConfigFlags)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700651{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800652 memset(pMe, 0, sizeof(QCBORDecodeContext));
653 UsefulInputBuf_Init(&(pMe->InBuf), EncodedCBOR);
654 /* Don't bother with error check on decode mode. If a bad value is
655 * passed it will just act as if the default normal mode of 0 was set.
656 */
Laurence Lundblade36b28f92024-11-19 21:47:28 -0800657 pMe->uDecodeMode = (uint32_t)uConfigFlags;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800658 DecodeNesting_Init(&(pMe->nesting));
659
660 /* Inialize me->auMappedTags to CBOR_TAG_INVALID16. See
661 * GetNext_TaggedItem() and MapTagNumber(). */
662 memset(pMe->auMappedTags, 0xff, sizeof(pMe->auMappedTags));
Laurence Lundblade721b56e2024-10-22 03:02:04 -0700663
664 pMe->uTagNumberCheckOffset = SIZE_MAX;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700665}
666
667
Laurence Lundblade721b56e2024-10-22 03:02:04 -0700668/*
669 * Public function, see header file
670 */
671void
672QCBORDecode_CompatibilityV1(QCBORDecodeContext *pMe)
673{
674 pMe->uDecodeMode |= QCBOR_DECODE_UNPROCESSED_TAG_NUMBERS;
675#ifndef QCBOR_DISABLE_TAGS
676 QCBORDecode_InstallTagDecoders(pMe, QCBORDecode_TagDecoderTablev1, NULL);
677#endif /* ! QCBOR_DISABLE_TAGS */
678}
679
680
681
682
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800683#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
684
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700685/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800686 * Public function, see header file
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700687 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700688void
689QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
690 QCBORStringAllocate pfAllocateFunction,
691 void *pAllocateContext,
692 bool bAllStrings)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700693{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800694 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
695 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
696 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700697}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800698#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700699
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800700
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800701
702
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800703
704
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700705/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800706 * Decoding items is done in six layers, one calling the next one
707 * down. If a layer has no work to do for a particular item, it
708 * returns quickly.
709 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700710 * 1. QCBORDecode_Private_GetNextTagContent - The top layer processes
711 * tagged data items, turning them into the local C representation.
712 * For the most simple it is just associating a QCBOR_TYPE with the
713 * data. For the complex ones that an aggregate of data items, there
714 * is some further decoding and some limited recursion.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800715 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700716 * 2. QCBORDecode_Private_GetNextMapOrArray - This manages the
717 * beginnings and ends of maps and arrays. It tracks descending into
718 * and ascending out of maps/arrays. It processes breaks that
719 * terminate indefinite-length maps and arrays.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800720 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700721 * 3. QCBORDecode_Private_GetNextMapEntry - This handles the combining
722 * of two items, the label and the data, that make up a map entry. It
723 * only does work on maps. It combines the label and data items into
724 * one labeled item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800725 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700726 * 4. QCBORDecode_Private_GetNextTagNumber - This decodes type 6 tag
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800727 * numbers. It turns the tag numbers into bit flags associated with
728 * the data item. No actual decoding of the contents of the tag is
729 * performed here.
730 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700731 * 5. QCBORDecode_Private_GetNextFullString - This assembles the
732 * sub-items that make up an indefinite-length string into one string
733 * item. It uses the string allocator to create contiguous space for
734 * the item. It processes all breaks that are part of
735 * indefinite-length strings.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800736 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700737 * 6. QCBOR_Private_DecodeAtomicDataItem - This decodes the atomic
738 * data items in CBOR. Each atomic data item has a "major type", an
739 * integer "argument" and optionally some content. For text and byte
740 * strings, the content is the bytes that make up the string. These
741 * are the smallest data items that are considered to be well-formed.
742 * The content may also be other data items in the case of aggregate
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800743 * types. They are not handled in this layer.
744 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700745 * This uses about 350 bytes of stack. This number comes from
746 * instrumenting (printf address of stack variables) the code on x86
747 * compiled for size optimization.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700748 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800749
750
751/*
752 * Note about use of int and unsigned variables.
753 *
754 * See http://www.unix.org/whitepapers/64bit.html for reasons int is
755 * used carefully here, and in particular why it isn't used in the
756 * public interface. Also see
757 * https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers
758 *
759 * Int is used for values that need less than 16-bits and would be
760 * subject to integer promotion and result in complaining from static
761 * analyzers.
762 */
763
764
765/**
766 * @brief Decode the CBOR head, the type and argument.
767 *
768 * @param[in] pUInBuf The input buffer to read from.
Laurence Lundblade36b28f92024-11-19 21:47:28 -0800769 * @param[in] uConfigFlags Decode mode flags.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800770 * @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
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700778 * longer description in QCBOREncode_EncodeHead().
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800779 *
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700780 * This does the network to host byte order conversion. The conversion
781 * here also provides the conversion for floats in addition to that
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800782 * for lengths, tags and integer values.
783 *
784 * The int type is preferred to uint8_t for some variables as this
785 * avoids integer promotions, can reduce code size and makes static
786 * analyzers happier.
787 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700788static QCBORError
Laurence Lundblade36b28f92024-11-19 21:47:28 -0800789QCBOR_Private_DecodeHead(UsefulInputBuf *pUInBuf,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700790#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
Laurence Lundblade36b28f92024-11-19 21:47:28 -0800791 QCBORDecodeMode uConfigFlags,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700792#endif
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700793 int *pnMajorType,
794 uint64_t *puArgument,
795 int *pnAdditionalInfo)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700796{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800797 QCBORError uReturn;
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700798 uint64_t uArgument;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800799
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700800 /* Get and break down initial byte that every CBOR data item has */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800801 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800802 const int nTmpMajorType = nInitialByte >> 5;
803 const int nAdditionalInfo = nInitialByte & 0x1f;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800804
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800805 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800806 /* Need to get 1,2,4 or 8 additional argument bytes. Map
807 * LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length.
808 */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800809 static const uint8_t aIterate[] = {1,2,4,8};
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800810
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800811 /* Loop getting all the bytes in the argument */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800812 uArgument = 0;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800813 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700814 /* This shift-and-add gives the endian conversion. */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800815 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
816 }
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700817
818#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
819 /* If requested, check that argument is in preferred form */
Laurence Lundblade36b28f92024-11-19 21:47:28 -0800820 if(uConfigFlags & QCBOR_DECODE_ONLY_PREFERRED_NUMBERS) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700821 uint64_t uMinArgument;
822
823 if(nAdditionalInfo == LEN_IS_ONE_BYTE) {
824 if(uArgument < 24) {
825 uReturn = QCBOR_ERR_PREFERRED_CONFORMANCE;
826 goto Done;
827 }
828 } else {
829 if(nTmpMajorType != CBOR_MAJOR_TYPE_SIMPLE) {
830 /* Check only if not a floating-point number */
831 int nArgLen = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE - 1];
832 uMinArgument = UINT64_MAX >> ((int)sizeof(uint64_t) - nArgLen) * 8;
833 if(uArgument <= uMinArgument) {
834 uReturn = QCBOR_ERR_PREFERRED_CONFORMANCE;
835 goto Done;
836 }
837 }
838 }
839 }
840#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
841
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800842 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800843 /* The reserved and thus-far unused additional info values */
844 uReturn = QCBOR_ERR_UNSUPPORTED;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800845 goto Done;
846 } else {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700847#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
Laurence Lundblade36b28f92024-11-19 21:47:28 -0800848 if(uConfigFlags & QCBOR_DECODE_NO_INDEF_LENGTH && nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700849 uReturn = QCBOR_ERR_PREFERRED_CONFORMANCE;
850 goto Done;
851 }
852#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
853
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800854 /* Less than 24, additional info is argument or 31, an
855 * indefinite-length. No more bytes to get.
856 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800857 uArgument = (uint64_t)nAdditionalInfo;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700858 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800859
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700860 if(UsefulInputBuf_GetError(pUInBuf)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800861 uReturn = QCBOR_ERR_HIT_END;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700862 goto Done;
863 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800864
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800865 /* All successful if arrived here. */
866 uReturn = QCBOR_SUCCESS;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800867 *pnMajorType = nTmpMajorType;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800868 *puArgument = uArgument;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800869 *pnAdditionalInfo = nAdditionalInfo;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800870
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700871Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800872 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700873}
874
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800875
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800876/**
877 * @brief Decode integer types, major types 0 and 1.
878 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700879 * @param[in] nMajorType The CBOR major type (0 or 1).
880 * @param[in] uArgument The argument from the head.
881 * @param[in] nAdditionalInfo So it can be error-checked.
882 * @param[out] pDecodedItem The filled in decoded item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800883 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700884 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered.
885 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800886 *
887 * Must only be called when major type is 0 or 1.
888 *
889 * CBOR doesn't explicitly specify two's compliment for integers but
890 * all CPUs use it these days and the test vectors in the RFC are
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700891 * so. All integers in encoded CBOR are unsigned and the CBOR major
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800892 * type indicates positive or negative. CBOR can express positive
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700893 * integers up to 2^64 - 1 negative integers down to -2^64. Note that
894 * negative numbers can be one more
895 * away from zero than positive because there is no negative zero.
896 *
897 * The "65-bit negs" are values CBOR can encode that can't fit
898 * into an int64_t or uint64_t. They decoded as a special type
899 * QCBOR_TYPE_65BIT_NEG_INT. Not that this type does NOT
900 * take into account the offset of one for CBOR negative integers.
901 * It must be applied to get the correct value. Applying this offset
902 * would overflow a uint64_t.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700903 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700904static QCBORError
905QCBOR_Private_DecodeInteger(const int nMajorType,
906 const uint64_t uArgument,
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700907 const int nAdditionalInfo,
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700908 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700909{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800910 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800911
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700912 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
913 uReturn = QCBOR_ERR_BAD_INT;
914 goto Done;
915 }
916
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700917 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800918 if (uArgument <= INT64_MAX) {
919 pDecodedItem->val.int64 = (int64_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700920 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800921
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700922 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800923 pDecodedItem->val.uint64 = uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700924 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700925 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800926
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700927 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800928 if(uArgument <= INT64_MAX) {
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700929 /* INT64_MIN is one further away from 0 than INT64_MAX
930 * so the -1 here doesn't overflow. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800931 pDecodedItem->val.int64 = (-(int64_t)uArgument) - 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700932 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800933
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700934 } else {
Laurence Lundblade2d493002024-02-01 11:09:17 -0700935 pDecodedItem->val.uint64 = uArgument;
936 pDecodedItem->uDataType = QCBOR_TYPE_65BIT_NEG_INT;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700937 }
938 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800939
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700940Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800941 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700942}
943
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800944
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700945/**
946 * @brief Decode text and byte strings
947 *
948 * @param[in] pMe Decoder context.
949 * @param[in] bAllocate Whether to allocate and copy string.
950 * @param[in] nMajorType Whether it is a byte or text string.
951 * @param[in] uStrLen The length of the string.
952 * @param[in] nAdditionalInfo Whether it is an indefinite-length string.
953 * @param[out] pDecodedItem The filled-in decoded item.
954 *
955 * @retval QCBOR_ERR_HIT_END Unexpected end of input.
956 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
957 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
958 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator
959 *
960 * This reads @c uStrlen bytes from the input and fills in @c
961 * pDecodedItem. If @c bAllocate is true, then memory for the string
962 * is allocated.
963 */
964static QCBORError
965QCBOR_Private_DecodeString(QCBORDecodeContext *pMe,
966 const bool bAllocate,
967 const int nMajorType,
968 const uint64_t uStrLen,
969 const int nAdditionalInfo,
970 QCBORItem *pDecodedItem)
971{
972 QCBORError uReturn = QCBOR_SUCCESS;
973
974 /* ---- Figure out the major type ---- */
975 #if CBOR_MAJOR_TYPE_BYTE_STRING + 4 != QCBOR_TYPE_BYTE_STRING
976 #error QCBOR_TYPE_BYTE_STRING not lined up with major type
977 #endif
978
979 #if CBOR_MAJOR_TYPE_TEXT_STRING + 4 != QCBOR_TYPE_TEXT_STRING
980 #error QCBOR_TYPE_TEXT_STRING not lined up with major type
981 #endif
982 pDecodedItem->uDataType = (uint8_t)(nMajorType + 4);
983
984 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
985 /* --- Just the head of an indefinite-length string --- */
986 pDecodedItem->val.string = (UsefulBufC){NULL, QCBOR_STRING_LENGTH_INDEFINITE};
987
988 } else {
989 /* --- A definite-length string --- */
990 /* --- (which might be a chunk of an indefinte-length string) --- */
991
992 /* CBOR lengths can be 64 bits, but size_t is not 64 bits on all
993 * CPUs. This check makes the casts to size_t below safe.
994 *
995 * The max is 4 bytes less than the largest sizeof() so this can be
996 * tested by putting a SIZE_MAX length in the CBOR test input (no
997 * one will care the limit on strings is 4 bytes shorter).
998 */
999 if(uStrLen > SIZE_MAX-4) {
1000 uReturn = QCBOR_ERR_STRING_TOO_LONG;
1001 goto Done;
1002 }
1003
1004 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(&(pMe->InBuf), (size_t)uStrLen);
1005 if(UsefulBuf_IsNULLC(Bytes)) {
1006 /* Failed to get the bytes for this string item */
1007 uReturn = QCBOR_ERR_HIT_END;
1008 goto Done;
1009 }
1010
1011 if(bAllocate) {
1012#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
1013 /* --- Put string in allocated memory --- */
1014
1015 /* Note that this is not where allocation to coalesce
1016 * indefinite-length strings is done. This is for when the
1017 * caller has requested all strings be allocated. Disabling
1018 * indefinite length strings also disables this allocate-all
1019 * option.
1020 */
1021
1022 if(pMe->StringAllocator.pfAllocator == NULL) {
1023 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1024 goto Done;
1025 }
1026 UsefulBuf NewMem = StringAllocator_Allocate(&(pMe->StringAllocator), (size_t)uStrLen);
1027 if(UsefulBuf_IsNULL(NewMem)) {
1028 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1029 goto Done;
1030 }
1031 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
1032 pDecodedItem->uDataAlloc = 1;
1033#else
1034 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1035#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1036 } else {
1037 /* --- Normal case with no string allocator --- */
1038 pDecodedItem->val.string = Bytes;
1039 }
1040 }
1041
1042Done:
1043 return uReturn;
1044}
1045
1046
1047/**
1048 * @brief Decode array or map.
1049 *
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001050 * @param[in] uConfigFlags Decoder mode.
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001051 * @param[in] nMajorType Whether it is a byte or text string.
1052 * @param[in] uItemCount The length of the string.
1053 * @param[in] nAdditionalInfo Whether it is an indefinite-length.
1054 * @param[out] pDecodedItem The filled-in decoded item.
1055 *
1056 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinites disabled.
1057 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map.
1058 *
1059 * Not much to do for arrays and maps. Just the type item count (but a
1060 * little messy because of ifdefs for indefinite-lengths and
1061 * map-as-array decoding).
1062 *
1063 * This also does the bulk of the work for @ref
1064 * QCBOR_DECODE_MODE_MAP_AS_ARRAY, a special mode to handle
1065 * arbitrarily complex map labels. This ifdefs out with
1066 * QCBOR_DISABLE_NON_INTEGER_LABELS.
1067 */
1068static QCBORError
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001069QCBOR_Private_DecodeArrayOrMap(const QCBORDecodeMode uConfigFlags,
1070 const int nMajorType,
1071 uint64_t uItemCount,
1072 const int nAdditionalInfo,
1073 QCBORItem *pDecodedItem)
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001074{
1075 QCBORError uReturn;
1076
1077 /* ------ Sort out the data type ------ */
1078 #if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
1079 #error QCBOR_TYPE_ARRAY value not lined up with major type
1080 #endif
1081
1082 #if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
1083 #error QCBOR_TYPE_MAP value not lined up with major type
1084 #endif
1085 pDecodedItem->uDataType = (uint8_t)nMajorType;
1086#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001087 if((uConfigFlags & QCBOR_DECODE_MODE_MAP_AS_ARRAY) && nMajorType == QCBOR_TYPE_MAP) {
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001088 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
1089 }
1090#else
Laurence Lundbladed76f0432024-11-21 21:06:20 -08001091 (void)uConfigFlags;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001092#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
1093
1094 uReturn = QCBOR_SUCCESS;
1095
1096 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1097 /* ------ Indefinite-length array/map ----- */
1098#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
1099 pDecodedItem->val.uCount = QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH;
1100#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1101 uReturn = QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED;
1102#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1103 } else {
Laurence Lundbladeb95afec2024-08-26 10:51:28 -07001104 /* ----- Definite-length array/map ----- */
1105 if(uItemCount > (nMajorType == QCBOR_TYPE_MAP ? QCBOR_MAX_ITEMS_IN_MAP : QCBOR_MAX_ITEMS_IN_ARRAY)) {
1106 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001107
Laurence Lundbladeb95afec2024-08-26 10:51:28 -07001108 } else {
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001109#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001110 if((uConfigFlags & QCBOR_DECODE_MODE_MAP_AS_ARRAY) && nMajorType == QCBOR_TYPE_MAP) {
Laurence Lundbladeb95afec2024-08-26 10:51:28 -07001111 /* ------ Map as array ------ */
1112 uItemCount *= 2;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001113 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001114#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundbladeb95afec2024-08-26 10:51:28 -07001115
1116 /* cast OK because of check above */
1117 pDecodedItem->val.uCount = (uint16_t)uItemCount;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001118 }
1119 }
1120
1121 return uReturn;
1122}
1123
1124
1125/**
1126 * @brief Decode a tag number.
1127 *
1128 * @param[in] uTagNumber The length of the string.
1129 * @param[in] nAdditionalInfo So this can be error-checked.
1130 * @param[out] pDecodedItem The filled-in decoded item.
1131 *
1132 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo is LEN_IS_INDEFINITE.
1133 * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined.
1134 *
1135 * Not much to do for tags, but fill in pDecodedItem and check for
1136 * error in nAdditionalInfo.
1137 */
1138static QCBORError
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001139QCBOR_Private_DecodeTagNumber(const uint64_t uTagNumber,
1140 const int nAdditionalInfo,
1141 QCBORItem *pDecodedItem)
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001142{
1143#ifndef QCBOR_DISABLE_TAGS
1144 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1145 return QCBOR_ERR_BAD_INT;
1146 } else {
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001147 pDecodedItem->val.uTagNumber = uTagNumber;
1148 pDecodedItem->uDataType = QCBOR_TYPE_TAG_NUMBER;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001149 return QCBOR_SUCCESS;
1150 }
1151#else /* QCBOR_DISABLE_TAGS */
1152 (void)nAdditionalInfo;
Laurence Lundblade6c9a8242024-06-12 20:34:52 -07001153 (void)uTagNumber;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001154 (void)pDecodedItem;
1155 return QCBOR_ERR_TAGS_DISABLED;
1156#endif /* QCBOR_DISABLE_TAGS */
1157}
1158
1159
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001160#ifndef USEFULBUF_DISABLE_ALL_FLOAT
1161
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001162#if !defined(QCBOR_DISABLE_DECODE_CONFORMANCE) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
1163
1164static QCBORError
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001165QCBORDecode_Private_HalfConformance(const double d, const QCBORDecodeMode uConfigFlags)
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001166{
1167 struct IEEE754_ToInt ToInt;
1168
1169 /* Only need to check for conversion to integer because
1170 * half-precision is always preferred serialization. Don't
1171 * need special checker for half-precision because whole
1172 * numbers always convert perfectly from half to double.
1173 *
1174 * This catches half-precision with NaN payload too.
1175 *
1176 * The only thing allowed here is a double/half-precision that
1177 * can't be converted to anything but a double.
1178 */
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001179 if(uConfigFlags & QCBOR_DECODE_ONLY_REDUCED_FLOATS) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001180 ToInt = IEEE754_DoubleToInt(d);
1181 if(ToInt.type != QCBOR_TYPE_DOUBLE) {
1182 return QCBOR_ERR_DCBOR_CONFORMANCE;
1183 }
1184 }
1185
1186 return QCBOR_SUCCESS;
1187}
1188
1189
1190static QCBORError
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001191QCBORDecode_Private_SingleConformance(const float f, const QCBORDecodeMode uconfigFlags)
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001192{
1193 struct IEEE754_ToInt ToInt;
1194 IEEE754_union ToSmaller;
1195
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001196 if(uconfigFlags & QCBOR_DECODE_ONLY_REDUCED_FLOATS) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001197 /* See if it could have been encoded as an integer */
1198 ToInt = IEEE754_SingleToInt(f);
1199 if(ToInt.type == IEEE754_ToInt_IS_INT || ToInt.type == IEEE754_ToInt_IS_UINT) {
1200 return QCBOR_ERR_DCBOR_CONFORMANCE;
1201 }
1202
1203 /* Make sure there is no NaN payload */
1204 if(IEEE754_SingleHasNaNPayload(f)) {
1205 return QCBOR_ERR_DCBOR_CONFORMANCE;
1206 }
1207 }
1208
1209 /* See if it could have been encoded shorter */
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001210 if(uconfigFlags & QCBOR_DECODE_ONLY_PREFERRED_NUMBERS) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001211 ToSmaller = IEEE754_SingleToHalf(f, true);
1212 if(ToSmaller.uSize != sizeof(float)) {
1213 return QCBOR_ERR_PREFERRED_CONFORMANCE;
1214 }
1215 }
1216
1217 return QCBOR_SUCCESS;
1218}
1219
1220
1221static QCBORError
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001222QCBORDecode_Private_DoubleConformance(const double d, QCBORDecodeMode uConfigFlags)
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001223{
1224 struct IEEE754_ToInt ToInt;
1225 IEEE754_union ToSmaller;
1226
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001227 if(uConfigFlags & QCBOR_DECODE_ONLY_REDUCED_FLOATS) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001228 /* See if it could have been encoded as an integer */
1229 ToInt = IEEE754_DoubleToInt(d);
1230 if(ToInt.type == IEEE754_ToInt_IS_INT || ToInt.type == IEEE754_ToInt_IS_UINT) {
1231 return QCBOR_ERR_DCBOR_CONFORMANCE;
1232 }
1233 /* Make sure there is no NaN payload */
1234 if(IEEE754_DoubleHasNaNPayload(d)) {
1235 return QCBOR_ERR_DCBOR_CONFORMANCE;
1236 }
1237 }
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001238
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001239 /* See if it could have been encoded shorter */
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001240 if(uConfigFlags & QCBOR_DECODE_ONLY_PREFERRED_NUMBERS) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001241 ToSmaller = IEEE754_DoubleToSmaller(d, true, true);
1242 if(ToSmaller.uSize != sizeof(double)) {
1243 return QCBOR_ERR_PREFERRED_CONFORMANCE;
1244 }
1245 }
1246
1247 return QCBOR_SUCCESS;
1248}
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001249#else /* ! QCBOR_DISABLE_DECODE_CONFORMANCE && ! QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001250
1251static QCBORError
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001252QCBORDecode_Private_SingleConformance(const float f, const QCBORDecodeMode uConfigFlags)
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001253{
1254 (void)f;
Laurence Lundbladed76f0432024-11-21 21:06:20 -08001255 if(uConfigFlags & (QCBOR_DECODE_ONLY_REDUCED_FLOATS | QCBOR_DECODE_ONLY_PREFERRED_NUMBERS)) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001256 return QCBOR_ERR_CANT_CHECK_FLOAT_CONFORMANCE;
1257 } else {
1258 return QCBOR_SUCCESS;
1259 }
1260}
1261
1262static QCBORError
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001263QCBORDecode_Private_DoubleConformance(const double d, const QCBORDecodeMode uConfigFlags)
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001264{
1265 (void)d;
Laurence Lundbladed76f0432024-11-21 21:06:20 -08001266 if(uConfigFlags & (QCBOR_DECODE_ONLY_REDUCED_FLOATS | QCBOR_DECODE_ONLY_PREFERRED_NUMBERS)) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001267 return QCBOR_ERR_CANT_CHECK_FLOAT_CONFORMANCE;
1268 } else {
1269 return QCBOR_SUCCESS;
1270 }
1271}
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001272#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE && ! QCBOR_DISABLE_PREFERRED_FLOAT */
1273
1274
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001275/*
1276 * Decode a float
1277 */
1278static QCBORError
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001279QCBOR_Private_DecodeFloat(const QCBORDecodeMode uConfigFlags,
1280 const int nAdditionalInfo,
1281 const uint64_t uArgument,
1282 QCBORItem *pDecodedItem)
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001283{
1284 QCBORError uReturn = QCBOR_SUCCESS;
1285 float single;
1286
1287 (void)single; /* Avoid unused error from various #ifndefs */
1288
1289 switch(nAdditionalInfo) {
1290 case HALF_PREC_FLOAT: /* 25 */
1291#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
1292 /* Half-precision is returned as a double. The cast to
1293 * uint16_t is safe because the encoded value was 16 bits. It
1294 * was widened to 64 bits to be passed in here.
1295 */
1296 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uArgument);
1297 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
1298
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001299 uReturn = QCBORDecode_Private_HalfConformance(pDecodedItem->val.dfnum, uConfigFlags);
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001300 if(uReturn != QCBOR_SUCCESS) {
1301 break;
1302 }
1303#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
1304 uReturn = FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS);
1305 break;
1306
1307 case SINGLE_PREC_FLOAT: /* 26 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001308 /* Single precision is normally returned as a double since
1309 * double is widely supported, there is no loss of precision,
1310 * it makes it easy for the caller in most cases and it can
1311 * be converted back to single with no loss of precision
1312 *
1313 * The cast to uint32_t is safe because the encoded value was
1314 * 32 bits. It was widened to 64 bits to be passed in here.
1315 */
1316 single = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uArgument);
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001317 uReturn = QCBORDecode_Private_SingleConformance(single, uConfigFlags);
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001318 if(uReturn != QCBOR_SUCCESS) {
1319 break;
1320 }
1321
1322#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1323 /* In the normal case, use HW to convert float to
1324 * double. */
1325 pDecodedItem->val.dfnum = (double)single;
1326 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
1327#else /* QCBOR_DISABLE_FLOAT_HW_USE */
1328 /* Use of float HW is disabled, return as a float. */
1329 pDecodedItem->val.fnum = single;
1330 pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
1331
1332 /* IEEE754_FloatToDouble() could be used here to return as
1333 * a double, but it adds object code and most likely
1334 * anyone disabling FLOAT HW use doesn't care about floats
1335 * and wants to save object code.
1336 */
1337#endif /* ! QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001338 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
1339 break;
1340
1341 case DOUBLE_PREC_FLOAT: /* 27 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001342 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uArgument);
1343 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
1344
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001345 uReturn = QCBORDecode_Private_DoubleConformance(pDecodedItem->val.dfnum, uConfigFlags);
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001346 if(uReturn != QCBOR_SUCCESS) {
1347 break;
1348 }
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001349 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
1350 break;
1351 }
1352
1353 return uReturn;
1354}
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001355#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */
1356
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001357
1358
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001359/* Make sure #define value line up as DecodeSimple counts on this. */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001360#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
1361#error QCBOR_TYPE_FALSE macro value wrong
1362#endif
1363
1364#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
1365#error QCBOR_TYPE_TRUE macro value wrong
1366#endif
1367
1368#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
1369#error QCBOR_TYPE_NULL macro value wrong
1370#endif
1371
1372#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
1373#error QCBOR_TYPE_UNDEF macro value wrong
1374#endif
1375
Laurence Lundblade0f99d692018-09-26 14:39:28 -07001376#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
1377#error QCBOR_TYPE_BREAK macro value wrong
1378#endif
1379
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001380#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
1381#error QCBOR_TYPE_DOUBLE macro value wrong
1382#endif
1383
1384#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
1385#error QCBOR_TYPE_FLOAT macro value wrong
1386#endif
1387
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001388/**
1389 * @brief Decode major type 7 -- true, false, floating-point, break...
1390 *
1391 * @param[in] nAdditionalInfo The lower five bits from the initial byte.
1392 * @param[in] uArgument The argument from the head.
1393 * @param[out] pDecodedItem The filled in decoded item.
1394 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001395 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1396 * of half-precision disabled
1397 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all float
1398 * decode is disabled.
1399 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of simple
1400 * type in input.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001401 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001402static QCBORError
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001403QCBOR_Private_DecodeType7(const QCBORDecodeMode uConfigFlags,
1404 const int nAdditionalInfo,
1405 const uint64_t uArgument,
1406 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001407{
1408 QCBORError uReturn = QCBOR_SUCCESS;
1409
1410 /* uAdditionalInfo is 5 bits from the initial byte. Compile time
1411 * checks above make sure uAdditionalInfo values line up with
1412 * uDataType values. DecodeHead() never returns an AdditionalInfo
1413 * > 0x1f so cast is safe.
1414 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001415 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001416
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001417 switch(nAdditionalInfo) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001418 /* No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they
1419 * are caught before this is called.
1420 */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001421
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001422 case HALF_PREC_FLOAT: /* 25 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001423 case SINGLE_PREC_FLOAT: /* 26 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001424 case DOUBLE_PREC_FLOAT: /* 27 */
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001425#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001426 uReturn = QCBOR_Private_DecodeFloat(uConfigFlags, nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001427#else
1428 uReturn = QCBOR_ERR_ALL_FLOAT_DISABLED;
1429#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001430 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001431
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001432 case CBOR_SIMPLEV_FALSE: /* 20 */
1433 case CBOR_SIMPLEV_TRUE: /* 21 */
1434 case CBOR_SIMPLEV_NULL: /* 22 */
1435 case CBOR_SIMPLEV_UNDEF: /* 23 */
1436 case CBOR_SIMPLE_BREAK: /* 31 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001437#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001438 if((uConfigFlags & QCBOR_DECODE_DISALLOW_DCBOR_SIMPLES) &&
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001439 nAdditionalInfo == CBOR_SIMPLEV_UNDEF) {
1440 uReturn = QCBOR_ERR_DCBOR_CONFORMANCE;
1441 goto Done;
1442 }
1443#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001444 break; /* nothing to do */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001445
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001446 case CBOR_SIMPLEV_ONEBYTE: /* 24 */
1447 if(uArgument <= CBOR_SIMPLE_BREAK) {
1448 /* This takes out f8 00 ... f8 1f which should be encoded
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001449 * as e0 … f7 -- preferred serialization check for simple values.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001450 */
1451 uReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001452 goto Done;
1453 }
Laurence Lundblade5e390822019-01-06 12:35:01 -08001454 /* FALLTHROUGH */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001455
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001456 default: /* 0-19 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001457#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001458 if((uConfigFlags & QCBOR_DECODE_DISALLOW_DCBOR_SIMPLES) &&
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001459 (uArgument < CBOR_SIMPLEV_FALSE || uArgument > CBOR_SIMPLEV_NULL)) {
1460 uReturn = QCBOR_ERR_DCBOR_CONFORMANCE;
1461 goto Done;
1462 }
1463#endif /* !QCBOR_DISABLE_DECODE_CONFORMANCE */
1464
1465 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
1466 /* QCBOR_Private_DecodeHead() will make uArgument equal to
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001467 * nAdditionalInfo when nAdditionalInfo is < 24. This cast is
1468 * safe because the 2, 4 and 8 byte lengths of uNumber are in
1469 * the double/float cases above
Laurence Lundbladeee851742020-01-08 08:37:05 -08001470 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001471 pDecodedItem->val.uSimple = (uint8_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001472 break;
1473 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001474
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001475Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001476 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001477}
1478
1479
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001480/**
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001481 * @brief Decode a single primitive data item (decode layer 6).
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001482 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001483 * @param[in] pMe Decoder context.
1484 * @param[in] bAllocateStrings If true, use allocator for strings.
1485 * @param[out] pDecodedItem The filled-in decoded item.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001486 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001487 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1488 * features
1489 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1490 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1491 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1492 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001493 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001494 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1495 * of half-precision disabled
1496 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1497 * float decode is disabled.
1498 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1499 * simple type in input.
1500 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1501 * in input, but indefinite
1502 * lengths disabled.
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001503 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte.
1504 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map.
1505 * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001506 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001507 * This decodes the most primitive/atomic data item. It does no
1508 * combining of data items.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001509 */
1510static QCBORError
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001511QCBOR_Private_DecodeAtomicDataItem(QCBORDecodeContext *pMe,
1512 const bool bAllocateStrings,
1513 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001514{
1515 QCBORError uReturn;
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001516 int nMajorType = 0;
1517 uint64_t uArgument = 0;
1518 int nAdditionalInfo = 0;
1519
1520 const QCBORDecodeMode uDecodeMode = pMe->uDecodeMode;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001521
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001522 memset(pDecodedItem, 0, sizeof(QCBORItem));
1523
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001524 /* Decode the "head" that every CBOR item has into the major type,
1525 * argument and the additional info.
1526 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001527 uReturn = QCBOR_Private_DecodeHead(&(pMe->InBuf),
1528#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
1529 // TODO: make this prettier; will optimizer take out stuff without ifdef?
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001530 uDecodeMode,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001531#endif /* !QCBOR_DISABLE_DECODE_CONFORMANCE */
1532 &nMajorType,
1533 &uArgument,
1534 &nAdditionalInfo);
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001535
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001536 if(uReturn != QCBOR_SUCCESS) {
1537 return uReturn;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001538 }
1539
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001540 /* All the functions below get inlined by the optimizer. This code
1541 * is easier to read with them all being similar functions, even if
1542 * some functions don't do much.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001543 */
1544 switch (nMajorType) {
1545 case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
1546 case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001547 return QCBOR_Private_DecodeInteger(nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001548 break;
1549
1550 case CBOR_MAJOR_TYPE_BYTE_STRING: /* Major type 2 */
1551 case CBOR_MAJOR_TYPE_TEXT_STRING: /* Major type 3 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001552 return QCBOR_Private_DecodeString(pMe, bAllocateStrings, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001553 break;
1554
1555 case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */
1556 case CBOR_MAJOR_TYPE_MAP: /* Major type 5 */
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001557 return QCBOR_Private_DecodeArrayOrMap(uDecodeMode, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001558 break;
1559
1560 case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001561 return QCBOR_Private_DecodeTagNumber(uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001562 break;
1563
1564 case CBOR_MAJOR_TYPE_SIMPLE:
1565 /* Major type 7: float, double, true, false, null... */
Laurence Lundblade36b28f92024-11-19 21:47:28 -08001566 return QCBOR_Private_DecodeType7(uDecodeMode, nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001567 break;
1568
1569 default:
1570 /* Never happens because DecodeHead() should never return > 7 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001571 return QCBOR_ERR_UNSUPPORTED;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001572 break;
1573 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001574}
1575
1576
1577/**
1578 * @brief Process indefinite-length strings (decode layer 5).
1579 *
1580 * @param[in] pMe Decoder context
1581 * @param[out] pDecodedItem The decoded item that work is done on.
1582 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001583 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1584 * features
1585 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1586 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1587 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1588 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1589 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1590 * of half-precision disabled
1591 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1592 * float decode is disabled.
1593 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1594 * simple type in input.
1595 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1596 * in input, but indefinite
1597 * lengths disabled.
1598 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1599 * but no string allocator.
1600 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1601 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1602 * input, but indefinite-length
1603 * strings are disabled.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001604 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001605 * If @c pDecodedItem is not an indefinite-length string, this does nothing.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001606 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001607 * If it is, this loops getting the subsequent chunk data items that
1608 * make up the string. The string allocator is used to make a
1609 * contiguous buffer for the chunks. When this completes @c
1610 * pDecodedItem contains the put-together string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001611 *
1612 * Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001613 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001614static QCBORError
1615QCBORDecode_Private_GetNextFullString(QCBORDecodeContext *pMe,
1616 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001617{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001618 /* Aproximate stack usage
1619 * 64-bit 32-bit
1620 * local vars 32 16
1621 * 2 UsefulBufs 32 16
1622 * QCBORItem 56 52
1623 * TOTAL 120 74
1624 */
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001625 QCBORError uReturn;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001626
1627 /* A note about string allocation -- Memory for strings is
1628 * allocated either because 1) indefinte-length string chunks are
1629 * being coalecsed or 2) caller has requested all strings be
1630 * allocated. The first case is handed below here. The second case
1631 * is handled in DecodeString if the bAllocate is true. That
1632 * boolean originates here with pMe->bStringAllocateAll immediately
1633 * below. That is, QCBOR_Private_DecodeAtomicDataItem() is called
1634 * in two different contexts here 1) main-line processing which is
1635 * where definite-length strings need to be allocated if
1636 * bStringAllocateAll is true and 2) processing chunks of
1637 * indefinite-lengths strings in in which case there must be no
1638 * allocation.
1639 */
1640
1641
1642 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, pMe->bStringAllocateAll, pDecodedItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001643 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001644 goto Done;
1645 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001646
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001647 /* This is where out-of-place break is detected for the whole
1648 * decoding stack. Break is an error for everything that calls
1649 * QCBORDecode_Private_GetNextFullString(), so the check is
1650 * centralized here.
1651 */
1652 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
1653 uReturn = QCBOR_ERR_BAD_BREAK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001654 goto Done;
1655 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001656
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001657
1658 /* Skip out if not an indefinite-length string */
1659 const uint8_t uStringType = pDecodedItem->uDataType;
1660 if(uStringType != QCBOR_TYPE_BYTE_STRING &&
1661 uStringType != QCBOR_TYPE_TEXT_STRING) {
1662 goto Done;
1663 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001664 if(pDecodedItem->val.string.len != QCBOR_STRING_LENGTH_INDEFINITE) {
1665 goto Done;
1666 }
1667
1668#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001669 /* Can't decode indefinite-length strings without a string allocator */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001670 if(!pMe->StringAllocator.pfAllocator) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001671 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1672 goto Done;
1673 }
1674
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001675 /* Loop getting chunks of the indefinite-length string */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001676 UsefulBufC FullString = NULLUsefulBufC;
1677
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001678 for(;;) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001679 /* Get QCBORItem for next chunk */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001680 QCBORItem StringChunkItem;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001681 /* Pass false to DecodeAtomicDataItem() because the individual
1682 * string chunks in an indefinite-length must not be
1683 * allocated. They are always copied into the allocated
1684 * contiguous buffer allocated here.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001685 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001686 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &StringChunkItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001687 if(uReturn) {
1688 break;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001689 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001690
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001691 /* Is item is the marker for end of the indefinite-length string? */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001692 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001693 /* String is complete */
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001694 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301695 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001696 break;
1697 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001698
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001699 /* All chunks must be of the same type, the type of the item
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001700 * that introduces the indefinite-length string. This also
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001701 * catches errors where the chunk is not a string at all and an
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001702 * indefinite-length string inside an indefinite-length string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001703 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001704 if(StringChunkItem.uDataType != uStringType ||
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001705 StringChunkItem.val.string.len == QCBOR_STRING_LENGTH_INDEFINITE) {
1706 uReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001707 break;
1708 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001709
David Navarro9123e5b2022-03-28 16:04:03 +02001710 if (StringChunkItem.val.string.len > 0) {
1711 /* The first time throurgh FullString.ptr is NULL and this is
1712 * equivalent to StringAllocator_Allocate(). Subsequently it is
1713 * not NULL and a reallocation happens.
1714 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001715 UsefulBuf NewMem = StringAllocator_Reallocate(&(pMe->StringAllocator),
David Navarro9123e5b2022-03-28 16:04:03 +02001716 FullString.ptr,
1717 FullString.len + StringChunkItem.val.string.len);
David Navarro9123e5b2022-03-28 16:04:03 +02001718 if(UsefulBuf_IsNULL(NewMem)) {
1719 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1720 break;
1721 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001722
David Navarro9123e5b2022-03-28 16:04:03 +02001723 /* Copy new string chunk to the end of accumulated string */
1724 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001725 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001726 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001727
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001728 if(uReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
1729 /* Getting the item failed, clean up the allocated memory */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001730 StringAllocator_Free(&(pMe->StringAllocator), FullString.ptr);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001731 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001732#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1733 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1734#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001735
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001736Done:
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001737 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001738}
1739
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001740
Laurence Lundblade37286c02022-09-03 10:05:02 -07001741#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001742/**
1743 * @brief This converts a tag number to a shorter mapped value for storage.
1744 *
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001745 * @param[in] pMe The decode context.
1746 * @param[in] uUnMappedTag The tag number to map
1747 * @param[out] puMappedTagNumber The stored tag number.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001748 *
1749 * @return error code.
1750 *
1751 * The main point of mapping tag numbers is make QCBORItem
1752 * smaller. With this mapping storage of 4 tags takes up 8
1753 * bytes. Without, it would take up 32 bytes.
1754 *
1755 * This maps tag numbers greater than QCBOR_LAST_UNMAPPED_TAG.
1756 * QCBOR_LAST_UNMAPPED_TAG is a little smaller than MAX_UINT16.
1757 *
1758 * See also UnMapTagNumber() and @ref QCBORItem.
1759 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001760static QCBORError
1761QCBORDecode_Private_MapTagNumber(QCBORDecodeContext *pMe,
1762 const uint64_t uUnMappedTag,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001763 uint16_t *puMappedTagNumber)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001764{
1765 if(uUnMappedTag > QCBOR_LAST_UNMAPPED_TAG) {
1766 unsigned uTagMapIndex;
1767 /* Is there room in the tag map, or is it in it already? */
1768 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
1769 if(pMe->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID64) {
1770 break;
1771 }
1772 if(pMe->auMappedTags[uTagMapIndex] == uUnMappedTag) {
1773 break;
1774 }
1775 }
1776 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
1777 return QCBOR_ERR_TOO_MANY_TAGS;
1778 }
1779
1780 /* Covers the cases where tag is new and were it is already in the map */
1781 pMe->auMappedTags[uTagMapIndex] = uUnMappedTag;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001782 *puMappedTagNumber = (uint16_t)(uTagMapIndex + QCBOR_LAST_UNMAPPED_TAG + 1);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001783
1784 } else {
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001785 *puMappedTagNumber = (uint16_t)uUnMappedTag;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001786 }
1787
1788 return QCBOR_SUCCESS;
1789}
1790
1791
1792/**
1793 * @brief This converts a mapped tag number to the actual tag number.
1794 *
1795 * @param[in] pMe The decode context.
1796 * @param[in] uMappedTagNumber The stored tag number.
1797 *
1798 * @return The actual tag number is returned or
1799 * @ref CBOR_TAG_INVALID64 on error.
1800 *
1801 * This is the reverse of MapTagNumber()
1802 */
1803static uint64_t
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001804QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe,
1805 const uint16_t uMappedTagNumber)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001806{
1807 if(uMappedTagNumber <= QCBOR_LAST_UNMAPPED_TAG) {
1808 return uMappedTagNumber;
1809 } else if(uMappedTagNumber == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07001810 return CBOR_TAG_INVALID64;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001811 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001812 /* This won't be negative because of code below in
1813 * MapTagNumber()
1814 */
1815 const unsigned uIndex = uMappedTagNumber - (QCBOR_LAST_UNMAPPED_TAG + 1);
1816 return pMe->auMappedTags[uIndex];
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001817 }
1818}
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001819
1820
1821static const struct QCBORTagDecoderEntry *
1822QCBORDecode_Private_LookUpTagDecoder(const struct QCBORTagDecoderEntry *pTagContentTable,
1823 const uint64_t uTagNumber)
1824{
1825 const struct QCBORTagDecoderEntry *pTE;
1826
1827 if(pTagContentTable == NULL) {
1828 return NULL;
1829 }
1830
1831 for(pTE = pTagContentTable; pTE->uTagNumber != CBOR_TAG_INVALID64; pTE++) {
1832 if(pTE->uTagNumber == uTagNumber || pTE->uTagNumber == CBOR_TAG_ANY) {
1833 break;
1834 }
1835 }
1836
1837 if(pTE->uTagNumber == CBOR_TAG_INVALID64) {
1838 return NULL;
1839 }
1840
1841 return pTE;
1842}
1843#endif /* ! QCBOR_DISABLE_TAGS */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001844
Laurence Lundblade9b334962020-08-27 10:55:53 -07001845
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001846/**
1847 * @brief Aggregate all tags wrapping a data item (decode layer 4).
1848 *
1849 * @param[in] pMe Decoder context
1850 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001851 *
1852 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1853 * features
1854 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1855 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1856 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1857 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1858 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1859 * of half-precision disabled
1860 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1861 * float decode is disabled.
1862 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1863 * simple type in input.
1864 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1865 * in input, but indefinite
1866 * lengths disabled.
1867 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1868 * but no string allocator.
1869 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1870 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1871 * input, but indefinite-length
1872 * strings are disabled.
1873 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001874 *
1875 * This loops getting atomic data items until one is not a tag
1876 * number. Usually this is largely pass-through because most
1877 * item are not tag numbers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001878 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001879static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001880QCBORDecode_Private_GetNextTagNumber(QCBORDecodeContext *pMe,
1881 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001882{
Laurence Lundblade37286c02022-09-03 10:05:02 -07001883#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001884 int nIndex;
1885 QCBORError uErr;
1886 uint16_t uMappedTagNumber;
1887 QCBORError uReturn;
1888
1889 /* Accummulate the tag numbers from multiple items here and then
1890 * copy them into the last item, the non-tag-number item.
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001891 */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001892 QCBORMappedTagNumbers auTagNumbers;;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001893
1894 /* Initialize to CBOR_TAG_INVALID16 */
1895 #if CBOR_TAG_INVALID16 != 0xffff
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001896 /* Be sure the memset is initializing to CBOR_TAG_INVALID16 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001897 #err CBOR_TAG_INVALID16 tag not defined as expected
1898 #endif
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001899 memset(auTagNumbers, 0xff, sizeof(auTagNumbers));
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001900
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001901 /* Loop fetching data items until the item fetched is not a tag number */
1902 uReturn = QCBOR_SUCCESS;
1903 for(nIndex = 0; ; nIndex++) {
1904 uErr = QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07001905 if(uErr != QCBOR_SUCCESS) {
1906 uReturn = uErr;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001907 break;
1908 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001909
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001910 if(pDecodedItem->uDataType != QCBOR_TYPE_TAG_NUMBER) {
1911 /* Successful exit from loop; maybe got some tags, maybe not */
1912 memcpy(pDecodedItem->auTagNumbers, auTagNumbers, sizeof(auTagNumbers));
1913 break;
1914 }
1915
1916 if(nIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
1917 /* No room in the item's tag number array */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001918 uReturn = QCBOR_ERR_TOO_MANY_TAGS;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001919 /* Continue on to get all tag numbers wrapping this item even
1920 * though it is erroring out in the end. This allows decoding
1921 * to continue. This is a QCBOR resource limit error, not a
1922 * problem with being well-formed CBOR.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001923 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001924 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001925 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001926
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001927 /* Map the tag number */
1928 uMappedTagNumber = 0;
1929 uReturn = QCBORDecode_Private_MapTagNumber(pMe, pDecodedItem->val.uTagNumber, &uMappedTagNumber);
1930 /* Continue even on error so as to consume all tag numbers
1931 * wrapping this data item so decoding can go on. If
1932 * QCBORDecode_Private_MapTagNumber() errors once it will
1933 * continue to error.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001934 */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001935
1936 auTagNumbers[nIndex] = uMappedTagNumber;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001937 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001938
Laurence Lundblade9b334962020-08-27 10:55:53 -07001939 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001940
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001941#else /* ! QCBOR_DISABLE_TAGS */
Laurence Lundblade37286c02022-09-03 10:05:02 -07001942
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07001943 return QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07001944
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001945#endif /* ! QCBOR_DISABLE_TAGS */
Laurence Lundblade37286c02022-09-03 10:05:02 -07001946}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001947
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001948
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001949/**
1950 * @brief Combine a map entry label and value into one item (decode layer 3).
1951 *
1952 * @param[in] pMe Decoder context
1953 * @param[out] pDecodedItem The decoded item that work is done on.
1954 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001955 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1956 * features
1957 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1958 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1959 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1960 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1961 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1962 * of half-precision disabled
1963 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1964 * float decode is disabled.
1965 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1966 * simple type in input.
1967 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1968 * in input, but indefinite
1969 * lengths disabled.
1970 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1971 * but no string allocator.
1972 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1973 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1974 * input, but indefinite-length
1975 * strings are disabled.
1976 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1977 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1978 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001979 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001980 * If the current nesting level is a map, then this combines pairs of
1981 * items into one data item with a label and value.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001982 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001983 * This is passthrough if the current nesting level is not a map.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001984 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001985 * This also implements maps-as-array mode where a map is treated like
1986 * an array to allow caller to do their own label processing.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001987 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001988static QCBORError
1989QCBORDecode_Private_GetNextMapEntry(QCBORDecodeContext *pMe,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001990 QCBORItem *pDecodedItem,
1991 uint32_t *puLabelEndOffset)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001992{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001993 QCBORItem LabelItem;
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001994 QCBORError uErr, uErr2;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001995
1996 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1997 if(QCBORDecode_IsUnrecoverableError(uErr)) {
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001998 goto Done;
1999 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002000
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002001 if(!DecodeNesting_IsCurrentTypeMap(&(pMe->nesting))) {
2002 /* Not decoding a map. Nothing to do. */
2003 /* When decoding maps-as-arrays, the type will be
2004 * QCBOR_TYPE_MAP_AS_ARRAY and this function will exit
2005 * here. This is now map processing for maps-as-arrays is not
2006 * done. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002007 goto Done;
2008 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08002009
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002010 /* Decoding a map entry, so the item decoded above was the label */
2011 LabelItem = *pDecodedItem;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002012
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002013 if(puLabelEndOffset != NULL) {
2014 /* Cast is OK because lengths are all 32-bit in QCBOR */
2015 *puLabelEndOffset = (uint32_t)UsefulInputBuf_Tell(&(pMe->InBuf));
2016 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08002017
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002018 /* Get the value of the map item */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002019 uErr2 = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
2020 if(QCBORDecode_IsUnrecoverableError(uErr2)) {
2021 uErr = uErr2;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002022 goto Done;
2023 }
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002024 if(uErr2 != QCBOR_SUCCESS) {
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002025 /* The recoverable error for the value overrides the recoverable
2026 * error for the label, if there was an error for the label */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002027 uErr = uErr2;
2028 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002029
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002030 /* Combine the label item and value item into one */
2031 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
2032 pDecodedItem->uLabelType = LabelItem.uDataType;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09002033
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002034#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002035 /* TODO: QCBOR_DECODE_MODE_MAP_STRINGS_ONLY might have been a bad idea. Maybe
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002036 * get rid of it in QCBOR 2.0
2037 */
Laurence Lundblade36b28f92024-11-19 21:47:28 -08002038 if(pMe->uDecodeMode & QCBOR_DECODE_MODE_MAP_STRINGS_ONLY &&
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002039 LabelItem.uDataType != QCBOR_TYPE_TEXT_STRING) {
2040 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
2041 goto Done;
2042 }
2043#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
2044
2045 switch(LabelItem.uDataType) {
2046 case QCBOR_TYPE_INT64:
2047 pDecodedItem->label.int64 = LabelItem.val.int64;
2048 break;
2049
2050#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
2051 case QCBOR_TYPE_UINT64:
2052 pDecodedItem->label.uint64 = LabelItem.val.uint64;
2053 break;
2054
2055 case QCBOR_TYPE_TEXT_STRING:
2056 case QCBOR_TYPE_BYTE_STRING:
2057 pDecodedItem->label.string = LabelItem.val.string;
2058 break;
2059#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
2060
2061 default:
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002062 /* It is possible to skip over labels that are non-aggregate
2063 * types like floats, but not to skip over labels that are
2064 * arrays or maps. We might eventually handle more label
2065 * types like floats as they are not too hard and we now
2066 * have QCBOR_DISABLE_NON_INTEGER_LABELS */
2067 if(!pMe->bAllowAllLabels || QCBORItem_IsMapOrArray(LabelItem)) {
2068 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
2069 goto Done;
2070 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002071 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002072
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002073Done:
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002074 return uErr;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002075}
2076
2077
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002078#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002079/**
2080 * @brief Peek and see if next data item is a break;
2081 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002082 * param[in] pUIB UsefulInputBuf to read from.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002083 * @param[out] pbNextIsBreak Indicate if next was a break or not.
2084 *
2085 * @return Any decoding error.
2086 *
2087 * See if next item is a CBOR break. If it is, it is consumed,
2088 * if not it is not consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07002089*/
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002090static QCBORError
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002091QCBOR_Private_NextIsBreak(QCBORDecodeContext *pMe, bool *pbNextIsBreak)
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002092{
2093 *pbNextIsBreak = false;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002094 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) != 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002095 QCBORItem Peek;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002096 size_t uPeek = UsefulInputBuf_Tell(&(pMe->InBuf));
2097 QCBORError uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &Peek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002098 if(uReturn != QCBOR_SUCCESS) {
2099 return uReturn;
2100 }
2101 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002102 /* It is not a break, rewind so it can be processed normally. */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002103 UsefulInputBuf_Seek(&(pMe->InBuf), uPeek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002104 } else {
2105 *pbNextIsBreak = true;
2106 }
2107 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002108
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002109 return QCBOR_SUCCESS;
2110}
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002111#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002112
2113
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002114/**
2115 * @brief Ascend up nesting levels if all items in them have been consumed.
2116 *
2117 * @param[in] pMe The decode context.
2118 * @param[in] bMarkEnd If true mark end of maps/arrays with count of zero.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002119 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002120 *
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002121 * An item was just consumed, now figure out if it was the
2122 * end of an array/map map that can be closed out. That
2123 * may in turn close out the above array/map...
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002124 *
2125 * When ascending indefinite-length arrays and maps, this will correctly
2126 * consume the break for the level above. This is a problem for the
2127 * implementation of QCBORDecode_GetArray() that must not return
2128 * that break. @c pbBreak is set to true to indicate that one
2129 * byte should be removed.
2130 *
2131 * Improvement: this could reduced further if indef is disabled
2132 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002133static QCBORError
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002134QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd, bool *pbBreak)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002135{
2136 QCBORError uReturn;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002137
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002138 /* Loop ascending nesting levels as long as there is ascending to do */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002139 while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002140 if(pbBreak) {
2141 *pbBreak = false;
2142 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002143
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002144 if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) {
2145 /* Nesting level is bstr-wrapped CBOR */
2146
2147 /* Ascent for bstr-wrapped CBOR is always by explicit call
2148 * so no further ascending can happen.
2149 */
2150 break;
2151
2152 } else if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
2153 /* Level is a definite-length array/map */
2154
2155 /* Decrement the item count the definite-length array/map */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002156 DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(&(pMe->nesting));
2157 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002158 /* Didn't close out array/map, so all work here is done */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002159 break;
2160 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002161 /* All items in a definite-length array were consumed so it
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002162 * is time to ascend one level. This happens below.
2163 */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002164
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002165#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002166 } else {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002167 /* Level is an indefinite-length array/map. */
2168
2169 /* Check for a break which is what ends indefinite-length arrays/maps */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002170 bool bIsBreak = false;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002171 uReturn = QCBOR_Private_NextIsBreak(pMe, &bIsBreak);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002172 if(uReturn != QCBOR_SUCCESS) {
2173 goto Done;
2174 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002175
2176 if(!bIsBreak) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002177 /* Not a break so array/map does not close out. All work is done */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002178 break;
2179 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002180
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002181 /* It was a break in an indefinitelength map / array so
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002182 * it is time to ascend one level.
2183 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002184 if(pbBreak) {
2185 *pbBreak = true;
2186 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002187
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002188#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002189 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002190
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002191
2192 /* All items in the array/map have been consumed. */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002193
Laurence Lundblade93d89472020-10-03 22:30:50 -07002194 /* But ascent in bounded mode is only by explicit call to
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002195 * QCBORDecode_ExitBoundedMode().
2196 */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07002197 if(DecodeNesting_IsCurrentBounded(&(pMe->nesting))) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002198 /* Set the count to zero for definite-length arrays to indicate
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002199 * cursor is at end of bounded array/map */
Laurence Lundbladed0304932020-06-27 10:59:38 -07002200 if(bMarkEnd) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002201 /* Used for definite and indefinite to signal end */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07002202 DecodeNesting_ZeroMapOrArrayCount(&(pMe->nesting));
Laurence Lundbladed0304932020-06-27 10:59:38 -07002203
Laurence Lundblade2c1faf92020-06-26 22:43:56 -07002204 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002205 break;
2206 }
2207
2208 /* Finally, actually ascend one level. */
2209 DecodeNesting_Ascend(&(pMe->nesting));
2210 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002211
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002212 uReturn = QCBOR_SUCCESS;
2213
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002214#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002215Done:
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002216#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
2217
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002218 return uReturn;
2219}
2220
2221
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002222/**
2223 * @brief Ascending & Descending out of nesting levels (decode layer 2).
2224 *
2225 * @param[in] pMe Decoder context
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002226 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002227 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002228
2229 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
2230 * features
2231 * @retval QCBOR_ERR_HIT_END Unexpected end of input
2232 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
2233 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
2234 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
2235 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
2236 * of half-precision disabled
2237 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
2238 * float decode is disabled.
2239 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
2240 * simple type in input.
2241 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
2242 * in input, but indefinite
2243 * lengths disabled.
2244 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
2245 * but no string allocator.
2246 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
2247 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
2248 * input, but indefinite-length
2249 * strings are disabled.
2250 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
2251 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
2252 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
2253 * @retval QCBOR_ERR_NO_MORE_ITEMS Need more items for map or array.
2254 * @retval QCBOR_ERR_BAD_BREAK Indefinite-length break in wrong
2255 * place.
2256 * @retval QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP Nesting deeper than QCBOR
2257 * can handle.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002258 *
2259 * This handles the traversal descending into and asecnding out of
2260 * maps, arrays and bstr-wrapped CBOR. It figures out the ends of
2261 * definite- and indefinte-length maps and arrays by looking at the
2262 * item count or finding CBOR breaks. It detects the ends of the
2263 * top-level sequence and of bstr-wrapped CBOR by byte count.
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002264 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002265static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002266QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002267 bool *pbBreak,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002268 QCBORItem *pDecodedItem,
2269 uint32_t *puLabelEndOffset)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002270{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002271 QCBORError uReturn;
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002272 /* ==== First: figure out if at the end of a traversal ==== */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002273
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002274 /* If out of bytes to consume, it is either the end of the
2275 * top-level sequence of some bstr-wrapped CBOR that was entered.
2276 *
2277 * In the case of bstr-wrapped CBOR, the length of the
2278 * UsefulInputBuf was set to that of the bstr-wrapped CBOR. When
2279 * the bstr-wrapped CBOR is exited, the length is set back to the
2280 * top-level's length or to the next highest bstr-wrapped CBOR.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002281 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002282 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) == 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002283 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002284 goto Done;
2285 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07002286
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002287 /* Check to see if at the end of a bounded definite-length map or
2288 * array. The check for a break ending indefinite-length array is
2289 * later in QCBORDecode_NestLevelAscender().
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002290 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002291 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002292 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002293 goto Done;
2294 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002295
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002296 /* ==== Next: not at the end, so get another item ==== */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002297 uReturn = QCBORDecode_Private_GetNextMapEntry(pMe, pDecodedItem, puLabelEndOffset);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002298 if(QCBORDecode_IsUnrecoverableError(uReturn)) {
2299 /* Error is so bad that traversal is not possible. */
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002300 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002301 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05302302
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002303 /* Record the nesting level for this data item before processing
2304 * any of decrementing and descending.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002305 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002306 pDecodedItem->uNestingLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002307
Laurence Lundblade642282a2020-06-23 12:00:33 -07002308
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002309 /* ==== Next: Process the item for descent, ascent, decrement... ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002310 if(QCBORItem_IsMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002311 /* If the new item is a map or array, descend.
2312 *
2313 * Empty indefinite-length maps and arrays are descended into,
2314 * but then ascended out of in the next chunk of code.
2315 *
2316 * Maps and arrays do count as items in the map/array that
2317 * encloses them so a decrement needs to be done for them too,
2318 * but that is done only when all the items in them have been
2319 * processed, not when they are opened with the exception of an
2320 * empty map or array.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002321 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002322 QCBORError uDescendErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002323 uDescendErr = DecodeNesting_DescendMapOrArray(&(pMe->nesting),
Laurence Lundbladeb95afec2024-08-26 10:51:28 -07002324 pDecodedItem->uDataType,
2325 pDecodedItem->val.uCount);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002326 if(uDescendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002327 /* This error is probably a traversal error and it overrides
2328 * the non-traversal error.
2329 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002330 uReturn = uDescendErr;
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002331 goto Done;
2332 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002333 }
2334
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002335 if(!QCBORItem_IsMapOrArray(*pDecodedItem) ||
2336 QCBORItem_IsEmptyDefiniteLengthMapOrArray(*pDecodedItem) ||
2337 QCBORItem_IsIndefiniteLengthMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002338 /* The following cases are handled here:
2339 * - A non-aggregate item like an integer or string
2340 * - An empty definite-length map or array
2341 * - An indefinite-length map or array that might be empty or might not.
2342 *
2343 * QCBORDecode_NestLevelAscender() does the work of decrementing the count
2344 * for an definite-length map/array and break detection for an
2345 * indefinite-0length map/array. If the end of the map/array was
2346 * reached, then it ascends nesting levels, possibly all the way
2347 * to the top level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002348 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002349 QCBORError uAscendErr;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002350 uAscendErr = QCBORDecode_Private_NestLevelAscender(pMe, true, pbBreak);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002351 if(uAscendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002352 /* This error is probably a traversal error and it overrides
2353 * the non-traversal error.
2354 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002355 uReturn = uAscendErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002356 goto Done;
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002357 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05302358 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002359
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002360 /* ==== Last: tell the caller the nest level of the next item ==== */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002361 /* Tell the caller what level is next. This tells them what
2362 * maps/arrays were closed out and makes it possible for them to
2363 * reconstruct the tree with just the information returned in a
2364 * QCBORItem.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002365 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002366 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07002367 /* At end of a bounded map/array; uNextNestLevel 0 to indicate this */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002368 pDecodedItem->uNextNestLevel = 0;
2369 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002370 pDecodedItem->uNextNestLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002371 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002372
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002373Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002374 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002375}
2376
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002377
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002378/**
2379 * @brief Decode tag content for select tags (decoding layer 1).
2380 *
2381 * @param[in] pMe The decode context.
2382 * @param[out] pDecodedItem The decoded item.
2383 *
2384 * @return Decoding error code.
2385 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002386 * CBOR tag numbers for the item were decoded in GetNext_TaggedItem(),
2387 * but the whole tag was not decoded. Here, the whole tags (tag number
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002388 * and tag content) are decoded. This is a
Laurence Lundblade99615302020-11-29 11:19:47 -08002389 * quick pass through for items that are not tags.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002390 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002391static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002392QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2393 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002394{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002395 QCBORError uErr;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002396
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002397 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pDecodedItem, NULL);
2398
2399#ifndef QCBOR_DISABLE_TAGS
2400 uint64_t uTagNumber;
2401 int nTagIndex;
2402 const struct QCBORTagDecoderEntry *pTagDecoder;
2403
2404 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002405 goto Done;
2406 }
2407
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002408 /* Loop over tag numbers in reverse, those closest to content first */
2409 for(nTagIndex = QCBOR_MAX_TAGS_PER_ITEM-1; nTagIndex >= 0; nTagIndex--) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002410
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002411 if(pDecodedItem->auTagNumbers[nTagIndex] == CBOR_TAG_INVALID16) {
2412 continue; /* Empty slot, skip to next */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002413 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002414
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002415 /* See if there's a content decoder for it */
2416 uTagNumber = QCBORDecode_Private_UnMapTagNumber(pMe, pDecodedItem->auTagNumbers[nTagIndex]);
2417 pTagDecoder = QCBORDecode_Private_LookUpTagDecoder(pMe->pTagDecoderTable, uTagNumber);
2418 if(pTagDecoder == NULL) {
2419 break; /* Successful exist -- a tag that we can't decode */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002420 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002421
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002422 /* Call the content decoder */
2423 uErr = pTagDecoder->pfContentDecoder(pMe, pMe->pTagDecodersContext, pTagDecoder->uTagNumber, pDecodedItem);
2424 if(uErr != QCBOR_SUCCESS) {
2425 break; /* Error exit from the loop */
2426 }
2427
2428 /* Remove tag number from list since its content was decoded */
2429 pDecodedItem->auTagNumbers[nTagIndex] = CBOR_TAG_INVALID16;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002430 }
2431
2432Done:
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002433#endif /* ! QCBOR_DISABLE_TAGS */
2434
2435 return uErr;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002436}
2437
2438
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002439/**
2440 * @brief Consume an entire map or array including its contents.
2441 *
2442 * @param[in] pMe The decoder context.
2443 * @param[in] pItemToConsume The array/map whose contents are to be
2444 * consumed.
2445 * @param[out] puNextNestLevel The next nesting level after the item was
2446 * fully consumed.
2447 *
2448 * This may be called when @c pItemToConsume is not an array or
2449 * map. In that case, this is just a pass through for @c puNextNestLevel
2450 * since there is nothing to do.
2451 */
2452static QCBORError
2453QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
2454 const QCBORItem *pItemToConsume,
2455 bool *pbBreak,
2456 uint8_t *puNextNestLevel)
2457{
2458 QCBORError uReturn;
2459 QCBORItem Item;
2460
2461 /* If it is a map or array, this will tell if it is empty. */
2462 const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel);
2463
2464 if(QCBORItem_IsMapOrArray(*pItemToConsume) && !bIsEmpty) {
2465 /* There is only real work to do for non-empty maps and arrays */
2466
2467 /* This works for definite- and indefinite-length maps and
2468 * arrays by using the nesting level
2469 */
2470 do {
2471 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pbBreak, &Item, NULL);
2472 if(QCBORDecode_IsUnrecoverableError(uReturn) ||
2473 uReturn == QCBOR_ERR_NO_MORE_ITEMS) {
2474 goto Done;
2475 }
2476 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
2477
2478 *puNextNestLevel = Item.uNextNestLevel;
2479
2480 uReturn = QCBOR_SUCCESS;
2481
2482 } else {
2483 /* pItemToConsume is not a map or array. Just pass the nesting
2484 * level through. */
2485 *puNextNestLevel = pItemToConsume->uNextNestLevel;
2486
2487 uReturn = QCBOR_SUCCESS;
2488 }
2489
2490Done:
2491 return uReturn;
2492}
2493
2494
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002495#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002496/*
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002497 * This consumes the next item. It returns the starting position of
2498 * the label and the length of the label. It also returns the nest
2499 * level of the item consumed.
2500 */
2501static QCBORError
2502QCBORDecode_Private_GetLabelAndConsume(QCBORDecodeContext *pMe,
2503 uint8_t *puNestLevel,
2504 size_t *puLabelStart,
2505 size_t *puLabelLen)
2506{
2507 QCBORError uErr;
2508 QCBORItem Item;
2509 uint8_t uLevel;
2510 uint32_t uLabelOffset;
2511
2512 /* Get the label and consume it should it be complex */
2513 *puLabelStart = UsefulInputBuf_Tell(&(pMe->InBuf));
2514
2515 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, &Item, &uLabelOffset);
2516 if(uErr != QCBOR_SUCCESS) {
2517 goto Done;
2518 }
2519 *puLabelLen = uLabelOffset - *puLabelStart;
2520 *puNestLevel = Item.uNestingLevel;
2521 uErr = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uLevel);
2522
2523Done:
2524 return uErr;
2525}
2526
2527
2528/* Loop over items in a map until the end of the map looking for
2529 * duplicates. This starts at the current position in the map, not at
2530 * the beginning of the map.
2531 *
2532 * This saves and restores the traversal cursor and nest tracking so
2533 * they are the same on exit as they were on entry.
2534 */
2535static QCBORError
2536QCBORDecode_Private_CheckDups(QCBORDecodeContext *pMe,
2537 const uint8_t uNestLevel,
2538 const size_t uCompareLabelStart,
2539 const size_t uCompareLabelLen)
2540{
2541 QCBORError uErr;
2542 size_t uLabelStart;
2543 size_t uLabelLen;
2544 uint8_t uLevel;
2545 int nCompare;
2546
2547 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2548 const UsefulInputBuf Save = pMe->InBuf;
2549
2550 do {
2551 uErr = QCBORDecode_Private_GetLabelAndConsume(pMe, &uLevel, &uLabelStart, &uLabelLen);
2552 if(uErr != QCBOR_SUCCESS) {
2553 if(uErr == QCBOR_ERR_NO_MORE_ITEMS) {
2554 uErr = QCBOR_SUCCESS; /* Successful end */
2555 }
2556 break;
2557 }
2558
2559 if(uLevel != uNestLevel) {
2560 break; /* Successful end of loop */
2561 }
2562
2563 /* This check for dups works for labels that are preferred
2564 * serialization and are not maps. If the labels are not in
2565 * preferred serialization, then the check has to be more
2566 * complicated and is type-specific because it uses the decoded
2567 * value, not the encoded CBOR. It is further complicated for
2568 * maps because the order of items in a map that is a label
2569 * doesn't matter when checking that is is the duplicate of
2570 * another map that is a label. QCBOR so far only turns on this
2571 * dup checking as part of CDE checking which requires preferred
2572 * serialization. See 5.6 in RFC 8949.
2573 */
2574 nCompare = UsefulInputBuf_Compare(&(pMe->InBuf),
2575 uCompareLabelStart, uCompareLabelLen,
2576 uLabelStart, uLabelLen);
2577 if(nCompare == 0) {
2578 uErr = QCBOR_ERR_DUPLICATE_LABEL;
2579 break;
2580 }
2581 } while (1);
2582
2583 pMe->nesting = SaveNesting;
2584 pMe->InBuf = Save;
2585
2586 return uErr;
2587}
2588
2589
2590/* This does sort order and duplicate detection on a map. The and all
2591 * it's members must be in preferred serialization so the comparisons
2592 * work correctly.
2593 */
2594static QCBORError
2595QCBORDecode_Private_CheckMap(QCBORDecodeContext *pMe, const QCBORItem *pMapToCheck)
2596{
2597 QCBORError uErr;
2598 uint8_t uNestLevel;
2599 size_t offset2, offset1, length2, length1;
2600
2601 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2602 const UsefulInputBuf Save = pMe->InBuf;
2603 pMe->bAllowAllLabels = 1;
2604
2605 /* This loop runs over all the items in the map once, comparing
2606 * each adjacent pair for correct ordering. It also calls CheckDup
2607 * on each one which also runs over the remaining items in the map
2608 * checking for duplicates. So duplicate checking runs in n^2.
2609 */
2610
2611 offset2 = SIZE_MAX;
2612 length2 = SIZE_MAX; // To avoid uninitialized warning
2613 while(1) {
2614 uErr = QCBORDecode_Private_GetLabelAndConsume(pMe, &uNestLevel, &offset1, &length1);
2615 if(uErr != QCBOR_SUCCESS) {
2616 if(uErr == QCBOR_ERR_NO_MORE_ITEMS) {
2617 uErr = QCBOR_SUCCESS; /* Successful exit from loop */
2618 }
2619 break;
2620 }
2621
2622 if(uNestLevel < pMapToCheck->uNextNestLevel) {
2623 break; /* Successful exit from loop */
2624 }
2625
2626 if(offset2 != SIZE_MAX) {
2627 /* Check that the labels are ordered. Check is not done the
2628 * first time through the loop when offset2 is unset. Since
2629 * this does comparison of the items in encoded form they
2630 * must be preferred serialization encoded. See RFC 8949
2631 * 4.2.1.
2632 */
2633 if(UsefulInputBuf_Compare(&(pMe->InBuf), offset2, length2, offset1, length1) > 0) {
2634 uErr = QCBOR_ERR_UNSORTED;
2635 break;
2636 }
2637 }
2638
2639 uErr = QCBORDecode_Private_CheckDups(pMe, pMapToCheck->uNextNestLevel, offset1, length1);
2640 if(uErr != QCBOR_SUCCESS) {
2641 break;
2642 }
2643
2644 offset2 = offset1;
2645 length2 = length1;
2646 }
2647
2648 pMe->bAllowAllLabels = 0;
2649 pMe->nesting = SaveNesting;
2650 pMe->InBuf = Save;
2651
2652 return uErr;
2653}
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002654#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
2655
2656static QCBORError
2657QCBORDecode_Private_GetItemChecks(QCBORDecodeContext *pMe,
2658 QCBORError uErr,
2659 const size_t uOffset,
2660 QCBORItem *pDecodedItem)
2661{
2662 (void)pMe; /* Avoid warning for next two ifdefs */
2663 (void)uOffset;
2664
2665#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
2666 if(uErr == QCBOR_SUCCESS &&
Laurence Lundblade36b28f92024-11-19 21:47:28 -08002667 pMe->uDecodeMode & QCBOR_DECODE_ONLY_SORTED_MAPS &&
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002668 pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
2669 /* Traverse map checking sort order and for duplicates */
2670 uErr = QCBORDecode_Private_CheckMap(pMe, pDecodedItem);
2671 }
2672#endif /* ! QCBOR_DISABLE_CONFORMANCE */
2673
2674#ifndef QCBOR_DISABLE_TAGS
2675 if(uErr == QCBOR_SUCCESS &&
2676 !(pMe->uDecodeMode & QCBOR_DECODE_UNPROCESSED_TAG_NUMBERS) &&
2677 pDecodedItem->auTagNumbers[0] != CBOR_TAG_INVALID16) {
2678 /* Not QCBOR v1; there are tag numbers -- check they were consumed */
2679 if(uOffset != pMe->uTagNumberCheckOffset || pMe->uTagNumberIndex != 255) {
2680 uErr = QCBOR_ERR_UNPROCESSED_TAG_NUMBER;
2681 }
2682 }
2683#endif /* ! QCBOR_DISABLE_TAGS */
2684
2685 if(uErr != QCBOR_SUCCESS) {
2686 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2687 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
2688 }
2689
2690 return uErr;
2691}
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002692
2693
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002694/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002695 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002696 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002697QCBORError
2698QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2699{
2700 QCBORError uErr;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002701 size_t uOffset;
2702
2703 uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002704 uErr = QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem);
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002705 uErr = QCBORDecode_Private_GetItemChecks(pMe, uErr, uOffset, pDecodedItem);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002706 return uErr;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002707}
2708
2709
2710/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002711 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08002712 */
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002713QCBORError
2714QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2715{
2716 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2717 const UsefulInputBuf Save = pMe->InBuf;
2718
2719 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
2720
2721 pMe->nesting = SaveNesting;
2722 pMe->InBuf = Save;
2723
2724 return uErr;
2725}
2726
2727
2728/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002729 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002730 */
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002731void
2732QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2733{
2734 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002735 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2736 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002737 return;
2738 }
2739
2740 pMe->uLastError = (uint8_t)QCBORDecode_PeekNext(pMe, pDecodedItem);
2741}
2742
2743
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002744static void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002745QCBORDecode_Private_SaveTagNumbers(QCBORDecodeContext *pMe, const QCBORItem *pItem)
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002746{
2747#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002748 memcpy(pMe->auLastTags, pItem->auTagNumbers, sizeof(pItem->auTagNumbers));
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002749#else
2750 (void)pMe;
2751 (void)pItem;
2752#endif
2753}
2754
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002755/*
2756 * Public function, see header qcbor/qcbor_decode.h file
2757 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002758void
2759QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002760{
2761 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002762 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2763 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002764 return;
2765 }
2766
2767 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem);
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002768 QCBORDecode_Private_SaveTagNumbers(pMe, pDecodedItem);
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002769}
2770
2771
2772/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002773 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002774 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002775QCBORError
2776QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002777{
Laurence Lundblade87495732021-02-26 10:05:55 -07002778 if(puConsumed != NULL) {
2779 *puConsumed = pMe->InBuf.cursor;
2780 }
2781
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002782 QCBORError uReturn = pMe->uLastError;
Laurence Lundblade085d7952020-07-24 10:26:30 -07002783
2784 if(uReturn != QCBOR_SUCCESS) {
2785 goto Done;
2786 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002787
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002788 /* Error out if all the maps/arrays are not closed out */
2789 if(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002790 uReturn = QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002791 goto Done;
2792 }
2793
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002794 /* Error out if not all the bytes are consumed */
2795 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf))) {
Laurence Lundblade085d7952020-07-24 10:26:30 -07002796 uReturn = QCBOR_ERR_EXTRA_BYTES;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002797 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002798
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002799Done:
Laurence Lundblade87495732021-02-26 10:05:55 -07002800 return uReturn;
2801}
2802
2803
2804/*
2805 * Public function, see header qcbor/qcbor_decode.h file
2806 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002807QCBORError
2808QCBORDecode_Finish(QCBORDecodeContext *pMe)
Laurence Lundblade87495732021-02-26 10:05:55 -07002809{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002810#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002811 /* Call the destructor for the string allocator if there is one.
2812 * Always called, even if there are errors; always have to clean up.
2813 */
2814 StringAllocator_Destruct(&(pMe->StringAllocator));
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002815#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002816
Laurence Lundblade87495732021-02-26 10:05:55 -07002817 return QCBORDecode_PartialFinish(pMe, NULL);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002818}
2819
2820
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002821#ifndef QCBOR_DISABLE_TAGS
2822/*
2823 * Public function, see header qcbor/qcbor_decode.h file
2824 */
2825uint64_t
2826QCBORDecode_GetNthTagNumber(const QCBORDecodeContext *pMe,
2827 const QCBORItem *pItem,
2828 uint8_t uIndex)
2829{
2830 if(pItem->uDataType == QCBOR_TYPE_NONE) {
2831 return CBOR_TAG_INVALID64;
2832 }
2833 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2834 return CBOR_TAG_INVALID64;
2835 }
2836
2837 return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->auTagNumbers[uIndex]);
2838}
2839
2840
2841/*
2842 * Public function, see header qcbor/qcbor_decode.h file
2843 */
2844uint64_t
2845QCBORDecode_GetNthTagNumberOfLast(QCBORDecodeContext *pMe,
2846 uint8_t uIndex)
2847{
2848 if(pMe->uLastError != QCBOR_SUCCESS) {
2849 return CBOR_TAG_INVALID64;
2850 }
2851 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2852 return CBOR_TAG_INVALID64;
2853 }
2854
2855 return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->auLastTags[uIndex]);
2856}
2857
2858
2859/*
2860 * Public function, see header qcbor/qcbor_decode.h file
2861 */
2862static uint64_t
2863QCBORDecode_Private_GetNthTagNumberReverse(const QCBORDecodeContext *pMe,
2864 const uint16_t puTagNumbers[],
2865 const uint32_t uIndex)
2866{
2867 uint32_t uArrayIndex;
2868
2869 /* Find number of tag numbers */
2870 for(uArrayIndex = QCBOR_MAX_TAGS_PER_ITEM-1; uArrayIndex > 0; uArrayIndex--) {
2871 if(puTagNumbers[uArrayIndex] != CBOR_TAG_INVALID16) {
2872 break;
2873 }
2874 }
2875 if(uIndex > uArrayIndex) {
2876 return CBOR_TAG_INVALID64;
2877 }
2878
2879 return QCBORDecode_Private_UnMapTagNumber(pMe, puTagNumbers[uArrayIndex - uIndex]);
2880}
2881
2882
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002883/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002884 * Public function, see header qcbor/qcbor_decode.h file
2885 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002886uint64_t
2887QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
2888 const QCBORItem *pItem,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002889 const uint32_t uIndex)
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002890{
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002891 if(pItem->uDataType == QCBOR_TYPE_NONE) {
2892 return CBOR_TAG_INVALID64;
2893 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002894
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002895 return QCBORDecode_Private_GetNthTagNumberReverse(pMe, pItem->auTagNumbers, uIndex);
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002896}
2897
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002898
Laurence Lundblade9b334962020-08-27 10:55:53 -07002899/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002900 * Public function, see header qcbor/qcbor_decode.h file
2901 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002902uint64_t
2903QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe,
2904 uint32_t uIndex)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002905{
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002906 if(pMe->uLastError != QCBOR_SUCCESS) {
2907 return CBOR_TAG_INVALID64;
2908 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002909 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2910 return CBOR_TAG_INVALID64;
Laurence Lundblade9b334962020-08-27 10:55:53 -07002911 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002912
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002913 return QCBORDecode_Private_GetNthTagNumberReverse(pMe, pMe->auLastTags, uIndex);
Laurence Lundblade9b334962020-08-27 10:55:53 -07002914}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002915
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002916
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002917/*
2918 * Public function, see header qcbor/qcbor_decode.h file
2919 */
2920QCBORError
2921QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pMe, uint64_t *puTagNumber)
2922{
2923 QCBORItem Item;
2924 size_t uOffset;
2925 QCBORError uErr;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002926
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002927 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2928 const UsefulInputBuf Save = pMe->InBuf;
2929
2930 uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
2931 if(uOffset == pMe->uTagNumberCheckOffset) {
2932 pMe->uTagNumberIndex++;
2933 } else {
2934 pMe->uTagNumberIndex = 0;
2935 }
2936
2937 *puTagNumber = CBOR_TAG_INVALID64;
2938 uErr = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
2939 if(uErr) {
2940 return uErr;
2941 }
2942
2943 *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &Item, pMe->uTagNumberIndex);
2944 if(*puTagNumber == CBOR_TAG_INVALID64 ||
2945 QCBORDecode_GetNthTagNumber(pMe, &Item, pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
2946 pMe->uTagNumberIndex = QCBOR_ALL_TAGS_PROCESSED;
2947 }
2948 pMe->uTagNumberCheckOffset = uOffset;
2949
2950 pMe->nesting = SaveNesting;
2951 pMe->InBuf = Save;
2952
2953 return QCBOR_SUCCESS;
2954}
2955
2956
2957/*
2958 * Public function, see header qcbor/qcbor_decode.h file
2959 */
2960void
2961QCBORDecode_VGetNextTagNumber(QCBORDecodeContext *pMe, uint64_t *puTagNumber)
2962{
2963 pMe->uLastError = (uint8_t)QCBORDecode_GetNextTagNumber(pMe, puTagNumber);
2964}
2965
2966#endif /* ! QCBOR_DISABLE_TAGS */
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002967
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002968#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladef6531662018-12-04 10:42:22 +09002969
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002970/* ===========================================================================
2971 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002972
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002973 This implements a simple sting allocator for indefinite-length
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002974 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
2975 implements the function type QCBORStringAllocate and allows easy
2976 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09002977
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002978 This particular allocator is built-in for convenience. The caller
2979 can implement their own. All of this following code will get
2980 dead-stripped if QCBORDecode_SetMemPool() is not called.
2981
2982 This is a very primitive memory allocator. It does not track
2983 individual allocations, only a high-water mark. A free or
2984 reallocation must be of the last chunk allocated.
2985
2986 The size of the pool and offset to free memory are packed into the
2987 first 8 bytes of the memory pool so we don't have to keep them in
2988 the decode context. Since the address of the pool may not be
2989 aligned, they have to be packed and unpacked as if they were
2990 serialized data of the wire or such.
2991
2992 The sizes packed in are uint32_t to be the same on all CPU types
2993 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08002994 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002995
2996
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002997static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08002998MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002999{
3000 // Use of UsefulInputBuf is overkill, but it is convenient.
3001 UsefulInputBuf UIB;
3002
Laurence Lundbladeee851742020-01-08 08:37:05 -08003003 // Just assume the size here. It was checked during SetUp so
3004 // the assumption is safe.
Laurence Lundblade93d89472020-10-03 22:30:50 -07003005 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem,QCBOR_DECODE_MIN_MEM_POOL_SIZE});
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003006 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
3007 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
3008 return UsefulInputBuf_GetError(&UIB);
3009}
3010
3011
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003012static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08003013MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003014{
3015 // Use of UsefulOutBuf is overkill, but convenient. The
3016 // length check performed here is useful.
3017 UsefulOutBuf UOB;
3018
3019 UsefulOutBuf_Init(&UOB, Pool);
3020 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
3021 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
3022 return UsefulOutBuf_GetError(&UOB);
3023}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003024
3025
3026/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003027 Internal function for an allocation, reallocation free and destuct.
3028
3029 Having only one function rather than one each per mode saves space in
3030 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003031
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003032 Code Reviewers: THIS FUNCTION DOES POINTER MATH
3033 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08003034static UsefulBuf
3035MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003036{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003037 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003038
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003039 uint32_t uPoolSize;
3040 uint32_t uFreeOffset;
3041
3042 if(uNewSize > UINT32_MAX) {
3043 // This allocator is only good up to 4GB. This check should
3044 // optimize out if sizeof(size_t) == sizeof(uint32_t)
3045 goto Done;
3046 }
3047 const uint32_t uNewSize32 = (uint32_t)uNewSize;
3048
3049 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
3050 goto Done;
3051 }
3052
3053 if(uNewSize) {
3054 if(pMem) {
3055 // REALLOCATION MODE
3056 // Calculate pointer to the end of the memory pool. It is
3057 // assumed that pPool + uPoolSize won't wrap around by
3058 // assuming the caller won't pass a pool buffer in that is
3059 // not in legitimate memory space.
3060 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
3061
3062 // Check that the pointer for reallocation is in the range of the
3063 // pool. This also makes sure that pointer math further down
3064 // doesn't wrap under or over.
3065 if(pMem >= pPool && pMem < pPoolEnd) {
3066 // Offset to start of chunk for reallocation. This won't
3067 // wrap under because of check that pMem >= pPool. Cast
3068 // is safe because the pool is always less than UINT32_MAX
3069 // because of check in QCBORDecode_SetMemPool().
3070 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3071
3072 // Check to see if the allocation will fit. uPoolSize -
3073 // uMemOffset will not wrap under because of check that
3074 // pMem is in the range of the uPoolSize by check above.
3075 if(uNewSize <= uPoolSize - uMemOffset) {
3076 ReturnValue.ptr = pMem;
3077 ReturnValue.len = uNewSize;
3078
3079 // Addition won't wrap around over because uNewSize was
3080 // checked to be sure it is less than the pool size.
3081 uFreeOffset = uMemOffset + uNewSize32;
3082 }
3083 }
3084 } else {
3085 // ALLOCATION MODE
3086 // uPoolSize - uFreeOffset will not underflow because this
3087 // pool implementation makes sure uFreeOffset is always
3088 // smaller than uPoolSize through this check here and
3089 // reallocation case.
3090 if(uNewSize <= uPoolSize - uFreeOffset) {
3091 ReturnValue.len = uNewSize;
3092 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08003093 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003094 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003095 }
3096 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003097 if(pMem) {
3098 // FREE MODE
3099 // Cast is safe because of limit on pool size in
3100 // QCBORDecode_SetMemPool()
3101 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3102 } else {
3103 // DESTRUCT MODE
3104 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003105 }
3106 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003107
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003108 UsefulBuf Pool = {pPool, uPoolSize};
3109 MemPool_Pack(Pool, uFreeOffset);
3110
3111Done:
3112 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003113}
3114
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003115
Laurence Lundbladef6531662018-12-04 10:42:22 +09003116/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003117 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09003118 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003119QCBORError
3120QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
3121 UsefulBuf Pool,
3122 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003123{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003124 // The pool size and free mem offset are packed into the beginning
Dave Thaler93c01182022-08-06 15:08:35 -04003125 // of the pool memory. This compile time check makes sure the
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003126 // constant in the header is correct. This check should optimize
3127 // down to nothing.
Dave Thaler93c01182022-08-06 15:08:35 -04003128#ifdef _MSC_VER
3129#pragma warning(push)
3130#pragma warning(disable:4127) // conditional expression is constant
3131#endif
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003132 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003133 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003134 }
Dave Thaler93c01182022-08-06 15:08:35 -04003135#ifdef _MSC_VER
3136#pragma warning(pop)
3137#endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003138
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003139 // The pool size and free offset packed in to the beginning of pool
3140 // memory are only 32-bits. This check will optimize out on 32-bit
3141 // machines.
3142 if(Pool.len > UINT32_MAX) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003143 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003144 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003145
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003146 // This checks that the pool buffer given is big enough.
3147 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003148 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003149 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003150
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003151 QCBORDecode_SetUpAllocator(pMe, MemPool_Function, Pool.ptr, bAllStrings);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003152
Laurence Lundblade30816f22018-11-10 13:40:22 +07003153 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003154}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003155#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003156
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003157
3158
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003159/*
3160 * Public function, see header qcbor/qcbor_decode.h file
3161 */
3162void
3163QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003164{
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003165 QCBORDecode_VGetNext(pMe, pDecodedItem);
3166
3167 if(pMe->uLastError == QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003168 pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL,
Máté Tóth-Pálc6d59682021-05-26 18:55:30 +02003169 &pDecodedItem->uNextNestLevel);
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003170 }
3171}
3172
3173
Laurence Lundblade11654912024-05-09 11:49:24 -07003174/*
3175 * Public function, see header qcbor/qcbor_decode.h file
3176 */
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003177QCBORError
3178QCBORDecode_EndCheck(QCBORDecodeContext *pMe)
Laurence Lundblade11654912024-05-09 11:49:24 -07003179{
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003180 size_t uCursorOffset;
3181 QCBORError uErr;
Laurence Lundblade11654912024-05-09 11:49:24 -07003182
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003183 uErr = QCBORDecode_GetError(pMe);
3184 if(uErr != QCBOR_SUCCESS) {
3185 return uErr;
Laurence Lundblade11654912024-05-09 11:49:24 -07003186 }
3187
3188 uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
3189
3190 if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003191 return QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade11654912024-05-09 11:49:24 -07003192 }
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003193
3194 return QCBOR_SUCCESS;
Laurence Lundblade11654912024-05-09 11:49:24 -07003195}
3196
3197
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003198/**
3199 * @brief Rewind cursor to start as if map or array were just entered.
3200 *
3201 * @param[in] pMe The decoding context
3202 *
3203 * This affects the nesting tracking and the UsefulInputBuf.
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003204 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003205static void
3206QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003207{
3208 /* Reset nesting tracking to the deepest bounded level */
3209 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3210
3211 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3212
3213 /* Reposition traversal cursor to the start of the map/array */
3214 UsefulInputBuf_Seek(&(pMe->InBuf),
3215 DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
3216}
3217
3218
3219/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003220 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003221 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003222void
3223QCBORDecode_Rewind(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003224{
3225 if(pMe->nesting.pCurrentBounded != NULL) {
3226 /* In a bounded map, array or bstr-wrapped CBOR */
3227
3228 if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
3229 /* In bstr-wrapped CBOR. */
3230
3231 /* Reposition traversal cursor to start of wrapping byte string */
3232 UsefulInputBuf_Seek(&(pMe->InBuf),
3233 pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
3234 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3235
3236 } else {
3237 /* In a map or array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003238 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003239 }
3240
3241 } else {
3242 /* Not in anything bounded */
3243
3244 /* Reposition traversal cursor to the start of input CBOR */
3245 UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
3246
3247 /* Reset nesting tracking to beginning of input. */
3248 DecodeNesting_Init(&(pMe->nesting));
3249 }
3250
3251 pMe->uLastError = QCBOR_SUCCESS;
3252}
3253
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003254
Laurence Lundblade9b334962020-08-27 10:55:53 -07003255
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003256
3257
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003258typedef struct {
3259 void *pCBContext;
3260 QCBORItemCallback pfCallback;
3261} MapSearchCallBack;
3262
3263typedef struct {
3264 size_t uStartOffset;
3265 uint16_t uItemCount;
3266} MapSearchInfo;
3267
3268
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003269/**
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003270 * @brief Search a map for a set of items.
3271 *
3272 * @param[in] pMe The decode context to search.
3273 * @param[in,out] pItemArray The items to search for and the items found.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003274 * @param[out] pInfo Several bits of meta-info returned by search.
3275 * @param[in] pCallBack Callback object or @c NULL.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003276 *
3277 * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map.
3278 *
3279 * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label)
3280 * were found for one of the labels being
3281 * search for. This duplicate detection is
3282 * only performed for items in pItemArray,
3283 * not every item in the map.
3284 *
3285 * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was
3286 * wrong for the matchd label.
3287 *
3288 * @retval Also errors returned by QCBORDecode_GetNext().
3289 *
Laurence Lundblade88ba5662024-11-03 02:10:24 -08003290 * On input, @c pItemArray contains a list of labels and data types of
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003291 * items to be found.
3292 *
3293 * On output, the fully retrieved items are filled in with values and
3294 * such. The label was matched, so it never changes.
3295 *
3296 * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE.
3297 *
3298 * This also finds the ends of maps and arrays when they are exited.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003299 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003300static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003301QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
3302 QCBORItem *pItemArray,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003303 MapSearchInfo *pInfo,
3304 MapSearchCallBack *pCallBack)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003305{
Laurence Lundbladee6f15112020-07-23 18:44:16 -07003306 QCBORError uReturn;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003307 uint64_t uFoundItemBitMap = 0;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07003308
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003309 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003310 uReturn = pMe->uLastError;
3311 goto Done2;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003312 }
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003313
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003314 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) &&
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003315 pItemArray->uLabelType != QCBOR_TYPE_NONE) {
3316 /* QCBOR_TYPE_NONE as first item indicates just looking
3317 for the end of an array, so don't give error. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003318 uReturn = QCBOR_ERR_MAP_NOT_ENTERED;
3319 goto Done2;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003320 }
3321
Laurence Lundblade085d7952020-07-24 10:26:30 -07003322 if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) {
3323 // It is an empty bounded array or map
3324 if(pItemArray->uLabelType == QCBOR_TYPE_NONE) {
3325 // Just trying to find the end of the map or array
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003326 pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003327 uReturn = QCBOR_SUCCESS;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003328 } else {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003329 // Nothing is ever found in an empty array or map. All items
3330 // are marked as not found below.
Laurence Lundblade085d7952020-07-24 10:26:30 -07003331 uReturn = QCBOR_SUCCESS;
3332 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003333 goto Done2;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003334 }
3335
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003336 QCBORDecodeNesting SaveNesting;
Laurence Lundblade11654912024-05-09 11:49:24 -07003337 size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003338 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3339
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003340 /* Reposition to search from the start of the map / array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003341 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundblade1341c592020-04-11 14:19:05 -07003342
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003343 /*
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003344 Loop over all the items in the map or array. Each item
3345 could be a map or array, but label matching is only at
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003346 the main level. This handles definite- and indefinite-
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003347 length maps and arrays. The only reason this is ever
3348 called on arrays is to find their end position.
3349
3350 This will always run over all items in order to do
3351 duplicate detection.
3352
3353 This will exit with failure if it encounters an
3354 unrecoverable error, but continue on for recoverable
3355 errors.
3356
3357 If a recoverable error occurs on a matched item, then
3358 that error code is returned.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003359 */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07003360 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003361 if(pInfo) {
3362 pInfo->uItemCount = 0;
3363 }
Máté Tóth-Pál2f2aa5f2021-05-17 21:35:09 +02003364 uint8_t uNextNestLevel;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003365 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003366 /* Remember offset of the item because sometimes it has to be returned */
Laurence Lundblade1341c592020-04-11 14:19:05 -07003367 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003368
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003369 /* Get the item */
3370 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003371 /* QCBORDecode_Private_GetNextTagContent() rather than GetNext()
3372 * because a label match is performed on recoverable errors to
3373 * be able to return the the error code for the found item. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003374 QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003375 if(QCBORDecode_IsUnrecoverableError(uResult)) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003376 /* The map/array can't be decoded when unrecoverable errors occur */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003377 uReturn = uResult;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003378 goto Done;
3379 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003380 if(uResult == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003381 /* Unexpected end of map or array. */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003382 uReturn = uResult;
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003383 goto Done;
3384 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003385
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003386 /* See if item has one of the labels that are of interest */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003387 bool bMatched = false;
3388 for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003389 if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003390 /* A label match has been found */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003391 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
3392 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003393 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003394 }
Laurence Lundblade63926052021-03-29 16:05:51 -07003395 if(uResult != QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003396 /* The label matches, but the data item is in error.
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003397 * It is OK to have recoverable errors on items that
3398 * are not matched. */
Laurence Lundblade63926052021-03-29 16:05:51 -07003399 uReturn = uResult;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003400 goto Done;
3401 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003402 if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) {
Laurence Lundblade63926052021-03-29 16:05:51 -07003403 /* The data item is not of the type(s) requested */
3404 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003405 goto Done;
3406 }
3407
Laurence Lundblade1341c592020-04-11 14:19:05 -07003408 /* Successful match. Return the item. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003409 pItemArray[nIndex] = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003410 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003411 if(pInfo) {
3412 pInfo->uStartOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003413 }
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003414 bMatched = true;
3415 }
3416 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003417
3418
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003419 if(!bMatched && pCallBack != NULL) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003420 /*
3421 Call the callback on unmatched labels.
3422 (It is tempting to do duplicate detection here, but that would
3423 require dynamic memory allocation because the number of labels
3424 that might be encountered is unbounded.)
3425 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003426 uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item);
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003427 if(uReturn != QCBOR_SUCCESS) {
3428 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003429 }
3430 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003431
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003432 /*
3433 Consume the item whether matched or not. This
3434 does the work of traversing maps and array and
3435 everything in them. In this loop only the
3436 items at the current nesting level are examined
3437 to match the labels.
3438 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003439 uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel);
Laurence Lundbladec7114722020-08-13 05:11:40 -07003440 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003441 goto Done;
3442 }
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003443
3444 if(pInfo) {
3445 pInfo->uItemCount++;
3446 }
3447
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003448 } while (uNextNestLevel >= uMapNestLevel);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003449
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003450 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003451
3452 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003453
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003454 // Check here makes sure that this won't accidentally be
3455 // QCBOR_MAP_OFFSET_CACHE_INVALID which is larger than
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003456 // QCBOR_MAX_DECODE_INPUT_SIZE.
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -08003457 // Cast to uint32_t to possibly address cases where SIZE_MAX < UINT32_MAX
3458 if((uint32_t)uEndOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003459 uReturn = QCBOR_ERR_INPUT_TOO_LARGE;
3460 goto Done;
3461 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003462 /* Cast OK because encoded CBOR is limited to UINT32_MAX */
3463 pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003464
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003465 Done:
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003466 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade11654912024-05-09 11:49:24 -07003467 UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos);
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003468
3469 Done2:
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003470 /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */
Laurence Lundbladec7114722020-08-13 05:11:40 -07003471 for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003472 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003473 pItemArray[i].uDataType = QCBOR_TYPE_NONE;
3474 pItemArray[i].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003475 }
3476 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003477
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003478 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003479}
3480
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003481
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003482/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003483 * Public function, see header qcbor/qcbor_decode.h file
3484 */
3485void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003486QCBORDecode_SeekToLabelN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003487{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003488 MapSearchInfo Info;
3489 QCBORItem OneItemSeach[2];
3490
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003491 if(pMe->uLastError != QCBOR_SUCCESS) {
3492 return;
3493 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003494
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003495 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3496 OneItemSeach[0].label.int64 = nLabel;
3497 OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
3498 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
3499
3500 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
3501 if(pMe->uLastError == QCBOR_SUCCESS) {
3502 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
3503 }
3504}
3505
3506
3507void
3508QCBORDecode_SeekToLabelSZ(QCBORDecodeContext *pMe, const char *szLabel)
3509{
3510#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
3511 MapSearchInfo Info;
3512 QCBORItem OneItemSeach[2];
3513
3514 if(pMe->uLastError != QCBOR_SUCCESS) {
3515 return;
3516 }
3517
3518 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3519 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3520 OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
3521 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
3522
3523 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
3524 if(pMe->uLastError == QCBOR_SUCCESS) {
3525 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
3526 }
3527#else
3528 (void)pMe;
3529 (void)szLabel;
3530 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
3531#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
3532}
3533
3534
3535void
3536QCBORDecode_Private_GetItemInMapNoCheck(QCBORDecodeContext *pMe,
3537 QCBORItem *OneItemSeach,
3538 QCBORItem *pItem,
3539 size_t *puOffset)
3540{
3541 QCBORError uErr;
3542 MapSearchInfo SearchInfo;
3543
3544 if(pMe->uLastError != QCBOR_SUCCESS) {
3545 return;
3546 }
3547
3548 uErr = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &SearchInfo, NULL);
3549
3550 if(uErr == QCBOR_SUCCESS && OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
3551 uErr = QCBOR_ERR_LABEL_NOT_FOUND;
3552 }
3553 *pItem = OneItemSeach[0];
3554 *puOffset = SearchInfo.uStartOffset;
3555
3556 if(uErr == QCBOR_SUCCESS) {
3557 QCBORDecode_Private_SaveTagNumbers(pMe, pItem);
3558 }
3559
3560 pMe->uLastError = (uint8_t)uErr;
3561}
3562
3563
3564static void
3565QCBORDecode_Private_GetItemInMap(QCBORDecodeContext *pMe, QCBORItem *OneItemSeach, QCBORItem *pItem)
3566{
3567 QCBORError uErr;
3568 size_t uOffset;
3569
3570 QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, &uOffset);
3571
3572 uErr = QCBORDecode_Private_GetItemChecks(pMe, pMe->uLastError, uOffset, pItem);
3573 if(uErr != QCBOR_SUCCESS) {
3574 goto Done;
3575 }
3576
3577 QCBORDecode_Private_SaveTagNumbers(pMe, pItem);
3578
3579Done:
3580 pMe->uLastError = (uint8_t)uErr;
3581}
3582
3583
3584/*
3585 * Public function, see header qcbor/qcbor_decode.h file
3586 */
3587void
3588QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
3589 const int64_t nLabel,
3590 const uint8_t uQcborType,
3591 QCBORItem *pItem)
3592{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003593 QCBORItem OneItemSeach[2];
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003594
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003595 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3596 OneItemSeach[0].label.int64 = nLabel;
3597 OneItemSeach[0].uDataType = uQcborType;
3598 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003599
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003600 QCBORDecode_Private_GetItemInMap(pMe, OneItemSeach, pItem);
3601}
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003602
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003603
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003604/**
3605 * @brief Get an item by label by type.
3606 *
3607 * @param[in] pMe The decode context.
3608 * @param[in] nLabel The label to search map for.
3609 * @param[in] uQcborType The QCBOR type to look for.
3610 * @param[out] pItem The item found.
3611 * @param[out] puOffset The offset of item for tag consumption check.
3612 *
3613 * This finds the item with the given label in currently open
3614 * map. This does not call QCBORDecode_Private_GetItemChecks()
3615 * to check tag number consumption or decode conformance.
3616 */
3617static void
3618QCBORDecode_GetItemInMapNoCheckN(QCBORDecodeContext *pMe,
3619 const int64_t nLabel,
3620 const uint8_t uQcborType,
3621 QCBORItem *pItem,
3622 size_t *puOffset)
3623{
3624 QCBORItem OneItemSeach[2];
Laurence Lundblade1341c592020-04-11 14:19:05 -07003625
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003626 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3627 OneItemSeach[0].label.int64 = nLabel;
3628 OneItemSeach[0].uDataType = uQcborType;
3629 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003630
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003631 QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, puOffset);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003632}
3633
3634
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003635/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003636 * Public function, see header qcbor/qcbor_decode.h file
3637 */
3638void
3639QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
3640 const char *szLabel,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003641 const uint8_t uQcborType,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003642 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003643{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003644#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003645 QCBORItem OneItemSeach[2];
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003646
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003647 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3648 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3649 OneItemSeach[0].uDataType = uQcborType;
3650 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003651
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003652 QCBORDecode_Private_GetItemInMap(pMe, OneItemSeach, pItem);
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003653
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003654#else
3655 (void)pMe;
3656 (void)szLabel;
3657 (void)uQcborType;
3658 (void)pItem;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003659 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003660#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003661}
3662
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003663/**
3664 * @brief Get an item by string label of a particular type
3665 *
3666 * @param[in] pMe The decode context.
3667 * @param[in] szLabel The label to search map for.
3668 * @param[in] uQcborType The QCBOR type to look for.
3669 * @param[out] pItem The item found.
3670 * @param[out] puOffset The offset of item for tag consumption check.
3671 *
3672 * This finds the item with the given label in currently open
3673 * map. This does not call QCBORDecode_Private_GetItemChecks()
3674 * to check tag number consumption or decode conformance.
3675 */
3676static void
3677QCBORDecode_GetItemInMapNoCheckSZ(QCBORDecodeContext *pMe,
3678 const char *szLabel,
3679 const uint8_t uQcborType,
3680 QCBORItem *pItem,
3681 size_t *puOffset)
3682{
3683#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
3684 QCBORItem OneItemSeach[2];
3685
3686 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3687 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3688 OneItemSeach[0].uDataType = uQcborType;
3689 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
3690
3691 QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, puOffset);
3692
3693#else
3694 (void)pMe;
3695 (void)szLabel;
3696 (void)uQcborType;
3697 (void)pItem;
3698 (void)puOffset;
3699 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
3700#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
3701}
3702
3703
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003704
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003705
3706/**
3707 * @brief Semi-private. Get pointer, length and item for an array or map.
3708 *
3709 * @param[in] pMe The decode context.
3710 * @param[in] uType CBOR major type, either array/map.
3711 * @param[out] pItem The item for the array/map.
3712 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3713 *
Laurence Lundblade88ba5662024-11-03 02:10:24 -08003714 * The next item to be decoded must be a map or array as specified by @c uType.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003715 *
Laurence Lundblade88ba5662024-11-03 02:10:24 -08003716 * @c pItem will be filled in with the label and tags of the array or map
3717 * in addition to @c pEncodedCBOR giving the pointer and length of the
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003718 * encoded CBOR.
3719 *
3720 * When this is complete, the traversal cursor is at the end of the array or
3721 * map that was retrieved.
3722 */
3723void
3724QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe,
3725 const uint8_t uType,
3726 QCBORItem *pItem,
3727 UsefulBufC *pEncodedCBOR)
3728{
3729 QCBORError uErr;
3730 uint8_t uNestLevel;
3731 size_t uStartingCursor;
3732 size_t uStartOfReturned;
3733 size_t uEndOfReturned;
3734 size_t uTempSaveCursor;
3735 bool bInMap;
3736 QCBORItem LabelItem;
3737 bool EndedByBreak;
3738
3739 uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3740 bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting));
3741
3742 /* Could call GetNext here, but don't need to because this
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07003743 * is only interested in arrays and maps. TODO: switch to GetNext()? */
3744 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem, NULL);
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003745 if(uErr != QCBOR_SUCCESS) {
3746 pMe->uLastError = (uint8_t)uErr;
3747 return;
3748 }
3749
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003750 uint8_t uItemDataType = pItem->uDataType;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003751#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003752 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
3753 uItemDataType = QCBOR_TYPE_ARRAY;
3754 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003755#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003756
3757 if(uItemDataType != uType) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003758 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
3759 return;
3760 }
3761
3762 if(bInMap) {
3763 /* If the item is in a map, the start of the array/map
3764 * itself, not the label, must be found. Do this by
3765 * rewinding to the starting position and fetching
3766 * just the label data item. QCBORDecode_Private_GetNextTagNumber()
3767 * doesn't do any of the array/map item counting or nesting
3768 * level tracking. Used here it will just fetech the label
3769 * data item.
3770 *
3771 * Have to save the cursor and put it back to the position
3772 * after the full item once the label as been fetched by
3773 * itself.
3774 */
3775 uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3776 UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor);
3777
3778 /* Item has been fetched once so safe to ignore error */
3779 (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem);
3780
3781 uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3782 UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor);
3783 } else {
3784 uStartOfReturned = uStartingCursor;
3785 }
3786
3787 /* Consume the entire array/map to find the end */
3788 uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel);
3789 if(uErr != QCBOR_SUCCESS) {
3790 pMe->uLastError = (uint8_t)uErr;
3791 goto Done;
3792 }
3793
3794 /* Fill in returned values */
3795 uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3796 if(EndedByBreak) {
3797 /* When ascending nesting levels, a break for the level above
3798 * was consumed. That break is not a part of what is consumed here. */
3799 uEndOfReturned--;
3800 }
3801 pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned);
3802 pEncodedCBOR->len = uEndOfReturned - uStartOfReturned;
3803
3804Done:
3805 return;
3806}
3807
3808
3809/**
3810 * @brief Semi-private. Get pointer, length and item count of an array or map.
3811 *
3812 * @param[in] pMe The decode context.
3813 * @param[in] pTarget The label and type of the array or map to retrieve.
3814 * @param[out] pItem The item for the array/map.
3815 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3816 *
Laurence Lundblade88ba5662024-11-03 02:10:24 -08003817 * The next item to be decoded must be a map or array as specified by @c uType.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003818 *
3819 * When this is complete, the traversal cursor is unchanged.
3820 */void
3821QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe,
3822 QCBORItem *pTarget,
3823 QCBORItem *pItem,
3824 UsefulBufC *pEncodedCBOR)
3825{
3826 MapSearchInfo Info;
3827 QCBORDecodeNesting SaveNesting;
3828 size_t uSaveCursor;
3829
3830 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL);
3831 if(pMe->uLastError != QCBOR_SUCCESS) {
3832 return;
3833 }
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003834 pMe->uLastError = (uint8_t)QCBORDecode_Private_GetItemChecks(pMe, pMe->uLastError, Info.uStartOffset, pItem);
3835 if(pMe->uLastError != QCBOR_SUCCESS) {
3836 return;
3837 }
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003838
3839 /* Save the whole position of things so they can be restored.
3840 * so the cursor position is unchanged by this operation, like
3841 * all the other GetXxxxInMap() operations. */
3842 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3843 uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3844
3845 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3846 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
3847 QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR);
3848
3849 UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor);
3850 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
3851}
3852
3853
3854
3855
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003856static void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003857QCBORDecode_Private_ProcessTagOne(QCBORDecodeContext *pMe,
3858 QCBORItem *pItem,
3859 const uint8_t uTagRequirement,
3860 const uint8_t uQCBORType,
3861 const uint64_t uTagNumber,
3862 QCBORTagContentCallBack *pfCB,
3863 size_t uOffset);
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003864
3865/**
3866 * @brief Semi-private to get an string by label to match a tag specification.
3867 *
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003868 * @param[in] pMe The decode context.
3869 * @param[in] nLabel Label to search map for.
3870 * @param[in] uTagRequirement Whether or not tag number is required.
3871 * See @ref QCBOR_TAG_REQUIREMENT_TAG.
3872 * @param[in] uQCBOR_Type QCBOR type to search for.
3873 * @param[in] uTagNumber Tag number to match.
3874 * @param[out] pString The string found.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003875 *
3876 * This finds the string with the given label in currently open
3877 * map. Then checks that its tag number and types matches the tag
3878 * specification. If not, an error is set in the decode context.
3879 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003880void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003881QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
3882 const int64_t nLabel,
3883 const uint8_t uTagRequirement,
3884 const uint8_t uQCBOR_Type,
3885 const uint64_t uTagNumber,
3886 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003887{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003888 QCBORItem Item;
3889 size_t uOffset;
3890
3891 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
3892 QCBORDecode_Private_ProcessTagOne(pMe,
3893 &Item,
3894 uTagRequirement,
3895 uQCBOR_Type,
3896 uTagNumber,
3897 QCBORDecode_StringsTagCB,
3898 uOffset);
3899
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003900 if(pMe->uLastError == QCBOR_SUCCESS) {
3901 *pString = Item.val.string;
3902 }
3903}
3904
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003905
3906/**
3907 * @brief Semi-private to get an string by label to match a tag specification.
3908 *
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003909 * @param[in] pMe The decode context.
3910 * @param[in] szLabel Label to search map for.
3911 * @param[in] uTagRequirement Whether or not tag number is required.
3912 * See @ref QCBOR_TAG_REQUIREMENT_TAG.
3913 * @param[in] uQCBOR_Type QCBOR type to search for.
3914 * @param[in] uTagNumber Tag number to match.
3915 * @param[out] pString The string found.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003916 *
3917 * This finds the string with the given label in currently open
3918 * map. Then checks that its tag number and types matches the tag
3919 * specification. If not, an error is set in the decode context.
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003920 */
3921void
3922QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
3923 const char *szLabel,
3924 uint8_t uTagRequirement,
3925 uint8_t uQCBOR_Type,
3926 uint64_t uTagNumber,
3927 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003928{
3929 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003930 size_t uOffset;
3931
3932 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
3933 QCBORDecode_Private_ProcessTagOne(pMe,
3934 &Item,
3935 uTagRequirement,
3936 uQCBOR_Type,
3937 uTagNumber,
3938 QCBORDecode_StringsTagCB,
3939 uOffset);
3940
3941
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003942 if(pMe->uLastError == QCBOR_SUCCESS) {
3943 *pString = Item.val.string;
3944 }
3945}
Laurence Lundblade1341c592020-04-11 14:19:05 -07003946
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003947
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003948/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003949 * Public function, see header qcbor/qcbor_decode.h file
3950 */
3951void
3952QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003953{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003954 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003955}
3956
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003957/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003958 * Public function, see header qcbor/qcbor_decode.h file
3959 */
3960void
3961QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe,
3962 QCBORItem *pItemList,
3963 void *pCallbackCtx,
3964 QCBORItemCallback pfCB)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003965{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003966 MapSearchCallBack CallBack;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003967
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003968 CallBack.pCBContext = pCallbackCtx;
3969 CallBack.pfCallback = pfCB;
3970
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003971 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003972}
3973
3974
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003975#ifndef QCBOR_DISABLE_TAGS
3976/*
3977 * Public function, see header qcbor/qcbor_decode.h file
3978 */
3979QCBORError
3980QCBORDecode_GetNextTagNumberInMapN(QCBORDecodeContext *pMe, const int64_t nLabel, uint64_t *puTagNumber)
3981{
3982 size_t uOffset;
3983 MapSearchInfo Info;
3984 QCBORItem OneItemSeach[2];
3985
3986 if(pMe->uLastError != QCBOR_SUCCESS) {
3987 return pMe->uLastError;
3988 }
3989
3990 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3991 OneItemSeach[0].label.int64 = nLabel;
3992 OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
3993 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
3994
3995 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
3996
3997 uOffset = Info.uStartOffset;
3998 if(uOffset == pMe->uTagNumberCheckOffset) {
3999 pMe->uTagNumberIndex++;
4000 } else {
4001 pMe->uTagNumberIndex = 0;
4002 }
4003
4004 *puTagNumber = CBOR_TAG_INVALID64;
4005
4006 *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex);
4007 if(*puTagNumber == CBOR_TAG_INVALID64 ||
4008 QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
4009 pMe->uTagNumberIndex = QCBOR_ALL_TAGS_PROCESSED;
4010 }
4011 pMe->uTagNumberCheckOffset = uOffset;
4012
4013 return uReturn;
4014}
4015
4016
4017/*
4018 * Public function, see header qcbor/qcbor_decode.h file
4019 */
4020QCBORError
4021QCBORDecode_GetNextTagNumberInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint64_t *puTagNumber)
4022{
4023#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
4024 size_t uOffset;
4025 MapSearchInfo Info;
4026 QCBORItem OneItemSeach[2];
4027
4028 if(pMe->uLastError != QCBOR_SUCCESS) {
4029 return pMe->uLastError;
4030 }
4031
4032 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4033 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4034 OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
4035 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
4036
4037 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
4038
4039
4040 uOffset = Info.uStartOffset;
4041 if(uOffset == pMe->uTagNumberCheckOffset) {
4042 pMe->uTagNumberIndex++;
4043 } else {
4044 pMe->uTagNumberIndex = 0;
4045 }
4046
4047 *puTagNumber = CBOR_TAG_INVALID64;
4048
4049 *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex);
4050 if(*puTagNumber == CBOR_TAG_INVALID64 ||
4051 QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
4052 pMe->uTagNumberIndex = 255; /* All tags clear for this item */
4053 }
4054 pMe->uTagNumberCheckOffset = uOffset;
4055
4056 return uReturn;
4057#else
4058 (void)pMe;
4059 (void)szLabel;
4060 (void)puTagNumber;
4061 return QCBOR_ERR_LABEL_NOT_FOUND;
4062#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
4063}
4064#endif /* ! QCBOR_DISABLE_TAGS */
4065
4066
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004067/**
4068 * @brief Search for a map/array by label and enter it
4069 *
4070 * @param[in] pMe The decode context.
4071 * @param[in] pSearch The map/array to search for.
4072 *
4073 * @c pSearch is expected to contain one item of type map or array
4074 * with the label specified. The current bounded map will be searched for
4075 * this and if found will be entered.
4076 *
4077 * If the label is not found, or the item found is not a map or array,
4078 * the error state is set.
4079 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004080static void
4081QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07004082{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004083 QCBORError uErr;
4084 MapSearchInfo SearchInfo;
4085
Laurence Lundblade323f8a92020-09-06 19:43:09 -07004086 // The first item in pSearch is the one that is to be
4087 // entered. It should be the only one filled in. Any other
4088 // will be ignored unless it causes an error.
Laurence Lundblade34691b92020-05-18 22:25:25 -07004089 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07004090 return;
4091 }
4092
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004093 uErr = QCBORDecode_Private_MapSearch(pMe, pSearch, &SearchInfo, NULL);
4094
4095 pMe->uLastError = (uint8_t)QCBORDecode_Private_GetItemChecks(pMe, uErr, SearchInfo.uStartOffset, pSearch);
4096
Laurence Lundblade34691b92020-05-18 22:25:25 -07004097 if(pMe->uLastError != QCBOR_SUCCESS) {
4098 return;
4099 }
4100
Laurence Lundblade9b334962020-08-27 10:55:53 -07004101 if(pSearch->uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004102 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004103 return;
4104 }
4105
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004106
4107 /* The map or array was found. Now enter it.
4108 *
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004109 * QCBORDecode_EnterBoundedMapOrArray() used here, requires the
4110 * next item for the pre-order traversal cursor to be the map/array
4111 * found by MapSearch(). The next few lines of code force the
4112 * cursor to that.
4113 *
4114 * There is no need to retain the old cursor because
4115 * QCBORDecode_EnterBoundedMapOrArray() will set it to the
4116 * beginning of the map/array being entered.
4117 *
4118 * The cursor is forced by: 1) setting the input buffer position to
4119 * the item offset found by MapSearch(), 2) setting the map/array
4120 * counter to the total in the map/array, 3) setting the nesting
4121 * level. Setting the map/array counter to the total is not
4122 * strictly correct, but this is OK because this cursor only needs
4123 * to be used to get one item and MapSearch() has already found it
4124 * confirming it exists.
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004125 */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004126 UsefulInputBuf_Seek(&(pMe->InBuf), SearchInfo.uStartOffset);
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004127
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004128 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
4129
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004130 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07004131
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004132 QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004133}
4134
4135
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004136/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004137 * Public function, see header qcbor/qcbor_decode.h file
4138 */
4139void
4140QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004141{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004142 QCBORItem OneItemSeach[2];
4143 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4144 OneItemSeach[0].label.int64 = nLabel;
4145 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4146 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004147
Laurence Lundblade9b334962020-08-27 10:55:53 -07004148 /* The map to enter was found, now finish off entering it. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004149 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004150}
4151
4152
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004153/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004154 * Public function, see header qcbor/qcbor_decode.h file
4155 */
4156void
4157QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004158{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004159#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004160 QCBORItem OneItemSeach[2];
4161 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4162 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4163 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4164 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004165
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004166 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004167#else
4168 (void)szLabel;
4169 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
4170#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004171}
4172
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004173/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004174 * Public function, see header qcbor/qcbor_decode.h file
4175 */
4176void
4177QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07004178{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004179 QCBORItem OneItemSeach[2];
4180 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4181 OneItemSeach[0].label.int64 = nLabel;
4182 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4183 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004184
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004185 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07004186}
4187
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004188/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004189 * Public function, see header qcbor/qcbor_decode.h file
4190 */
4191void
4192QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundblade34691b92020-05-18 22:25:25 -07004193{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004194#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004195 QCBORItem OneItemSeach[2];
4196 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4197 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4198 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4199 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004200
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004201 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004202#else
4203 (void)szLabel;
4204 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
4205#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade1341c592020-04-11 14:19:05 -07004206}
4207
4208
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004209/**
4210 * @brief Semi-private to do the the work for EnterMap() and EnterArray().
4211 *
4212 * @param[in] pMe The decode context
4213 * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY.
4214 * @param[out] pItem The data item for the map or array entered.
4215 *
4216 * The next item in the traversal must be a map or array. This
4217 * consumes that item and does the book keeping to enter the map or
4218 * array.
4219 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004220void
4221QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe,
4222 const uint8_t uType,
4223 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004224{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004225 QCBORError uErr;
4226
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004227 /* Must only be called on maps and arrays. */
Laurence Lundblade34691b92020-05-18 22:25:25 -07004228 if(pMe->uLastError != QCBOR_SUCCESS) {
4229 // Already in error state; do nothing.
4230 return;
4231 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07004232
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004233 /* Get the data item that is the map or array being entered. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004234 QCBORItem Item;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004235 uErr = QCBORDecode_GetNext(pMe, &Item);
4236 if(uErr != QCBOR_SUCCESS) {
4237 goto Done;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07004238 }
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004239
4240 uint8_t uItemDataType = Item.uDataType;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004241
4242#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004243 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) {
4244 uItemDataType = QCBOR_TYPE_ARRAY;
4245 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004246#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
4247
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004248 if(uItemDataType != uType) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004249 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
4250 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004251 }
4252
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004253 QCBORDecode_Private_SaveTagNumbers(pMe, &Item);
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004254
4255
Laurence Lundbladef0499502020-08-01 11:55:57 -07004256 const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
Laurence Lundblade085d7952020-07-24 10:26:30 -07004257 if(bIsEmpty) {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004258 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
4259 // Undo decrement done by QCBORDecode_GetNext() so the the
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004260 // the decrement when exiting the map/array works correctly
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004261 pMe->nesting.pCurrent->u.ma.uCountCursor++;
4262 }
Laurence Lundblade93d89472020-10-03 22:30:50 -07004263 // Special case to increment nesting level for zero-length maps
4264 // and arrays entered in bounded mode.
Laurence Lundbladee6f15112020-07-23 18:44:16 -07004265 DecodeNesting_Descend(&(pMe->nesting), uType);
4266 }
4267
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004268 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004269
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004270 uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty,
4271 UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004272
Laurence Lundblade6545d1b2020-10-14 11:13:13 -07004273 if(pItem != NULL) {
4274 *pItem = Item;
4275 }
4276
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004277Done:
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004278 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004279}
4280
Laurence Lundblade02625d42020-06-25 14:41:41 -07004281
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004282/**
4283 * @brief Exit a bounded map, array or bstr (semi-private).
4284 *
4285 * @param[in] pMe Decode context.
4286 * @param[in] uEndOffset The input buffer offset of the end of item exited.
4287 *
4288 * @returns QCBOR_SUCCESS or an error code.
4289 *
4290 * This is the common work for exiting a level that is a bounded map,
4291 * array or bstr wrapped CBOR.
4292 *
4293 * One chunk of work is to set up the pre-order traversal so it is at
4294 * the item just after the bounded map, array or bstr that is being
4295 * exited. This is somewhat complex.
4296 *
4297 * The other work is to level-up the bounded mode to next higest
4298 * bounded mode or the top level if there isn't one.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004299 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004300static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004301QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
4302 const uint32_t uEndOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004303{
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004304 QCBORError uErr;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004305
Laurence Lundblade02625d42020-06-25 14:41:41 -07004306 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004307 * First the pre-order-traversal byte offset is positioned to the
4308 * item just after the bounded mode item that was just consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004309 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004310 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
4311
Laurence Lundblade02625d42020-06-25 14:41:41 -07004312 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004313 * Next, set the current nesting level to one above the bounded
4314 * level that was just exited.
4315 *
4316 * DecodeNesting_CheckBoundedType() is always called before this
4317 * and makes sure pCurrentBounded is valid.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004318 */
4319 DecodeNesting_LevelUpCurrent(&(pMe->nesting));
4320
4321 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004322 * This does the complex work of leveling up the pre-order
4323 * traversal when the end of a map or array or another bounded
4324 * level is reached. It may do nothing, or ascend all the way to
4325 * the top level.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004326 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004327 uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004328 if(uErr != QCBOR_SUCCESS) {
4329 goto Done;
4330 }
4331
Laurence Lundblade02625d42020-06-25 14:41:41 -07004332 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004333 * This makes the next highest bounded level the current bounded
4334 * level. If there is no next highest level, then no bounded mode
4335 * is in effect.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004336 */
4337 DecodeNesting_LevelUpBounded(&(pMe->nesting));
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004338
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004339 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004340
4341Done:
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004342 return uErr;
4343}
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004344
Laurence Lundblade02625d42020-06-25 14:41:41 -07004345
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004346/**
4347 * @brief Get started exiting a map or array (semi-private)
4348 *
4349 * @param[in] pMe The decode context
4350 * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP
4351 *
4352 * This does some work for map and array exiting (but not
4353 * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel()
4354 * is called to do the rest.
4355 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004356void
4357QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe,
4358 const uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004359{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004360 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07004361 /* Already in error state; do nothing. */
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004362 return;
4363 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004364
Laurence Lundblade02625d42020-06-25 14:41:41 -07004365 QCBORError uErr;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004366
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004367 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004368 uErr = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004369 goto Done;
4370 }
4371
Laurence Lundblade02625d42020-06-25 14:41:41 -07004372 /*
4373 Have to set the offset to the end of the map/array
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004374 that is being exited. If there is no cached value,
Laurence Lundblade02625d42020-06-25 14:41:41 -07004375 from previous map search, then do a dummy search.
4376 */
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004377 if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004378 QCBORItem Dummy;
4379 Dummy.uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004380 uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL);
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004381 if(uErr != QCBOR_SUCCESS) {
4382 goto Done;
4383 }
4384 }
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004385
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004386 uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004387
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004388Done:
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004389 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004390}
4391
4392
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004393// TODO: re order this file with tags stuff last. bstr is a tag thing
4394static QCBORError
4395QCBORDecode_Private_CheckTagNType(QCBORDecodeContext *pMe,
4396 const QCBORItem *pItem,
4397 const size_t uOffset,
4398 const uint8_t *uQCBORTypes,
4399 const uint64_t *uTagNumbers,
4400 const uint8_t uTagRequirement,
4401 bool *bTypeMatched);
4402
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004403/**
4404 * @brief The main work of entering some byte-string wrapped CBOR.
4405 *
4406 * @param[in] pMe The decode context.
4407 * @param[in] pItem The byte string item.
4408 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX
4409 * @param[out] pBstr Pointer and length of byte string entered.
4410 *
4411 * This is called once the byte string item has been decoded to do all
4412 * the book keeping work for descending a nesting level into the
4413 * nested CBOR.
4414 *
4415 * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement.
4416 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004417static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004418QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe,
4419 const QCBORItem *pItem,
4420 const uint8_t uTagRequirement,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004421 const size_t uOffset,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004422 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004423{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004424 bool bTypeMatched;
4425 QCBORError uError;
4426
4427 const uint8_t uTypes[] = {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE};
4428 const uint64_t uTagNumbers[] = {CBOR_TAG_CBOR, CBOR_TAG_CBOR_SEQUENCE, CBOR_TAG_INVALID64};
4429
4430
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004431 if(pBstr) {
4432 *pBstr = NULLUsefulBufC;
4433 }
4434
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004435 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004436 return pMe->uLastError;
4437 }
4438
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004439 if(pItem->uDataAlloc) {
4440 return QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004441 }
4442
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004443 uError = QCBORDecode_Private_CheckTagNType(pMe,
4444 pItem,
4445 uOffset,
4446 uTypes, // TODO: maybe this should be empty
4447 uTagNumbers,
4448 uTagRequirement,
4449 &bTypeMatched);
4450
4451 if(pItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
4452 uError = QCBOR_ERR_BAD_TAG_CONTENT; // TODO: error
4453 }
4454
4455
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004456 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004457 /* Reverse the decrement done by GetNext() for the bstr so the
4458 * increment in QCBORDecode_NestLevelAscender() called by
4459 * ExitBoundedLevel() will work right.
4460 */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004461 DecodeNesting_ReverseDecrement(&(pMe->nesting));
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07004462 }
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004463
4464 if(pBstr) {
4465 *pBstr = pItem->val.string;
4466 }
4467
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004468 /* This saves the current length of the UsefulInputBuf and then
4469 * narrows the UsefulInputBuf to start and length of the wrapped
4470 * CBOR that is being entered.
4471 *
4472 * Most of these calls are simple inline accessors so this doesn't
4473 * amount to much code.
4474 */
4475
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004476 const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004477 /* This check makes the cast of uPreviousLength to uint32_t below safe. */
4478 if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004479 uError = QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladef76a2622020-08-06 19:51:03 -07004480 goto Done;
4481 }
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004482
4483 const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
4484 pItem->val.string.ptr);
4485 /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
4486 if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
4487 /* This should never happen because pItem->val.string.ptr should
4488 * always be valid since it was just returned.
4489 */
4490 uError = QCBOR_ERR_INPUT_TOO_LARGE;
4491 goto Done;
4492 }
4493
4494 const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
4495
4496 UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004497 UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004498
Laurence Lundblade02625d42020-06-25 14:41:41 -07004499 uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004500 (uint32_t)uPreviousLength,
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004501 (uint32_t)uStartOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004502Done:
4503 return uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004504}
4505
4506
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004507static void
4508QCBORDecode_Private_GetAndTell(QCBORDecodeContext *pMe, QCBORItem *Item, size_t *uOffset)
4509{
4510#ifndef QCBOR_DISABLE_TAGS
4511 if(pMe->uLastError != QCBOR_SUCCESS) {
4512 return;
4513 }
4514
4515 *uOffset = QCBORDecode_Tell(pMe);
4516#else
4517 *uOffset = SIZE_MAX;
4518
4519#endif /* ! QCBOR_DISABLE_TAGS */
4520 pMe->uLastError = (uint8_t)QCBORDecode_Private_GetNextTagContent(pMe, Item);
4521}
4522
4523
Laurence Lundblade02625d42020-06-25 14:41:41 -07004524/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004525 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004526 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004527void
4528QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe,
4529 const uint8_t uTagRequirement,
4530 UsefulBufC *pBstr)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004531{
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004532 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004533 size_t uOffset;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004534
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004535 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004536 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4537 &Item,
4538 uTagRequirement,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004539 uOffset,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004540 pBstr);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004541}
4542
4543
Laurence Lundblade02625d42020-06-25 14:41:41 -07004544/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004545 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004546 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004547void
4548QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe,
4549 const int64_t nLabel,
4550 const uint8_t uTagRequirement,
4551 UsefulBufC *pBstr)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004552{
4553 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004554 size_t uOffset;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004555
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004556 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_BYTE_STRING, &Item, &uOffset);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004557 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4558 &Item,
4559 uTagRequirement,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004560 uOffset,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004561 pBstr);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004562}
4563
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004564
Laurence Lundblade02625d42020-06-25 14:41:41 -07004565/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004566 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004567 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004568void
4569QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe,
4570 const char *szLabel,
4571 const uint8_t uTagRequirement,
4572 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004573{
4574 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004575 size_t uOffset;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004576
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004577 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_BYTE_STRING, &Item, &uOffset);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004578 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4579 &Item,
4580 uTagRequirement,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004581 uOffset,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004582 pBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004583}
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004584
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004585
Laurence Lundblade02625d42020-06-25 14:41:41 -07004586/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004587 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004588 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004589void
4590QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004591{
Laurence Lundblade02625d42020-06-25 14:41:41 -07004592 if(pMe->uLastError != QCBOR_SUCCESS) {
4593 // Already in error state; do nothing.
4594 return;
4595 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004596
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004597 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004598 pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade02625d42020-06-25 14:41:41 -07004599 return;
4600 }
4601
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004602 const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
4603
Laurence Lundblade02625d42020-06-25 14:41:41 -07004604 /*
4605 Reset the length of the UsefulInputBuf to what it was before
4606 the bstr wrapped CBOR was entered.
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004607 */
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004608 UsefulInputBuf_SetBufferLength(&(pMe->InBuf),
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004609 DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004610
4611
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004612 QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004613 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004614}
4615
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004616
Laurence Lundbladee6430642020-03-14 21:15:44 -07004617
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004618/**
4619 * @brief Process simple type true and false, a boolean
4620 *
4621 * @param[in] pMe The decode context.
4622 * @param[in] pItem The item with either true or false.
4623 * @param[out] pBool The boolean value output.
4624 *
4625 * Sets the internal error if the item isn't a true or a false. Also
4626 * records any tag numbers as the tag numbers of the last item.
4627 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004628static void
4629QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe,
4630 const QCBORItem *pItem,
4631 bool *pBool)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004632{
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004633 if(pMe->uLastError != QCBOR_SUCCESS) {
4634 /* Already in error state, do nothing */
4635 return;
4636 }
4637
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004638 switch(pItem->uDataType) {
4639 case QCBOR_TYPE_TRUE:
4640 *pBool = true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004641 break;
4642
4643 case QCBOR_TYPE_FALSE:
4644 *pBool = false;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004645 break;
4646
4647 default:
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004648 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004649 break;
4650 }
4651}
Laurence Lundbladee6430642020-03-14 21:15:44 -07004652
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004653
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004654/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004655 * Public function, see header qcbor/qcbor_decode.h file
4656 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004657void
4658QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004659{
Laurence Lundbladec4537442020-04-14 18:53:22 -07004660 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07004661 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004662 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004663}
4664
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004665
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004666/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004667 * Public function, see header qcbor/qcbor_decode.h file
4668 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004669void
4670QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe,
4671 const int64_t nLabel,
4672 bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004673{
4674 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004675 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004676 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004677}
4678
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004679
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004680/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004681 * Public function, see header qcbor/qcbor_decode.h file
4682 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004683void
4684QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe,
4685 const char *szLabel,
4686 bool *pValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004687{
4688 QCBORItem Item;
4689 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004690 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004691}
4692
4693
Laurence Lundblade3888f002024-06-12 21:20:56 -07004694/**
4695 * @brief Process simple values.
4696 *
4697 * @param[in] pMe The decode context.
4698 * @param[in] pItem The item with the simple value.
4699 * @param[out] puSimple The simple value output.
4700 *
4701 * Sets the internal error if the item isn't a true or a false. Also
4702 * records any tag numbers as the tag numbers of the last item.
4703 */
4704static void
4705QCBORDecode_Private_ProcessSimple(QCBORDecodeContext *pMe,
4706 const QCBORItem *pItem,
4707 uint8_t *puSimple)
4708{
4709 if(pMe->uLastError != QCBOR_SUCCESS) {
4710 return;
4711 }
4712
4713 /* It's kind of lame to remap true...undef back to simple values, but
4714 * this function isn't used much and to not do it would require
4715 * changing GetNext() behavior in an incompatible way.
4716 */
4717 switch(pItem->uDataType) {
4718 case QCBOR_TYPE_UKNOWN_SIMPLE:
4719 *puSimple = pItem->val.uSimple;
4720 break;
4721
4722 case QCBOR_TYPE_TRUE:
4723 *puSimple = CBOR_SIMPLEV_TRUE;
4724 break;
4725
4726 case QCBOR_TYPE_FALSE:
4727 *puSimple = CBOR_SIMPLEV_FALSE;
4728 break;
4729
4730 case QCBOR_TYPE_NULL:
4731 *puSimple = CBOR_SIMPLEV_NULL;
4732 break;
4733
4734 case QCBOR_TYPE_UNDEF:
4735 *puSimple = CBOR_SIMPLEV_UNDEF;
4736 break;
4737
4738 default:
4739 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4740 return;
4741 }
Laurence Lundblade3888f002024-06-12 21:20:56 -07004742}
4743
4744/*
4745 * Public function, see header qcbor/qcbor_decode.h file
4746 */
4747void
4748QCBORDecode_GetSimple(QCBORDecodeContext *pMe, uint8_t *puSimple)
4749{
4750 QCBORItem Item;
Laurence Lundblade3888f002024-06-12 21:20:56 -07004751 QCBORDecode_VGetNext(pMe, &Item);
4752 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimple);
4753}
4754
4755/*
4756 * Public function, see header qcbor/qcbor_decode.h file
4757 */
4758void
4759QCBORDecode_GetSimpleInMapN(QCBORDecodeContext *pMe,
4760 int64_t nLabel,
4761 uint8_t *puSimpleValue)
4762{
4763 QCBORItem Item;
4764 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3888f002024-06-12 21:20:56 -07004765 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
4766}
4767
4768/*
4769 * Public function, see header qcbor/qcbor_decode.h file
4770 */
4771void
4772QCBORDecode_GetSimpleInMapSZ(QCBORDecodeContext *pMe,
4773 const char *szLabel,
4774 uint8_t *puSimpleValue)
4775{
4776 QCBORItem Item;
4777 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3888f002024-06-12 21:20:56 -07004778 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
4779}
4780
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004781
Laurence Lundbladec7114722020-08-13 05:11:40 -07004782
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004783
4784#ifndef QCBOR_DISABLE_TAGS
4785// TODO: uTagNumber might be better a list than calling this multiple times
4786static QCBORError
4787QCBORDecode_Private_Check1TagNumber(const QCBORDecodeContext *pMe,
4788 const QCBORItem *pItem,
4789 const uint64_t uTagNumber,
4790 const size_t uOffset)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004791{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004792 if(pItem->auTagNumbers[0] == CBOR_TAG_INVALID16) {
4793 /* There are no tag numbers at all, so no unprocessed */
4794 return QCBOR_SUCCESS;
4795 }
4796
4797 /* There are some tag numbers, so keep checking. This check passes
4798 * if there is one and only one tag number that matches uTagNumber
4799 */
4800
4801 // TODO: behave different in v1 and v2?
4802
4803 const uint64_t uInnerTag = QCBORDecode_GetNthTagNumber(pMe, pItem, 0);
4804
4805 if(uInnerTag == uTagNumber && pItem->auTagNumbers[1] == CBOR_TAG_INVALID16 ) {
4806 /* The only tag number is the one we are processing so no unprocessed */
4807 return QCBOR_SUCCESS;
4808 }
4809
4810 if(uOffset != pMe->uTagNumberCheckOffset) {
4811 /* processed tag numbers are for some other item, not us */
4812 return QCBOR_ERR_UNPROCESSED_TAG_NUMBER;
4813 }
4814
4815 if(pMe->uTagNumberIndex != 1) {
4816 return QCBOR_ERR_UNPROCESSED_TAG_NUMBER;
4817 }
4818
4819 return QCBOR_SUCCESS;
4820}
4821#endif
4822
4823
4824static QCBORError
4825QCBORDecode_Private_CheckTagNType(QCBORDecodeContext *pMe,
4826 const QCBORItem *pItem,
4827 const size_t uOffset,
4828 const uint8_t *uQCBORTypes,
4829 const uint64_t *uTagNumbers,
4830 const uint8_t uTagRequirement,
4831 bool *bTypeMatched)
4832{
4833 const int nTagReq = uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
4834
4835 *bTypeMatched = false;
4836 for(const uint8_t *pTNum = uQCBORTypes; *pTNum != QCBOR_TYPE_NONE; pTNum++) {
4837 if(pItem->uDataType == *pTNum) {
4838 *bTypeMatched = true;
4839 break;
4840 }
4841 }
4842
4843#ifndef QCBOR_DISABLE_TAGS
4844 bool bTagNumberMatched;
4845 QCBORError uErr;
4846 const uint64_t uInnerTag = QCBORDecode_GetNthTagNumber(pMe, pItem, 0);
4847
4848 bTagNumberMatched = false;
4849 for(const uint64_t *pQType = uTagNumbers; *pQType != CBOR_TAG_INVALID64; pQType++) {
4850 if(uInnerTag == *pQType) {
4851 bTagNumberMatched = true;
4852 break;
4853 }
4854 }
4855
4856
4857 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
4858 /* There must be a tag number */
4859 if(!bTagNumberMatched && !*bTypeMatched) {
4860 return QCBOR_ERR_UNEXPECTED_TYPE; // TODO: error code
4861 }
4862
4863 } else if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
4864 if(bTagNumberMatched || *bTypeMatched) {
4865 return QCBOR_ERR_UNEXPECTED_TYPE; // TODO: error code
4866 }
4867
4868 } else if(nTagReq == QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG) {
4869 /* No check necessary */
4870 }
4871
4872 /* Now check if there are extra tags and if there's an error in them */
4873 if(!(uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS)) {
4874 /* The flag to ignore extra is not set, so keep checking */
4875 for(const uint64_t *pTNum = uTagNumbers; *pTNum != CBOR_TAG_INVALID64; pTNum++) {
4876 uErr = QCBORDecode_Private_Check1TagNumber(pMe, pItem, *pTNum, uOffset);
4877 if(uErr != QCBOR_SUCCESS) {
4878 return uErr;
4879 }
4880 }
4881 }
4882
4883 return QCBOR_SUCCESS;
4884#else
4885 (void)pMe;
4886 (void)uOffset;
4887 (void)uTagNumbers;
4888
4889 if(nTagReq != QCBOR_TAG_REQUIREMENT_TAG && bTypeMatched) {
4890 return QCBOR_SUCCESS;
4891 } else {
4892 return QCBOR_ERR_UNEXPECTED_TYPE;
4893 }
4894
4895#endif
4896
4897}
4898
4899
Laurence Lundblade68769332024-11-03 13:09:20 -08004900static void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004901QCBORDecode_Private_ProcessTagItemMulti(QCBORDecodeContext *pMe,
4902 QCBORItem *pItem,
4903 const uint8_t uTagRequirement,
4904 const uint8_t uQCBORTypes[],
4905 const uint64_t uTagNumbers[],
4906 QCBORTagContentCallBack *pfCB,
4907 size_t uOffset)
4908{
4909 QCBORError uErr;
4910 bool bTypeMatched;
4911
Laurence Lundbladec7114722020-08-13 05:11:40 -07004912 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec7114722020-08-13 05:11:40 -07004913 return;
4914 }
4915
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004916 uErr = QCBORDecode_Private_CheckTagNType(pMe,
4917 pItem,
4918 uOffset,
4919 uQCBORTypes,
4920 uTagNumbers,
4921 uTagRequirement,
4922 &bTypeMatched);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004923 if(uErr != QCBOR_SUCCESS) {
4924 goto Done;
4925 }
4926
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004927 if(!bTypeMatched) {
4928 /* Tag content wasn't previously processed, do it now */
4929 uErr = (*pfCB)(pMe, NULL, uTagNumbers[0], pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004930 if(uErr != QCBOR_SUCCESS) {
4931 goto Done;
4932 }
4933 }
4934
Laurence Lundbladec7114722020-08-13 05:11:40 -07004935Done:
4936 pMe->uLastError = (uint8_t)uErr;
4937}
4938
4939
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004940/*
4941 **/
Laurence Lundblade68769332024-11-03 13:09:20 -08004942static void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004943QCBORDecode_Private_ProcessTagItem(QCBORDecodeContext *pMe,
4944 QCBORItem *pItem,
4945 const uint8_t uTagRequirement,
4946 const uint8_t uQCBORTypes[],
4947 const uint64_t uTagNumber,
4948 QCBORTagContentCallBack *pfCB,
4949 size_t uOffset)
4950{
4951 uint64_t auTagNumbers[2];
4952
4953 auTagNumbers[0] = uTagNumber;
4954 auTagNumbers[1] = CBOR_TAG_INVALID64;
4955
4956 QCBORDecode_Private_ProcessTagItemMulti(pMe,
4957 pItem,
4958 uTagRequirement,
4959 uQCBORTypes,
4960 auTagNumbers,
4961 pfCB,
4962 uOffset);
4963}
4964
4965
4966static void
Laurence Lundblade68769332024-11-03 13:09:20 -08004967QCBORDecode_Private_ProcessTagOne(QCBORDecodeContext *pMe,
4968 QCBORItem *pItem,
4969 const uint8_t uTagRequirement,
4970 const uint8_t uQCBORType,
4971 const uint64_t uTagNumber,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004972 QCBORTagContentCallBack *pfCB,
Laurence Lundblade68769332024-11-03 13:09:20 -08004973 const size_t uOffset)
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004974{
4975 uint8_t auQCBORType[2];
4976
4977 auQCBORType[0] = uQCBORType;
4978 auQCBORType[1] = QCBOR_TYPE_NONE;
4979
4980 QCBORDecode_Private_ProcessTagItem(pMe,
4981 pItem,
4982 uTagRequirement,
4983 auQCBORType,
4984 uTagNumber,
4985 pfCB,
4986 uOffset);
4987}
4988
4989
4990
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004991
4992/*
4993 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4994 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004995void
4996QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
4997 uint8_t uTagRequirement,
4998 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004999{
Laurence Lundbladec7114722020-08-13 05:11:40 -07005000 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005001 size_t uOffset;
5002
5003 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
5004 QCBORDecode_Private_ProcessTagOne(pMe,
5005 &Item,
5006 uTagRequirement,
5007 QCBOR_TYPE_DATE_EPOCH,
5008 CBOR_TAG_DATE_EPOCH,
5009 QCBORDecode_DateEpochTagCB,
5010 uOffset);
5011 *pnTime = Item.val.epochDate.nSeconds;
Laurence Lundbladec7114722020-08-13 05:11:40 -07005012}
5013
5014
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005015/*
5016 * Public function, see header qcbor/qcbor_spiffy_decode.h file
5017 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07005018void
5019QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
5020 int64_t nLabel,
5021 uint8_t uTagRequirement,
5022 int64_t *pnTime)
5023{
5024 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005025 size_t uOffset;
5026
5027 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
5028 QCBORDecode_Private_ProcessTagOne(pMe,
5029 &Item,
5030 uTagRequirement,
5031 QCBOR_TYPE_DATE_EPOCH,
5032 CBOR_TAG_DATE_EPOCH,
5033 QCBORDecode_DateEpochTagCB,
5034 uOffset);
5035 *pnTime = Item.val.epochDate.nSeconds;
Laurence Lundbladec7114722020-08-13 05:11:40 -07005036}
5037
5038
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005039/*
5040 * Public function, see header qcbor/qcbor_spiffy_decode.h file
5041 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07005042void
5043QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
5044 const char *szLabel,
5045 uint8_t uTagRequirement,
5046 int64_t *pnTime)
5047{
5048 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005049 size_t uOffset;
Laurence Lundbladec7114722020-08-13 05:11:40 -07005050
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005051 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
5052 QCBORDecode_Private_ProcessTagOne(pMe,
5053 &Item,
5054 uTagRequirement,
5055 QCBOR_TYPE_DATE_EPOCH,
5056 CBOR_TAG_DATE_EPOCH,
5057 QCBORDecode_DateEpochTagCB,
5058 uOffset);
5059 *pnTime = Item.val.epochDate.nSeconds;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005060}
5061
5062
5063/*
5064 * Public function, see header qcbor/qcbor_decode.h
5065 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005066void
5067QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe,
5068 uint8_t uTagRequirement,
5069 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005070{
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005071 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005072 size_t uOffset;
5073
5074 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
5075 QCBORDecode_Private_ProcessTagOne(pMe,
5076 &Item,
5077 uTagRequirement,
5078 QCBOR_TYPE_DAYS_EPOCH,
5079 CBOR_TAG_DAYS_EPOCH,
5080 QCBORDecode_DaysEpochTagCB,
5081 uOffset);
5082 *pnDays = Item.val.epochDays;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005083}
5084
5085
5086/*
5087 * Public function, see header qcbor/qcbor_decode.h
5088 */
5089void
5090QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe,
5091 int64_t nLabel,
5092 uint8_t uTagRequirement,
5093 int64_t *pnDays)
5094{
5095 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005096 size_t uOffset;
5097
5098 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
5099 QCBORDecode_Private_ProcessTagOne(pMe,
5100 &Item,
5101 uTagRequirement,
5102 QCBOR_TYPE_DAYS_EPOCH,
5103 CBOR_TAG_DAYS_EPOCH,
5104 QCBORDecode_DaysEpochTagCB,
5105 uOffset);
5106 *pnDays = Item.val.epochDays;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005107}
5108
5109
5110/*
5111 * Public function, see header qcbor/qcbor_decode.h
5112 */
5113void
5114QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe,
5115 const char *szLabel,
5116 uint8_t uTagRequirement,
5117 int64_t *pnDays)
5118{
5119 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005120 size_t uOffset;
5121
5122 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
5123 QCBORDecode_Private_ProcessTagOne(pMe,
5124 &Item,
5125 uTagRequirement,
5126 QCBOR_TYPE_DAYS_EPOCH,
5127 CBOR_TAG_DAYS_EPOCH,
5128 QCBORDecode_DaysEpochTagCB,
5129 uOffset);
5130 *pnDays = Item.val.epochDays;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005131}
5132
5133
5134
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005135
Laurence Lundblade37286c02022-09-03 10:05:02 -07005136void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005137QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
5138 const uint8_t uTagRequirement,
5139 const uint8_t uQCBOR_Type,
5140 const uint64_t uTagNumber,
5141 UsefulBufC *pStr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005142{
Laurence Lundbladec4537442020-04-14 18:53:22 -07005143 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005144 size_t uOffset;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005145
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005146 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
5147 QCBORDecode_Private_ProcessTagOne(pMe,
5148 &Item,
5149 uTagRequirement,
5150 uQCBOR_Type,
5151 uTagNumber,
5152 QCBORDecode_StringsTagCB,
5153 uOffset);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005154
5155 if(pMe->uLastError == QCBOR_SUCCESS) {
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005156 *pStr = Item.val.string;
Laurence Lundbladeab40c6f2020-08-28 11:24:58 -07005157 } else {
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005158 *pStr = NULLUsefulBufC;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005159 }
5160}
5161
Laurence Lundbladec4537442020-04-14 18:53:22 -07005162
5163
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005164static void
5165QCBORDecode_Private_GetMIME(QCBORDecodeContext *pMe,
5166 const uint8_t uTagRequirement,
5167 QCBORItem *pItem,
5168 UsefulBufC *pValue,
5169 bool *pbIsTag257,
5170 size_t uOffset)
5171{
5172 QCBORError uErr;
5173
5174 const uint8_t puTypes[] = {QCBOR_TYPE_MIME, QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE};
5175
5176 const uint64_t puTNs[] = {CBOR_TAG_MIME, CBOR_TAG_BINARY_MIME, CBOR_TAG_INVALID64};
5177
5178 QCBORDecode_Private_ProcessTagItemMulti(pMe,
5179 pItem,
5180 uTagRequirement,
5181 puTypes,
5182 puTNs,
5183 QCBORDecode_MIMETagCB,
5184 uOffset);
5185 if(pMe->uLastError) {
5186 return;
5187 }
5188
5189 if(pItem->uDataType == QCBOR_TYPE_MIME) {
5190 *pbIsTag257 = false;
5191 } else if(pItem->uDataType == QCBOR_TYPE_BINARY_MIME) {
5192 *pbIsTag257 = true;
5193 }
5194 *pValue = pItem->val.string;
5195
5196
5197 uErr = QCBOR_SUCCESS;
5198
5199 pMe->uLastError = (uint8_t)uErr;
5200}
5201
5202
5203void
5204QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pMe,
5205 const uint8_t uTagRequirement,
5206 UsefulBufC *pMessage,
5207 bool *pbIsTag257)
5208{
5209 QCBORItem Item;
5210 size_t uOffset;
5211
5212 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
5213 QCBORDecode_Private_GetMIME(pMe,
5214 uTagRequirement,
5215 &Item,
5216 pMessage,
5217 pbIsTag257,
5218 uOffset);
5219}
5220
5221void
5222QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pMe,
5223 const int64_t nLabel,
5224 const uint8_t uTagRequirement,
5225 UsefulBufC *pMessage,
5226 bool *pbIsTag257)
5227{
5228 QCBORItem Item;
5229 size_t uOffset;
5230
5231 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
5232 QCBORDecode_Private_GetMIME(pMe,
5233 uTagRequirement,
5234 &Item,
5235 pMessage,
5236 pbIsTag257,
5237 uOffset);
5238}
5239
5240void
5241QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pMe,
5242 const char *szLabel,
5243 const uint8_t uTagRequirement,
5244 UsefulBufC *pMessage,
5245 bool *pbIsTag257)
5246{
5247 QCBORItem Item;
5248 size_t uOffset;
5249
5250 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
5251 QCBORDecode_Private_GetMIME(pMe,
5252 uTagRequirement,
5253 &Item,
5254 pMessage,
5255 pbIsTag257,
5256 uOffset);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005257}
5258
5259
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005260
Laurence Lundblade93d89472020-10-03 22:30:50 -07005261// Improvement: add methods for wrapped CBOR, a simple alternate
5262// to EnterBstrWrapped
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005263
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005264
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005265#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundbladee6430642020-03-14 21:15:44 -07005266
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005267/**
5268 * @brief Prototype for conversion of exponent and mantissa to unsigned integer.
5269 *
5270 * @param[in] uMantissa The mantissa.
5271 * @param[in] nExponent The exponent.
5272 * @param[out] puResult The resulting integer.
5273 *
5274 * Concrete implementations of this are for exponent base 10 and 2 supporting
5275 * decimal fractions and big floats.
5276 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005277typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005278
5279
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005280/**
5281 * @brief Base 10 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5282 *
5283 * @param[in] uMantissa The unsigned integer mantissa.
5284 * @param[in] nExponent The signed integer exponent.
5285 * @param[out] puResult Place to return the unsigned integer result.
5286 *
5287 * This computes: mantissa * 10 ^^ exponent as for a decimal fraction. The output is a 64-bit
5288 * unsigned integer.
5289 *
5290 * There are many inputs for which the result will not fit in the
Laurence Lundblade88ba5662024-11-03 02:10:24 -08005291 * 64-bit integer and @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005292 * be returned.
5293 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005294static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005295QCBOR_Private_Exponentitate10(const uint64_t uMantissa,
5296 int64_t nExponent,
5297 uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005298{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005299 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005300
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005301 if(uResult != 0) {
5302 /* This loop will run a maximum of 19 times because
5303 * UINT64_MAX < 10 ^^ 19. More than that will cause
5304 * exit with the overflow error
5305 */
5306 for(; nExponent > 0; nExponent--) {
5307 if(uResult > UINT64_MAX / 10) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005308 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005309 }
5310 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005311 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005312
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005313 for(; nExponent < 0; nExponent++) {
5314 uResult = uResult / 10;
5315 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005316 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005317 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005318 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005319 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005320 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07005321
5322 *puResult = uResult;
5323
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005324 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005325}
5326
5327
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005328/**
5329 * @brief Base 2 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5330 *
5331 * @param[in] uMantissa The unsigned integer mantissa.
5332 * @param[in] nExponent The signed integer exponent.
5333 * @param[out] puResult Place to return the unsigned integer result.
5334 *
5335 * This computes: mantissa * 2 ^^ exponent as for a big float. The
5336 * output is a 64-bit unsigned integer.
5337 *
5338 * There are many inputs for which the result will not fit in the
Laurence Lundblade88ba5662024-11-03 02:10:24 -08005339 * 64-bit integer and @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005340 * be returned.
5341 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005342static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005343QCBOR_Private_Exponentitate2(const uint64_t uMantissa,
5344 int64_t nExponent,
5345 uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005346{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005347 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005348
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005349 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005350
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005351 /* This loop will run a maximum of 64 times because INT64_MAX <
5352 * 2^31. More than that will cause exit with the overflow error
Laurence Lundbladee6430642020-03-14 21:15:44 -07005353 */
5354 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005355 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005356 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005357 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005358 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005359 nExponent--;
5360 }
5361
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005362 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005363 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005364 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005365 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005366 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005367 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005368 }
5369
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005370 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005371
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005372 return QCBOR_SUCCESS;
5373}
5374
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005375
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005376/**
5377 * @brief Exponentiate a signed mantissa and signed exponent to produce a signed result.
5378 *
5379 * @param[in] nMantissa Signed integer mantissa.
5380 * @param[in] nExponent Signed integer exponent.
5381 * @param[out] pnResult Place to put the signed integer result.
5382 * @param[in] pfExp Exponentiation function.
5383 *
5384 * @returns Error code
5385 *
Laurence Lundblade88ba5662024-11-03 02:10:24 -08005386 * @c pfExp performs exponentiation on and unsigned mantissa and
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005387 * produces an unsigned result. This converts the mantissa from signed
5388 * and converts the result to signed. The exponentiation function is
5389 * either for base 2 or base 10 (and could be other if needed).
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005390 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005391static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005392QCBOR_Private_ExponentiateNN(const int64_t nMantissa,
5393 const int64_t nExponent,
5394 int64_t *pnResult,
5395 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005396{
5397 uint64_t uResult;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005398 uint64_t uMantissa;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005399
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005400 /* Take the absolute value and put it into an unsigned. */
5401 if(nMantissa >= 0) {
5402 /* Positive case is straightforward */
5403 uMantissa = (uint64_t)nMantissa;
5404 } else if(nMantissa != INT64_MIN) {
5405 /* The common negative case. See next. */
5406 uMantissa = (uint64_t)-nMantissa;
5407 } else {
5408 /* int64_t and uint64_t are always two's complement per the
5409 * C standard (and since QCBOR uses these it only works with
5410 * two's complement, which is pretty much universal these
5411 * days). The range of a negative two's complement integer is
5412 * one more that than a positive, so the simple code above might
5413 * not work all the time because you can't simply negate the
5414 * value INT64_MIN because it can't be represented in an
5415 * int64_t. -INT64_MIN can however be represented in a
5416 * uint64_t. Some compilers seem to recognize this case for the
5417 * above code and put the correct value in uMantissa, however
5418 * they are not required to do this by the C standard. This next
5419 * line does however work for all compilers.
5420 *
5421 * This does assume two's complement where -INT64_MIN ==
5422 * INT64_MAX + 1 (which wouldn't be true for one's complement or
5423 * sign and magnitude (but we know we're using two's complement
5424 * because int64_t requires it)).
5425 *
5426 * See these, particularly the detailed commentary:
5427 * https://stackoverflow.com/questions/54915742/does-c99-mandate-a-int64-t-type-be-available-always
5428 * https://stackoverflow.com/questions/37301078/is-negating-int-min-undefined-behaviour
5429 */
5430 uMantissa = (uint64_t)INT64_MAX+1;
5431 }
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005432
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005433 /* Call the exponentiator passed for either base 2 or base 10.
5434 * Here is where most of the overflow errors are caught. */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005435 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
5436 if(uReturn) {
5437 return uReturn;
5438 }
5439
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005440 /* Convert back to the sign of the original mantissa */
5441 if(nMantissa >= 0) {
5442 if(uResult > INT64_MAX) {
5443 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5444 }
5445 *pnResult = (int64_t)uResult;
5446 } else {
5447 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
5448 * of INT64_MIN. This assumes two's compliment representation
5449 * where INT64_MIN is one increment farther from 0 than
5450 * INT64_MAX. Trying to write -INT64_MIN doesn't work to get
5451 * this because the compiler makes it an int64_t which can't
5452 * represent -INT64_MIN. Also see above.
5453 */
5454 if(uResult > (uint64_t)INT64_MAX+1) {
5455 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5456 }
5457 *pnResult = -(int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005458 }
5459
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005460 return QCBOR_SUCCESS;
5461}
5462
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005463
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005464/**
5465 * @brief Exponentiate an unsigned mantissa and signed exponent to produce an unsigned result.
5466 *
5467 * @param[in] nMantissa Signed integer mantissa.
5468 * @param[in] nExponent Signed integer exponent.
5469 * @param[out] puResult Place to put the signed integer result.
5470 * @param[in] pfExp Exponentiation function.
5471 *
5472 * @returns Error code
5473 *
Laurence Lundblade88ba5662024-11-03 02:10:24 -08005474 * @c pfExp performs exponentiation on and unsigned mantissa and
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005475 * produces an unsigned result. This errors out if the mantissa
5476 * is negative because the output is unsigned.
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005477 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005478static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005479QCBOR_Private_ExponentitateNU(const int64_t nMantissa,
5480 const int64_t nExponent,
5481 uint64_t *puResult,
5482 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005483{
5484 if(nMantissa < 0) {
5485 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5486 }
5487
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005488 /* Cast to unsigned is OK because of check for negative.
5489 * Cast to unsigned is OK because UINT64_MAX > INT64_MAX.
5490 * Exponentiation is straight forward
5491 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005492 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
5493}
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005494
5495
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005496/**
5497 * @brief Exponentiate an usnigned mantissa and unsigned exponent to produce an unsigned result.
5498 *
5499 * @param[in] uMantissa Unsigned integer mantissa.
5500 * @param[in] nExponent Unsigned integer exponent.
5501 * @param[out] puResult Place to put the unsigned integer result.
5502 * @param[in] pfExp Exponentiation function.
5503 *
5504 * @returns Error code
5505 *
Laurence Lundblade88ba5662024-11-03 02:10:24 -08005506 * @c pfExp performs exponentiation on and unsigned mantissa and
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005507 * produces an unsigned result so this is just a wrapper that does
5508 * nothing (and is likely inlined).
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005509 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005510static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005511QCBOR_Private_ExponentitateUU(const uint64_t uMantissa,
5512 const int64_t nExponent,
5513 uint64_t *puResult,
5514 fExponentiator pfExp)
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005515{
5516 return (*pfExp)(uMantissa, nExponent, puResult);
5517}
5518
Laurence Lundblade6658c952024-11-14 05:04:37 -08005519#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005520
5521
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005522
5523
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005524/**
5525 * @brief Convert a CBOR big number to a uint64_t.
5526 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005527 * @param[in] BigNumber Bytes of the big number to convert.
5528 * @param[in] uMax Maximum value allowed for the result.
5529 * @param[out] pResult Place to put the unsigned integer result.
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005530 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005531 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW When the bignumber is
5532 * too large to fit
5533 * @retval QCBOR_SUCCESS The conversion succeeded.
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005534 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005535 * Many values will overflow because a big number can represent a much
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005536 * larger range than uint64_t.
5537 */
5538static QCBORError
Laurence Lundblade05369de2024-11-17 17:00:28 -08005539QCBORDecode_Private_BigNumberToUInt(const UsefulBufC BigNumber,
5540 const uint64_t uMax,
5541 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005542{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005543 uint64_t uResult;
Laurence Lundblade05369de2024-11-17 17:00:28 -08005544 size_t uLen;
5545
5546 const uint8_t *pByte = BigNumber.ptr;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005547
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005548 uResult = 0;
Laurence Lundblade05369de2024-11-17 17:00:28 -08005549 for(uLen = BigNumber.len; uLen > 0; uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07005550 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005551 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005552 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07005553 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005554 }
5555
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005556 *pResult = uResult;
5557 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005558}
5559
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005560
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005561/**
5562 * @brief Convert a CBOR postive big number to a uint64_t.
5563 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005564 * @param[in] BigNumber Bytes of the big number to convert.
5565 * @param[out] pResult Place to put the unsigned integer result.
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005566 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005567 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW When the bignumber is
5568 * too large to fit
5569 * @retval QCBOR_SUCCESS The conversion succeeded.
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005570 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005571 * Many values will overflow because a big num can represent a much
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005572 * larger range than uint64_t.
5573 */
5574static QCBORError
Laurence Lundblade05369de2024-11-17 17:00:28 -08005575QCBORDecode_Private_PositiveBigNumberToUInt(const UsefulBufC BigNumber,
5576 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005577{
Laurence Lundblade05369de2024-11-17 17:00:28 -08005578 return QCBORDecode_Private_BigNumberToUInt(BigNumber, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005579}
5580
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005581
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005582/**
5583 * @brief Convert a CBOR positive big number to an int64_t.
5584 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005585 * @param[in] BigNumber Bytes of the big number to convert.
5586 * @param[out] pResult Place to put the signed integer result.
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005587 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005588 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW When the bignumber is
5589 * too large to fit
5590 * @retval QCBOR_SUCCESS The conversion succeeded.
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005591 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005592 * Many values will overflow because a big num can represent a much
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005593 * larger range than int64_t.
5594 */
5595static QCBORError
Laurence Lundblade05369de2024-11-17 17:00:28 -08005596QCBORDecode_Private_PositiveBigNumberToInt(const UsefulBufC BigNumber,
5597 int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005598{
Laurence Lundblade05369de2024-11-17 17:00:28 -08005599 uint64_t uResult;
5600 QCBORError uError;
5601
5602 uError = QCBORDecode_Private_BigNumberToUInt(BigNumber, INT64_MAX, &uResult);
5603 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005604 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005605 }
Laurence Lundblade05369de2024-11-17 17:00:28 -08005606 /* Cast safe because QCBORDecode_Private_BigNumberToUInt() limits to INT64_MAX */
Laurence Lundbladee6430642020-03-14 21:15:44 -07005607 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005608 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005609}
5610
5611
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005612/**
5613 * @brief Convert a CBOR negative big number to an int64_t.
5614 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005615 * @param[in] BigNumber Bytes of the big number to convert.
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005616 * @param[out] pnResult Place to put the signed integer result.
5617 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005618 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW When the bignumber is
5619 * too large to fit
5620 * @retval QCBOR_SUCCESS The conversion succeeded.
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005621 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005622 * Many values will overflow because a big num can represent a much
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005623 * larger range than int64_t.
5624 */
5625static QCBORError
Laurence Lundblade05369de2024-11-17 17:00:28 -08005626QCBORDecode_Private_NegativeBigNumberToInt(const UsefulBufC BigNumber,
5627 int64_t *pnResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005628{
Laurence Lundblade05369de2024-11-17 17:00:28 -08005629 uint64_t uResult;
5630 QCBORError uError;
Laurence Lundblade68769332024-11-03 13:09:20 -08005631
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005632 /* The negative integer furthest from zero for a C int64_t is
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005633 * INT64_MIN which is expressed as -INT64_MAX - 1. The value of a
5634 * negative number in CBOR is computed as -n - 1 where n is the
5635 * encoded integer, where n is what is in the variable BigNum. When
5636 * converting BigNum to a uint64_t, the maximum value is thus
5637 * INT64_MAX, so that when it -n - 1 is applied to it the result
5638 * will never be further from 0 than INT64_MIN.
5639 *
5640 * -n - 1 <= INT64_MIN.
5641 * -n - 1 <= -INT64_MAX - 1
5642 * n <= INT64_MAX.
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005643 */
Laurence Lundblade05369de2024-11-17 17:00:28 -08005644 uError = QCBORDecode_Private_BigNumberToUInt(BigNumber, INT64_MAX, &uResult);
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005645 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005646 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005647 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005648
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005649 /* Now apply -n - 1. The cast is safe because
5650 * ConvertBigNumToUnsigned() is limited to INT64_MAX which does fit
5651 * is the largest positive integer that an int64_t can
5652 * represent. */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005653 *pnResult = -(int64_t)uResult - 1;
5654
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005655 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005656}
5657
Laurence Lundblade05369de2024-11-17 17:00:28 -08005658/**
5659 * @brief Convert an integer to a big number.
5660 *
5661 * @param[in] uNum The integer to convert.
5662 * @param[in] BigNumberBuf The buffer to output the big number to.
5663 *
5664 * @returns The big number or NULLUsefulBufC is the buffer is to small.
5665 *
5666 * This always succeeds unless the buffer is too small.
5667 */
5668static UsefulBufC
5669QCBORDecode_Private_UIntToBigNumber(uint64_t uNum, const UsefulBuf BigNumberBuf)
5670{
5671 UsefulOutBuf UOB;
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005672
Laurence Lundblade05369de2024-11-17 17:00:28 -08005673 /* With a UsefulOutBuf, there's no pointer math */
5674 UsefulOutBuf_Init(&UOB, BigNumberBuf);
5675
5676 /* Must copy one byte even if zero. The loop, mask and shift
5677 * algorithm provides endian conversion.
5678 */
5679 do {
5680 UsefulOutBuf_InsertByte(&UOB, uNum & 0xff, 0);
5681 uNum >>= 8;
5682 } while(uNum);
5683
5684 return UsefulOutBuf_OutUBuf(&UOB);
5685}
5686
5687#ifndef QCBOR_DISABLE_FLOAT_HW_USE
5688/**
5689 * @brief Convert a big number to double-precision float.
5690 *
5691 * @param[in] BigNumber The big number to convert.
5692 *
5693 * @returns The double value.
5694 *
5695 * This will always succeed. It will lose precision for larger
5696 * numbers. If the big number is too large to fit (more than
5697 * 1.7976931348623157E+308) infinity will be returned. NaN is never
5698 * returned.
5699 */
5700static double
5701QCBORDecode_Private_BigNumberToDouble(const UsefulBufC BigNumber)
5702{
5703 double dResult;
5704 size_t uLen;
5705
5706 const uint8_t *pByte = BigNumber.ptr;
5707
5708 dResult = 0.0;
5709 /* This will overflow and become the float value INFINITY if the number
5710 * is too large to fit. */
5711 for(uLen = BigNumber.len; uLen > 0; uLen--){
5712 dResult = (dResult * 256.0) + (double)*pByte++;
5713 }
5714
5715 return dResult;
5716}
5717#endif /* ! QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005718
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005719
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005720/**
5721 * @brief Convert integers and floats to an int64_t.
5722 *
5723 * @param[in] pItem The item to convert.
5724 * @param[in] uConvertTypes Bit mask list of conversion options.
5725 * @param[out] pnValue The resulting converted value.
5726 *
5727 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5728 * in uConvertTypes.
5729 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5730 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5731 * or too small.
5732 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005733static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005734QCBOR_Private_ConvertInt64(const QCBORItem *pItem,
5735 const uint32_t uConvertTypes,
5736 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005737{
5738 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005739 case QCBOR_TYPE_FLOAT:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005740 case QCBOR_TYPE_DOUBLE:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005741#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005742 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005743 /* https://pubs.opengroup.org/onlinepubs/009695399/functions/llround.html
5744 http://www.cplusplus.com/reference/cmath/llround/
5745 */
5746 // Not interested in FE_INEXACT
5747 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005748 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5749 *pnValue = llround(pItem->val.dfnum);
5750 } else {
5751 *pnValue = lroundf(pItem->val.fnum);
5752 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005753 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5754 // llround() shouldn't result in divide by zero, but catch
5755 // it here in case it unexpectedly does. Don't try to
5756 // distinguish between the various exceptions because it seems
5757 // they vary by CPU, compiler and OS.
5758 return QCBOR_ERR_FLOAT_EXCEPTION;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005759 }
5760 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005761 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005762 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005763#else
5764 return QCBOR_ERR_HW_FLOAT_DISABLED;
5765#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005766 break;
5767
5768 case QCBOR_TYPE_INT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005769 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005770 *pnValue = pItem->val.int64;
5771 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005772 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005773 }
5774 break;
5775
5776 case QCBOR_TYPE_UINT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005777 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005778 if(pItem->val.uint64 < INT64_MAX) {
5779 *pnValue = pItem->val.int64;
5780 } else {
5781 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5782 }
5783 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005784 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005785 }
5786 break;
5787
Laurence Lundblade2d493002024-02-01 11:09:17 -07005788 case QCBOR_TYPE_65BIT_NEG_INT:
5789 /* This type occurs if the value won't fit into int64_t
5790 * so this is always an error. */
5791 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5792 break;
5793
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005794 default:
5795 return QCBOR_ERR_UNEXPECTED_TYPE;
5796 }
5797 return QCBOR_SUCCESS;
5798}
5799
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005800
Laurence Lundblade05369de2024-11-17 17:00:28 -08005801
5802#if !defined(USEFULBUF_DISABLE_ALL_FLOAT) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
5803/*
5804 * Public function, see header qcbor/qcbor_spiffy_decode.h file
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005805 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005806void
Laurence Lundblade05369de2024-11-17 17:00:28 -08005807QCBORDecode_GetNumberConvertPrecisely(QCBORDecodeContext *pMe,
5808 QCBORItem *pNumber)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005809{
Laurence Lundblade05369de2024-11-17 17:00:28 -08005810 QCBORItem Item;
5811 struct IEEE754_ToInt ToInt;
5812 double dNum;
5813 QCBORError uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005814
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005815 if(pMe->uLastError != QCBOR_SUCCESS) {
5816 return;
5817 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005818
Laurence Lundblade05369de2024-11-17 17:00:28 -08005819 // TODO:VGetNext?
5820 uError = QCBORDecode_GetNext(pMe, &Item);
5821 if(uError != QCBOR_SUCCESS) {
5822 *pNumber = Item;
5823 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005824 return;
5825 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005826
Laurence Lundblade05369de2024-11-17 17:00:28 -08005827 switch(Item.uDataType) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005828 case QCBOR_TYPE_INT64:
Laurence Lundblade05369de2024-11-17 17:00:28 -08005829 case QCBOR_TYPE_UINT64:
5830 *pNumber = Item;
5831 break;
5832
5833 case QCBOR_TYPE_DOUBLE:
5834 ToInt = IEEE754_DoubleToInt(Item.val.dfnum);
5835 if(ToInt.type == IEEE754_ToInt_IS_INT) {
5836 pNumber->uDataType = QCBOR_TYPE_INT64;
5837 pNumber->val.int64 = ToInt.integer.is_signed;
5838 } else if(ToInt.type == IEEE754_ToInt_IS_UINT) {
5839 if(ToInt.integer.un_signed <= INT64_MAX) {
5840 /* Do the same as base QCBOR integer decoding */
5841 pNumber->uDataType = QCBOR_TYPE_INT64;
5842 pNumber->val.int64 = (int64_t)ToInt.integer.un_signed;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005843 } else {
Laurence Lundblade05369de2024-11-17 17:00:28 -08005844 pNumber->uDataType = QCBOR_TYPE_UINT64;
5845 pNumber->val.uint64 = ToInt.integer.un_signed;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005846 }
5847 } else {
Laurence Lundblade05369de2024-11-17 17:00:28 -08005848 *pNumber = Item;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005849 }
5850 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005851
Laurence Lundblade05369de2024-11-17 17:00:28 -08005852 case QCBOR_TYPE_FLOAT:
5853 ToInt = IEEE754_SingleToInt(Item.val.fnum);
5854 if(ToInt.type == IEEE754_ToInt_IS_INT) {
5855 pNumber->uDataType = QCBOR_TYPE_INT64;
5856 pNumber->val.int64 = ToInt.integer.is_signed;
5857 } else if(ToInt.type == IEEE754_ToInt_IS_UINT) {
5858 if(ToInt.integer.un_signed <= INT64_MAX) {
5859 /* Do the same as base QCBOR integer decoding */
5860 pNumber->uDataType = QCBOR_TYPE_INT64;
5861 pNumber->val.int64 = (int64_t)ToInt.integer.un_signed;
5862 } else {
5863 pNumber->uDataType = QCBOR_TYPE_UINT64;
5864 pNumber->val.uint64 = ToInt.integer.un_signed;
5865 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005866 } else {
Laurence Lundblade05369de2024-11-17 17:00:28 -08005867 *pNumber = Item;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005868 }
5869 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005870
Laurence Lundblade2d493002024-02-01 11:09:17 -07005871 case QCBOR_TYPE_65BIT_NEG_INT:
Laurence Lundblade05369de2024-11-17 17:00:28 -08005872 if(Item.val.uint64 == UINT64_MAX) {
5873 /* The value -18446744073709551616 is encoded as an
5874 * unsigned 18446744073709551615. It's a whole number that
5875 * needs to be returned as a double. It can't be handled
5876 * by IEEE754_UintToDouble because 18446744073709551616
5877 * doesn't fit into a uint64_t. You can't get it by adding
5878 * 1 to 18446744073709551615.
5879 */
5880 pNumber->val.dfnum = -18446744073709551616.0;
5881 pNumber->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005882 } else {
Laurence Lundblade05369de2024-11-17 17:00:28 -08005883 dNum = IEEE754_UintToDouble(Item.val.uint64 + 1, 1);
5884 if(dNum == IEEE754_UINT_TO_DOUBLE_OOB) {
5885 *pNumber = Item;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005886 } else {
Laurence Lundblade05369de2024-11-17 17:00:28 -08005887 pNumber->val.dfnum = dNum;
5888 pNumber->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005889 }
5890 }
5891 break;
5892
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005893 default:
Laurence Lundblade05369de2024-11-17 17:00:28 -08005894 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
5895 pNumber->uDataType = QCBOR_TYPE_NONE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005896 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005897 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005898}
5899
Laurence Lundblade05369de2024-11-17 17:00:28 -08005900#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT && ! QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundbladee6430642020-03-14 21:15:44 -07005901
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005902
Laurence Lundblade05369de2024-11-17 17:00:28 -08005903/* Add one to the big number and put the result in a new UsefulBufC
5904 * from storage in UsefulBuf.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005905 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005906 * Leading zeros must be removed before calling this.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005907 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005908 * Code Reviewers: THIS FUNCTION DOES POINTER MATH
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005909 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005910static UsefulBufC
Laurence Lundblade05369de2024-11-17 17:00:28 -08005911QCBORDecode_BigNumberCopyPlusOne(UsefulBufC BigNumber, UsefulBuf BigNumberBuf)
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005912{
Laurence Lundblade05369de2024-11-17 17:00:28 -08005913 uint8_t uCarry;
5914 uint8_t uSourceValue;
5915 const uint8_t *pSource;
5916 uint8_t *pDest;
5917 ptrdiff_t uDestBytesLeft;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005918
Laurence Lundblade05369de2024-11-17 17:00:28 -08005919 /* Start adding at the LSB */
5920 pSource = &((const uint8_t *)BigNumber.ptr)[BigNumber.len-1];
5921 pDest = &((uint8_t *)BigNumberBuf.ptr)[BigNumberBuf.len-1];
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005922
Laurence Lundblade05369de2024-11-17 17:00:28 -08005923 uCarry = 1; /* Gets set back to zero if add the next line doesn't wrap */
5924 *pDest = *pSource + 1;
5925 while(1) {
5926 /* Wrap around from 0xff to 0 is a defined operation for
5927 * unsigned addition in C.*/
5928 if(*pDest != 0) {
5929 /* The add operation didn't wrap so no more carry. This
5930 * funciton only adds one, so when there is no more carry,
5931 * carrying is over to the end.
5932 */
5933 uCarry = 0;
5934 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005935
Laurence Lundblade05369de2024-11-17 17:00:28 -08005936 uDestBytesLeft = pDest - (uint8_t *)BigNumberBuf.ptr;
5937 if(pSource <= (const uint8_t *)BigNumber.ptr && uCarry == 0) {
5938 break; /* Successful exit */
5939 }
5940 if(pSource > (const uint8_t *)BigNumber.ptr) {
5941 uSourceValue = *--pSource;
5942 } else {
5943 /* All source bytes processed, but not the last carry */
5944 uSourceValue = 0;
5945 }
5946
5947 pDest--;
5948 if(uDestBytesLeft < 0) {
5949 return NULLUsefulBufC; /* Not enough space in destination buffer */
5950 }
5951
5952 *pDest = uSourceValue + uCarry;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005953 }
5954
Laurence Lundblade05369de2024-11-17 17:00:28 -08005955 return (UsefulBufC){pDest, BigNumberBuf.len - (size_t)uDestBytesLeft};
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005956}
5957
Laurence Lundblade05369de2024-11-17 17:00:28 -08005958
5959/* This returns 1 when uNum is 0 */
5960static size_t
5961QCBORDecode_Private_CountNonZeroBytes(uint64_t uNum)
5962{
5963 size_t uCount = 0;
5964 do {
5965 uCount++;
5966 uNum >>= 8;
5967 } while(uNum);
5968
5969 return uCount;
5970}
5971
5972
5973/*
5974 * Public function, see header qcbor/qcbor_decode.h
5975 */
5976QCBORError
5977QCBORDecode_ProcessBigNumberNoPreferred(const QCBORItem Item,
5978 const UsefulBuf BigNumberBuf,
5979 UsefulBufC *pBigNumber,
5980 bool *pbIsNegative)
5981{
5982 size_t uLen;
5983 UsefulBufC BigNumber;
5984 int uType;
5985
5986 uType = Item.uDataType;
5987 if(uType == QCBOR_TYPE_BYTE_STRING) {
5988 uType = *pbIsNegative ? QCBOR_TYPE_NEGBIGNUM : QCBOR_TYPE_POSBIGNUM;
5989 }
5990
5991 static const uint8_t Zero[] = {0x00};
5992 BigNumber = UsefulBuf_SkipLeading(Item.val.bigNum, 0);
5993 if(BigNumber.len == 0) {
5994 BigNumber = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(Zero);
5995 }
5996
5997 /* Compute required length so it can be returned if buffer is too small */
5998 switch(uType) {
5999
6000 case QCBOR_TYPE_POSBIGNUM:
6001 uLen = BigNumber.len;
6002 break;
6003
6004 case QCBOR_TYPE_NEGBIGNUM:
6005 uLen = BigNumber.len;
6006 if(UsefulBuf_IsValue(UsefulBuf_SkipLeading(BigNumber, 0), 0xff) == SIZE_MAX) {
6007 uLen++;
6008 }
6009 break;
6010
6011 default:
6012 return QCBOR_ERR_UNEXPECTED_TYPE;
6013 }
6014
6015 *pBigNumber = (UsefulBufC){NULL, uLen};
6016
6017 if(BigNumberBuf.len < uLen || uLen == 0 || BigNumberBuf.ptr == NULL) {
6018 return BigNumberBuf.ptr == NULL ? QCBOR_SUCCESS : QCBOR_ERR_BUFFER_TOO_SMALL;
6019 /* Buffer is too short or type is wrong */
6020 }
6021
6022
6023 if(uType == QCBOR_TYPE_POSBIGNUM) {
6024 *pBigNumber = UsefulBuf_Copy(BigNumberBuf, BigNumber);
6025 *pbIsNegative = false;
6026 } else if(uType == QCBOR_TYPE_NEGBIGNUM) {
6027 /* The messy one. Take the stuff in the buffer and copy it to
6028 * the new buffer, adding one to it. This might be one byte
6029 * bigger than the original because of the carry from adding
6030 * one.*/
6031 *pbIsNegative = true;
6032 *pBigNumber = QCBORDecode_BigNumberCopyPlusOne(BigNumber, BigNumberBuf);
6033 }
6034
6035 return QCBOR_SUCCESS;
6036}
6037
6038
6039/*
6040 * Public function, see header qcbor/qcbor_decode.h
6041 */
6042QCBORError
6043QCBORDecode_ProcessBigNumber(const QCBORItem Item,
6044 UsefulBuf BigNumberBuf,
6045 UsefulBufC *pBigNumber,
6046 bool *pbIsNegative)
6047{
6048 QCBORError uResult;
6049 size_t uLen;
6050 int uType;
6051
6052 uType = Item.uDataType;
6053
6054 switch(uType) {
6055 case QCBOR_TYPE_POSBIGNUM:
6056 case QCBOR_TYPE_NEGBIGNUM:
6057 case QCBOR_TYPE_BYTE_STRING:
6058 return QCBORDecode_ProcessBigNumberNoPreferred(Item, BigNumberBuf, pBigNumber, pbIsNegative);
6059 break;
6060
6061 case QCBOR_TYPE_INT64:
6062 uLen = QCBORDecode_Private_CountNonZeroBytes((uint64_t)ABSOLUTE_VALUE(Item.val.int64));
6063 break;
6064
6065 case QCBOR_TYPE_UINT64:
6066 uLen = QCBORDecode_Private_CountNonZeroBytes(Item.val.uint64);
6067 break;
6068
6069 case QCBOR_TYPE_65BIT_NEG_INT:
6070 uLen = Item.val.uint64 == UINT64_MAX ? 9 : QCBORDecode_Private_CountNonZeroBytes(Item.val.uint64);
6071 break;
6072
6073 default:
6074 return QCBOR_ERR_UNEXPECTED_TYPE;
6075 }
6076
6077
6078 *pBigNumber = (UsefulBufC){NULL, uLen};
6079
6080 if(BigNumberBuf.len < uLen || uLen == 0 || BigNumberBuf.ptr == NULL) {
6081 return BigNumberBuf.ptr == NULL ? QCBOR_SUCCESS : QCBOR_ERR_BUFFER_TOO_SMALL;
6082 /* Buffer is too short or type is wrong */
6083 }
6084
6085 uResult = QCBOR_SUCCESS;
6086
6087 if(uType == QCBOR_TYPE_UINT64) {
6088 *pBigNumber = QCBORDecode_Private_UIntToBigNumber(Item.val.uint64, BigNumberBuf);
6089 *pbIsNegative = false;
6090 } else if(uType == QCBOR_TYPE_INT64) {
6091 /* Offset of 1 for negative numbers already performed */
6092 *pbIsNegative = Item.val.int64 < 0;
6093 *pBigNumber = QCBORDecode_Private_UIntToBigNumber((uint64_t)(*pbIsNegative ? -Item.val.int64 : Item.val.int64), BigNumberBuf);
6094 } else if(uType == QCBOR_TYPE_65BIT_NEG_INT) {
6095 /* Offset of 1 for negative numbers NOT already performed */
6096 *pbIsNegative = true;
6097 if(Item.val.uint64 == UINT64_MAX) {
6098 /* The one value that can't be done with a computation
6099 * because it would overflow a uint64_t */
6100 static const uint8_t TwoToThe64[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
6101 *pBigNumber = UsefulBuf_Copy(BigNumberBuf, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(TwoToThe64));
6102 } else {
6103 /* +1 because negative big numbers are encoded one less than actual */
6104 *pBigNumber = QCBORDecode_Private_UIntToBigNumber(Item.val.uint64 + 1, BigNumberBuf);
6105 }
6106 }
6107
6108 return uResult;
6109}
6110
6111
6112
6113static const uint64_t QCBORDecode_Private_BigNumberTagNumbers[] = {
6114 CBOR_TAG_POS_BIGNUM,
6115 CBOR_TAG_NEG_BIGNUM,
6116 CBOR_TAG_INVALID64};
6117
6118static const uint8_t QCBORDecode_Private_BigNumberTypes[] = {
6119 QCBOR_TYPE_INT64,
6120 QCBOR_TYPE_UINT64,
6121 QCBOR_TYPE_65BIT_NEG_INT,
6122 QCBOR_TYPE_POSBIGNUM,
6123 QCBOR_TYPE_NEGBIGNUM,
6124 QCBOR_TYPE_NONE};
6125
6126#define QCBORDecode_Private_BigNumberTypesNoPreferred &QCBORDecode_Private_BigNumberTypes[3]
6127
6128/**
6129 * @brief Common processing for a big number tag.
6130 *
6131 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
6132 * @param[in] pItem The item with the date.
6133 * @param[out] pBignumber The returned big number
6134 * @param[out] pbIsNegative The returned sign of the big number.
6135 *
6136 * Common processing for the big number tag. Mostly make sure
6137 * the tag content is correct and copy forward any further other tag
6138 * numbers.
6139 */
6140static void
6141QCBORDecode_Private_BigNumberRawMain(QCBORDecodeContext *pMe,
6142 const uint8_t uTagRequirement,
6143 QCBORItem *pItem,
6144 UsefulBufC *pBignumber,
6145 bool *pbIsNegative,
6146 size_t uOffset)
6147{
6148 QCBORDecode_Private_ProcessTagItemMulti(pMe,
6149 pItem,
6150 uTagRequirement,
6151 QCBORDecode_Private_BigNumberTypesNoPreferred,
6152 QCBORDecode_Private_BigNumberTagNumbers,
6153 QCBORDecode_StringsTagCB,
6154 uOffset);
6155 if(pMe->uLastError) {
6156 return;
6157 }
6158
6159 if(pItem->uDataType == QCBOR_TYPE_POSBIGNUM) {
6160 *pbIsNegative = false;
6161 } else if(pItem->uDataType == QCBOR_TYPE_NEGBIGNUM) {
6162 *pbIsNegative = true;
6163 }
6164 *pBignumber = pItem->val.bigNum;
6165}
6166
6167
6168static void
6169QCBORDecode_Private_BigNumberNoPreferredMain(QCBORDecodeContext *pMe,
6170 const uint8_t uTagRequirement,
6171 QCBORItem *pItem,
6172 const size_t uOffset,
6173 UsefulBuf BigNumberBuf,
6174 UsefulBufC *pBigNumber,
6175 bool *pbIsNegative)
6176{
6177 QCBORDecode_Private_ProcessTagItemMulti(pMe,
6178 pItem,
6179 uTagRequirement,
6180 QCBORDecode_Private_BigNumberTypesNoPreferred,
6181 QCBORDecode_Private_BigNumberTagNumbers,
6182 QCBORDecode_StringsTagCB,
6183 uOffset);
6184 if(pMe->uLastError) {
6185 return;
6186 }
6187
6188 pMe->uLastError = (uint8_t)QCBORDecode_ProcessBigNumberNoPreferred(*pItem, BigNumberBuf, pBigNumber, pbIsNegative);
6189}
6190
6191
6192static void
6193QCBORDecode_Private_BigNumberMain(QCBORDecodeContext *pMe,
6194 const uint8_t uTagRequirement,
6195 QCBORItem *pItem,
6196 const size_t uOffset,
6197 UsefulBuf BigNumberBuf,
6198 UsefulBufC *pBigNumber,
6199 bool *pbIsNegative)
6200{
6201 QCBORDecode_Private_ProcessTagItemMulti(pMe,
6202 pItem,
6203 uTagRequirement,
6204 QCBORDecode_Private_BigNumberTypes,
6205 QCBORDecode_Private_BigNumberTagNumbers,
6206 QCBORDecode_StringsTagCB,
6207 uOffset);
6208 if(pMe->uLastError) {
6209 return;
6210 }
6211
6212 pMe->uLastError = (uint8_t)QCBORDecode_ProcessBigNumber(*pItem, BigNumberBuf, pBigNumber, pbIsNegative);
6213}
6214
6215
6216/*
6217 * Public function, see header qcbor/qcbor_decode.h
6218 */
6219void
6220QCBORDecode_GetTBigNumber(QCBORDecodeContext *pMe,
6221 const uint8_t uTagRequirement,
6222 UsefulBuf BigNumberBuf,
6223 UsefulBufC *pBigNumber,
6224 bool *pbIsNegative)
6225{
6226 QCBORItem Item;
6227 size_t uOffset;
6228
6229 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
6230 QCBORDecode_Private_BigNumberMain(pMe, uTagRequirement, &Item, uOffset, BigNumberBuf, pBigNumber, pbIsNegative);
6231}
6232
6233/*
6234 * Public function, see header qcbor/qcbor_decode.h
6235 */
6236void
6237QCBORDecode_GetTBigNumberInMapN(QCBORDecodeContext *pMe,
6238 const int64_t nLabel,
6239 const uint8_t uTagRequirement,
6240 UsefulBuf BigNumberBuf,
6241 UsefulBufC *pBigNumber,
6242 bool *pbIsNegative)
6243{
6244 QCBORItem Item;
6245 size_t uOffset;
6246
6247 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
6248 QCBORDecode_Private_BigNumberMain(pMe,
6249 uTagRequirement,
6250 &Item,
6251 uOffset,
6252 BigNumberBuf,
6253 pBigNumber,
6254 pbIsNegative);
6255}
6256
6257/*
6258 * Public function, see header qcbor/qcbor_decode.h
6259 */
6260void
6261QCBORDecode_GetTBigNumberInMapSZ(QCBORDecodeContext *pMe,
6262 const char *szLabel,
6263 const uint8_t uTagRequirement,
6264 UsefulBuf BigNumberBuf,
6265 UsefulBufC *pBigNumber,
6266 bool *pbIsNegative)
6267{
6268 QCBORItem Item;
6269 size_t uOffset;
6270
6271 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
6272 QCBORDecode_Private_BigNumberMain(pMe,
6273 uTagRequirement,
6274 &Item,
6275 uOffset,
6276 BigNumberBuf,
6277 pBigNumber,
6278 pbIsNegative);
6279}
6280
6281
6282/*
6283 * Public function, see header qcbor/qcbor_decode.h
6284 */
6285void
6286QCBORDecode_GetTBigNumberNoPreferred(QCBORDecodeContext *pMe,
6287 const uint8_t uTagRequirement,
6288 UsefulBuf BigNumberBuf,
6289 UsefulBufC *pBigNumber,
6290 bool *pbIsNegative)
6291{
6292 QCBORItem Item;
6293 size_t uOffset;
6294
6295 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
6296 QCBORDecode_Private_BigNumberNoPreferredMain(pMe, uTagRequirement, &Item, uOffset, BigNumberBuf, pBigNumber, pbIsNegative);
6297}
6298
6299/*
6300 * Public function, see header qcbor/qcbor_decode.h
6301 */
6302void
6303QCBORDecode_GetTBigNumberNoPreferredInMapN(QCBORDecodeContext *pMe,
6304 const int64_t nLabel,
6305 const uint8_t uTagRequirement,
6306 UsefulBuf BigNumberBuf,
6307 UsefulBufC *pBigNumber,
6308 bool *pbIsNegative)
6309{
6310 QCBORItem Item;
6311 size_t uOffset;
6312
6313 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
6314 QCBORDecode_Private_BigNumberNoPreferredMain(pMe, uTagRequirement, &Item, uOffset, BigNumberBuf, pBigNumber, pbIsNegative);
6315
6316}
6317
6318/*
6319 * Public function, see header qcbor/qcbor_decode.h
6320 */
6321void
6322QCBORDecode_GetTBigNumberNoPreferredInMapSZ(QCBORDecodeContext *pMe,
6323 const char *szLabel,
6324 const uint8_t uTagRequirement,
6325 UsefulBuf BigNumberBuf,
6326 UsefulBufC *pBigNumber,
6327 bool *pbIsNegative)
6328{
6329 QCBORItem Item;
6330 size_t uOffset;
6331
6332 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
6333 QCBORDecode_Private_BigNumberNoPreferredMain(pMe, uTagRequirement, &Item, uOffset, BigNumberBuf, pBigNumber, pbIsNegative);
6334}
6335
6336
6337
6338/*
6339 * Public function, see header qcbor/qcbor_spiffy_decode.h
6340 */
6341void
6342QCBORDecode_GetTBigNumberRaw(QCBORDecodeContext *pMe,
6343 const uint8_t uTagRequirement,
6344 UsefulBufC *pBignumber,
6345 bool *pbIsNegative)
6346{
6347 QCBORItem Item;
6348 size_t uOffset;
6349
6350 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
6351 QCBORDecode_Private_BigNumberRawMain(pMe,
6352 uTagRequirement,
6353 &Item,
6354 pBignumber,
6355 pbIsNegative,
6356 uOffset);
6357}
6358
6359/*
6360 * Public function, see header qcbor/qcbor_spiffy_decode.h
6361 */
6362void
6363QCBORDecode_GetTBigNumberRawInMapN(QCBORDecodeContext *pMe,
6364 const int64_t nLabel,
6365 const uint8_t uTagRequirement,
6366 UsefulBufC *pBigNumber,
6367 bool *pbIsNegative)
6368{
6369 QCBORItem Item;
6370 size_t uOffset;
6371
6372 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
6373 QCBORDecode_Private_BigNumberRawMain(pMe,
6374 uTagRequirement,
6375 &Item,
6376 pBigNumber,
6377 pbIsNegative,
6378 uOffset);
6379}
6380
6381/*
6382 * Public function, see header qcbor/qcbor_spiffy_decode.h
6383 */
6384void
6385QCBORDecode_GetTBigNumberRawInMapSZ(QCBORDecodeContext *pMe,
6386 const char *szLabel,
6387 const uint8_t uTagRequirement,
6388 UsefulBufC *pBigNumber,
6389 bool *pbIsNegative)
6390{
6391 QCBORItem Item;
6392 size_t uOffset;
6393
6394 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
6395 QCBORDecode_Private_BigNumberRawMain(pMe,
6396 uTagRequirement,
6397 &Item,
6398 pBigNumber,
6399 pbIsNegative,
6400 uOffset);
6401}
6402
6403
6404#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
6405
6406
6407// TODO: relocate these notes?
Laurence Lundblade37286c02022-09-03 10:05:02 -07006408/* Some notes from the work to disable tags.
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006409 * Some are out of date since tag refactoring.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006410 *
6411 * The API for big floats and decimal fractions seems good.
6412 * If there's any issue with it it's that the code size to
6413 * implement is a bit large because of the conversion
6414 * to/from int and bignum that is required. There is no API
6415 * that doesn't do the conversion so dead stripping will never
6416 * leave that code out.
6417 *
6418 * The implementation itself seems correct, but not as clean
6419 * and neat as it could be. It could probably be smaller too.
6420 *
6421 * The implementation has three main parts / functions
6422 * - The decoding of the array of two
6423 * - All the tag and type checking for the various API functions
6424 * - Conversion to/from bignum and int
6425 *
6426 * The type checking seems like it wastes the most code for
6427 * what it needs to do.
6428 *
6429 * The inlining for the conversion is probably making the
6430 * overall code base larger.
6431 *
6432 * The tests cases could be organized a lot better and be
6433 * more thorough.
6434 *
6435 * Seems also like there could be more common code in the
6436 * first tier part of the public API. Some functions only
6437 * vary by a TagSpec.
6438 */
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006439
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006440
6441static const uint8_t QCBORDecode_Private_DecimalFractionTypes[] = {
6442 QCBOR_TYPE_DECIMAL_FRACTION,
6443 QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6444 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM,
Laurence Lundblade68769332024-11-03 13:09:20 -08006445 QCBOR_TYPE_DECIMAL_FRACTION_POS_U64,
6446 QCBOR_TYPE_DECIMAL_FRACTION_NEG_U64,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006447 QCBOR_TYPE_NONE};
6448
6449static const uint8_t QCBORDecode_Private_BigFloatTypes[] = {
6450 QCBOR_TYPE_BIGFLOAT,
6451 QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
6452 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM,
Laurence Lundblade68769332024-11-03 13:09:20 -08006453 QCBOR_TYPE_BIGFLOAT_POS_U64,
6454 QCBOR_TYPE_BIGFLOAT_NEG_U64,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006455 QCBOR_TYPE_NONE};
6456
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006457/**
Laurence Lundblade68769332024-11-03 13:09:20 -08006458 * @brief Common processor for exponent and int64_t mantissa.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006459 *
6460 * @param[in] pMe The decode context.
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006461 * @param[in] uTagRequirement Whether tag number must be present or not.
6462 * @param[in] uTagNumber The tag number for which content is expected.
6463 * @param[in] uOffset Cursor offset for tag number consumption checking.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006464 * @param[in] pItem The data item to process.
6465 * @param[out] pnMantissa The returned mantissa as an int64_t.
6466 * @param[out] pnExponent The returned exponent as an int64_t.
6467 *
6468 * This handles exponent and mantissa for base 2 and 10. This
6469 * is limited to a mantissa that is an int64_t. See also
6470 * QCBORDecode_Private_ProcessExpMantissaBig().
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006471 *
6472 * On output, the item is always a fully decoded decimal fraction or
6473 * big float.
6474 *
Laurence Lundblade68769332024-11-03 13:09:20 -08006475 * This errors out if the input tag and type aren't as required.
6476 *
6477 * This always provides the correctly offset mantissa, even when the
6478 * input CBOR is a negative big number. This works the
6479 * same in QCBOR v1 and v2.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006480 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006481static void
Laurence Lundblade68769332024-11-03 13:09:20 -08006482QCBORDecode_Private_ExpIntMantissaMain(QCBORDecodeContext *pMe,
6483 const uint8_t uTagRequirement,
6484 const uint64_t uTagNumber,
6485 const size_t uOffset,
6486 QCBORItem *pItem,
6487 int64_t *pnMantissa,
6488 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006489{
Laurence Lundblade68769332024-11-03 13:09:20 -08006490 QCBORError uErr;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006491 const uint8_t *qTypes;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006492
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07006493 if(pMe->uLastError) {
6494 return;
6495 }
6496
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006497 if(uTagNumber == CBOR_TAG_BIGFLOAT) {
6498 qTypes = QCBORDecode_Private_BigFloatTypes;
6499 } else {
6500 qTypes = QCBORDecode_Private_DecimalFractionTypes;
6501 }
6502
6503 QCBORDecode_Private_ProcessTagItem(pMe,
6504 pItem,
6505 uTagRequirement,
6506 qTypes,
6507 uTagNumber,
6508 QCBORDecode_ExpMantissaTagCB,
6509 uOffset);
6510
6511 if(pMe->uLastError != QCBOR_SUCCESS) {
6512 return;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006513 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006514
Laurence Lundblade68769332024-11-03 13:09:20 -08006515 uErr = QCBOR_SUCCESS;
Laurence Lundblade9b334962020-08-27 10:55:53 -07006516 switch (pItem->uDataType) {
6517
6518 case QCBOR_TYPE_DECIMAL_FRACTION:
6519 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade9b334962020-08-27 10:55:53 -07006520 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006521 *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
Laurence Lundblade9b334962020-08-27 10:55:53 -07006522 break;
6523
Laurence Lundblade37286c02022-09-03 10:05:02 -07006524#ifndef QCBOR_DISABLE_TAGS
6525 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006526 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
6527 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
6528 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade05369de2024-11-17 17:00:28 -08006529 uErr = QCBORDecode_Private_PositiveBigNumberToInt(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006530 break;
6531
6532 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
6533 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
6534 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade05369de2024-11-17 17:00:28 -08006535 uErr = QCBORDecode_Private_NegativeBigNumberToInt(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006536 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006537#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006538
Laurence Lundblade68769332024-11-03 13:09:20 -08006539 case QCBOR_TYPE_BIGFLOAT_NEG_U64:
6540 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_U64:
6541 case QCBOR_TYPE_BIGFLOAT_POS_U64:
6542 case QCBOR_TYPE_DECIMAL_FRACTION_POS_U64:
6543 uErr = QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
6544 break;
6545
Laurence Lundblade9b334962020-08-27 10:55:53 -07006546 default:
6547 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
6548 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006549
Laurence Lundblade68769332024-11-03 13:09:20 -08006550 pMe->uLastError = (uint8_t)uErr;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006551}
6552
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006553static void
Laurence Lundblade68769332024-11-03 13:09:20 -08006554QCBORDecode_Private_ExpBigMantissaRawMain(QCBORDecodeContext *pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006555 const uint8_t uTagRequirement,
6556 const uint64_t uTagNumber,
6557 const size_t uOffset,
6558 QCBORItem *pItem,
6559 const UsefulBuf BufferForMantissa,
6560 UsefulBufC *pMantissa,
6561 bool *pbIsNegative,
6562 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006563{
Laurence Lundblade033574f2024-11-03 17:42:35 -08006564 QCBORError uErr;
6565 uint64_t uMantissa;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006566 const uint8_t *qTypes;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006567
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006568 if(pMe->uLastError) {
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07006569 return;
6570 }
6571
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006572 if(uTagNumber == CBOR_TAG_BIGFLOAT) {
6573 qTypes = QCBORDecode_Private_BigFloatTypes;
6574 } else {
6575 qTypes = QCBORDecode_Private_DecimalFractionTypes;
6576 }
6577
6578 QCBORDecode_Private_ProcessTagItem(pMe,
6579 pItem,
6580 uTagRequirement,
6581 qTypes,
6582 uTagNumber,
6583 QCBORDecode_ExpMantissaTagCB,
6584 uOffset);
6585
6586 if(pMe->uLastError != QCBOR_SUCCESS) {
6587 return;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006588 }
6589
Laurence Lundblade68769332024-11-03 13:09:20 -08006590 uErr = QCBOR_SUCCESS;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006591
6592 switch (pItem->uDataType) {
6593
6594 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006595 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006596 if(pItem->val.expAndMantissa.Mantissa.nInt >= 0) {
6597 uMantissa = (uint64_t)pItem->val.expAndMantissa.Mantissa.nInt;
6598 *pbIsNegative = false;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006599 } else {
Laurence Lundblade68769332024-11-03 13:09:20 -08006600 if(pItem->val.expAndMantissa.Mantissa.nInt != INT64_MIN) {
6601 uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt;
6602 } else {
6603 /* Can't negate like above when int64_t is INT64_MIN because it
6604 * will overflow. See ExponentNN() */
6605 uMantissa = (uint64_t)INT64_MAX+1;
6606 }
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006607 *pbIsNegative = true;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006608 }
Laurence Lundblade68769332024-11-03 13:09:20 -08006609 /* Reverse the offset by 1 for type 1 negative value to be consistent
6610 * with big num case below which don't offset because it requires
6611 * big number arithmetic. This is a bug fix for QCBOR v1.5.
6612 */
6613 uMantissa--;
Laurence Lundblade05369de2024-11-17 17:00:28 -08006614 *pMantissa = QCBORDecode_Private_UIntToBigNumber(uMantissa, BufferForMantissa);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006615 *pnExponent = pItem->val.expAndMantissa.nExponent;
6616 break;
6617
Laurence Lundblade37286c02022-09-03 10:05:02 -07006618#ifndef QCBOR_DISABLE_TAGS
6619 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006620 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006621 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006622 *pnExponent = pItem->val.expAndMantissa.nExponent;
6623 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6624 *pbIsNegative = false;
6625 break;
6626
6627 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006628 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006629 *pnExponent = pItem->val.expAndMantissa.nExponent;
6630 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6631 *pbIsNegative = true;
6632 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006633#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006634
6635 default:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006636 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006637 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006638
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006639 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006640}
6641
6642
Laurence Lundblade68769332024-11-03 13:09:20 -08006643/**
6644 * @brief Decode exponent and mantissa into a big number with negative offset of 1.
6645 *
6646 * @param[in] pMe The decode context.
6647 * @param[in] uTagRequirement Whether a tag number must be present or not.
6648 * @param[in] pItem Item to decode and convert.
6649 * @param[in] BufferForMantissa Buffer to output mantissa into.
6650 * @param[out] pMantissa The output mantissa.
6651 * @param[out] pbIsNegative The sign of the output.
6652 * @param[out] pnExponent The mantissa of the output.
6653 *
6654 * This is the common processing of a decimal fraction or a big float
6655 * into a big number. This will decode and consume all the CBOR items
6656 * that make up the decimal fraction or big float.
6657 *
6658 * This performs the subtraction of 1 from the negative value so the
6659 * caller doesn't need to. This links more object code than QCBORDecode_Private_ProcessExpMantissaBig().
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006660 */
Laurence Lundblade68769332024-11-03 13:09:20 -08006661static void
6662QCBORDecode_Private_ExpBigMantissaMain(QCBORDecodeContext *pMe,
6663 const uint8_t uTagRequirement,
6664 const uint64_t uTagNumber,
6665 const size_t uOffset,
6666 QCBORItem *pItem,
6667 const UsefulBuf BufferForMantissa,
6668 UsefulBufC *pMantissa,
6669 bool *pbIsNegative,
6670 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006671{
Laurence Lundblade68769332024-11-03 13:09:20 -08006672 QCBORError uErr;
6673 QCBORItem TempMantissa;
6674 const uint8_t *qTypes;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006675
Laurence Lundblade68769332024-11-03 13:09:20 -08006676 if(pMe->uLastError) {
6677 return;
6678 }
6679
6680 if(uTagNumber == CBOR_TAG_BIGFLOAT) {
6681 qTypes = QCBORDecode_Private_BigFloatTypes;
6682 } else {
6683 qTypes = QCBORDecode_Private_DecimalFractionTypes;
6684 }
6685
6686 QCBORDecode_Private_ProcessTagItem(pMe,
6687 pItem,
6688 uTagRequirement,
6689 qTypes,
6690 uTagNumber,
6691 QCBORDecode_ExpMantissaTagCB,
6692 uOffset);
6693
6694 if(pMe->uLastError != QCBOR_SUCCESS) {
6695 return;
6696 }
6697
6698 memset(&TempMantissa, 0, sizeof(TempMantissa));
6699
6700 switch (pItem->uDataType) {
6701
6702 case QCBOR_TYPE_DECIMAL_FRACTION:
6703 case QCBOR_TYPE_BIGFLOAT:
6704 TempMantissa.uDataType = QCBOR_TYPE_INT64;
6705 TempMantissa.val.int64 = pItem->val.expAndMantissa.Mantissa.nInt;
6706 break;
6707
6708 case QCBOR_TYPE_DECIMAL_FRACTION_POS_U64:
6709 case QCBOR_TYPE_BIGFLOAT_POS_U64:
6710 TempMantissa.uDataType = QCBOR_TYPE_UINT64;
6711 TempMantissa.val.uint64 = pItem->val.expAndMantissa.Mantissa.uInt;
6712 break;
6713
6714 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_U64:
6715 case QCBOR_TYPE_BIGFLOAT_NEG_U64:
6716 TempMantissa.uDataType = QCBOR_TYPE_65BIT_NEG_INT;
6717 TempMantissa.val.uint64 = pItem->val.expAndMantissa.Mantissa.uInt;
6718 break;
6719
6720#ifndef QCBOR_DISABLE_TAGS
6721 /* If tags are disabled, mantissas can never be big nums */
6722 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
6723 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
6724 TempMantissa.uDataType = QCBOR_TYPE_BYTE_STRING;
6725 TempMantissa.val.bigNum = pItem->val.expAndMantissa.Mantissa.bigNum;
6726 *pbIsNegative = false;
6727 break;
6728
6729 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
6730 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
6731 TempMantissa.uDataType = QCBOR_TYPE_BYTE_STRING;
6732 TempMantissa.val.bigNum = pItem->val.expAndMantissa.Mantissa.bigNum;
6733 *pbIsNegative = true;
6734 break;
6735#endif /* ! QCBOR_DISABLE_TAGS */
6736 }
6737
6738 *pnExponent = pItem->val.expAndMantissa.nExponent;
6739 uErr = QCBORDecode_ProcessBigNumber(TempMantissa, BufferForMantissa, pMantissa, pbIsNegative);
6740
6741 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006742}
6743
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006744
6745/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006746 * Public function, see header qcbor/qcbor_decode.h file
6747 */
6748void
Laurence Lundblade68769332024-11-03 13:09:20 -08006749QCBORDecode_GetTDecimalFraction(QCBORDecodeContext *pMe,
6750 const uint8_t uTagRequirement,
6751 int64_t *pnMantissa,
6752 int64_t *pnExponent)
6753{
6754 QCBORItem Item;
6755 size_t uOffset;
6756
6757 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
6758 QCBORDecode_Private_ExpIntMantissaMain(pMe,
6759 uTagRequirement,
6760 CBOR_TAG_DECIMAL_FRACTION,
6761 uOffset,
6762 &Item,
6763 pnMantissa,
6764 pnExponent);
6765}
6766
6767
6768/*
6769 * Public function, see header qcbor/qcbor_decode.h file
6770 */
6771void
6772QCBORDecode_GetTDecimalFractionInMapN(QCBORDecodeContext *pMe,
6773 const int64_t nLabel,
6774 const uint8_t uTagRequirement,
6775 int64_t *pnMantissa,
6776 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006777{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006778 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006779 size_t uOffset;
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006780
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006781 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade68769332024-11-03 13:09:20 -08006782 QCBORDecode_Private_ExpIntMantissaMain(pMe,
6783 uTagRequirement,
6784 CBOR_TAG_DECIMAL_FRACTION,
6785 uOffset,
6786 &Item,
6787 pnMantissa,
6788 pnExponent);
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006789
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006790}
6791
6792
6793/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006794 * Public function, see header qcbor/qcbor_decode.h file
6795 */
6796void
Laurence Lundblade68769332024-11-03 13:09:20 -08006797QCBORDecode_GetTDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
6798 const char *szLabel,
6799 const uint8_t uTagRequirement,
6800 int64_t *pnMantissa,
6801 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006802{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006803 QCBORItem Item;
6804 size_t uOffset;
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006805
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006806 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade68769332024-11-03 13:09:20 -08006807 QCBORDecode_Private_ExpIntMantissaMain(pMe,
6808 uTagRequirement,
6809 CBOR_TAG_DECIMAL_FRACTION,
6810 uOffset,
6811 &Item,
6812 pnMantissa,
6813 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006814}
6815
6816
6817/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006818 * Public function, see header qcbor/qcbor_decode.h file
6819 */
6820void
Laurence Lundblade68769332024-11-03 13:09:20 -08006821QCBORDecode_GetTDecimalFractionBigMantissa(QCBORDecodeContext *pMe,
6822 const uint8_t uTagRequirement,
6823 const UsefulBuf MantissaBuffer,
6824 UsefulBufC *pMantissa,
6825 bool *pbMantissaIsNegative,
6826 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006827{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006828 QCBORItem Item;
6829 size_t uOffset;
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006830
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006831 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
Laurence Lundblade68769332024-11-03 13:09:20 -08006832 QCBORDecode_Private_ExpBigMantissaMain(pMe,
6833 uTagRequirement,
6834 CBOR_TAG_DECIMAL_FRACTION,
6835 uOffset,
6836 &Item,
6837 MantissaBuffer,
6838 pMantissa,
6839 pbMantissaIsNegative,
6840 pnExponent);
6841}
6842
6843
6844/*
6845 * Public function, see header qcbor/qcbor_decode.h file
6846 */
6847void
6848QCBORDecode_GetTDecimalFractionBigMantissaInMapN(QCBORDecodeContext *pMe,
6849 const int64_t nLabel,
6850 const uint8_t uTagRequirement,
6851 const UsefulBuf BufferForMantissa,
6852 UsefulBufC *pMantissa,
6853 bool *pbIsNegative,
6854 int64_t *pnExponent)
6855{
6856 QCBORItem Item;
6857 size_t uOffset;
6858
6859 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
6860 QCBORDecode_Private_ExpBigMantissaMain(pMe,
6861 uTagRequirement,
6862 CBOR_TAG_DECIMAL_FRACTION,
6863 uOffset,
6864 &Item,
6865 BufferForMantissa,
6866 pMantissa,
6867 pbIsNegative,
6868 pnExponent);
6869}
6870
6871
6872/*
6873 * Public function, see header qcbor/qcbor_decode.h file
6874 */
6875void
6876QCBORDecode_GetTDecimalFractionBigMantissaInMapSZ(QCBORDecodeContext *pMe,
6877 const char *szLabel,
6878 const uint8_t uTagRequirement,
6879 const UsefulBuf BufferForMantissa,
6880 UsefulBufC *pMantissa,
6881 bool *pbIsNegative,
6882 int64_t *pnExponent)
6883{
6884 QCBORItem Item;
6885 size_t uOffset;
6886
6887 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
6888 QCBORDecode_Private_ExpBigMantissaMain(pMe,
6889 uTagRequirement,
6890 CBOR_TAG_DECIMAL_FRACTION,
6891 uOffset,
6892 &Item,
6893 BufferForMantissa,
6894 pMantissa,
6895 pbIsNegative,
6896 pnExponent);
6897}
6898
6899/*
6900 * Public function, see header qcbor/qcbor_decode.h file
6901 */
6902void
6903QCBORDecode_GetTDecimalFractionBigMantissaRaw(QCBORDecodeContext *pMe,
6904 const uint8_t uTagRequirement,
6905 const UsefulBuf MantissaBuffer,
6906 UsefulBufC *pMantissa,
6907 bool *pbMantissaIsNegative,
6908 int64_t *pnExponent)
6909{
6910 QCBORItem Item;
6911 size_t uOffset;
6912
6913 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
6914 QCBORDecode_Private_ExpBigMantissaRawMain(pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006915 uTagRequirement,
6916 CBOR_TAG_DECIMAL_FRACTION,
6917 uOffset,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006918 &Item,
6919 MantissaBuffer,
6920 pMantissa,
6921 pbMantissaIsNegative,
6922 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006923}
6924
6925
6926/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006927 * Public function, see header qcbor/qcbor_decode.h file
6928 */
6929void
Laurence Lundblade68769332024-11-03 13:09:20 -08006930QCBORDecode_GetTDecimalFractionBigMantissaRawInMapN(QCBORDecodeContext *pMe,
6931 const int64_t nLabel,
6932 const uint8_t uTagRequirement,
6933 const UsefulBuf BufferForMantissa,
6934 UsefulBufC *pMantissa,
6935 bool *pbIsNegative,
6936 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006937{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006938 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006939 size_t uOffset;
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006940
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006941 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade68769332024-11-03 13:09:20 -08006942 QCBORDecode_Private_ExpBigMantissaRawMain(pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006943 uTagRequirement,
6944 CBOR_TAG_DECIMAL_FRACTION,
6945 uOffset,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006946 &Item,
6947 BufferForMantissa,
6948 pMantissa,
6949 pbIsNegative,
6950 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006951}
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006952
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006953
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006954/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006955 * Public function, see header qcbor/qcbor_decode.h file
6956 */
6957void
Laurence Lundblade68769332024-11-03 13:09:20 -08006958QCBORDecode_GetTDecimalFractionBigMantissaRawInMapSZ(QCBORDecodeContext *pMe,
6959 const char *szLabel,
6960 const uint8_t uTagRequirement,
6961 const UsefulBuf BufferForMantissa,
6962 UsefulBufC *pMantissa,
6963 bool *pbIsNegative,
6964 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006965{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006966 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006967 size_t uOffset;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006968
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006969 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade68769332024-11-03 13:09:20 -08006970 QCBORDecode_Private_ExpBigMantissaRawMain(pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006971 uTagRequirement,
6972 CBOR_TAG_DECIMAL_FRACTION,
6973 uOffset,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006974 &Item,
6975 BufferForMantissa,
6976 pMantissa,
6977 pbIsNegative,
6978 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006979}
6980
6981
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006982/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006983 * Public function, see header qcbor/qcbor_decode.h file
6984 */
6985void
Laurence Lundblade68769332024-11-03 13:09:20 -08006986QCBORDecode_GetTBigFloat(QCBORDecodeContext *pMe,
6987 const uint8_t uTagRequirement,
6988 int64_t *pnMantissa,
6989 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006990{
Laurence Lundblade68769332024-11-03 13:09:20 -08006991 QCBORItem Item;
6992 size_t uOffset;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07006993
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006994 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
Laurence Lundblade68769332024-11-03 13:09:20 -08006995 QCBORDecode_Private_ExpIntMantissaMain(pMe,
6996 uTagRequirement,
6997 CBOR_TAG_BIGFLOAT,
6998 uOffset,
6999 &Item,
7000 pnMantissa,
7001 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007002}
7003
7004
7005/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007006 * Public function, see header qcbor/qcbor_decode.h file
7007 */
7008void
Laurence Lundblade68769332024-11-03 13:09:20 -08007009QCBORDecode_GetTBigFloatInMapN(QCBORDecodeContext *pMe,
7010 const int64_t nLabel,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007011 const uint8_t uTagRequirement,
7012 int64_t *pnMantissa,
7013 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007014{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007015 QCBORItem Item;
7016 size_t uOffset;
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007017
Laurence Lundblade68769332024-11-03 13:09:20 -08007018 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
7019 QCBORDecode_Private_ExpIntMantissaMain(pMe,
7020 uTagRequirement,
7021 CBOR_TAG_BIGFLOAT,
7022 uOffset,
7023 &Item,
7024 pnMantissa,
7025 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007026}
7027
7028
7029/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007030 * Public function, see header qcbor/qcbor_decode.h file
7031 */
7032void
Laurence Lundblade68769332024-11-03 13:09:20 -08007033QCBORDecode_GetTBigFloatInMapSZ(QCBORDecodeContext *pMe,
7034 const char *szLabel,
7035 const uint8_t uTagRequirement,
7036 int64_t *pnMantissa,
7037 int64_t *pnExponent)
7038{
7039 QCBORItem Item;
7040 size_t uOffset;
7041
7042 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
7043 QCBORDecode_Private_ExpIntMantissaMain(pMe,
7044 uTagRequirement,
7045 CBOR_TAG_BIGFLOAT,
7046 uOffset,
7047 &Item,
7048 pnMantissa,
7049 pnExponent);
7050}
7051
7052
7053/*
7054 * Public function, see header qcbor/qcbor_decode.h file
7055 */
7056void
7057QCBORDecode_GetTBigFloatBigMantissa(QCBORDecodeContext *pMe,
7058 const uint8_t uTagRequirement,
7059 const UsefulBuf MantissaBuffer,
7060 UsefulBufC *pMantissa,
7061 bool *pbMantissaIsNegative,
7062 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007063{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007064 QCBORItem Item;
7065 size_t uOffset;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007066
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007067 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
Laurence Lundblade68769332024-11-03 13:09:20 -08007068 QCBORDecode_Private_ExpBigMantissaMain(pMe,
7069 uTagRequirement,
7070 CBOR_TAG_BIGFLOAT,
7071 uOffset,
7072 &Item,
7073 MantissaBuffer,
7074 pMantissa,
7075 pbMantissaIsNegative,
7076 pnExponent);
7077}
7078
7079
7080
7081/*
7082 * Public function, see header qcbor/qcbor_decode.h file
7083 */
7084void
7085QCBORDecode_GetTBigFloatBigMantissaInMapN(QCBORDecodeContext *pMe,
7086 const int64_t nLabel,
7087 const uint8_t uTagRequirement,
7088 const UsefulBuf BufferForMantissa,
7089 UsefulBufC *pMantissa,
7090 bool *pbIsNegative,
7091 int64_t *pnExponent)
7092{
7093 QCBORItem Item;
7094 size_t uOffset;
7095
7096 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
7097 QCBORDecode_Private_ExpBigMantissaMain(pMe,
7098 uTagRequirement,
7099 CBOR_TAG_BIGFLOAT,
7100 uOffset,
7101 &Item,
7102 BufferForMantissa,
7103 pMantissa,
7104 pbIsNegative,
7105 pnExponent);
7106}
7107
7108
7109/*
7110 * Public function, see header qcbor/qcbor_decode.h file
7111 */
7112void
7113QCBORDecode_GetTBigFloatBigMantissaInMapSZ(QCBORDecodeContext *pMe,
7114 const char *szLabel,
7115 const uint8_t uTagRequirement,
7116 const UsefulBuf BufferForMantissa,
7117 UsefulBufC *pMantissa,
7118 bool *pbIsNegative,
7119 int64_t *pnExponent)
7120{
7121 QCBORItem Item;
7122 size_t uOffset;
7123
7124 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
7125 QCBORDecode_Private_ExpBigMantissaMain(pMe,
7126 uTagRequirement,
7127 CBOR_TAG_BIGFLOAT,
7128 uOffset,
7129 &Item,
7130 BufferForMantissa,
7131 pMantissa,
7132 pbIsNegative,
7133 pnExponent);
7134}
7135
7136
Laurence Lundblade05369de2024-11-17 17:00:28 -08007137/*
7138 * Public function, see header qcbor/qcbor_decode.h file
7139 */
Laurence Lundblade68769332024-11-03 13:09:20 -08007140void
7141QCBORDecode_GetTBigFloatBigMantissaRaw(QCBORDecodeContext *pMe,
7142 const uint8_t uTagRequirement,
7143 const UsefulBuf MantissaBuffer,
7144 UsefulBufC *pMantissa,
7145 bool *pbMantissaIsNegative,
7146 int64_t *pnExponent)
7147{
7148 QCBORItem Item;
7149 size_t uOffset;
7150
7151 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
7152 QCBORDecode_Private_ExpBigMantissaRawMain(pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007153 uTagRequirement,
7154 CBOR_TAG_BIGFLOAT,
7155 uOffset,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007156 &Item,
7157 MantissaBuffer,
7158 pMantissa,
7159 pbMantissaIsNegative,
7160 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007161}
7162
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007163/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007164 * Public function, see header qcbor/qcbor_decode.h file
7165 */
7166void
Laurence Lundblade68769332024-11-03 13:09:20 -08007167QCBORDecode_GetTBigFloatBigMantissaRawInMapN(QCBORDecodeContext *pMe,
7168 const int64_t nLabel,
7169 const uint8_t uTagRequirement,
7170 const UsefulBuf BufferForMantissa,
7171 UsefulBufC *pMantissa,
7172 bool *pbIsNegative,
7173 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007174{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007175 QCBORItem Item;
7176 size_t uOffset;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007177
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007178 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade68769332024-11-03 13:09:20 -08007179 QCBORDecode_Private_ExpBigMantissaRawMain(pMe,
7180 uTagRequirement,
7181 CBOR_TAG_BIGFLOAT,
7182 uOffset,
7183 &Item,
7184 BufferForMantissa,
7185 pMantissa,
7186 pbIsNegative,
7187 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007188}
7189
7190
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007191/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007192 * Public function, see header qcbor/qcbor_decode.h file
7193 */
7194void
Laurence Lundblade68769332024-11-03 13:09:20 -08007195QCBORDecode_GetTBigFloatBigMantissaRawInMapSZ(QCBORDecodeContext *pMe,
7196 const char *szLabel,
7197 const uint8_t uTagRequirement,
7198 const UsefulBuf BufferForMantissa,
7199 UsefulBufC *pMantissa,
7200 bool *pbIsNegative,
7201 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007202{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007203 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007204 size_t uOffset;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007205
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007206 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade68769332024-11-03 13:09:20 -08007207 QCBORDecode_Private_ExpBigMantissaRawMain(pMe,
7208 uTagRequirement,
7209 CBOR_TAG_BIGFLOAT,
7210 uOffset,
7211 &Item,
7212 BufferForMantissa,
7213 pMantissa,
7214 pbIsNegative,
7215 pnExponent);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007216}
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007217
Laurence Lundblade68769332024-11-03 13:09:20 -08007218#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007219
7220
Laurence Lundblade05369de2024-11-17 17:00:28 -08007221
7222
7223/**
7224 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
7225 *
7226 * @param[in] pMe The decode context.
7227 * @param[in] uConvertTypes Bit mask list of conversion options.
7228 * @param[out] pnValue Result of the conversion.
7229 * @param[in,out] pItem Temporary space to store Item, returned item.
7230 *
7231 * See QCBORDecode_GetInt64Convert().
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007232 */
7233void
Laurence Lundblade05369de2024-11-17 17:00:28 -08007234QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pMe,
7235 uint32_t uConvertTypes,
7236 int64_t *pnValue,
7237 QCBORItem *pItem)
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007238{
Laurence Lundblade05369de2024-11-17 17:00:28 -08007239 QCBORDecode_VGetNext(pMe, pItem);
7240 if(pMe->uLastError) {
7241 return;
7242 }
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007243
Laurence Lundblade05369de2024-11-17 17:00:28 -08007244 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
7245 uConvertTypes,
7246 pnValue);
7247}
7248
7249/**
7250 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
7251 *
7252 * @param[in] pMe The decode context.
7253 * @param[in] nLabel Label to find in map.
7254 * @param[in] uConvertTypes Bit mask list of conversion options.
7255 * @param[out] pnValue Result of the conversion.
7256 * @param[in,out] pItem Temporary space to store Item, returned item.
7257 *
7258 * See QCBORDecode_GetInt64ConvertInMapN().
7259 */
7260void
7261QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pMe,
7262 int64_t nLabel,
7263 uint32_t uConvertTypes,
7264 int64_t *pnValue,
7265 QCBORItem *pItem)
7266{
7267 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007268 if(pMe->uLastError != QCBOR_SUCCESS) {
7269 return;
7270 }
7271
Laurence Lundblade05369de2024-11-17 17:00:28 -08007272 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
7273 uConvertTypes,
7274 pnValue);
7275}
7276
7277/**
7278 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
7279 *
7280 * @param[in] pMe The decode context.
7281 * @param[in] szLabel Label to find in map.
7282 * @param[in] uConvertTypes Bit mask list of conversion options.
7283 * @param[out] pnValue Result of the conversion.
7284 * @param[in,out] pItem Temporary space to store Item, returned item.
7285 *
7286 * See QCBORDecode_GetInt64ConvertInMapSZ().
7287 */
7288void
7289QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
7290 const char * szLabel,
7291 uint32_t uConvertTypes,
7292 int64_t *pnValue,
7293 QCBORItem *pItem)
7294{
7295 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
7296 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007297 return;
7298 }
7299
Laurence Lundblade05369de2024-11-17 17:00:28 -08007300 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
7301 uConvertTypes,
7302 pnValue);
7303}
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007304
Laurence Lundblade05369de2024-11-17 17:00:28 -08007305
7306/**
7307 * @brief Convert many number types to an int64_t.
7308 *
7309 * @param[in] pItem The item to convert.
7310 * @param[in] uConvertTypes Bit mask list of conversion options.
7311 * @param[out] pnValue The resulting converted value.
7312 *
7313 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
7314 * in uConvertTypes.
7315 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
7316 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
7317 * or too small.
7318 */
7319static QCBORError
7320QCBOR_Private_Int64ConvertAll(const QCBORItem *pItem,
7321 const uint32_t uConvertTypes,
7322 int64_t *pnValue)
7323{
7324 switch(pItem->uDataType) {
7325
7326 case QCBOR_TYPE_POSBIGNUM:
7327 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
7328 return QCBORDecode_Private_PositiveBigNumberToInt(pItem->val.bigNum, pnValue);
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007329 } else {
Laurence Lundblade05369de2024-11-17 17:00:28 -08007330 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007331 }
7332 break;
7333
Laurence Lundblade05369de2024-11-17 17:00:28 -08007334 case QCBOR_TYPE_NEGBIGNUM:
7335 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
7336 return QCBORDecode_Private_NegativeBigNumberToInt(pItem->val.bigNum, pnValue);
7337 } else {
7338 return QCBOR_ERR_UNEXPECTED_TYPE;
7339 }
7340 break;
7341
7342#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
7343 case QCBOR_TYPE_DECIMAL_FRACTION:
7344 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
7345 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
7346 pItem->val.expAndMantissa.nExponent,
7347 pnValue,
7348 &QCBOR_Private_Exponentitate10);
7349 } else {
7350 return QCBOR_ERR_UNEXPECTED_TYPE;
7351 }
7352 break;
7353
7354 case QCBOR_TYPE_BIGFLOAT:
7355 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
7356 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
7357 pItem->val.expAndMantissa.nExponent,
7358 pnValue,
7359 QCBOR_Private_Exponentitate2);
7360 } else {
7361 return QCBOR_ERR_UNEXPECTED_TYPE;
7362 }
7363 break;
7364
7365 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
7366 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
7367 int64_t nMantissa;
7368 QCBORError uErr;
7369 uErr = QCBORDecode_Private_PositiveBigNumberToInt(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
7370 if(uErr) {
7371 return uErr;
7372 }
7373 return QCBOR_Private_ExponentiateNN(nMantissa,
7374 pItem->val.expAndMantissa.nExponent,
7375 pnValue,
7376 QCBOR_Private_Exponentitate10);
7377 } else {
7378 return QCBOR_ERR_UNEXPECTED_TYPE;
7379 }
7380 break;
7381
7382 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
7383 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
7384 int64_t nMantissa;
7385 QCBORError uErr;
7386 uErr = QCBORDecode_Private_NegativeBigNumberToInt(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
7387 if(uErr) {
7388 return uErr;
7389 }
7390 return QCBOR_Private_ExponentiateNN(nMantissa,
7391 pItem->val.expAndMantissa.nExponent,
7392 pnValue,
7393 QCBOR_Private_Exponentitate10);
7394 } else {
7395 return QCBOR_ERR_UNEXPECTED_TYPE;
7396 }
7397 break;
7398
7399 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
7400 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
7401 int64_t nMantissa;
7402 QCBORError uErr;
7403 uErr = QCBORDecode_Private_PositiveBigNumberToInt(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
7404 if(uErr) {
7405 return uErr;
7406 }
7407 return QCBOR_Private_ExponentiateNN(nMantissa,
7408 pItem->val.expAndMantissa.nExponent,
7409 pnValue,
7410 QCBOR_Private_Exponentitate2);
7411 } else {
7412 return QCBOR_ERR_UNEXPECTED_TYPE;
7413 }
7414 break;
7415
7416 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
7417 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
7418 int64_t nMantissa;
7419 QCBORError uErr;
7420 uErr = QCBORDecode_Private_NegativeBigNumberToInt(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
7421 if(uErr) {
7422 return uErr;
7423 }
7424 return QCBOR_Private_ExponentiateNN(nMantissa,
7425 pItem->val.expAndMantissa.nExponent,
7426 pnValue,
7427 QCBOR_Private_Exponentitate2);
7428 } else {
7429 return QCBOR_ERR_UNEXPECTED_TYPE;
7430 }
7431 break;
7432#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
7433
7434
7435 default:
7436 return QCBOR_ERR_UNEXPECTED_TYPE; }
7437}
7438
7439
7440/*
7441 * Public function, see header qcbor/qcbor_decode.h file
7442 */
7443void
7444QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe,
7445 const uint32_t uConvertTypes,
7446 int64_t *pnValue)
7447{
7448 QCBORItem Item;
7449
7450 QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item);
7451
7452 if(pMe->uLastError == QCBOR_SUCCESS) {
7453 // The above conversion succeeded
7454 return;
7455 }
7456
7457 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
7458 // The above conversion failed in a way that code below can't correct
7459 return;
7460 }
7461
7462 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
7463 uConvertTypes,
7464 pnValue);
7465}
7466
7467
7468/*
7469 * Public function, see header qcbor/qcbor_decode.h file
7470 */
7471void
7472QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
7473 const int64_t nLabel,
7474 const uint32_t uConvertTypes,
7475 int64_t *pnValue)
7476{
7477 QCBORItem Item;
7478
7479 QCBORDecode_Private_GetInt64ConvertInMapN(pMe,
7480 nLabel,
7481 uConvertTypes,
7482 pnValue,
7483 &Item);
7484
7485 if(pMe->uLastError == QCBOR_SUCCESS) {
7486 // The above conversion succeeded
7487 return;
7488 }
7489
7490 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
7491 // The above conversion failed in a way that code below can't correct
7492 return;
7493 }
7494
7495 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
7496 uConvertTypes,
7497 pnValue);
7498}
7499
7500
7501/*
7502 * Public function, see header qcbor/qcbor_decode.h file
7503 */
7504void
7505QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
7506 const char *szLabel,
7507 const uint32_t uConvertTypes,
7508 int64_t *pnValue)
7509{
7510 QCBORItem Item;
7511 QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe,
7512 szLabel,
7513 uConvertTypes,
7514 pnValue,
7515 &Item);
7516
7517 if(pMe->uLastError == QCBOR_SUCCESS) {
7518 // The above conversion succeeded
7519 return;
7520 }
7521
7522 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
7523 // The above conversion failed in a way that code below can't correct
7524 return;
7525 }
7526
7527 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
7528 uConvertTypes,
7529 pnValue);
7530}
7531
7532
7533/**
7534 * @brief Convert many number types to an uint64_t.
7535 *
7536 * @param[in] pItem The item to convert.
7537 * @param[in] uConvertTypes Bit mask list of conversion options.
7538 * @param[out] puValue The resulting converted value.
7539 *
7540 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
7541 * in uConvertTypes.
7542 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
7543 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
7544 * or too small.
7545 */
7546static QCBORError
7547QCBOR_Private_ConvertUInt64(const QCBORItem *pItem,
7548 const uint32_t uConvertTypes,
7549 uint64_t *puValue)
7550{
7551 switch(pItem->uDataType) {
7552 case QCBOR_TYPE_DOUBLE:
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007553 case QCBOR_TYPE_FLOAT:
Laurence Lundblade05369de2024-11-17 17:00:28 -08007554#ifndef QCBOR_DISABLE_FLOAT_HW_USE
7555 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
7556 // Can't use llround here because it will not convert values
7557 // greater than INT64_MAX and less than UINT64_MAX that
7558 // need to be converted so it is more complicated.
7559 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
7560 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
7561 if(isnan(pItem->val.dfnum)) {
7562 return QCBOR_ERR_FLOAT_EXCEPTION;
7563 } else if(pItem->val.dfnum < 0) {
7564 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
7565 } else {
7566 double dRounded = round(pItem->val.dfnum);
7567 // See discussion in DecodeDateEpoch() for
7568 // explanation of - 0x7ff
7569 if(dRounded > (double)(UINT64_MAX- 0x7ff)) {
7570 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
7571 }
7572 *puValue = (uint64_t)dRounded;
7573 }
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007574 } else {
Laurence Lundblade05369de2024-11-17 17:00:28 -08007575 if(isnan(pItem->val.fnum)) {
7576 return QCBOR_ERR_FLOAT_EXCEPTION;
7577 } else if(pItem->val.fnum < 0) {
7578 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
7579 } else {
7580 float fRounded = roundf(pItem->val.fnum);
7581 // See discussion in DecodeDateEpoch() for
7582 // explanation of - 0x7ff
7583 if(fRounded > (float)(UINT64_MAX- 0x7ff)) {
7584 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
7585 }
7586 *puValue = (uint64_t)fRounded;
7587 }
7588 }
7589 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
7590 // round() and roundf() shouldn't result in exceptions here, but
7591 // catch them to be robust and thorough. Don't try to
7592 // distinguish between the various exceptions because it seems
7593 // they vary by CPU, compiler and OS.
7594 return QCBOR_ERR_FLOAT_EXCEPTION;
7595 }
7596
7597 } else {
7598 return QCBOR_ERR_UNEXPECTED_TYPE;
7599 }
7600#else
7601 return QCBOR_ERR_HW_FLOAT_DISABLED;
7602#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
7603 break;
7604
7605 case QCBOR_TYPE_INT64:
7606 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
7607 if(pItem->val.int64 >= 0) {
7608 *puValue = (uint64_t)pItem->val.int64;
7609 } else {
7610 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007611 }
7612 } else {
Laurence Lundblade05369de2024-11-17 17:00:28 -08007613 return QCBOR_ERR_UNEXPECTED_TYPE;
7614 }
7615 break;
7616
7617 case QCBOR_TYPE_UINT64:
7618 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
7619 *puValue = pItem->val.uint64;
7620 } else {
7621 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007622 }
7623 break;
7624
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007625 case QCBOR_TYPE_65BIT_NEG_INT:
Laurence Lundblade05369de2024-11-17 17:00:28 -08007626 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
Laurence Lundblade68769332024-11-03 13:09:20 -08007627
7628 default:
7629 return QCBOR_ERR_UNEXPECTED_TYPE;
7630 }
7631
Laurence Lundblade68769332024-11-03 13:09:20 -08007632 return QCBOR_SUCCESS;
7633}
7634
7635
Laurence Lundblade05369de2024-11-17 17:00:28 -08007636/**
7637 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
7638 *
7639 * @param[in] pMe The decode context.
7640 * @param[in] uConvertTypes Bit mask list of conversion options.
7641 * @param[out] puValue Result of the conversion.
7642 * @param[in,out] pItem Temporary space to store Item, returned item.
7643 *
7644 * See QCBORDecode_GetUInt64Convert().
Laurence Lundblade68769332024-11-03 13:09:20 -08007645 */
Laurence Lundblade05369de2024-11-17 17:00:28 -08007646void
7647QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pMe,
7648 const uint32_t uConvertTypes,
7649 uint64_t *puValue,
7650 QCBORItem *pItem)
Laurence Lundblade68769332024-11-03 13:09:20 -08007651{
Laurence Lundblade05369de2024-11-17 17:00:28 -08007652 QCBORDecode_VGetNext(pMe, pItem);
7653 if(pMe->uLastError) {
7654 return;
7655 }
Laurence Lundblade68769332024-11-03 13:09:20 -08007656
Laurence Lundblade05369de2024-11-17 17:00:28 -08007657 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
7658 uConvertTypes,
7659 puValue);
7660}
Laurence Lundblade68769332024-11-03 13:09:20 -08007661
Laurence Lundblade05369de2024-11-17 17:00:28 -08007662
7663/**
7664 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
7665 *
7666 * @param[in] pMe The decode context.
7667 * @param[in] nLabel Label to find in map.
7668 * @param[in] uConvertTypes Bit mask list of conversion options.
7669 * @param[out] puValue Result of the conversion.
7670 * @param[in,out] pItem Temporary space to store Item, returned item.
7671 *
7672 * See QCBORDecode_GetUInt64ConvertInMapN().
7673 */
7674void
7675QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe,
7676 const int64_t nLabel,
7677 const uint32_t uConvertTypes,
7678 uint64_t *puValue,
7679 QCBORItem *pItem)
7680{
7681 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
7682 if(pMe->uLastError != QCBOR_SUCCESS) {
7683 return;
7684 }
7685
7686 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
7687 uConvertTypes,
7688 puValue);
7689}
7690
7691
7692/**
7693 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
7694 *
7695 * @param[in] pMe The decode context.
7696 * @param[in] szLabel Label to find in map.
7697 * @param[in] uConvertTypes Bit mask list of conversion options.
7698 * @param[out] puValue Result of the conversion.
7699 * @param[in,out] pItem Temporary space to store Item, returned item.
7700 *
7701 * See QCBORDecode_GetUInt64ConvertInMapSZ().
7702 */
7703void
7704QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
7705 const char *szLabel,
7706 const uint32_t uConvertTypes,
7707 uint64_t *puValue,
7708 QCBORItem *pItem)
7709{
7710 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
7711 if(pMe->uLastError != QCBOR_SUCCESS) {
7712 return;
7713 }
7714
7715 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
7716 uConvertTypes,
7717 puValue);
7718}
7719
7720
7721/**
7722 * @brief Convert many number types to an unt64_t.
7723 *
7724 * @param[in] pItem The item to convert.
7725 * @param[in] uConvertTypes Bit mask list of conversion options.
7726 * @param[out] puValue The resulting converted value.
7727 *
7728 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
7729 * in uConvertTypes.
7730 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
7731 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
7732 * or too small.
7733 */
7734static QCBORError
7735QCBOR_Private_UInt64ConvertAll(const QCBORItem *pItem,
7736 const uint32_t uConvertTypes,
7737 uint64_t *puValue)
7738{
7739 switch(pItem->uDataType) { /* -Wmaybe-uninitialized falsly warns here */
7740
Laurence Lundblade68769332024-11-03 13:09:20 -08007741 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade05369de2024-11-17 17:00:28 -08007742 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
7743 return QCBORDecode_Private_PositiveBigNumberToUInt(pItem->val.bigNum, puValue);
7744 } else {
7745 return QCBOR_ERR_UNEXPECTED_TYPE;
7746 }
7747 break;
7748
Laurence Lundblade68769332024-11-03 13:09:20 -08007749 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade05369de2024-11-17 17:00:28 -08007750 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
7751 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
7752 } else {
7753 return QCBOR_ERR_UNEXPECTED_TYPE;
7754 }
7755 break;
7756
7757#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
7758
7759 case QCBOR_TYPE_DECIMAL_FRACTION:
7760 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
7761 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
7762 pItem->val.expAndMantissa.nExponent,
7763 puValue,
7764 QCBOR_Private_Exponentitate10);
7765 } else {
7766 return QCBOR_ERR_UNEXPECTED_TYPE;
7767 }
7768 break;
7769
7770 case QCBOR_TYPE_BIGFLOAT:
7771 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
7772 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
7773 pItem->val.expAndMantissa.nExponent,
7774 puValue,
7775 QCBOR_Private_Exponentitate2);
7776 } else {
7777 return QCBOR_ERR_UNEXPECTED_TYPE;
7778 }
7779 break;
7780
7781 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
7782 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
7783 uint64_t uMantissa;
7784 QCBORError uErr;
7785 uErr = QCBORDecode_Private_PositiveBigNumberToUInt(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa);
7786 if(uErr != QCBOR_SUCCESS) {
7787 return uErr;
7788 }
7789 return QCBOR_Private_ExponentitateUU(uMantissa,
7790 pItem->val.expAndMantissa.nExponent,
7791 puValue,
7792 QCBOR_Private_Exponentitate10);
7793 } else {
7794 return QCBOR_ERR_UNEXPECTED_TYPE;
7795 }
7796 break;
7797
7798 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
7799 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
7800 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
7801 } else {
7802 return QCBOR_ERR_UNEXPECTED_TYPE;
7803 }
7804 break;
7805
7806 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
7807 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
7808 uint64_t uMantissa;
7809 QCBORError uErr;
7810 uErr = QCBORDecode_Private_PositiveBigNumberToUInt(pItem->val.expAndMantissa.Mantissa.bigNum,
7811 &uMantissa);
7812 if(uErr != QCBOR_SUCCESS) {
7813 return uErr;
7814 }
7815 return QCBOR_Private_ExponentitateUU(uMantissa,
7816 pItem->val.expAndMantissa.nExponent,
7817 puValue,
7818 QCBOR_Private_Exponentitate2);
7819 } else {
7820 return QCBOR_ERR_UNEXPECTED_TYPE;
7821 }
7822 break;
7823
7824 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
7825 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
7826 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
7827 } else {
7828 return QCBOR_ERR_UNEXPECTED_TYPE;
7829 }
7830 break;
7831#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
7832 default:
7833 return QCBOR_ERR_UNEXPECTED_TYPE;
7834 }
7835}
7836
7837
7838/*
7839 * Public function, see header qcbor/qcbor_decode.h file
7840 */
7841void
7842QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe,
7843 const uint32_t uConvertTypes,
7844 uint64_t *puValue)
7845{
7846 QCBORItem Item;
7847
7848 QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item);
7849
7850 if(pMe->uLastError == QCBOR_SUCCESS) {
7851 // The above conversion succeeded
7852 return;
7853 }
7854
7855 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
7856 // The above conversion failed in a way that code below can't correct
7857 return;
7858 }
7859
7860 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
7861 uConvertTypes,
7862 puValue);
7863}
7864
7865
7866/*
7867 * Public function, see header qcbor/qcbor_decode.h file
7868 */
7869void
7870QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
7871 const int64_t nLabel,
7872 const uint32_t uConvertTypes,
7873 uint64_t *puValue)
7874{
7875 QCBORItem Item;
7876
7877 QCBORDecode_Private_GetUInt64ConvertInMapN(pMe,
7878 nLabel,
7879 uConvertTypes,
7880 puValue,
7881 &Item);
7882
7883 if(pMe->uLastError == QCBOR_SUCCESS) {
7884 // The above conversion succeeded
7885 return;
7886 }
7887
7888 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
7889 // The above conversion failed in a way that code below can't correct
7890 return;
7891 }
7892
7893 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
7894 uConvertTypes,
7895 puValue);
7896}
7897
7898
7899/*
7900 * Public function, see header qcbor/qcbor_decode.h file
7901 */
7902void
7903QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
7904 const char *szLabel,
7905 const uint32_t uConvertTypes,
7906 uint64_t *puValue)
7907{
7908 QCBORItem Item;
7909 QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe,
7910 szLabel,
7911 uConvertTypes,
7912 puValue,
7913 &Item);
7914
7915 if(pMe->uLastError == QCBOR_SUCCESS) {
7916 // The above conversion succeeded
7917 return;
7918 }
7919
7920 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
7921 // The above conversion failed in a way that code below can't correct
7922 return;
7923 }
7924
7925 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
7926 uConvertTypes,
7927 puValue);
7928}
7929
7930
7931
7932
7933#ifndef USEFULBUF_DISABLE_ALL_FLOAT
7934/**
7935 * @brief Basic conversions to a double.
7936 *
7937 * @param[in] pItem The item to convert
7938 * @param[in] uConvertTypes Bit flags indicating source types for conversion
7939 * @param[out] pdValue The value converted to a double
7940 *
7941 * This does the conversions that don't need much object code,
7942 * the conversions from int, uint and float to double.
7943 *
7944 * See QCBOR_Private_DoubleConvertAll() for the full set
7945 * of conversions.
7946 */
7947static QCBORError
7948QCBOR_Private_ConvertDouble(const QCBORItem *pItem,
7949 const uint32_t uConvertTypes,
7950 double *pdValue)
7951{
7952 switch(pItem->uDataType) {
7953 case QCBOR_TYPE_FLOAT:
7954#ifndef QCBOR_DISABLE_FLOAT_HW_USE
7955 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
7956 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
7957 // Simple cast does the job.
7958 *pdValue = (double)pItem->val.fnum;
7959 } else {
7960 return QCBOR_ERR_UNEXPECTED_TYPE;
7961 }
7962 }
7963#else /* QCBOR_DISABLE_FLOAT_HW_USE */
7964 return QCBOR_ERR_HW_FLOAT_DISABLED;
7965#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
7966 break;
7967
7968 case QCBOR_TYPE_DOUBLE:
7969 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
7970 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
7971 *pdValue = pItem->val.dfnum;
7972 } else {
7973 return QCBOR_ERR_UNEXPECTED_TYPE;
7974 }
7975 }
Laurence Lundblade68769332024-11-03 13:09:20 -08007976 break;
7977
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007978 case QCBOR_TYPE_INT64:
Laurence Lundblade05369de2024-11-17 17:00:28 -08007979#ifndef QCBOR_DISABLE_FLOAT_HW_USE
7980 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
7981 // A simple cast seems to do the job with no worry of exceptions.
7982 // There will be precision loss for some values.
7983 *pdValue = (double)pItem->val.int64;
7984
7985 } else {
7986 return QCBOR_ERR_UNEXPECTED_TYPE;
7987 }
7988#else
7989 return QCBOR_ERR_HW_FLOAT_DISABLED;
7990#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007991 break;
7992
7993 case QCBOR_TYPE_UINT64:
Laurence Lundblade05369de2024-11-17 17:00:28 -08007994#ifndef QCBOR_DISABLE_FLOAT_HW_USE
7995 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
7996 // A simple cast seems to do the job with no worry of exceptions.
7997 // There will be precision loss for some values.
7998 *pdValue = (double)pItem->val.uint64;
7999 } else {
8000 return QCBOR_ERR_UNEXPECTED_TYPE;
8001 }
Laurence Lundblade14ce2282024-07-24 22:13:35 -07008002 break;
Laurence Lundblade05369de2024-11-17 17:00:28 -08008003#else
8004 return QCBOR_ERR_HW_FLOAT_DISABLED;
8005#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade14ce2282024-07-24 22:13:35 -07008006
8007 case QCBOR_TYPE_65BIT_NEG_INT:
Laurence Lundblade05369de2024-11-17 17:00:28 -08008008#ifndef QCBOR_DISABLE_FLOAT_HW_USE
8009 // TODO: don't use float HW. We have the function to do it.
8010 *pdValue = -(double)pItem->val.uint64 - 1;
Laurence Lundblade14ce2282024-07-24 22:13:35 -07008011 break;
Laurence Lundblade05369de2024-11-17 17:00:28 -08008012#else
8013 return QCBOR_ERR_HW_FLOAT_DISABLED;
8014#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade14ce2282024-07-24 22:13:35 -07008015
8016 default:
Laurence Lundblade68769332024-11-03 13:09:20 -08008017 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade14ce2282024-07-24 22:13:35 -07008018 }
8019
Laurence Lundblade05369de2024-11-17 17:00:28 -08008020 return QCBOR_SUCCESS;
Laurence Lundblade14ce2282024-07-24 22:13:35 -07008021}
8022
8023
Laurence Lundblade05369de2024-11-17 17:00:28 -08008024/**
8025 * @brief Almost-public method to decode a number and convert to double (semi-private).
8026 *
8027 * @param[in] pMe The decode context.
8028 * @param[in] uConvertTypes Bit mask list of conversion options
8029 * @param[out] pdValue The output of the conversion.
8030 * @param[in,out] pItem Temporary space to store Item, returned item.
8031 *
8032 * See QCBORDecode_GetDoubleConvert().
8033 */
8034void
8035QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pMe,
8036 const uint32_t uConvertTypes,
8037 double *pdValue,
8038 QCBORItem *pItem)
Laurence Lundblade14ce2282024-07-24 22:13:35 -07008039{
Laurence Lundblade05369de2024-11-17 17:00:28 -08008040 QCBORDecode_VGetNext(pMe, pItem);
Laurence Lundblade721b56e2024-10-22 03:02:04 -07008041 if(pMe->uLastError) {
8042 return;
8043 }
8044
Laurence Lundblade05369de2024-11-17 17:00:28 -08008045 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
8046 uConvertTypes,
8047 pdValue);
Laurence Lundblade68769332024-11-03 13:09:20 -08008048}
8049
8050
Laurence Lundblade05369de2024-11-17 17:00:28 -08008051/**
8052 * @brief Almost-public method to decode a number and convert to double (semi-private).
8053 *
8054 * @param[in] pMe The decode context.
8055 * @param[in] nLabel Label to find in map.
8056 * @param[in] uConvertTypes Bit mask list of conversion options
8057 * @param[out] pdValue The output of the conversion.
8058 * @param[in,out] pItem Temporary space to store Item, returned item.
8059 *
8060 * See QCBORDecode_GetDoubleConvertInMapN().
Laurence Lundblade14ce2282024-07-24 22:13:35 -07008061 */
8062void
Laurence Lundblade05369de2024-11-17 17:00:28 -08008063QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pMe,
Laurence Lundblade68769332024-11-03 13:09:20 -08008064 const int64_t nLabel,
Laurence Lundblade05369de2024-11-17 17:00:28 -08008065 const uint32_t uConvertTypes,
8066 double *pdValue,
8067 QCBORItem *pItem)
Laurence Lundblade68769332024-11-03 13:09:20 -08008068{
Laurence Lundblade05369de2024-11-17 17:00:28 -08008069 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
8070 if(pMe->uLastError != QCBOR_SUCCESS) {
8071 return;
8072 }
Laurence Lundblade68769332024-11-03 13:09:20 -08008073
Laurence Lundblade05369de2024-11-17 17:00:28 -08008074 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
8075 uConvertTypes,
8076 pdValue);
Laurence Lundblade68769332024-11-03 13:09:20 -08008077}
8078
Laurence Lundblade05369de2024-11-17 17:00:28 -08008079
8080/**
8081 * @brief Almost-public method to decode a number and convert to double (semi-private).
8082 *
8083 * @param[in] pMe The decode context.
8084 * @param[in] szLabel Label to find in map.
8085 * @param[in] uConvertTypes Bit mask list of conversion options
8086 * @param[out] pdValue The output of the conversion.
8087 * @param[in,out] pItem Temporary space to store Item, returned item.
8088 *
8089 * See QCBORDecode_GetDoubleConvertInMapSZ().
Laurence Lundblade68769332024-11-03 13:09:20 -08008090 */
8091void
Laurence Lundblade05369de2024-11-17 17:00:28 -08008092QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe,
Laurence Lundblade68769332024-11-03 13:09:20 -08008093 const char *szLabel,
Laurence Lundblade05369de2024-11-17 17:00:28 -08008094 const uint32_t uConvertTypes,
8095 double *pdValue,
8096 QCBORItem *pItem)
Laurence Lundblade68769332024-11-03 13:09:20 -08008097{
Laurence Lundblade05369de2024-11-17 17:00:28 -08008098 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
8099 if(pMe->uLastError != QCBOR_SUCCESS) {
8100 return;
8101 }
Laurence Lundblade68769332024-11-03 13:09:20 -08008102
Laurence Lundblade05369de2024-11-17 17:00:28 -08008103 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
8104 uConvertTypes,
8105 pdValue);
Laurence Lundblade14ce2282024-07-24 22:13:35 -07008106}
8107
Laurence Lundblade05369de2024-11-17 17:00:28 -08008108
8109/**
8110 * @brief Convert many number types to a double.
8111 *
8112 * @param[in] pItem The item to convert.
8113 * @param[in] uConvertTypes Bit mask list of conversion options.
8114 * @param[out] pdValue The resulting converted value.
8115 *
8116 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
8117 * in uConvertTypes.
8118 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
8119 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
8120 * or too small.
8121 */
8122static QCBORError
8123QCBOR_Private_DoubleConvertAll(const QCBORItem *pItem,
8124 const uint32_t uConvertTypes,
8125 double *pdValue)
8126{
8127#ifndef QCBOR_DISABLE_FLOAT_HW_USE
8128 /*
8129 * What Every Computer Scientist Should Know About Floating-Point Arithmetic
8130 * https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
8131 */
8132 switch(pItem->uDataType) {
8133
8134#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
8135 case QCBOR_TYPE_DECIMAL_FRACTION:
8136 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
8137 // Underflow gives 0, overflow gives infinity
8138 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
8139 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
8140 } else {
8141 return QCBOR_ERR_UNEXPECTED_TYPE;
8142 }
8143 break;
8144
8145 case QCBOR_TYPE_BIGFLOAT:
8146 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
8147 // Underflow gives 0, overflow gives infinity
8148 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
8149 exp2((double)pItem->val.expAndMantissa.nExponent);
8150 } else {
8151 return QCBOR_ERR_UNEXPECTED_TYPE;
8152 }
8153 break;
8154#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
8155
8156 case QCBOR_TYPE_POSBIGNUM:
8157 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
8158 *pdValue = QCBORDecode_Private_BigNumberToDouble(pItem->val.bigNum);
8159 } else {
8160 return QCBOR_ERR_UNEXPECTED_TYPE;
8161 }
8162 break;
8163
8164 case QCBOR_TYPE_NEGBIGNUM:
8165 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
8166 *pdValue = -1-QCBORDecode_Private_BigNumberToDouble(pItem->val.bigNum);
8167 } else {
8168 return QCBOR_ERR_UNEXPECTED_TYPE;
8169 }
8170 break;
8171
8172#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
8173 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
8174 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
8175 double dMantissa = QCBORDecode_Private_BigNumberToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
8176 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
8177 } else {
8178 return QCBOR_ERR_UNEXPECTED_TYPE;
8179 }
8180 break;
8181
8182 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
8183 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
8184 /* Must subtract 1 for CBOR negative integer offset */
8185 double dMantissa = -1-QCBORDecode_Private_BigNumberToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
8186 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
8187 } else {
8188 return QCBOR_ERR_UNEXPECTED_TYPE;
8189 }
8190 break;
8191
8192 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
8193 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
8194 double dMantissa = QCBORDecode_Private_BigNumberToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
8195 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
8196 } else {
8197 return QCBOR_ERR_UNEXPECTED_TYPE;
8198 }
8199 break;
8200
8201 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
8202 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
8203 double dMantissa = -1-QCBORDecode_Private_BigNumberToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
8204 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
8205 } else {
8206 return QCBOR_ERR_UNEXPECTED_TYPE;
8207 }
8208 break;
8209#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
8210
8211 default:
8212 return QCBOR_ERR_UNEXPECTED_TYPE;
8213 }
8214
8215 return QCBOR_SUCCESS;
8216
8217#else
8218 (void)pItem;
8219 (void)uConvertTypes;
8220 (void)pdValue;
8221 return QCBOR_ERR_HW_FLOAT_DISABLED;
8222#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
8223
8224}
8225
8226
8227/*
8228 * Public function, see header qcbor/qcbor_decode.h file
8229 */
8230void
8231QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe,
8232 const uint32_t uConvertTypes,
8233 double *pdValue)
8234{
8235
8236 QCBORItem Item;
8237
8238 QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item);
8239
8240 if(pMe->uLastError == QCBOR_SUCCESS) {
8241 // The above conversion succeeded
8242 return;
8243 }
8244
8245 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
8246 // The above conversion failed in a way that code below can't correct
8247 return;
8248 }
8249
8250 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
8251 uConvertTypes,
8252 pdValue);
8253}
8254
8255
8256/*
8257 * Public function, see header qcbor/qcbor_decode.h file
8258 */
8259void
8260QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe,
8261 const int64_t nLabel,
8262 const uint32_t uConvertTypes,
8263 double *pdValue)
8264{
8265 QCBORItem Item;
8266
8267 QCBORDecode_Private_GetDoubleConvertInMapN(pMe,
8268 nLabel,
8269 uConvertTypes,
8270 pdValue,
8271 &Item);
8272
8273 if(pMe->uLastError == QCBOR_SUCCESS) {
8274 // The above conversion succeeded
8275 return;
8276 }
8277
8278 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
8279 // The above conversion failed in a way that code below can't correct
8280 return;
8281 }
8282
8283 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
8284 uConvertTypes,
8285 pdValue);
8286}
8287
8288
8289/*
8290 * Public function, see header qcbor/qcbor_decode.h file
8291 */
8292void
8293QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe,
8294 const char *szLabel,
8295 const uint32_t uConvertTypes,
8296 double *pdValue)
8297{
8298 QCBORItem Item;
8299 QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe,
8300 szLabel,
8301 uConvertTypes,
8302 pdValue,
8303 &Item);
8304
8305 if(pMe->uLastError == QCBOR_SUCCESS) {
8306 // The above conversion succeeded
8307 return;
8308 }
8309
8310 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
8311 // The above conversion failed in a way that code below can't correct
8312 return;
8313 }
8314
8315 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
8316 uConvertTypes,
8317 pdValue);
8318}
8319#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
8320
8321
Laurence Lundblade721b56e2024-10-22 03:02:04 -07008322// TODO: re order above functions in tag number order