blob: fd163228b11635762e462053722cca9725387fe1 [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,
650 QCBORDecodeMode nDecodeMode)
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 */
657 pMe->uDecodeMode = (uint8_t)nDecodeMode;
658 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 Lundblade9b2ae8a2024-07-12 11:00:20 -0700769 * @param[in] bRequirePreferred Require preferred serialization for argument.
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
789QCBOR_Private_DecodeHead(UsefulInputBuf *pUInBuf,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700790#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
791 bool bRequirePreferred,
792#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 */
820 if(bRequirePreferred) {
821 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
848 if(bRequirePreferred && nAdditionalInfo == LEN_IS_INDEFINITE) {
849 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 Lundblade721b56e2024-10-22 03:02:04 -07001050 * @param[in] uDecodeMode3Bit 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 Lundblade721b56e2024-10-22 03:02:04 -07001069QCBOR_Private_DecodeArrayOrMap(const uint8_t uDecodeMode3Bit,
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001070 const int nMajorType,
Laurence Lundbladeb95afec2024-08-26 10:51:28 -07001071 uint64_t uItemCount,
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001072 const int nAdditionalInfo,
1073 QCBORItem *pDecodedItem)
1074{
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 Lundblade721b56e2024-10-22 03:02:04 -07001087 if(uDecodeMode3Bit == 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 Lundblade721b56e2024-10-22 03:02:04 -07001091 (void)uDecodeMode3Bit;
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 Lundblade721b56e2024-10-22 03:02:04 -07001110 if(uDecodeMode3Bit == 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 Lundblade721b56e2024-10-22 03:02:04 -07001165QCBORDecode_Private_HalfConformance(const double d, const uint8_t uDecodeMode3Bit)
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 Lundblade721b56e2024-10-22 03:02:04 -07001179 if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_DCBOR) {
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 Lundblade721b56e2024-10-22 03:02:04 -07001191QCBORDecode_Private_SingleConformance(const float f, const uint8_t uDecodeMode3Bit)
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001192{
1193 struct IEEE754_ToInt ToInt;
1194 IEEE754_union ToSmaller;
1195
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001196 if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_DCBOR) {
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 Lundblade721b56e2024-10-22 03:02:04 -07001210 if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_PREFERRED) {
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 Lundblade721b56e2024-10-22 03:02:04 -07001222QCBORDecode_Private_DoubleConformance(const double d, uint8_t uDecodeMode3Bit)
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001223{
1224 struct IEEE754_ToInt ToInt;
1225 IEEE754_union ToSmaller;
1226
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001227 if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_DCBOR) {
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 Lundblade721b56e2024-10-22 03:02:04 -07001240 if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_PREFERRED) {
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 Lundblade721b56e2024-10-22 03:02:04 -07001252QCBORDecode_Private_SingleConformance(const float f, uint8_t uDecodeMode3Bit)
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001253{
1254 (void)f;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001255 if(uDecodeMode3Bit>= QCBOR_DECODE_MODE_PREFERRED) {
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 Lundblade721b56e2024-10-22 03:02:04 -07001263QCBORDecode_Private_DoubleConformance(const double d, uint8_t uDecodeMode3Bit)
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001264{
1265 (void)d;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001266 if(uDecodeMode3Bit>= QCBOR_DECODE_MODE_PREFERRED) {
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 Lundblade721b56e2024-10-22 03:02:04 -07001279QCBOR_Private_DecodeFloat(const uint8_t uDecodeMode3Bit,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001280 const int nAdditionalInfo,
1281 const uint64_t uArgument,
1282 QCBORItem *pDecodedItem)
1283{
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 Lundblade721b56e2024-10-22 03:02:04 -07001299 uReturn = QCBORDecode_Private_HalfConformance(pDecodedItem->val.dfnum, uDecodeMode3Bit);
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 Lundblade721b56e2024-10-22 03:02:04 -07001317 uReturn = QCBORDecode_Private_SingleConformance(single, uDecodeMode3Bit);
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 Lundblade721b56e2024-10-22 03:02:04 -07001345 uReturn = QCBORDecode_Private_DoubleConformance(pDecodedItem->val.dfnum, uDecodeMode3Bit);
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 Lundblade721b56e2024-10-22 03:02:04 -07001403QCBOR_Private_DecodeType7(const uint8_t uDecodeMode3Bit,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001404 const int nAdditionalInfo,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001405 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 Lundblade721b56e2024-10-22 03:02:04 -07001426 uReturn = QCBOR_Private_DecodeFloat(uDecodeMode3Bit, 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 Lundblade82634b62024-11-20 22:37:45 -08001438 if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_DCBOR &&
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 Lundblade82634b62024-11-20 22:37:45 -08001458 if(uDecodeMode3Bit >= QCBOR_DECODE_MODE_DCBOR &&
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 Lundbladede2e1502024-08-26 11:37:05 -07001516 int nMajorType = 0;
1517 uint64_t uArgument = 0;
1518 int nAdditionalInfo = 0;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001519 uint8_t uDecodeMode3Bit = pMe->uDecodeMode & QCBOR_DECODE_MODE_MASK;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001520
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001521 memset(pDecodedItem, 0, sizeof(QCBORItem));
1522
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001523 /* Decode the "head" that every CBOR item has into the major type,
1524 * argument and the additional info.
1525 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001526 uReturn = QCBOR_Private_DecodeHead(&(pMe->InBuf),
1527#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
1528 // TODO: make this prettier; will optimizer take out stuff without ifdef?
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001529 uDecodeMode3Bit >= QCBOR_DECODE_MODE_PREFERRED,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001530#endif /* !QCBOR_DISABLE_DECODE_CONFORMANCE */
1531 &nMajorType,
1532 &uArgument,
1533 &nAdditionalInfo);
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001534
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001535 if(uReturn != QCBOR_SUCCESS) {
1536 return uReturn;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001537 }
1538
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001539 /* All the functions below get inlined by the optimizer. This code
1540 * is easier to read with them all being similar functions, even if
1541 * some functions don't do much.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001542 */
1543 switch (nMajorType) {
1544 case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
1545 case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001546 return QCBOR_Private_DecodeInteger(nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001547 break;
1548
1549 case CBOR_MAJOR_TYPE_BYTE_STRING: /* Major type 2 */
1550 case CBOR_MAJOR_TYPE_TEXT_STRING: /* Major type 3 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001551 return QCBOR_Private_DecodeString(pMe, bAllocateStrings, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001552 break;
1553
1554 case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */
1555 case CBOR_MAJOR_TYPE_MAP: /* Major type 5 */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001556 return QCBOR_Private_DecodeArrayOrMap(uDecodeMode3Bit, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001557 break;
1558
1559 case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001560 return QCBOR_Private_DecodeTagNumber(uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001561 break;
1562
1563 case CBOR_MAJOR_TYPE_SIMPLE:
1564 /* Major type 7: float, double, true, false, null... */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001565 return QCBOR_Private_DecodeType7(uDecodeMode3Bit, nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001566 break;
1567
1568 default:
1569 /* Never happens because DecodeHead() should never return > 7 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001570 return QCBOR_ERR_UNSUPPORTED;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001571 break;
1572 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001573}
1574
1575
1576/**
1577 * @brief Process indefinite-length strings (decode layer 5).
1578 *
1579 * @param[in] pMe Decoder context
1580 * @param[out] pDecodedItem The decoded item that work is done on.
1581 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001582 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1583 * features
1584 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1585 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1586 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1587 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1588 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1589 * of half-precision disabled
1590 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1591 * float decode is disabled.
1592 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1593 * simple type in input.
1594 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1595 * in input, but indefinite
1596 * lengths disabled.
1597 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1598 * but no string allocator.
1599 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1600 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1601 * input, but indefinite-length
1602 * strings are disabled.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001603 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001604 * If @c pDecodedItem is not an indefinite-length string, this does nothing.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001605 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001606 * If it is, this loops getting the subsequent chunk data items that
1607 * make up the string. The string allocator is used to make a
1608 * contiguous buffer for the chunks. When this completes @c
1609 * pDecodedItem contains the put-together string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001610 *
1611 * Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001612 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001613static QCBORError
1614QCBORDecode_Private_GetNextFullString(QCBORDecodeContext *pMe,
1615 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001616{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001617 /* Aproximate stack usage
1618 * 64-bit 32-bit
1619 * local vars 32 16
1620 * 2 UsefulBufs 32 16
1621 * QCBORItem 56 52
1622 * TOTAL 120 74
1623 */
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001624 QCBORError uReturn;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001625
1626 /* A note about string allocation -- Memory for strings is
1627 * allocated either because 1) indefinte-length string chunks are
1628 * being coalecsed or 2) caller has requested all strings be
1629 * allocated. The first case is handed below here. The second case
1630 * is handled in DecodeString if the bAllocate is true. That
1631 * boolean originates here with pMe->bStringAllocateAll immediately
1632 * below. That is, QCBOR_Private_DecodeAtomicDataItem() is called
1633 * in two different contexts here 1) main-line processing which is
1634 * where definite-length strings need to be allocated if
1635 * bStringAllocateAll is true and 2) processing chunks of
1636 * indefinite-lengths strings in in which case there must be no
1637 * allocation.
1638 */
1639
1640
1641 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, pMe->bStringAllocateAll, pDecodedItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001642 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001643 goto Done;
1644 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001645
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001646 /* This is where out-of-place break is detected for the whole
1647 * decoding stack. Break is an error for everything that calls
1648 * QCBORDecode_Private_GetNextFullString(), so the check is
1649 * centralized here.
1650 */
1651 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
1652 uReturn = QCBOR_ERR_BAD_BREAK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001653 goto Done;
1654 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001655
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001656
1657 /* Skip out if not an indefinite-length string */
1658 const uint8_t uStringType = pDecodedItem->uDataType;
1659 if(uStringType != QCBOR_TYPE_BYTE_STRING &&
1660 uStringType != QCBOR_TYPE_TEXT_STRING) {
1661 goto Done;
1662 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001663 if(pDecodedItem->val.string.len != QCBOR_STRING_LENGTH_INDEFINITE) {
1664 goto Done;
1665 }
1666
1667#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001668 /* Can't decode indefinite-length strings without a string allocator */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001669 if(!pMe->StringAllocator.pfAllocator) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001670 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1671 goto Done;
1672 }
1673
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001674 /* Loop getting chunks of the indefinite-length string */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001675 UsefulBufC FullString = NULLUsefulBufC;
1676
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001677 for(;;) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001678 /* Get QCBORItem for next chunk */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001679 QCBORItem StringChunkItem;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001680 /* Pass false to DecodeAtomicDataItem() because the individual
1681 * string chunks in an indefinite-length must not be
1682 * allocated. They are always copied into the allocated
1683 * contiguous buffer allocated here.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001684 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001685 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &StringChunkItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001686 if(uReturn) {
1687 break;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001688 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001689
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001690 /* Is item is the marker for end of the indefinite-length string? */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001691 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001692 /* String is complete */
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001693 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301694 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001695 break;
1696 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001697
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001698 /* All chunks must be of the same type, the type of the item
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001699 * that introduces the indefinite-length string. This also
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001700 * catches errors where the chunk is not a string at all and an
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001701 * indefinite-length string inside an indefinite-length string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001702 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001703 if(StringChunkItem.uDataType != uStringType ||
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001704 StringChunkItem.val.string.len == QCBOR_STRING_LENGTH_INDEFINITE) {
1705 uReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001706 break;
1707 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001708
David Navarro9123e5b2022-03-28 16:04:03 +02001709 if (StringChunkItem.val.string.len > 0) {
1710 /* The first time throurgh FullString.ptr is NULL and this is
1711 * equivalent to StringAllocator_Allocate(). Subsequently it is
1712 * not NULL and a reallocation happens.
1713 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001714 UsefulBuf NewMem = StringAllocator_Reallocate(&(pMe->StringAllocator),
David Navarro9123e5b2022-03-28 16:04:03 +02001715 FullString.ptr,
1716 FullString.len + StringChunkItem.val.string.len);
David Navarro9123e5b2022-03-28 16:04:03 +02001717 if(UsefulBuf_IsNULL(NewMem)) {
1718 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1719 break;
1720 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001721
David Navarro9123e5b2022-03-28 16:04:03 +02001722 /* Copy new string chunk to the end of accumulated string */
1723 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001724 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001725 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001726
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001727 if(uReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
1728 /* Getting the item failed, clean up the allocated memory */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001729 StringAllocator_Free(&(pMe->StringAllocator), FullString.ptr);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001730 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001731#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1732 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1733#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001734
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001735Done:
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001736 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001737}
1738
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001739
Laurence Lundblade37286c02022-09-03 10:05:02 -07001740#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001741/**
1742 * @brief This converts a tag number to a shorter mapped value for storage.
1743 *
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001744 * @param[in] pMe The decode context.
1745 * @param[in] uUnMappedTag The tag number to map
1746 * @param[out] puMappedTagNumber The stored tag number.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001747 *
1748 * @return error code.
1749 *
1750 * The main point of mapping tag numbers is make QCBORItem
1751 * smaller. With this mapping storage of 4 tags takes up 8
1752 * bytes. Without, it would take up 32 bytes.
1753 *
1754 * This maps tag numbers greater than QCBOR_LAST_UNMAPPED_TAG.
1755 * QCBOR_LAST_UNMAPPED_TAG is a little smaller than MAX_UINT16.
1756 *
1757 * See also UnMapTagNumber() and @ref QCBORItem.
1758 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001759static QCBORError
1760QCBORDecode_Private_MapTagNumber(QCBORDecodeContext *pMe,
1761 const uint64_t uUnMappedTag,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001762 uint16_t *puMappedTagNumber)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001763{
1764 if(uUnMappedTag > QCBOR_LAST_UNMAPPED_TAG) {
1765 unsigned uTagMapIndex;
1766 /* Is there room in the tag map, or is it in it already? */
1767 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
1768 if(pMe->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID64) {
1769 break;
1770 }
1771 if(pMe->auMappedTags[uTagMapIndex] == uUnMappedTag) {
1772 break;
1773 }
1774 }
1775 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
1776 return QCBOR_ERR_TOO_MANY_TAGS;
1777 }
1778
1779 /* Covers the cases where tag is new and were it is already in the map */
1780 pMe->auMappedTags[uTagMapIndex] = uUnMappedTag;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001781 *puMappedTagNumber = (uint16_t)(uTagMapIndex + QCBOR_LAST_UNMAPPED_TAG + 1);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001782
1783 } else {
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001784 *puMappedTagNumber = (uint16_t)uUnMappedTag;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001785 }
1786
1787 return QCBOR_SUCCESS;
1788}
1789
1790
1791/**
1792 * @brief This converts a mapped tag number to the actual tag number.
1793 *
1794 * @param[in] pMe The decode context.
1795 * @param[in] uMappedTagNumber The stored tag number.
1796 *
1797 * @return The actual tag number is returned or
1798 * @ref CBOR_TAG_INVALID64 on error.
1799 *
1800 * This is the reverse of MapTagNumber()
1801 */
1802static uint64_t
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001803QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe,
1804 const uint16_t uMappedTagNumber)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001805{
1806 if(uMappedTagNumber <= QCBOR_LAST_UNMAPPED_TAG) {
1807 return uMappedTagNumber;
1808 } else if(uMappedTagNumber == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07001809 return CBOR_TAG_INVALID64;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001810 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001811 /* This won't be negative because of code below in
1812 * MapTagNumber()
1813 */
1814 const unsigned uIndex = uMappedTagNumber - (QCBOR_LAST_UNMAPPED_TAG + 1);
1815 return pMe->auMappedTags[uIndex];
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001816 }
1817}
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001818
1819
1820static const struct QCBORTagDecoderEntry *
1821QCBORDecode_Private_LookUpTagDecoder(const struct QCBORTagDecoderEntry *pTagContentTable,
1822 const uint64_t uTagNumber)
1823{
1824 const struct QCBORTagDecoderEntry *pTE;
1825
1826 if(pTagContentTable == NULL) {
1827 return NULL;
1828 }
1829
1830 for(pTE = pTagContentTable; pTE->uTagNumber != CBOR_TAG_INVALID64; pTE++) {
1831 if(pTE->uTagNumber == uTagNumber || pTE->uTagNumber == CBOR_TAG_ANY) {
1832 break;
1833 }
1834 }
1835
1836 if(pTE->uTagNumber == CBOR_TAG_INVALID64) {
1837 return NULL;
1838 }
1839
1840 return pTE;
1841}
1842#endif /* ! QCBOR_DISABLE_TAGS */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001843
Laurence Lundblade9b334962020-08-27 10:55:53 -07001844
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001845/**
1846 * @brief Aggregate all tags wrapping a data item (decode layer 4).
1847 *
1848 * @param[in] pMe Decoder context
1849 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001850 *
1851 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1852 * features
1853 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1854 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1855 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1856 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1857 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1858 * of half-precision disabled
1859 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1860 * float decode is disabled.
1861 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1862 * simple type in input.
1863 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1864 * in input, but indefinite
1865 * lengths disabled.
1866 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1867 * but no string allocator.
1868 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1869 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1870 * input, but indefinite-length
1871 * strings are disabled.
1872 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001873 *
1874 * This loops getting atomic data items until one is not a tag
1875 * number. Usually this is largely pass-through because most
1876 * item are not tag numbers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001877 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001878static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001879QCBORDecode_Private_GetNextTagNumber(QCBORDecodeContext *pMe,
1880 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001881{
Laurence Lundblade37286c02022-09-03 10:05:02 -07001882#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001883 int nIndex;
1884 QCBORError uErr;
1885 uint16_t uMappedTagNumber;
1886 QCBORError uReturn;
1887
1888 /* Accummulate the tag numbers from multiple items here and then
1889 * copy them into the last item, the non-tag-number item.
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001890 */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001891 QCBORMappedTagNumbers auTagNumbers;;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001892
1893 /* Initialize to CBOR_TAG_INVALID16 */
1894 #if CBOR_TAG_INVALID16 != 0xffff
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001895 /* Be sure the memset is initializing to CBOR_TAG_INVALID16 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001896 #err CBOR_TAG_INVALID16 tag not defined as expected
1897 #endif
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001898 memset(auTagNumbers, 0xff, sizeof(auTagNumbers));
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001899
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001900 /* Loop fetching data items until the item fetched is not a tag number */
1901 uReturn = QCBOR_SUCCESS;
1902 for(nIndex = 0; ; nIndex++) {
1903 uErr = QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07001904 if(uErr != QCBOR_SUCCESS) {
1905 uReturn = uErr;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001906 break;
1907 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001908
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001909 if(pDecodedItem->uDataType != QCBOR_TYPE_TAG_NUMBER) {
1910 /* Successful exit from loop; maybe got some tags, maybe not */
1911 memcpy(pDecodedItem->auTagNumbers, auTagNumbers, sizeof(auTagNumbers));
1912 break;
1913 }
1914
1915 if(nIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
1916 /* No room in the item's tag number array */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001917 uReturn = QCBOR_ERR_TOO_MANY_TAGS;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001918 /* Continue on to get all tag numbers wrapping this item even
1919 * though it is erroring out in the end. This allows decoding
1920 * to continue. This is a QCBOR resource limit error, not a
1921 * problem with being well-formed CBOR.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001922 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001923 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001924 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001925
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001926 /* Map the tag number */
1927 uMappedTagNumber = 0;
1928 uReturn = QCBORDecode_Private_MapTagNumber(pMe, pDecodedItem->val.uTagNumber, &uMappedTagNumber);
1929 /* Continue even on error so as to consume all tag numbers
1930 * wrapping this data item so decoding can go on. If
1931 * QCBORDecode_Private_MapTagNumber() errors once it will
1932 * continue to error.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001933 */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001934
1935 auTagNumbers[nIndex] = uMappedTagNumber;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001936 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001937
Laurence Lundblade9b334962020-08-27 10:55:53 -07001938 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001939
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001940#else /* ! QCBOR_DISABLE_TAGS */
Laurence Lundblade37286c02022-09-03 10:05:02 -07001941
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07001942 return QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07001943
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001944#endif /* ! QCBOR_DISABLE_TAGS */
Laurence Lundblade37286c02022-09-03 10:05:02 -07001945}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001946
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001947
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001948/**
1949 * @brief Combine a map entry label and value into one item (decode layer 3).
1950 *
1951 * @param[in] pMe Decoder context
1952 * @param[out] pDecodedItem The decoded item that work is done on.
1953 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001954 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1955 * features
1956 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1957 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1958 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1959 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1960 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1961 * of half-precision disabled
1962 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1963 * float decode is disabled.
1964 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1965 * simple type in input.
1966 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1967 * in input, but indefinite
1968 * lengths disabled.
1969 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1970 * but no string allocator.
1971 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1972 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1973 * input, but indefinite-length
1974 * strings are disabled.
1975 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1976 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1977 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001978 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001979 * If the current nesting level is a map, then this combines pairs of
1980 * items into one data item with a label and value.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001981 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001982 * This is passthrough if the current nesting level is not a map.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001983 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001984 * This also implements maps-as-array mode where a map is treated like
1985 * an array to allow caller to do their own label processing.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001986 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001987static QCBORError
1988QCBORDecode_Private_GetNextMapEntry(QCBORDecodeContext *pMe,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001989 QCBORItem *pDecodedItem,
1990 uint32_t *puLabelEndOffset)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001991{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001992 QCBORItem LabelItem;
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001993 QCBORError uErr, uErr2;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001994
1995 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1996 if(QCBORDecode_IsUnrecoverableError(uErr)) {
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001997 goto Done;
1998 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001999
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002000 if(!DecodeNesting_IsCurrentTypeMap(&(pMe->nesting))) {
2001 /* Not decoding a map. Nothing to do. */
2002 /* When decoding maps-as-arrays, the type will be
2003 * QCBOR_TYPE_MAP_AS_ARRAY and this function will exit
2004 * here. This is now map processing for maps-as-arrays is not
2005 * done. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002006 goto Done;
2007 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08002008
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002009 /* Decoding a map entry, so the item decoded above was the label */
2010 LabelItem = *pDecodedItem;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002011
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002012 if(puLabelEndOffset != NULL) {
2013 /* Cast is OK because lengths are all 32-bit in QCBOR */
2014 *puLabelEndOffset = (uint32_t)UsefulInputBuf_Tell(&(pMe->InBuf));
2015 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08002016
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002017 /* Get the value of the map item */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002018 uErr2 = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
2019 if(QCBORDecode_IsUnrecoverableError(uErr2)) {
2020 uErr = uErr2;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002021 goto Done;
2022 }
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002023 if(uErr2 != QCBOR_SUCCESS) {
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002024 /* The recoverable error for the value overrides the recoverable
2025 * error for the label, if there was an error for the label */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002026 uErr = uErr2;
2027 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002028
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002029 /* Combine the label item and value item into one */
2030 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
2031 pDecodedItem->uLabelType = LabelItem.uDataType;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09002032
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002033#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002034 /* TODO: QCBOR_DECODE_MODE_MAP_STRINGS_ONLY might have been a bad idea. Maybe
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002035 * get rid of it in QCBOR 2.0
2036 */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002037 if((pMe->uDecodeMode & QCBOR_DECODE_MODE_MASK) == QCBOR_DECODE_MODE_MAP_STRINGS_ONLY &&
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002038 LabelItem.uDataType != QCBOR_TYPE_TEXT_STRING) {
2039 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
2040 goto Done;
2041 }
2042#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
2043
2044 switch(LabelItem.uDataType) {
2045 case QCBOR_TYPE_INT64:
2046 pDecodedItem->label.int64 = LabelItem.val.int64;
2047 break;
2048
2049#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
2050 case QCBOR_TYPE_UINT64:
2051 pDecodedItem->label.uint64 = LabelItem.val.uint64;
2052 break;
2053
2054 case QCBOR_TYPE_TEXT_STRING:
2055 case QCBOR_TYPE_BYTE_STRING:
2056 pDecodedItem->label.string = LabelItem.val.string;
2057 break;
2058#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
2059
2060 default:
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002061 /* It is possible to skip over labels that are non-aggregate
2062 * types like floats, but not to skip over labels that are
2063 * arrays or maps. We might eventually handle more label
2064 * types like floats as they are not too hard and we now
2065 * have QCBOR_DISABLE_NON_INTEGER_LABELS */
2066 if(!pMe->bAllowAllLabels || QCBORItem_IsMapOrArray(LabelItem)) {
2067 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
2068 goto Done;
2069 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002070 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002071
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002072Done:
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002073 return uErr;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002074}
2075
2076
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002077#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002078/**
2079 * @brief Peek and see if next data item is a break;
2080 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002081 * param[in] pUIB UsefulInputBuf to read from.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002082 * @param[out] pbNextIsBreak Indicate if next was a break or not.
2083 *
2084 * @return Any decoding error.
2085 *
2086 * See if next item is a CBOR break. If it is, it is consumed,
2087 * if not it is not consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07002088*/
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002089static QCBORError
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002090QCBOR_Private_NextIsBreak(QCBORDecodeContext *pMe, bool *pbNextIsBreak)
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002091{
2092 *pbNextIsBreak = false;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002093 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) != 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002094 QCBORItem Peek;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002095 size_t uPeek = UsefulInputBuf_Tell(&(pMe->InBuf));
2096 QCBORError uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &Peek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002097 if(uReturn != QCBOR_SUCCESS) {
2098 return uReturn;
2099 }
2100 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002101 /* It is not a break, rewind so it can be processed normally. */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002102 UsefulInputBuf_Seek(&(pMe->InBuf), uPeek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002103 } else {
2104 *pbNextIsBreak = true;
2105 }
2106 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002107
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002108 return QCBOR_SUCCESS;
2109}
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002110#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002111
2112
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002113/**
2114 * @brief Ascend up nesting levels if all items in them have been consumed.
2115 *
2116 * @param[in] pMe The decode context.
2117 * @param[in] bMarkEnd If true mark end of maps/arrays with count of zero.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002118 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002119 *
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002120 * An item was just consumed, now figure out if it was the
2121 * end of an array/map map that can be closed out. That
2122 * may in turn close out the above array/map...
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002123 *
2124 * When ascending indefinite-length arrays and maps, this will correctly
2125 * consume the break for the level above. This is a problem for the
2126 * implementation of QCBORDecode_GetArray() that must not return
2127 * that break. @c pbBreak is set to true to indicate that one
2128 * byte should be removed.
2129 *
2130 * Improvement: this could reduced further if indef is disabled
2131 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002132static QCBORError
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002133QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd, bool *pbBreak)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002134{
2135 QCBORError uReturn;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002136
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002137 /* Loop ascending nesting levels as long as there is ascending to do */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002138 while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002139 if(pbBreak) {
2140 *pbBreak = false;
2141 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002142
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002143 if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) {
2144 /* Nesting level is bstr-wrapped CBOR */
2145
2146 /* Ascent for bstr-wrapped CBOR is always by explicit call
2147 * so no further ascending can happen.
2148 */
2149 break;
2150
2151 } else if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
2152 /* Level is a definite-length array/map */
2153
2154 /* Decrement the item count the definite-length array/map */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002155 DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(&(pMe->nesting));
2156 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002157 /* Didn't close out array/map, so all work here is done */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002158 break;
2159 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002160 /* All items in a definite-length array were consumed so it
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002161 * is time to ascend one level. This happens below.
2162 */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002163
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002164#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002165 } else {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002166 /* Level is an indefinite-length array/map. */
2167
2168 /* Check for a break which is what ends indefinite-length arrays/maps */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002169 bool bIsBreak = false;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002170 uReturn = QCBOR_Private_NextIsBreak(pMe, &bIsBreak);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002171 if(uReturn != QCBOR_SUCCESS) {
2172 goto Done;
2173 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002174
2175 if(!bIsBreak) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002176 /* Not a break so array/map does not close out. All work is done */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002177 break;
2178 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002179
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002180 /* It was a break in an indefinitelength map / array so
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002181 * it is time to ascend one level.
2182 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002183 if(pbBreak) {
2184 *pbBreak = true;
2185 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002186
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002187#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002188 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002189
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002190
2191 /* All items in the array/map have been consumed. */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002192
Laurence Lundblade93d89472020-10-03 22:30:50 -07002193 /* But ascent in bounded mode is only by explicit call to
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002194 * QCBORDecode_ExitBoundedMode().
2195 */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07002196 if(DecodeNesting_IsCurrentBounded(&(pMe->nesting))) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002197 /* Set the count to zero for definite-length arrays to indicate
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002198 * cursor is at end of bounded array/map */
Laurence Lundbladed0304932020-06-27 10:59:38 -07002199 if(bMarkEnd) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002200 /* Used for definite and indefinite to signal end */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07002201 DecodeNesting_ZeroMapOrArrayCount(&(pMe->nesting));
Laurence Lundbladed0304932020-06-27 10:59:38 -07002202
Laurence Lundblade2c1faf92020-06-26 22:43:56 -07002203 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002204 break;
2205 }
2206
2207 /* Finally, actually ascend one level. */
2208 DecodeNesting_Ascend(&(pMe->nesting));
2209 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002210
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002211 uReturn = QCBOR_SUCCESS;
2212
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002213#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002214Done:
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002215#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
2216
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002217 return uReturn;
2218}
2219
2220
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002221/**
2222 * @brief Ascending & Descending out of nesting levels (decode layer 2).
2223 *
2224 * @param[in] pMe Decoder context
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002225 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002226 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002227
2228 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
2229 * features
2230 * @retval QCBOR_ERR_HIT_END Unexpected end of input
2231 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
2232 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
2233 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
2234 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
2235 * of half-precision disabled
2236 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
2237 * float decode is disabled.
2238 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
2239 * simple type in input.
2240 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
2241 * in input, but indefinite
2242 * lengths disabled.
2243 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
2244 * but no string allocator.
2245 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
2246 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
2247 * input, but indefinite-length
2248 * strings are disabled.
2249 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
2250 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
2251 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
2252 * @retval QCBOR_ERR_NO_MORE_ITEMS Need more items for map or array.
2253 * @retval QCBOR_ERR_BAD_BREAK Indefinite-length break in wrong
2254 * place.
2255 * @retval QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP Nesting deeper than QCBOR
2256 * can handle.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002257 *
2258 * This handles the traversal descending into and asecnding out of
2259 * maps, arrays and bstr-wrapped CBOR. It figures out the ends of
2260 * definite- and indefinte-length maps and arrays by looking at the
2261 * item count or finding CBOR breaks. It detects the ends of the
2262 * top-level sequence and of bstr-wrapped CBOR by byte count.
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002263 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002264static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002265QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002266 bool *pbBreak,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002267 QCBORItem *pDecodedItem,
2268 uint32_t *puLabelEndOffset)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002269{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002270 QCBORError uReturn;
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002271 /* ==== First: figure out if at the end of a traversal ==== */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002272
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002273 /* If out of bytes to consume, it is either the end of the
2274 * top-level sequence of some bstr-wrapped CBOR that was entered.
2275 *
2276 * In the case of bstr-wrapped CBOR, the length of the
2277 * UsefulInputBuf was set to that of the bstr-wrapped CBOR. When
2278 * the bstr-wrapped CBOR is exited, the length is set back to the
2279 * top-level's length or to the next highest bstr-wrapped CBOR.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002280 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002281 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) == 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002282 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002283 goto Done;
2284 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07002285
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002286 /* Check to see if at the end of a bounded definite-length map or
2287 * array. The check for a break ending indefinite-length array is
2288 * later in QCBORDecode_NestLevelAscender().
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002289 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002290 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002291 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002292 goto Done;
2293 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002294
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002295 /* ==== Next: not at the end, so get another item ==== */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002296 uReturn = QCBORDecode_Private_GetNextMapEntry(pMe, pDecodedItem, puLabelEndOffset);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002297 if(QCBORDecode_IsUnrecoverableError(uReturn)) {
2298 /* Error is so bad that traversal is not possible. */
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002299 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002300 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05302301
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002302 /* Record the nesting level for this data item before processing
2303 * any of decrementing and descending.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002304 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002305 pDecodedItem->uNestingLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002306
Laurence Lundblade642282a2020-06-23 12:00:33 -07002307
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002308 /* ==== Next: Process the item for descent, ascent, decrement... ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002309 if(QCBORItem_IsMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002310 /* If the new item is a map or array, descend.
2311 *
2312 * Empty indefinite-length maps and arrays are descended into,
2313 * but then ascended out of in the next chunk of code.
2314 *
2315 * Maps and arrays do count as items in the map/array that
2316 * encloses them so a decrement needs to be done for them too,
2317 * but that is done only when all the items in them have been
2318 * processed, not when they are opened with the exception of an
2319 * empty map or array.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002320 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002321 QCBORError uDescendErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002322 uDescendErr = DecodeNesting_DescendMapOrArray(&(pMe->nesting),
Laurence Lundbladeb95afec2024-08-26 10:51:28 -07002323 pDecodedItem->uDataType,
2324 pDecodedItem->val.uCount);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002325 if(uDescendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002326 /* This error is probably a traversal error and it overrides
2327 * the non-traversal error.
2328 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002329 uReturn = uDescendErr;
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002330 goto Done;
2331 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002332 }
2333
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002334 if(!QCBORItem_IsMapOrArray(*pDecodedItem) ||
2335 QCBORItem_IsEmptyDefiniteLengthMapOrArray(*pDecodedItem) ||
2336 QCBORItem_IsIndefiniteLengthMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002337 /* The following cases are handled here:
2338 * - A non-aggregate item like an integer or string
2339 * - An empty definite-length map or array
2340 * - An indefinite-length map or array that might be empty or might not.
2341 *
2342 * QCBORDecode_NestLevelAscender() does the work of decrementing the count
2343 * for an definite-length map/array and break detection for an
2344 * indefinite-0length map/array. If the end of the map/array was
2345 * reached, then it ascends nesting levels, possibly all the way
2346 * to the top level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002347 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002348 QCBORError uAscendErr;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002349 uAscendErr = QCBORDecode_Private_NestLevelAscender(pMe, true, pbBreak);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002350 if(uAscendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002351 /* This error is probably a traversal error and it overrides
2352 * the non-traversal error.
2353 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002354 uReturn = uAscendErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002355 goto Done;
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002356 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05302357 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002358
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002359 /* ==== Last: tell the caller the nest level of the next item ==== */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002360 /* Tell the caller what level is next. This tells them what
2361 * maps/arrays were closed out and makes it possible for them to
2362 * reconstruct the tree with just the information returned in a
2363 * QCBORItem.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002364 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002365 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07002366 /* At end of a bounded map/array; uNextNestLevel 0 to indicate this */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002367 pDecodedItem->uNextNestLevel = 0;
2368 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002369 pDecodedItem->uNextNestLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002370 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002371
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002372Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002373 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002374}
2375
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002376
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002377/**
2378 * @brief Decode tag content for select tags (decoding layer 1).
2379 *
2380 * @param[in] pMe The decode context.
2381 * @param[out] pDecodedItem The decoded item.
2382 *
2383 * @return Decoding error code.
2384 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002385 * CBOR tag numbers for the item were decoded in GetNext_TaggedItem(),
2386 * but the whole tag was not decoded. Here, the whole tags (tag number
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002387 * and tag content) are decoded. This is a
Laurence Lundblade99615302020-11-29 11:19:47 -08002388 * quick pass through for items that are not tags.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002389 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002390static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002391QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2392 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002393{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002394 QCBORError uErr;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002395
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002396 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pDecodedItem, NULL);
2397
2398#ifndef QCBOR_DISABLE_TAGS
2399 uint64_t uTagNumber;
2400 int nTagIndex;
2401 const struct QCBORTagDecoderEntry *pTagDecoder;
2402
2403 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002404 goto Done;
2405 }
2406
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002407 /* Loop over tag numbers in reverse, those closest to content first */
2408 for(nTagIndex = QCBOR_MAX_TAGS_PER_ITEM-1; nTagIndex >= 0; nTagIndex--) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002409
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002410 if(pDecodedItem->auTagNumbers[nTagIndex] == CBOR_TAG_INVALID16) {
2411 continue; /* Empty slot, skip to next */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002412 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002413
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002414 /* See if there's a content decoder for it */
2415 uTagNumber = QCBORDecode_Private_UnMapTagNumber(pMe, pDecodedItem->auTagNumbers[nTagIndex]);
2416 pTagDecoder = QCBORDecode_Private_LookUpTagDecoder(pMe->pTagDecoderTable, uTagNumber);
2417 if(pTagDecoder == NULL) {
2418 break; /* Successful exist -- a tag that we can't decode */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002419 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002420
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002421 /* Call the content decoder */
2422 uErr = pTagDecoder->pfContentDecoder(pMe, pMe->pTagDecodersContext, pTagDecoder->uTagNumber, pDecodedItem);
2423 if(uErr != QCBOR_SUCCESS) {
2424 break; /* Error exit from the loop */
2425 }
2426
2427 /* Remove tag number from list since its content was decoded */
2428 pDecodedItem->auTagNumbers[nTagIndex] = CBOR_TAG_INVALID16;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002429 }
2430
2431Done:
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002432#endif /* ! QCBOR_DISABLE_TAGS */
2433
2434 return uErr;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002435}
2436
2437
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002438/**
2439 * @brief Consume an entire map or array including its contents.
2440 *
2441 * @param[in] pMe The decoder context.
2442 * @param[in] pItemToConsume The array/map whose contents are to be
2443 * consumed.
2444 * @param[out] puNextNestLevel The next nesting level after the item was
2445 * fully consumed.
2446 *
2447 * This may be called when @c pItemToConsume is not an array or
2448 * map. In that case, this is just a pass through for @c puNextNestLevel
2449 * since there is nothing to do.
2450 */
2451static QCBORError
2452QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
2453 const QCBORItem *pItemToConsume,
2454 bool *pbBreak,
2455 uint8_t *puNextNestLevel)
2456{
2457 QCBORError uReturn;
2458 QCBORItem Item;
2459
2460 /* If it is a map or array, this will tell if it is empty. */
2461 const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel);
2462
2463 if(QCBORItem_IsMapOrArray(*pItemToConsume) && !bIsEmpty) {
2464 /* There is only real work to do for non-empty maps and arrays */
2465
2466 /* This works for definite- and indefinite-length maps and
2467 * arrays by using the nesting level
2468 */
2469 do {
2470 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pbBreak, &Item, NULL);
2471 if(QCBORDecode_IsUnrecoverableError(uReturn) ||
2472 uReturn == QCBOR_ERR_NO_MORE_ITEMS) {
2473 goto Done;
2474 }
2475 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
2476
2477 *puNextNestLevel = Item.uNextNestLevel;
2478
2479 uReturn = QCBOR_SUCCESS;
2480
2481 } else {
2482 /* pItemToConsume is not a map or array. Just pass the nesting
2483 * level through. */
2484 *puNextNestLevel = pItemToConsume->uNextNestLevel;
2485
2486 uReturn = QCBOR_SUCCESS;
2487 }
2488
2489Done:
2490 return uReturn;
2491}
2492
2493
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002494#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002495/*
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002496 * This consumes the next item. It returns the starting position of
2497 * the label and the length of the label. It also returns the nest
2498 * level of the item consumed.
2499 */
2500static QCBORError
2501QCBORDecode_Private_GetLabelAndConsume(QCBORDecodeContext *pMe,
2502 uint8_t *puNestLevel,
2503 size_t *puLabelStart,
2504 size_t *puLabelLen)
2505{
2506 QCBORError uErr;
2507 QCBORItem Item;
2508 uint8_t uLevel;
2509 uint32_t uLabelOffset;
2510
2511 /* Get the label and consume it should it be complex */
2512 *puLabelStart = UsefulInputBuf_Tell(&(pMe->InBuf));
2513
2514 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, &Item, &uLabelOffset);
2515 if(uErr != QCBOR_SUCCESS) {
2516 goto Done;
2517 }
2518 *puLabelLen = uLabelOffset - *puLabelStart;
2519 *puNestLevel = Item.uNestingLevel;
2520 uErr = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uLevel);
2521
2522Done:
2523 return uErr;
2524}
2525
2526
2527/* Loop over items in a map until the end of the map looking for
2528 * duplicates. This starts at the current position in the map, not at
2529 * the beginning of the map.
2530 *
2531 * This saves and restores the traversal cursor and nest tracking so
2532 * they are the same on exit as they were on entry.
2533 */
2534static QCBORError
2535QCBORDecode_Private_CheckDups(QCBORDecodeContext *pMe,
2536 const uint8_t uNestLevel,
2537 const size_t uCompareLabelStart,
2538 const size_t uCompareLabelLen)
2539{
2540 QCBORError uErr;
2541 size_t uLabelStart;
2542 size_t uLabelLen;
2543 uint8_t uLevel;
2544 int nCompare;
2545
2546 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2547 const UsefulInputBuf Save = pMe->InBuf;
2548
2549 do {
2550 uErr = QCBORDecode_Private_GetLabelAndConsume(pMe, &uLevel, &uLabelStart, &uLabelLen);
2551 if(uErr != QCBOR_SUCCESS) {
2552 if(uErr == QCBOR_ERR_NO_MORE_ITEMS) {
2553 uErr = QCBOR_SUCCESS; /* Successful end */
2554 }
2555 break;
2556 }
2557
2558 if(uLevel != uNestLevel) {
2559 break; /* Successful end of loop */
2560 }
2561
2562 /* This check for dups works for labels that are preferred
2563 * serialization and are not maps. If the labels are not in
2564 * preferred serialization, then the check has to be more
2565 * complicated and is type-specific because it uses the decoded
2566 * value, not the encoded CBOR. It is further complicated for
2567 * maps because the order of items in a map that is a label
2568 * doesn't matter when checking that is is the duplicate of
2569 * another map that is a label. QCBOR so far only turns on this
2570 * dup checking as part of CDE checking which requires preferred
2571 * serialization. See 5.6 in RFC 8949.
2572 */
2573 nCompare = UsefulInputBuf_Compare(&(pMe->InBuf),
2574 uCompareLabelStart, uCompareLabelLen,
2575 uLabelStart, uLabelLen);
2576 if(nCompare == 0) {
2577 uErr = QCBOR_ERR_DUPLICATE_LABEL;
2578 break;
2579 }
2580 } while (1);
2581
2582 pMe->nesting = SaveNesting;
2583 pMe->InBuf = Save;
2584
2585 return uErr;
2586}
2587
2588
2589/* This does sort order and duplicate detection on a map. The and all
2590 * it's members must be in preferred serialization so the comparisons
2591 * work correctly.
2592 */
2593static QCBORError
2594QCBORDecode_Private_CheckMap(QCBORDecodeContext *pMe, const QCBORItem *pMapToCheck)
2595{
2596 QCBORError uErr;
2597 uint8_t uNestLevel;
2598 size_t offset2, offset1, length2, length1;
2599
2600 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2601 const UsefulInputBuf Save = pMe->InBuf;
2602 pMe->bAllowAllLabels = 1;
2603
2604 /* This loop runs over all the items in the map once, comparing
2605 * each adjacent pair for correct ordering. It also calls CheckDup
2606 * on each one which also runs over the remaining items in the map
2607 * checking for duplicates. So duplicate checking runs in n^2.
2608 */
2609
2610 offset2 = SIZE_MAX;
2611 length2 = SIZE_MAX; // To avoid uninitialized warning
2612 while(1) {
2613 uErr = QCBORDecode_Private_GetLabelAndConsume(pMe, &uNestLevel, &offset1, &length1);
2614 if(uErr != QCBOR_SUCCESS) {
2615 if(uErr == QCBOR_ERR_NO_MORE_ITEMS) {
2616 uErr = QCBOR_SUCCESS; /* Successful exit from loop */
2617 }
2618 break;
2619 }
2620
2621 if(uNestLevel < pMapToCheck->uNextNestLevel) {
2622 break; /* Successful exit from loop */
2623 }
2624
2625 if(offset2 != SIZE_MAX) {
2626 /* Check that the labels are ordered. Check is not done the
2627 * first time through the loop when offset2 is unset. Since
2628 * this does comparison of the items in encoded form they
2629 * must be preferred serialization encoded. See RFC 8949
2630 * 4.2.1.
2631 */
2632 if(UsefulInputBuf_Compare(&(pMe->InBuf), offset2, length2, offset1, length1) > 0) {
2633 uErr = QCBOR_ERR_UNSORTED;
2634 break;
2635 }
2636 }
2637
2638 uErr = QCBORDecode_Private_CheckDups(pMe, pMapToCheck->uNextNestLevel, offset1, length1);
2639 if(uErr != QCBOR_SUCCESS) {
2640 break;
2641 }
2642
2643 offset2 = offset1;
2644 length2 = length1;
2645 }
2646
2647 pMe->bAllowAllLabels = 0;
2648 pMe->nesting = SaveNesting;
2649 pMe->InBuf = Save;
2650
2651 return uErr;
2652}
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002653#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
2654
2655static QCBORError
2656QCBORDecode_Private_GetItemChecks(QCBORDecodeContext *pMe,
2657 QCBORError uErr,
2658 const size_t uOffset,
2659 QCBORItem *pDecodedItem)
2660{
2661 (void)pMe; /* Avoid warning for next two ifdefs */
2662 (void)uOffset;
2663
2664#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
2665 if(uErr == QCBOR_SUCCESS &&
Laurence Lundblade82634b62024-11-20 22:37:45 -08002666 (pMe->uDecodeMode & QCBOR_DECODE_MODE_MASK) >= QCBOR_DECODE_MODE_CDE &&
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002667 pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
2668 /* Traverse map checking sort order and for duplicates */
2669 uErr = QCBORDecode_Private_CheckMap(pMe, pDecodedItem);
2670 }
2671#endif /* ! QCBOR_DISABLE_CONFORMANCE */
2672
2673#ifndef QCBOR_DISABLE_TAGS
2674 if(uErr == QCBOR_SUCCESS &&
2675 !(pMe->uDecodeMode & QCBOR_DECODE_UNPROCESSED_TAG_NUMBERS) &&
2676 pDecodedItem->auTagNumbers[0] != CBOR_TAG_INVALID16) {
2677 /* Not QCBOR v1; there are tag numbers -- check they were consumed */
2678 if(uOffset != pMe->uTagNumberCheckOffset || pMe->uTagNumberIndex != 255) {
2679 uErr = QCBOR_ERR_UNPROCESSED_TAG_NUMBER;
2680 }
2681 }
2682#endif /* ! QCBOR_DISABLE_TAGS */
2683
2684 if(uErr != QCBOR_SUCCESS) {
2685 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2686 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
2687 }
2688
2689 return uErr;
2690}
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002691
2692
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002693/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002694 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002695 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002696QCBORError
2697QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2698{
2699 QCBORError uErr;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002700 size_t uOffset;
2701
2702 uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002703 uErr = QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem);
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002704 uErr = QCBORDecode_Private_GetItemChecks(pMe, uErr, uOffset, pDecodedItem);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002705 return uErr;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002706}
2707
2708
2709/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002710 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08002711 */
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002712QCBORError
2713QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2714{
2715 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2716 const UsefulInputBuf Save = pMe->InBuf;
2717
2718 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
2719
2720 pMe->nesting = SaveNesting;
2721 pMe->InBuf = Save;
2722
2723 return uErr;
2724}
2725
2726
2727/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002728 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002729 */
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002730void
2731QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2732{
2733 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002734 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2735 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002736 return;
2737 }
2738
2739 pMe->uLastError = (uint8_t)QCBORDecode_PeekNext(pMe, pDecodedItem);
2740}
2741
2742
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002743static void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002744QCBORDecode_Private_SaveTagNumbers(QCBORDecodeContext *pMe, const QCBORItem *pItem)
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002745{
2746#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002747 memcpy(pMe->auLastTags, pItem->auTagNumbers, sizeof(pItem->auTagNumbers));
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002748#else
2749 (void)pMe;
2750 (void)pItem;
2751#endif
2752}
2753
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002754/*
2755 * Public function, see header qcbor/qcbor_decode.h file
2756 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002757void
2758QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002759{
2760 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002761 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2762 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002763 return;
2764 }
2765
2766 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem);
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002767 QCBORDecode_Private_SaveTagNumbers(pMe, pDecodedItem);
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002768}
2769
2770
2771/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002772 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002773 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002774QCBORError
2775QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002776{
Laurence Lundblade87495732021-02-26 10:05:55 -07002777 if(puConsumed != NULL) {
2778 *puConsumed = pMe->InBuf.cursor;
2779 }
2780
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002781 QCBORError uReturn = pMe->uLastError;
Laurence Lundblade085d7952020-07-24 10:26:30 -07002782
2783 if(uReturn != QCBOR_SUCCESS) {
2784 goto Done;
2785 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002786
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002787 /* Error out if all the maps/arrays are not closed out */
2788 if(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002789 uReturn = QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002790 goto Done;
2791 }
2792
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002793 /* Error out if not all the bytes are consumed */
2794 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf))) {
Laurence Lundblade085d7952020-07-24 10:26:30 -07002795 uReturn = QCBOR_ERR_EXTRA_BYTES;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002796 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002797
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002798Done:
Laurence Lundblade87495732021-02-26 10:05:55 -07002799 return uReturn;
2800}
2801
2802
2803/*
2804 * Public function, see header qcbor/qcbor_decode.h file
2805 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002806QCBORError
2807QCBORDecode_Finish(QCBORDecodeContext *pMe)
Laurence Lundblade87495732021-02-26 10:05:55 -07002808{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002809#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002810 /* Call the destructor for the string allocator if there is one.
2811 * Always called, even if there are errors; always have to clean up.
2812 */
2813 StringAllocator_Destruct(&(pMe->StringAllocator));
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002814#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002815
Laurence Lundblade87495732021-02-26 10:05:55 -07002816 return QCBORDecode_PartialFinish(pMe, NULL);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002817}
2818
2819
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002820#ifndef QCBOR_DISABLE_TAGS
2821/*
2822 * Public function, see header qcbor/qcbor_decode.h file
2823 */
2824uint64_t
2825QCBORDecode_GetNthTagNumber(const QCBORDecodeContext *pMe,
2826 const QCBORItem *pItem,
2827 uint8_t uIndex)
2828{
2829 if(pItem->uDataType == QCBOR_TYPE_NONE) {
2830 return CBOR_TAG_INVALID64;
2831 }
2832 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2833 return CBOR_TAG_INVALID64;
2834 }
2835
2836 return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->auTagNumbers[uIndex]);
2837}
2838
2839
2840/*
2841 * Public function, see header qcbor/qcbor_decode.h file
2842 */
2843uint64_t
2844QCBORDecode_GetNthTagNumberOfLast(QCBORDecodeContext *pMe,
2845 uint8_t uIndex)
2846{
2847 if(pMe->uLastError != QCBOR_SUCCESS) {
2848 return CBOR_TAG_INVALID64;
2849 }
2850 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2851 return CBOR_TAG_INVALID64;
2852 }
2853
2854 return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->auLastTags[uIndex]);
2855}
2856
2857
2858/*
2859 * Public function, see header qcbor/qcbor_decode.h file
2860 */
2861static uint64_t
2862QCBORDecode_Private_GetNthTagNumberReverse(const QCBORDecodeContext *pMe,
2863 const uint16_t puTagNumbers[],
2864 const uint32_t uIndex)
2865{
2866 uint32_t uArrayIndex;
2867
2868 /* Find number of tag numbers */
2869 for(uArrayIndex = QCBOR_MAX_TAGS_PER_ITEM-1; uArrayIndex > 0; uArrayIndex--) {
2870 if(puTagNumbers[uArrayIndex] != CBOR_TAG_INVALID16) {
2871 break;
2872 }
2873 }
2874 if(uIndex > uArrayIndex) {
2875 return CBOR_TAG_INVALID64;
2876 }
2877
2878 return QCBORDecode_Private_UnMapTagNumber(pMe, puTagNumbers[uArrayIndex - uIndex]);
2879}
2880
2881
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002882/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002883 * Public function, see header qcbor/qcbor_decode.h file
2884 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002885uint64_t
2886QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
2887 const QCBORItem *pItem,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002888 const uint32_t uIndex)
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002889{
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002890 if(pItem->uDataType == QCBOR_TYPE_NONE) {
2891 return CBOR_TAG_INVALID64;
2892 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002893
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002894 return QCBORDecode_Private_GetNthTagNumberReverse(pMe, pItem->auTagNumbers, uIndex);
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002895}
2896
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002897
Laurence Lundblade9b334962020-08-27 10:55:53 -07002898/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002899 * Public function, see header qcbor/qcbor_decode.h file
2900 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002901uint64_t
2902QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe,
2903 uint32_t uIndex)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002904{
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002905 if(pMe->uLastError != QCBOR_SUCCESS) {
2906 return CBOR_TAG_INVALID64;
2907 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002908 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2909 return CBOR_TAG_INVALID64;
Laurence Lundblade9b334962020-08-27 10:55:53 -07002910 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002911
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002912 return QCBORDecode_Private_GetNthTagNumberReverse(pMe, pMe->auLastTags, uIndex);
Laurence Lundblade9b334962020-08-27 10:55:53 -07002913}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002914
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002915
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002916/*
2917 * Public function, see header qcbor/qcbor_decode.h file
2918 */
2919QCBORError
2920QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pMe, uint64_t *puTagNumber)
2921{
2922 QCBORItem Item;
2923 size_t uOffset;
2924 QCBORError uErr;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002925
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002926 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2927 const UsefulInputBuf Save = pMe->InBuf;
2928
2929 uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
2930 if(uOffset == pMe->uTagNumberCheckOffset) {
2931 pMe->uTagNumberIndex++;
2932 } else {
2933 pMe->uTagNumberIndex = 0;
2934 }
2935
2936 *puTagNumber = CBOR_TAG_INVALID64;
2937 uErr = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
2938 if(uErr) {
2939 return uErr;
2940 }
2941
2942 *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &Item, pMe->uTagNumberIndex);
2943 if(*puTagNumber == CBOR_TAG_INVALID64 ||
2944 QCBORDecode_GetNthTagNumber(pMe, &Item, pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
2945 pMe->uTagNumberIndex = QCBOR_ALL_TAGS_PROCESSED;
2946 }
2947 pMe->uTagNumberCheckOffset = uOffset;
2948
2949 pMe->nesting = SaveNesting;
2950 pMe->InBuf = Save;
2951
2952 return QCBOR_SUCCESS;
2953}
2954
2955
2956/*
2957 * Public function, see header qcbor/qcbor_decode.h file
2958 */
2959void
2960QCBORDecode_VGetNextTagNumber(QCBORDecodeContext *pMe, uint64_t *puTagNumber)
2961{
2962 pMe->uLastError = (uint8_t)QCBORDecode_GetNextTagNumber(pMe, puTagNumber);
2963}
2964
2965#endif /* ! QCBOR_DISABLE_TAGS */
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002966
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002967#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladef6531662018-12-04 10:42:22 +09002968
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002969/* ===========================================================================
2970 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002971
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002972 This implements a simple sting allocator for indefinite-length
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002973 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
2974 implements the function type QCBORStringAllocate and allows easy
2975 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09002976
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002977 This particular allocator is built-in for convenience. The caller
2978 can implement their own. All of this following code will get
2979 dead-stripped if QCBORDecode_SetMemPool() is not called.
2980
2981 This is a very primitive memory allocator. It does not track
2982 individual allocations, only a high-water mark. A free or
2983 reallocation must be of the last chunk allocated.
2984
2985 The size of the pool and offset to free memory are packed into the
2986 first 8 bytes of the memory pool so we don't have to keep them in
2987 the decode context. Since the address of the pool may not be
2988 aligned, they have to be packed and unpacked as if they were
2989 serialized data of the wire or such.
2990
2991 The sizes packed in are uint32_t to be the same on all CPU types
2992 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08002993 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002994
2995
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002996static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08002997MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002998{
2999 // Use of UsefulInputBuf is overkill, but it is convenient.
3000 UsefulInputBuf UIB;
3001
Laurence Lundbladeee851742020-01-08 08:37:05 -08003002 // Just assume the size here. It was checked during SetUp so
3003 // the assumption is safe.
Laurence Lundblade93d89472020-10-03 22:30:50 -07003004 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem,QCBOR_DECODE_MIN_MEM_POOL_SIZE});
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003005 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
3006 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
3007 return UsefulInputBuf_GetError(&UIB);
3008}
3009
3010
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003011static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08003012MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003013{
3014 // Use of UsefulOutBuf is overkill, but convenient. The
3015 // length check performed here is useful.
3016 UsefulOutBuf UOB;
3017
3018 UsefulOutBuf_Init(&UOB, Pool);
3019 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
3020 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
3021 return UsefulOutBuf_GetError(&UOB);
3022}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003023
3024
3025/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003026 Internal function for an allocation, reallocation free and destuct.
3027
3028 Having only one function rather than one each per mode saves space in
3029 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003030
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003031 Code Reviewers: THIS FUNCTION DOES POINTER MATH
3032 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08003033static UsefulBuf
3034MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003035{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003036 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003037
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003038 uint32_t uPoolSize;
3039 uint32_t uFreeOffset;
3040
3041 if(uNewSize > UINT32_MAX) {
3042 // This allocator is only good up to 4GB. This check should
3043 // optimize out if sizeof(size_t) == sizeof(uint32_t)
3044 goto Done;
3045 }
3046 const uint32_t uNewSize32 = (uint32_t)uNewSize;
3047
3048 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
3049 goto Done;
3050 }
3051
3052 if(uNewSize) {
3053 if(pMem) {
3054 // REALLOCATION MODE
3055 // Calculate pointer to the end of the memory pool. It is
3056 // assumed that pPool + uPoolSize won't wrap around by
3057 // assuming the caller won't pass a pool buffer in that is
3058 // not in legitimate memory space.
3059 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
3060
3061 // Check that the pointer for reallocation is in the range of the
3062 // pool. This also makes sure that pointer math further down
3063 // doesn't wrap under or over.
3064 if(pMem >= pPool && pMem < pPoolEnd) {
3065 // Offset to start of chunk for reallocation. This won't
3066 // wrap under because of check that pMem >= pPool. Cast
3067 // is safe because the pool is always less than UINT32_MAX
3068 // because of check in QCBORDecode_SetMemPool().
3069 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3070
3071 // Check to see if the allocation will fit. uPoolSize -
3072 // uMemOffset will not wrap under because of check that
3073 // pMem is in the range of the uPoolSize by check above.
3074 if(uNewSize <= uPoolSize - uMemOffset) {
3075 ReturnValue.ptr = pMem;
3076 ReturnValue.len = uNewSize;
3077
3078 // Addition won't wrap around over because uNewSize was
3079 // checked to be sure it is less than the pool size.
3080 uFreeOffset = uMemOffset + uNewSize32;
3081 }
3082 }
3083 } else {
3084 // ALLOCATION MODE
3085 // uPoolSize - uFreeOffset will not underflow because this
3086 // pool implementation makes sure uFreeOffset is always
3087 // smaller than uPoolSize through this check here and
3088 // reallocation case.
3089 if(uNewSize <= uPoolSize - uFreeOffset) {
3090 ReturnValue.len = uNewSize;
3091 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08003092 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003093 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003094 }
3095 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003096 if(pMem) {
3097 // FREE MODE
3098 // Cast is safe because of limit on pool size in
3099 // QCBORDecode_SetMemPool()
3100 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3101 } else {
3102 // DESTRUCT MODE
3103 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003104 }
3105 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003106
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003107 UsefulBuf Pool = {pPool, uPoolSize};
3108 MemPool_Pack(Pool, uFreeOffset);
3109
3110Done:
3111 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003112}
3113
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003114
Laurence Lundbladef6531662018-12-04 10:42:22 +09003115/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003116 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09003117 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003118QCBORError
3119QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
3120 UsefulBuf Pool,
3121 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003122{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003123 // The pool size and free mem offset are packed into the beginning
Dave Thaler93c01182022-08-06 15:08:35 -04003124 // of the pool memory. This compile time check makes sure the
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003125 // constant in the header is correct. This check should optimize
3126 // down to nothing.
Dave Thaler93c01182022-08-06 15:08:35 -04003127#ifdef _MSC_VER
3128#pragma warning(push)
3129#pragma warning(disable:4127) // conditional expression is constant
3130#endif
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003131 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003132 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003133 }
Dave Thaler93c01182022-08-06 15:08:35 -04003134#ifdef _MSC_VER
3135#pragma warning(pop)
3136#endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003137
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003138 // The pool size and free offset packed in to the beginning of pool
3139 // memory are only 32-bits. This check will optimize out on 32-bit
3140 // machines.
3141 if(Pool.len > UINT32_MAX) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003142 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003143 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003144
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003145 // This checks that the pool buffer given is big enough.
3146 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003147 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003148 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003149
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003150 QCBORDecode_SetUpAllocator(pMe, MemPool_Function, Pool.ptr, bAllStrings);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003151
Laurence Lundblade30816f22018-11-10 13:40:22 +07003152 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003153}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003154#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003155
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003156
3157
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003158/*
3159 * Public function, see header qcbor/qcbor_decode.h file
3160 */
3161void
3162QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003163{
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003164 QCBORDecode_VGetNext(pMe, pDecodedItem);
3165
3166 if(pMe->uLastError == QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003167 pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL,
Máté Tóth-Pálc6d59682021-05-26 18:55:30 +02003168 &pDecodedItem->uNextNestLevel);
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003169 }
3170}
3171
3172
Laurence Lundblade11654912024-05-09 11:49:24 -07003173/*
3174 * Public function, see header qcbor/qcbor_decode.h file
3175 */
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003176QCBORError
3177QCBORDecode_EndCheck(QCBORDecodeContext *pMe)
Laurence Lundblade11654912024-05-09 11:49:24 -07003178{
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003179 size_t uCursorOffset;
3180 QCBORError uErr;
Laurence Lundblade11654912024-05-09 11:49:24 -07003181
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003182 uErr = QCBORDecode_GetError(pMe);
3183 if(uErr != QCBOR_SUCCESS) {
3184 return uErr;
Laurence Lundblade11654912024-05-09 11:49:24 -07003185 }
3186
3187 uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
3188
3189 if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003190 return QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade11654912024-05-09 11:49:24 -07003191 }
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003192
3193 return QCBOR_SUCCESS;
Laurence Lundblade11654912024-05-09 11:49:24 -07003194}
3195
3196
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003197/**
3198 * @brief Rewind cursor to start as if map or array were just entered.
3199 *
3200 * @param[in] pMe The decoding context
3201 *
3202 * This affects the nesting tracking and the UsefulInputBuf.
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003203 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003204static void
3205QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003206{
3207 /* Reset nesting tracking to the deepest bounded level */
3208 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3209
3210 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3211
3212 /* Reposition traversal cursor to the start of the map/array */
3213 UsefulInputBuf_Seek(&(pMe->InBuf),
3214 DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
3215}
3216
3217
3218/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003219 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003220 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003221void
3222QCBORDecode_Rewind(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003223{
3224 if(pMe->nesting.pCurrentBounded != NULL) {
3225 /* In a bounded map, array or bstr-wrapped CBOR */
3226
3227 if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
3228 /* In bstr-wrapped CBOR. */
3229
3230 /* Reposition traversal cursor to start of wrapping byte string */
3231 UsefulInputBuf_Seek(&(pMe->InBuf),
3232 pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
3233 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3234
3235 } else {
3236 /* In a map or array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003237 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003238 }
3239
3240 } else {
3241 /* Not in anything bounded */
3242
3243 /* Reposition traversal cursor to the start of input CBOR */
3244 UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
3245
3246 /* Reset nesting tracking to beginning of input. */
3247 DecodeNesting_Init(&(pMe->nesting));
3248 }
3249
3250 pMe->uLastError = QCBOR_SUCCESS;
3251}
3252
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003253
Laurence Lundblade9b334962020-08-27 10:55:53 -07003254
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003255
3256
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003257typedef struct {
3258 void *pCBContext;
3259 QCBORItemCallback pfCallback;
3260} MapSearchCallBack;
3261
3262typedef struct {
3263 size_t uStartOffset;
3264 uint16_t uItemCount;
3265} MapSearchInfo;
3266
3267
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003268/**
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003269 * @brief Search a map for a set of items.
3270 *
3271 * @param[in] pMe The decode context to search.
3272 * @param[in,out] pItemArray The items to search for and the items found.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003273 * @param[out] pInfo Several bits of meta-info returned by search.
3274 * @param[in] pCallBack Callback object or @c NULL.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003275 *
3276 * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map.
3277 *
3278 * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label)
3279 * were found for one of the labels being
3280 * search for. This duplicate detection is
3281 * only performed for items in pItemArray,
3282 * not every item in the map.
3283 *
3284 * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was
3285 * wrong for the matchd label.
3286 *
3287 * @retval Also errors returned by QCBORDecode_GetNext().
3288 *
Laurence Lundblade88ba5662024-11-03 02:10:24 -08003289 * On input, @c pItemArray contains a list of labels and data types of
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003290 * items to be found.
3291 *
3292 * On output, the fully retrieved items are filled in with values and
3293 * such. The label was matched, so it never changes.
3294 *
3295 * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE.
3296 *
3297 * This also finds the ends of maps and arrays when they are exited.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003298 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003299static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003300QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
3301 QCBORItem *pItemArray,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003302 MapSearchInfo *pInfo,
3303 MapSearchCallBack *pCallBack)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003304{
Laurence Lundbladee6f15112020-07-23 18:44:16 -07003305 QCBORError uReturn;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003306 uint64_t uFoundItemBitMap = 0;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07003307
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003308 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003309 uReturn = pMe->uLastError;
3310 goto Done2;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003311 }
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003312
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003313 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) &&
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003314 pItemArray->uLabelType != QCBOR_TYPE_NONE) {
3315 /* QCBOR_TYPE_NONE as first item indicates just looking
3316 for the end of an array, so don't give error. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003317 uReturn = QCBOR_ERR_MAP_NOT_ENTERED;
3318 goto Done2;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003319 }
3320
Laurence Lundblade085d7952020-07-24 10:26:30 -07003321 if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) {
3322 // It is an empty bounded array or map
3323 if(pItemArray->uLabelType == QCBOR_TYPE_NONE) {
3324 // Just trying to find the end of the map or array
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003325 pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003326 uReturn = QCBOR_SUCCESS;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003327 } else {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003328 // Nothing is ever found in an empty array or map. All items
3329 // are marked as not found below.
Laurence Lundblade085d7952020-07-24 10:26:30 -07003330 uReturn = QCBOR_SUCCESS;
3331 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003332 goto Done2;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003333 }
3334
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003335 QCBORDecodeNesting SaveNesting;
Laurence Lundblade11654912024-05-09 11:49:24 -07003336 size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003337 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3338
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003339 /* Reposition to search from the start of the map / array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003340 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundblade1341c592020-04-11 14:19:05 -07003341
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003342 /*
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003343 Loop over all the items in the map or array. Each item
3344 could be a map or array, but label matching is only at
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003345 the main level. This handles definite- and indefinite-
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003346 length maps and arrays. The only reason this is ever
3347 called on arrays is to find their end position.
3348
3349 This will always run over all items in order to do
3350 duplicate detection.
3351
3352 This will exit with failure if it encounters an
3353 unrecoverable error, but continue on for recoverable
3354 errors.
3355
3356 If a recoverable error occurs on a matched item, then
3357 that error code is returned.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003358 */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07003359 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003360 if(pInfo) {
3361 pInfo->uItemCount = 0;
3362 }
Máté Tóth-Pál2f2aa5f2021-05-17 21:35:09 +02003363 uint8_t uNextNestLevel;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003364 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003365 /* Remember offset of the item because sometimes it has to be returned */
Laurence Lundblade1341c592020-04-11 14:19:05 -07003366 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003367
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003368 /* Get the item */
3369 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003370 /* QCBORDecode_Private_GetNextTagContent() rather than GetNext()
3371 * because a label match is performed on recoverable errors to
3372 * be able to return the the error code for the found item. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003373 QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003374 if(QCBORDecode_IsUnrecoverableError(uResult)) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003375 /* The map/array can't be decoded when unrecoverable errors occur */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003376 uReturn = uResult;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003377 goto Done;
3378 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003379 if(uResult == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003380 /* Unexpected end of map or array. */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003381 uReturn = uResult;
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003382 goto Done;
3383 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003384
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003385 /* See if item has one of the labels that are of interest */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003386 bool bMatched = false;
3387 for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003388 if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003389 /* A label match has been found */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003390 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
3391 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003392 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003393 }
Laurence Lundblade63926052021-03-29 16:05:51 -07003394 if(uResult != QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003395 /* The label matches, but the data item is in error.
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003396 * It is OK to have recoverable errors on items that
3397 * are not matched. */
Laurence Lundblade63926052021-03-29 16:05:51 -07003398 uReturn = uResult;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003399 goto Done;
3400 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003401 if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) {
Laurence Lundblade63926052021-03-29 16:05:51 -07003402 /* The data item is not of the type(s) requested */
3403 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003404 goto Done;
3405 }
3406
Laurence Lundblade1341c592020-04-11 14:19:05 -07003407 /* Successful match. Return the item. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003408 pItemArray[nIndex] = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003409 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003410 if(pInfo) {
3411 pInfo->uStartOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003412 }
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003413 bMatched = true;
3414 }
3415 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003416
3417
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003418 if(!bMatched && pCallBack != NULL) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003419 /*
3420 Call the callback on unmatched labels.
3421 (It is tempting to do duplicate detection here, but that would
3422 require dynamic memory allocation because the number of labels
3423 that might be encountered is unbounded.)
3424 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003425 uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item);
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003426 if(uReturn != QCBOR_SUCCESS) {
3427 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003428 }
3429 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003430
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003431 /*
3432 Consume the item whether matched or not. This
3433 does the work of traversing maps and array and
3434 everything in them. In this loop only the
3435 items at the current nesting level are examined
3436 to match the labels.
3437 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003438 uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel);
Laurence Lundbladec7114722020-08-13 05:11:40 -07003439 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003440 goto Done;
3441 }
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003442
3443 if(pInfo) {
3444 pInfo->uItemCount++;
3445 }
3446
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003447 } while (uNextNestLevel >= uMapNestLevel);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003448
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003449 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003450
3451 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003452
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003453 // Check here makes sure that this won't accidentally be
3454 // QCBOR_MAP_OFFSET_CACHE_INVALID which is larger than
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003455 // QCBOR_MAX_DECODE_INPUT_SIZE.
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -08003456 // Cast to uint32_t to possibly address cases where SIZE_MAX < UINT32_MAX
3457 if((uint32_t)uEndOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003458 uReturn = QCBOR_ERR_INPUT_TOO_LARGE;
3459 goto Done;
3460 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003461 /* Cast OK because encoded CBOR is limited to UINT32_MAX */
3462 pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003463
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003464 Done:
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003465 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade11654912024-05-09 11:49:24 -07003466 UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos);
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003467
3468 Done2:
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003469 /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */
Laurence Lundbladec7114722020-08-13 05:11:40 -07003470 for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003471 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003472 pItemArray[i].uDataType = QCBOR_TYPE_NONE;
3473 pItemArray[i].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003474 }
3475 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003476
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003477 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003478}
3479
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003480
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003481/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003482 * Public function, see header qcbor/qcbor_decode.h file
3483 */
3484void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003485QCBORDecode_SeekToLabelN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003486{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003487 MapSearchInfo Info;
3488 QCBORItem OneItemSeach[2];
3489
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003490 if(pMe->uLastError != QCBOR_SUCCESS) {
3491 return;
3492 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003493
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003494 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3495 OneItemSeach[0].label.int64 = nLabel;
3496 OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
3497 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
3498
3499 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
3500 if(pMe->uLastError == QCBOR_SUCCESS) {
3501 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
3502 }
3503}
3504
3505
3506void
3507QCBORDecode_SeekToLabelSZ(QCBORDecodeContext *pMe, const char *szLabel)
3508{
3509#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
3510 MapSearchInfo Info;
3511 QCBORItem OneItemSeach[2];
3512
3513 if(pMe->uLastError != QCBOR_SUCCESS) {
3514 return;
3515 }
3516
3517 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3518 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3519 OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
3520 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
3521
3522 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
3523 if(pMe->uLastError == QCBOR_SUCCESS) {
3524 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
3525 }
3526#else
3527 (void)pMe;
3528 (void)szLabel;
3529 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
3530#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
3531}
3532
3533
3534void
3535QCBORDecode_Private_GetItemInMapNoCheck(QCBORDecodeContext *pMe,
3536 QCBORItem *OneItemSeach,
3537 QCBORItem *pItem,
3538 size_t *puOffset)
3539{
3540 QCBORError uErr;
3541 MapSearchInfo SearchInfo;
3542
3543 if(pMe->uLastError != QCBOR_SUCCESS) {
3544 return;
3545 }
3546
3547 uErr = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &SearchInfo, NULL);
3548
3549 if(uErr == QCBOR_SUCCESS && OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
3550 uErr = QCBOR_ERR_LABEL_NOT_FOUND;
3551 }
3552 *pItem = OneItemSeach[0];
3553 *puOffset = SearchInfo.uStartOffset;
3554
3555 if(uErr == QCBOR_SUCCESS) {
3556 QCBORDecode_Private_SaveTagNumbers(pMe, pItem);
3557 }
3558
3559 pMe->uLastError = (uint8_t)uErr;
3560}
3561
3562
3563static void
3564QCBORDecode_Private_GetItemInMap(QCBORDecodeContext *pMe, QCBORItem *OneItemSeach, QCBORItem *pItem)
3565{
3566 QCBORError uErr;
3567 size_t uOffset;
3568
3569 QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, &uOffset);
3570
3571 uErr = QCBORDecode_Private_GetItemChecks(pMe, pMe->uLastError, uOffset, pItem);
3572 if(uErr != QCBOR_SUCCESS) {
3573 goto Done;
3574 }
3575
3576 QCBORDecode_Private_SaveTagNumbers(pMe, pItem);
3577
3578Done:
3579 pMe->uLastError = (uint8_t)uErr;
3580}
3581
3582
3583/*
3584 * Public function, see header qcbor/qcbor_decode.h file
3585 */
3586void
3587QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
3588 const int64_t nLabel,
3589 const uint8_t uQcborType,
3590 QCBORItem *pItem)
3591{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003592 QCBORItem OneItemSeach[2];
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003593
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003594 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3595 OneItemSeach[0].label.int64 = nLabel;
3596 OneItemSeach[0].uDataType = uQcborType;
3597 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003598
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003599 QCBORDecode_Private_GetItemInMap(pMe, OneItemSeach, pItem);
3600}
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003601
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003602
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003603/**
3604 * @brief Get an item by label by type.
3605 *
3606 * @param[in] pMe The decode context.
3607 * @param[in] nLabel The label to search map for.
3608 * @param[in] uQcborType The QCBOR type to look for.
3609 * @param[out] pItem The item found.
3610 * @param[out] puOffset The offset of item for tag consumption check.
3611 *
3612 * This finds the item with the given label in currently open
3613 * map. This does not call QCBORDecode_Private_GetItemChecks()
3614 * to check tag number consumption or decode conformance.
3615 */
3616static void
3617QCBORDecode_GetItemInMapNoCheckN(QCBORDecodeContext *pMe,
3618 const int64_t nLabel,
3619 const uint8_t uQcborType,
3620 QCBORItem *pItem,
3621 size_t *puOffset)
3622{
3623 QCBORItem OneItemSeach[2];
Laurence Lundblade1341c592020-04-11 14:19:05 -07003624
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003625 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3626 OneItemSeach[0].label.int64 = nLabel;
3627 OneItemSeach[0].uDataType = uQcborType;
3628 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003629
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003630 QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, puOffset);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003631}
3632
3633
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003634/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003635 * Public function, see header qcbor/qcbor_decode.h file
3636 */
3637void
3638QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
3639 const char *szLabel,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003640 const uint8_t uQcborType,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003641 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003642{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003643#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003644 QCBORItem OneItemSeach[2];
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003645
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003646 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3647 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3648 OneItemSeach[0].uDataType = uQcborType;
3649 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003650
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003651 QCBORDecode_Private_GetItemInMap(pMe, OneItemSeach, pItem);
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003652
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003653#else
3654 (void)pMe;
3655 (void)szLabel;
3656 (void)uQcborType;
3657 (void)pItem;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003658 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003659#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003660}
3661
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003662/**
3663 * @brief Get an item by string label of a particular type
3664 *
3665 * @param[in] pMe The decode context.
3666 * @param[in] szLabel The label to search map for.
3667 * @param[in] uQcborType The QCBOR type to look for.
3668 * @param[out] pItem The item found.
3669 * @param[out] puOffset The offset of item for tag consumption check.
3670 *
3671 * This finds the item with the given label in currently open
3672 * map. This does not call QCBORDecode_Private_GetItemChecks()
3673 * to check tag number consumption or decode conformance.
3674 */
3675static void
3676QCBORDecode_GetItemInMapNoCheckSZ(QCBORDecodeContext *pMe,
3677 const char *szLabel,
3678 const uint8_t uQcborType,
3679 QCBORItem *pItem,
3680 size_t *puOffset)
3681{
3682#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
3683 QCBORItem OneItemSeach[2];
3684
3685 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3686 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3687 OneItemSeach[0].uDataType = uQcborType;
3688 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
3689
3690 QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, puOffset);
3691
3692#else
3693 (void)pMe;
3694 (void)szLabel;
3695 (void)uQcborType;
3696 (void)pItem;
3697 (void)puOffset;
3698 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
3699#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
3700}
3701
3702
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003703
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003704
3705/**
3706 * @brief Semi-private. Get pointer, length and item for an array or map.
3707 *
3708 * @param[in] pMe The decode context.
3709 * @param[in] uType CBOR major type, either array/map.
3710 * @param[out] pItem The item for the array/map.
3711 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3712 *
Laurence Lundblade88ba5662024-11-03 02:10:24 -08003713 * The next item to be decoded must be a map or array as specified by @c uType.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003714 *
Laurence Lundblade88ba5662024-11-03 02:10:24 -08003715 * @c pItem will be filled in with the label and tags of the array or map
3716 * in addition to @c pEncodedCBOR giving the pointer and length of the
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003717 * encoded CBOR.
3718 *
3719 * When this is complete, the traversal cursor is at the end of the array or
3720 * map that was retrieved.
3721 */
3722void
3723QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe,
3724 const uint8_t uType,
3725 QCBORItem *pItem,
3726 UsefulBufC *pEncodedCBOR)
3727{
3728 QCBORError uErr;
3729 uint8_t uNestLevel;
3730 size_t uStartingCursor;
3731 size_t uStartOfReturned;
3732 size_t uEndOfReturned;
3733 size_t uTempSaveCursor;
3734 bool bInMap;
3735 QCBORItem LabelItem;
3736 bool EndedByBreak;
3737
3738 uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3739 bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting));
3740
3741 /* Could call GetNext here, but don't need to because this
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07003742 * is only interested in arrays and maps. TODO: switch to GetNext()? */
3743 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem, NULL);
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003744 if(uErr != QCBOR_SUCCESS) {
3745 pMe->uLastError = (uint8_t)uErr;
3746 return;
3747 }
3748
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003749 uint8_t uItemDataType = pItem->uDataType;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003750#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003751 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
3752 uItemDataType = QCBOR_TYPE_ARRAY;
3753 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003754#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003755
3756 if(uItemDataType != uType) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003757 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
3758 return;
3759 }
3760
3761 if(bInMap) {
3762 /* If the item is in a map, the start of the array/map
3763 * itself, not the label, must be found. Do this by
3764 * rewinding to the starting position and fetching
3765 * just the label data item. QCBORDecode_Private_GetNextTagNumber()
3766 * doesn't do any of the array/map item counting or nesting
3767 * level tracking. Used here it will just fetech the label
3768 * data item.
3769 *
3770 * Have to save the cursor and put it back to the position
3771 * after the full item once the label as been fetched by
3772 * itself.
3773 */
3774 uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3775 UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor);
3776
3777 /* Item has been fetched once so safe to ignore error */
3778 (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem);
3779
3780 uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3781 UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor);
3782 } else {
3783 uStartOfReturned = uStartingCursor;
3784 }
3785
3786 /* Consume the entire array/map to find the end */
3787 uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel);
3788 if(uErr != QCBOR_SUCCESS) {
3789 pMe->uLastError = (uint8_t)uErr;
3790 goto Done;
3791 }
3792
3793 /* Fill in returned values */
3794 uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3795 if(EndedByBreak) {
3796 /* When ascending nesting levels, a break for the level above
3797 * was consumed. That break is not a part of what is consumed here. */
3798 uEndOfReturned--;
3799 }
3800 pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned);
3801 pEncodedCBOR->len = uEndOfReturned - uStartOfReturned;
3802
3803Done:
3804 return;
3805}
3806
3807
3808/**
3809 * @brief Semi-private. Get pointer, length and item count of an array or map.
3810 *
3811 * @param[in] pMe The decode context.
3812 * @param[in] pTarget The label and type of the array or map to retrieve.
3813 * @param[out] pItem The item for the array/map.
3814 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3815 *
Laurence Lundblade88ba5662024-11-03 02:10:24 -08003816 * The next item to be decoded must be a map or array as specified by @c uType.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003817 *
3818 * When this is complete, the traversal cursor is unchanged.
3819 */void
3820QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe,
3821 QCBORItem *pTarget,
3822 QCBORItem *pItem,
3823 UsefulBufC *pEncodedCBOR)
3824{
3825 MapSearchInfo Info;
3826 QCBORDecodeNesting SaveNesting;
3827 size_t uSaveCursor;
3828
3829 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL);
3830 if(pMe->uLastError != QCBOR_SUCCESS) {
3831 return;
3832 }
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003833 pMe->uLastError = (uint8_t)QCBORDecode_Private_GetItemChecks(pMe, pMe->uLastError, Info.uStartOffset, pItem);
3834 if(pMe->uLastError != QCBOR_SUCCESS) {
3835 return;
3836 }
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003837
3838 /* Save the whole position of things so they can be restored.
3839 * so the cursor position is unchanged by this operation, like
3840 * all the other GetXxxxInMap() operations. */
3841 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3842 uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3843
3844 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3845 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
3846 QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR);
3847
3848 UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor);
3849 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
3850}
3851
3852
3853
3854
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003855static void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003856QCBORDecode_Private_ProcessTagOne(QCBORDecodeContext *pMe,
3857 QCBORItem *pItem,
3858 const uint8_t uTagRequirement,
3859 const uint8_t uQCBORType,
3860 const uint64_t uTagNumber,
3861 QCBORTagContentCallBack *pfCB,
3862 size_t uOffset);
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003863
3864/**
3865 * @brief Semi-private to get an string by label to match a tag specification.
3866 *
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003867 * @param[in] pMe The decode context.
3868 * @param[in] nLabel Label to search map for.
3869 * @param[in] uTagRequirement Whether or not tag number is required.
3870 * See @ref QCBOR_TAG_REQUIREMENT_TAG.
3871 * @param[in] uQCBOR_Type QCBOR type to search for.
3872 * @param[in] uTagNumber Tag number to match.
3873 * @param[out] pString The string found.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003874 *
3875 * This finds the string with the given label in currently open
3876 * map. Then checks that its tag number and types matches the tag
3877 * specification. If not, an error is set in the decode context.
3878 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003879void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003880QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
3881 const int64_t nLabel,
3882 const uint8_t uTagRequirement,
3883 const uint8_t uQCBOR_Type,
3884 const uint64_t uTagNumber,
3885 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003886{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003887 QCBORItem Item;
3888 size_t uOffset;
3889
3890 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
3891 QCBORDecode_Private_ProcessTagOne(pMe,
3892 &Item,
3893 uTagRequirement,
3894 uQCBOR_Type,
3895 uTagNumber,
3896 QCBORDecode_StringsTagCB,
3897 uOffset);
3898
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003899 if(pMe->uLastError == QCBOR_SUCCESS) {
3900 *pString = Item.val.string;
3901 }
3902}
3903
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003904
3905/**
3906 * @brief Semi-private to get an string by label to match a tag specification.
3907 *
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003908 * @param[in] pMe The decode context.
3909 * @param[in] szLabel Label to search map for.
3910 * @param[in] uTagRequirement Whether or not tag number is required.
3911 * See @ref QCBOR_TAG_REQUIREMENT_TAG.
3912 * @param[in] uQCBOR_Type QCBOR type to search for.
3913 * @param[in] uTagNumber Tag number to match.
3914 * @param[out] pString The string found.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003915 *
3916 * This finds the string with the given label in currently open
3917 * map. Then checks that its tag number and types matches the tag
3918 * specification. If not, an error is set in the decode context.
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003919 */
3920void
3921QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
3922 const char *szLabel,
3923 uint8_t uTagRequirement,
3924 uint8_t uQCBOR_Type,
3925 uint64_t uTagNumber,
3926 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003927{
3928 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003929 size_t uOffset;
3930
3931 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
3932 QCBORDecode_Private_ProcessTagOne(pMe,
3933 &Item,
3934 uTagRequirement,
3935 uQCBOR_Type,
3936 uTagNumber,
3937 QCBORDecode_StringsTagCB,
3938 uOffset);
3939
3940
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003941 if(pMe->uLastError == QCBOR_SUCCESS) {
3942 *pString = Item.val.string;
3943 }
3944}
Laurence Lundblade1341c592020-04-11 14:19:05 -07003945
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003946
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003947/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003948 * Public function, see header qcbor/qcbor_decode.h file
3949 */
3950void
3951QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003952{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003953 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003954}
3955
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003956/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003957 * Public function, see header qcbor/qcbor_decode.h file
3958 */
3959void
3960QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe,
3961 QCBORItem *pItemList,
3962 void *pCallbackCtx,
3963 QCBORItemCallback pfCB)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003964{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003965 MapSearchCallBack CallBack;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003966
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003967 CallBack.pCBContext = pCallbackCtx;
3968 CallBack.pfCallback = pfCB;
3969
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003970 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003971}
3972
3973
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003974#ifndef QCBOR_DISABLE_TAGS
3975/*
3976 * Public function, see header qcbor/qcbor_decode.h file
3977 */
3978QCBORError
3979QCBORDecode_GetNextTagNumberInMapN(QCBORDecodeContext *pMe, const int64_t nLabel, uint64_t *puTagNumber)
3980{
3981 size_t uOffset;
3982 MapSearchInfo Info;
3983 QCBORItem OneItemSeach[2];
3984
3985 if(pMe->uLastError != QCBOR_SUCCESS) {
3986 return pMe->uLastError;
3987 }
3988
3989 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3990 OneItemSeach[0].label.int64 = nLabel;
3991 OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
3992 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
3993
3994 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
3995
3996 uOffset = Info.uStartOffset;
3997 if(uOffset == pMe->uTagNumberCheckOffset) {
3998 pMe->uTagNumberIndex++;
3999 } else {
4000 pMe->uTagNumberIndex = 0;
4001 }
4002
4003 *puTagNumber = CBOR_TAG_INVALID64;
4004
4005 *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex);
4006 if(*puTagNumber == CBOR_TAG_INVALID64 ||
4007 QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
4008 pMe->uTagNumberIndex = QCBOR_ALL_TAGS_PROCESSED;
4009 }
4010 pMe->uTagNumberCheckOffset = uOffset;
4011
4012 return uReturn;
4013}
4014
4015
4016/*
4017 * Public function, see header qcbor/qcbor_decode.h file
4018 */
4019QCBORError
4020QCBORDecode_GetNextTagNumberInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint64_t *puTagNumber)
4021{
4022#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
4023 size_t uOffset;
4024 MapSearchInfo Info;
4025 QCBORItem OneItemSeach[2];
4026
4027 if(pMe->uLastError != QCBOR_SUCCESS) {
4028 return pMe->uLastError;
4029 }
4030
4031 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4032 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4033 OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
4034 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
4035
4036 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
4037
4038
4039 uOffset = Info.uStartOffset;
4040 if(uOffset == pMe->uTagNumberCheckOffset) {
4041 pMe->uTagNumberIndex++;
4042 } else {
4043 pMe->uTagNumberIndex = 0;
4044 }
4045
4046 *puTagNumber = CBOR_TAG_INVALID64;
4047
4048 *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex);
4049 if(*puTagNumber == CBOR_TAG_INVALID64 ||
4050 QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
4051 pMe->uTagNumberIndex = 255; /* All tags clear for this item */
4052 }
4053 pMe->uTagNumberCheckOffset = uOffset;
4054
4055 return uReturn;
4056#else
4057 (void)pMe;
4058 (void)szLabel;
4059 (void)puTagNumber;
4060 return QCBOR_ERR_LABEL_NOT_FOUND;
4061#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
4062}
4063#endif /* ! QCBOR_DISABLE_TAGS */
4064
4065
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004066/**
4067 * @brief Search for a map/array by label and enter it
4068 *
4069 * @param[in] pMe The decode context.
4070 * @param[in] pSearch The map/array to search for.
4071 *
4072 * @c pSearch is expected to contain one item of type map or array
4073 * with the label specified. The current bounded map will be searched for
4074 * this and if found will be entered.
4075 *
4076 * If the label is not found, or the item found is not a map or array,
4077 * the error state is set.
4078 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004079static void
4080QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07004081{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004082 QCBORError uErr;
4083 MapSearchInfo SearchInfo;
4084
Laurence Lundblade323f8a92020-09-06 19:43:09 -07004085 // The first item in pSearch is the one that is to be
4086 // entered. It should be the only one filled in. Any other
4087 // will be ignored unless it causes an error.
Laurence Lundblade34691b92020-05-18 22:25:25 -07004088 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07004089 return;
4090 }
4091
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004092 uErr = QCBORDecode_Private_MapSearch(pMe, pSearch, &SearchInfo, NULL);
4093
4094 pMe->uLastError = (uint8_t)QCBORDecode_Private_GetItemChecks(pMe, uErr, SearchInfo.uStartOffset, pSearch);
4095
Laurence Lundblade34691b92020-05-18 22:25:25 -07004096 if(pMe->uLastError != QCBOR_SUCCESS) {
4097 return;
4098 }
4099
Laurence Lundblade9b334962020-08-27 10:55:53 -07004100 if(pSearch->uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004101 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004102 return;
4103 }
4104
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004105
4106 /* The map or array was found. Now enter it.
4107 *
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004108 * QCBORDecode_EnterBoundedMapOrArray() used here, requires the
4109 * next item for the pre-order traversal cursor to be the map/array
4110 * found by MapSearch(). The next few lines of code force the
4111 * cursor to that.
4112 *
4113 * There is no need to retain the old cursor because
4114 * QCBORDecode_EnterBoundedMapOrArray() will set it to the
4115 * beginning of the map/array being entered.
4116 *
4117 * The cursor is forced by: 1) setting the input buffer position to
4118 * the item offset found by MapSearch(), 2) setting the map/array
4119 * counter to the total in the map/array, 3) setting the nesting
4120 * level. Setting the map/array counter to the total is not
4121 * strictly correct, but this is OK because this cursor only needs
4122 * to be used to get one item and MapSearch() has already found it
4123 * confirming it exists.
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004124 */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004125 UsefulInputBuf_Seek(&(pMe->InBuf), SearchInfo.uStartOffset);
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004126
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004127 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
4128
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004129 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07004130
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004131 QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004132}
4133
4134
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004135/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004136 * Public function, see header qcbor/qcbor_decode.h file
4137 */
4138void
4139QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004140{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004141 QCBORItem OneItemSeach[2];
4142 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4143 OneItemSeach[0].label.int64 = nLabel;
4144 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4145 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004146
Laurence Lundblade9b334962020-08-27 10:55:53 -07004147 /* The map to enter was found, now finish off entering it. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004148 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004149}
4150
4151
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004152/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004153 * Public function, see header qcbor/qcbor_decode.h file
4154 */
4155void
4156QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004157{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004158#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004159 QCBORItem OneItemSeach[2];
4160 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4161 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4162 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4163 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004164
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004165 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004166#else
4167 (void)szLabel;
4168 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
4169#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004170}
4171
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004172/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004173 * Public function, see header qcbor/qcbor_decode.h file
4174 */
4175void
4176QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07004177{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004178 QCBORItem OneItemSeach[2];
4179 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4180 OneItemSeach[0].label.int64 = nLabel;
4181 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4182 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004183
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004184 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07004185}
4186
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004187/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004188 * Public function, see header qcbor/qcbor_decode.h file
4189 */
4190void
4191QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundblade34691b92020-05-18 22:25:25 -07004192{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004193#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004194 QCBORItem OneItemSeach[2];
4195 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4196 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4197 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4198 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004199
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004200 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004201#else
4202 (void)szLabel;
4203 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
4204#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade1341c592020-04-11 14:19:05 -07004205}
4206
4207
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004208/**
4209 * @brief Semi-private to do the the work for EnterMap() and EnterArray().
4210 *
4211 * @param[in] pMe The decode context
4212 * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY.
4213 * @param[out] pItem The data item for the map or array entered.
4214 *
4215 * The next item in the traversal must be a map or array. This
4216 * consumes that item and does the book keeping to enter the map or
4217 * array.
4218 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004219void
4220QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe,
4221 const uint8_t uType,
4222 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004223{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004224 QCBORError uErr;
4225
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004226 /* Must only be called on maps and arrays. */
Laurence Lundblade34691b92020-05-18 22:25:25 -07004227 if(pMe->uLastError != QCBOR_SUCCESS) {
4228 // Already in error state; do nothing.
4229 return;
4230 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07004231
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004232 /* Get the data item that is the map or array being entered. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004233 QCBORItem Item;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004234 uErr = QCBORDecode_GetNext(pMe, &Item);
4235 if(uErr != QCBOR_SUCCESS) {
4236 goto Done;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07004237 }
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004238
4239 uint8_t uItemDataType = Item.uDataType;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004240
4241#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004242 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) {
4243 uItemDataType = QCBOR_TYPE_ARRAY;
4244 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004245#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
4246
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004247 if(uItemDataType != uType) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004248 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
4249 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004250 }
4251
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004252 QCBORDecode_Private_SaveTagNumbers(pMe, &Item);
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004253
4254
Laurence Lundbladef0499502020-08-01 11:55:57 -07004255 const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
Laurence Lundblade085d7952020-07-24 10:26:30 -07004256 if(bIsEmpty) {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004257 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
4258 // Undo decrement done by QCBORDecode_GetNext() so the the
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004259 // the decrement when exiting the map/array works correctly
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004260 pMe->nesting.pCurrent->u.ma.uCountCursor++;
4261 }
Laurence Lundblade93d89472020-10-03 22:30:50 -07004262 // Special case to increment nesting level for zero-length maps
4263 // and arrays entered in bounded mode.
Laurence Lundbladee6f15112020-07-23 18:44:16 -07004264 DecodeNesting_Descend(&(pMe->nesting), uType);
4265 }
4266
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004267 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004268
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004269 uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty,
4270 UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004271
Laurence Lundblade6545d1b2020-10-14 11:13:13 -07004272 if(pItem != NULL) {
4273 *pItem = Item;
4274 }
4275
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004276Done:
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004277 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004278}
4279
Laurence Lundblade02625d42020-06-25 14:41:41 -07004280
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004281/**
4282 * @brief Exit a bounded map, array or bstr (semi-private).
4283 *
4284 * @param[in] pMe Decode context.
4285 * @param[in] uEndOffset The input buffer offset of the end of item exited.
4286 *
4287 * @returns QCBOR_SUCCESS or an error code.
4288 *
4289 * This is the common work for exiting a level that is a bounded map,
4290 * array or bstr wrapped CBOR.
4291 *
4292 * One chunk of work is to set up the pre-order traversal so it is at
4293 * the item just after the bounded map, array or bstr that is being
4294 * exited. This is somewhat complex.
4295 *
4296 * The other work is to level-up the bounded mode to next higest
4297 * bounded mode or the top level if there isn't one.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004298 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004299static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004300QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
4301 const uint32_t uEndOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004302{
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004303 QCBORError uErr;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004304
Laurence Lundblade02625d42020-06-25 14:41:41 -07004305 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004306 * First the pre-order-traversal byte offset is positioned to the
4307 * item just after the bounded mode item that was just consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004308 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004309 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
4310
Laurence Lundblade02625d42020-06-25 14:41:41 -07004311 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004312 * Next, set the current nesting level to one above the bounded
4313 * level that was just exited.
4314 *
4315 * DecodeNesting_CheckBoundedType() is always called before this
4316 * and makes sure pCurrentBounded is valid.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004317 */
4318 DecodeNesting_LevelUpCurrent(&(pMe->nesting));
4319
4320 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004321 * This does the complex work of leveling up the pre-order
4322 * traversal when the end of a map or array or another bounded
4323 * level is reached. It may do nothing, or ascend all the way to
4324 * the top level.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004325 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004326 uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004327 if(uErr != QCBOR_SUCCESS) {
4328 goto Done;
4329 }
4330
Laurence Lundblade02625d42020-06-25 14:41:41 -07004331 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004332 * This makes the next highest bounded level the current bounded
4333 * level. If there is no next highest level, then no bounded mode
4334 * is in effect.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004335 */
4336 DecodeNesting_LevelUpBounded(&(pMe->nesting));
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004337
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004338 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004339
4340Done:
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004341 return uErr;
4342}
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004343
Laurence Lundblade02625d42020-06-25 14:41:41 -07004344
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004345/**
4346 * @brief Get started exiting a map or array (semi-private)
4347 *
4348 * @param[in] pMe The decode context
4349 * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP
4350 *
4351 * This does some work for map and array exiting (but not
4352 * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel()
4353 * is called to do the rest.
4354 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004355void
4356QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe,
4357 const uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004358{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004359 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07004360 /* Already in error state; do nothing. */
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004361 return;
4362 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004363
Laurence Lundblade02625d42020-06-25 14:41:41 -07004364 QCBORError uErr;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004365
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004366 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004367 uErr = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004368 goto Done;
4369 }
4370
Laurence Lundblade02625d42020-06-25 14:41:41 -07004371 /*
4372 Have to set the offset to the end of the map/array
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004373 that is being exited. If there is no cached value,
Laurence Lundblade02625d42020-06-25 14:41:41 -07004374 from previous map search, then do a dummy search.
4375 */
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004376 if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004377 QCBORItem Dummy;
4378 Dummy.uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004379 uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL);
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004380 if(uErr != QCBOR_SUCCESS) {
4381 goto Done;
4382 }
4383 }
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004384
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004385 uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004386
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004387Done:
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004388 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004389}
4390
4391
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004392// TODO: re order this file with tags stuff last. bstr is a tag thing
4393static QCBORError
4394QCBORDecode_Private_CheckTagNType(QCBORDecodeContext *pMe,
4395 const QCBORItem *pItem,
4396 const size_t uOffset,
4397 const uint8_t *uQCBORTypes,
4398 const uint64_t *uTagNumbers,
4399 const uint8_t uTagRequirement,
4400 bool *bTypeMatched);
4401
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004402/**
4403 * @brief The main work of entering some byte-string wrapped CBOR.
4404 *
4405 * @param[in] pMe The decode context.
4406 * @param[in] pItem The byte string item.
4407 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX
4408 * @param[out] pBstr Pointer and length of byte string entered.
4409 *
4410 * This is called once the byte string item has been decoded to do all
4411 * the book keeping work for descending a nesting level into the
4412 * nested CBOR.
4413 *
4414 * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement.
4415 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004416static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004417QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe,
4418 const QCBORItem *pItem,
4419 const uint8_t uTagRequirement,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004420 const size_t uOffset,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004421 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004422{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004423 bool bTypeMatched;
4424 QCBORError uError;
4425
4426 const uint8_t uTypes[] = {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE};
4427 const uint64_t uTagNumbers[] = {CBOR_TAG_CBOR, CBOR_TAG_CBOR_SEQUENCE, CBOR_TAG_INVALID64};
4428
4429
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004430 if(pBstr) {
4431 *pBstr = NULLUsefulBufC;
4432 }
4433
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004434 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004435 return pMe->uLastError;
4436 }
4437
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004438 if(pItem->uDataAlloc) {
4439 return QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004440 }
4441
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004442 uError = QCBORDecode_Private_CheckTagNType(pMe,
4443 pItem,
4444 uOffset,
4445 uTypes, // TODO: maybe this should be empty
4446 uTagNumbers,
4447 uTagRequirement,
4448 &bTypeMatched);
4449
4450 if(pItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
4451 uError = QCBOR_ERR_BAD_TAG_CONTENT; // TODO: error
4452 }
4453
4454
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004455 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004456 /* Reverse the decrement done by GetNext() for the bstr so the
4457 * increment in QCBORDecode_NestLevelAscender() called by
4458 * ExitBoundedLevel() will work right.
4459 */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004460 DecodeNesting_ReverseDecrement(&(pMe->nesting));
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07004461 }
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004462
4463 if(pBstr) {
4464 *pBstr = pItem->val.string;
4465 }
4466
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004467 /* This saves the current length of the UsefulInputBuf and then
4468 * narrows the UsefulInputBuf to start and length of the wrapped
4469 * CBOR that is being entered.
4470 *
4471 * Most of these calls are simple inline accessors so this doesn't
4472 * amount to much code.
4473 */
4474
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004475 const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004476 /* This check makes the cast of uPreviousLength to uint32_t below safe. */
4477 if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004478 uError = QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladef76a2622020-08-06 19:51:03 -07004479 goto Done;
4480 }
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004481
4482 const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
4483 pItem->val.string.ptr);
4484 /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
4485 if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
4486 /* This should never happen because pItem->val.string.ptr should
4487 * always be valid since it was just returned.
4488 */
4489 uError = QCBOR_ERR_INPUT_TOO_LARGE;
4490 goto Done;
4491 }
4492
4493 const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
4494
4495 UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004496 UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004497
Laurence Lundblade02625d42020-06-25 14:41:41 -07004498 uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004499 (uint32_t)uPreviousLength,
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004500 (uint32_t)uStartOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004501Done:
4502 return uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004503}
4504
4505
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004506static void
4507QCBORDecode_Private_GetAndTell(QCBORDecodeContext *pMe, QCBORItem *Item, size_t *uOffset)
4508{
4509#ifndef QCBOR_DISABLE_TAGS
4510 if(pMe->uLastError != QCBOR_SUCCESS) {
4511 return;
4512 }
4513
4514 *uOffset = QCBORDecode_Tell(pMe);
4515#else
4516 *uOffset = SIZE_MAX;
4517
4518#endif /* ! QCBOR_DISABLE_TAGS */
4519 pMe->uLastError = (uint8_t)QCBORDecode_Private_GetNextTagContent(pMe, Item);
4520}
4521
4522
Laurence Lundblade02625d42020-06-25 14:41:41 -07004523/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004524 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004525 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004526void
4527QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe,
4528 const uint8_t uTagRequirement,
4529 UsefulBufC *pBstr)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004530{
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004531 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004532 size_t uOffset;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004533
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004534 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004535 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4536 &Item,
4537 uTagRequirement,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004538 uOffset,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004539 pBstr);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004540}
4541
4542
Laurence Lundblade02625d42020-06-25 14:41:41 -07004543/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004544 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004545 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004546void
4547QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe,
4548 const int64_t nLabel,
4549 const uint8_t uTagRequirement,
4550 UsefulBufC *pBstr)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004551{
4552 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004553 size_t uOffset;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004554
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004555 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_BYTE_STRING, &Item, &uOffset);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004556 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4557 &Item,
4558 uTagRequirement,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004559 uOffset,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004560 pBstr);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004561}
4562
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004563
Laurence Lundblade02625d42020-06-25 14:41:41 -07004564/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004565 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004566 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004567void
4568QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe,
4569 const char *szLabel,
4570 const uint8_t uTagRequirement,
4571 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004572{
4573 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004574 size_t uOffset;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004575
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004576 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_BYTE_STRING, &Item, &uOffset);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004577 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4578 &Item,
4579 uTagRequirement,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004580 uOffset,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004581 pBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004582}
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004583
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004584
Laurence Lundblade02625d42020-06-25 14:41:41 -07004585/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004586 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004587 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004588void
4589QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004590{
Laurence Lundblade02625d42020-06-25 14:41:41 -07004591 if(pMe->uLastError != QCBOR_SUCCESS) {
4592 // Already in error state; do nothing.
4593 return;
4594 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004595
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004596 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004597 pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade02625d42020-06-25 14:41:41 -07004598 return;
4599 }
4600
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004601 const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
4602
Laurence Lundblade02625d42020-06-25 14:41:41 -07004603 /*
4604 Reset the length of the UsefulInputBuf to what it was before
4605 the bstr wrapped CBOR was entered.
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004606 */
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004607 UsefulInputBuf_SetBufferLength(&(pMe->InBuf),
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004608 DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004609
4610
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004611 QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004612 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004613}
4614
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004615
Laurence Lundbladee6430642020-03-14 21:15:44 -07004616
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004617/**
4618 * @brief Process simple type true and false, a boolean
4619 *
4620 * @param[in] pMe The decode context.
4621 * @param[in] pItem The item with either true or false.
4622 * @param[out] pBool The boolean value output.
4623 *
4624 * Sets the internal error if the item isn't a true or a false. Also
4625 * records any tag numbers as the tag numbers of the last item.
4626 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004627static void
4628QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe,
4629 const QCBORItem *pItem,
4630 bool *pBool)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004631{
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004632 if(pMe->uLastError != QCBOR_SUCCESS) {
4633 /* Already in error state, do nothing */
4634 return;
4635 }
4636
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004637 switch(pItem->uDataType) {
4638 case QCBOR_TYPE_TRUE:
4639 *pBool = true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004640 break;
4641
4642 case QCBOR_TYPE_FALSE:
4643 *pBool = false;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004644 break;
4645
4646 default:
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004647 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004648 break;
4649 }
4650}
Laurence Lundbladee6430642020-03-14 21:15:44 -07004651
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004652
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004653/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004654 * Public function, see header qcbor/qcbor_decode.h file
4655 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004656void
4657QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004658{
Laurence Lundbladec4537442020-04-14 18:53:22 -07004659 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07004660 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004661 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004662}
4663
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004664
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004665/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004666 * Public function, see header qcbor/qcbor_decode.h file
4667 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004668void
4669QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe,
4670 const int64_t nLabel,
4671 bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004672{
4673 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004674 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004675 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004676}
4677
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004678
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004679/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004680 * Public function, see header qcbor/qcbor_decode.h file
4681 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004682void
4683QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe,
4684 const char *szLabel,
4685 bool *pValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004686{
4687 QCBORItem Item;
4688 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004689 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004690}
4691
4692
Laurence Lundblade3888f002024-06-12 21:20:56 -07004693/**
4694 * @brief Process simple values.
4695 *
4696 * @param[in] pMe The decode context.
4697 * @param[in] pItem The item with the simple value.
4698 * @param[out] puSimple The simple value output.
4699 *
4700 * Sets the internal error if the item isn't a true or a false. Also
4701 * records any tag numbers as the tag numbers of the last item.
4702 */
4703static void
4704QCBORDecode_Private_ProcessSimple(QCBORDecodeContext *pMe,
4705 const QCBORItem *pItem,
4706 uint8_t *puSimple)
4707{
4708 if(pMe->uLastError != QCBOR_SUCCESS) {
4709 return;
4710 }
4711
4712 /* It's kind of lame to remap true...undef back to simple values, but
4713 * this function isn't used much and to not do it would require
4714 * changing GetNext() behavior in an incompatible way.
4715 */
4716 switch(pItem->uDataType) {
4717 case QCBOR_TYPE_UKNOWN_SIMPLE:
4718 *puSimple = pItem->val.uSimple;
4719 break;
4720
4721 case QCBOR_TYPE_TRUE:
4722 *puSimple = CBOR_SIMPLEV_TRUE;
4723 break;
4724
4725 case QCBOR_TYPE_FALSE:
4726 *puSimple = CBOR_SIMPLEV_FALSE;
4727 break;
4728
4729 case QCBOR_TYPE_NULL:
4730 *puSimple = CBOR_SIMPLEV_NULL;
4731 break;
4732
4733 case QCBOR_TYPE_UNDEF:
4734 *puSimple = CBOR_SIMPLEV_UNDEF;
4735 break;
4736
4737 default:
4738 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4739 return;
4740 }
Laurence Lundblade3888f002024-06-12 21:20:56 -07004741}
4742
4743/*
4744 * Public function, see header qcbor/qcbor_decode.h file
4745 */
4746void
4747QCBORDecode_GetSimple(QCBORDecodeContext *pMe, uint8_t *puSimple)
4748{
4749 QCBORItem Item;
Laurence Lundblade3888f002024-06-12 21:20:56 -07004750 QCBORDecode_VGetNext(pMe, &Item);
4751 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimple);
4752}
4753
4754/*
4755 * Public function, see header qcbor/qcbor_decode.h file
4756 */
4757void
4758QCBORDecode_GetSimpleInMapN(QCBORDecodeContext *pMe,
4759 int64_t nLabel,
4760 uint8_t *puSimpleValue)
4761{
4762 QCBORItem Item;
4763 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3888f002024-06-12 21:20:56 -07004764 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
4765}
4766
4767/*
4768 * Public function, see header qcbor/qcbor_decode.h file
4769 */
4770void
4771QCBORDecode_GetSimpleInMapSZ(QCBORDecodeContext *pMe,
4772 const char *szLabel,
4773 uint8_t *puSimpleValue)
4774{
4775 QCBORItem Item;
4776 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3888f002024-06-12 21:20:56 -07004777 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
4778}
4779
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004780
Laurence Lundbladec7114722020-08-13 05:11:40 -07004781
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004782
4783#ifndef QCBOR_DISABLE_TAGS
4784// TODO: uTagNumber might be better a list than calling this multiple times
4785static QCBORError
4786QCBORDecode_Private_Check1TagNumber(const QCBORDecodeContext *pMe,
4787 const QCBORItem *pItem,
4788 const uint64_t uTagNumber,
4789 const size_t uOffset)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004790{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004791 if(pItem->auTagNumbers[0] == CBOR_TAG_INVALID16) {
4792 /* There are no tag numbers at all, so no unprocessed */
4793 return QCBOR_SUCCESS;
4794 }
4795
4796 /* There are some tag numbers, so keep checking. This check passes
4797 * if there is one and only one tag number that matches uTagNumber
4798 */
4799
4800 // TODO: behave different in v1 and v2?
4801
4802 const uint64_t uInnerTag = QCBORDecode_GetNthTagNumber(pMe, pItem, 0);
4803
4804 if(uInnerTag == uTagNumber && pItem->auTagNumbers[1] == CBOR_TAG_INVALID16 ) {
4805 /* The only tag number is the one we are processing so no unprocessed */
4806 return QCBOR_SUCCESS;
4807 }
4808
4809 if(uOffset != pMe->uTagNumberCheckOffset) {
4810 /* processed tag numbers are for some other item, not us */
4811 return QCBOR_ERR_UNPROCESSED_TAG_NUMBER;
4812 }
4813
4814 if(pMe->uTagNumberIndex != 1) {
4815 return QCBOR_ERR_UNPROCESSED_TAG_NUMBER;
4816 }
4817
4818 return QCBOR_SUCCESS;
4819}
4820#endif
4821
4822
4823static QCBORError
4824QCBORDecode_Private_CheckTagNType(QCBORDecodeContext *pMe,
4825 const QCBORItem *pItem,
4826 const size_t uOffset,
4827 const uint8_t *uQCBORTypes,
4828 const uint64_t *uTagNumbers,
4829 const uint8_t uTagRequirement,
4830 bool *bTypeMatched)
4831{
4832 const int nTagReq = uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
4833
4834 *bTypeMatched = false;
4835 for(const uint8_t *pTNum = uQCBORTypes; *pTNum != QCBOR_TYPE_NONE; pTNum++) {
4836 if(pItem->uDataType == *pTNum) {
4837 *bTypeMatched = true;
4838 break;
4839 }
4840 }
4841
4842#ifndef QCBOR_DISABLE_TAGS
4843 bool bTagNumberMatched;
4844 QCBORError uErr;
4845 const uint64_t uInnerTag = QCBORDecode_GetNthTagNumber(pMe, pItem, 0);
4846
4847 bTagNumberMatched = false;
4848 for(const uint64_t *pQType = uTagNumbers; *pQType != CBOR_TAG_INVALID64; pQType++) {
4849 if(uInnerTag == *pQType) {
4850 bTagNumberMatched = true;
4851 break;
4852 }
4853 }
4854
4855
4856 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
4857 /* There must be a tag number */
4858 if(!bTagNumberMatched && !*bTypeMatched) {
4859 return QCBOR_ERR_UNEXPECTED_TYPE; // TODO: error code
4860 }
4861
4862 } else if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
4863 if(bTagNumberMatched || *bTypeMatched) {
4864 return QCBOR_ERR_UNEXPECTED_TYPE; // TODO: error code
4865 }
4866
4867 } else if(nTagReq == QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG) {
4868 /* No check necessary */
4869 }
4870
4871 /* Now check if there are extra tags and if there's an error in them */
4872 if(!(uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS)) {
4873 /* The flag to ignore extra is not set, so keep checking */
4874 for(const uint64_t *pTNum = uTagNumbers; *pTNum != CBOR_TAG_INVALID64; pTNum++) {
4875 uErr = QCBORDecode_Private_Check1TagNumber(pMe, pItem, *pTNum, uOffset);
4876 if(uErr != QCBOR_SUCCESS) {
4877 return uErr;
4878 }
4879 }
4880 }
4881
4882 return QCBOR_SUCCESS;
4883#else
4884 (void)pMe;
4885 (void)uOffset;
4886 (void)uTagNumbers;
4887
4888 if(nTagReq != QCBOR_TAG_REQUIREMENT_TAG && bTypeMatched) {
4889 return QCBOR_SUCCESS;
4890 } else {
4891 return QCBOR_ERR_UNEXPECTED_TYPE;
4892 }
4893
4894#endif
4895
4896}
4897
4898
Laurence Lundblade68769332024-11-03 13:09:20 -08004899static void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004900QCBORDecode_Private_ProcessTagItemMulti(QCBORDecodeContext *pMe,
4901 QCBORItem *pItem,
4902 const uint8_t uTagRequirement,
4903 const uint8_t uQCBORTypes[],
4904 const uint64_t uTagNumbers[],
4905 QCBORTagContentCallBack *pfCB,
4906 size_t uOffset)
4907{
4908 QCBORError uErr;
4909 bool bTypeMatched;
4910
Laurence Lundbladec7114722020-08-13 05:11:40 -07004911 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec7114722020-08-13 05:11:40 -07004912 return;
4913 }
4914
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004915 uErr = QCBORDecode_Private_CheckTagNType(pMe,
4916 pItem,
4917 uOffset,
4918 uQCBORTypes,
4919 uTagNumbers,
4920 uTagRequirement,
4921 &bTypeMatched);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004922 if(uErr != QCBOR_SUCCESS) {
4923 goto Done;
4924 }
4925
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004926 if(!bTypeMatched) {
4927 /* Tag content wasn't previously processed, do it now */
4928 uErr = (*pfCB)(pMe, NULL, uTagNumbers[0], pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004929 if(uErr != QCBOR_SUCCESS) {
4930 goto Done;
4931 }
4932 }
4933
Laurence Lundbladec7114722020-08-13 05:11:40 -07004934Done:
4935 pMe->uLastError = (uint8_t)uErr;
4936}
4937
4938
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004939/*
4940 **/
Laurence Lundblade68769332024-11-03 13:09:20 -08004941static void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004942QCBORDecode_Private_ProcessTagItem(QCBORDecodeContext *pMe,
4943 QCBORItem *pItem,
4944 const uint8_t uTagRequirement,
4945 const uint8_t uQCBORTypes[],
4946 const uint64_t uTagNumber,
4947 QCBORTagContentCallBack *pfCB,
4948 size_t uOffset)
4949{
4950 uint64_t auTagNumbers[2];
4951
4952 auTagNumbers[0] = uTagNumber;
4953 auTagNumbers[1] = CBOR_TAG_INVALID64;
4954
4955 QCBORDecode_Private_ProcessTagItemMulti(pMe,
4956 pItem,
4957 uTagRequirement,
4958 uQCBORTypes,
4959 auTagNumbers,
4960 pfCB,
4961 uOffset);
4962}
4963
4964
4965static void
Laurence Lundblade68769332024-11-03 13:09:20 -08004966QCBORDecode_Private_ProcessTagOne(QCBORDecodeContext *pMe,
4967 QCBORItem *pItem,
4968 const uint8_t uTagRequirement,
4969 const uint8_t uQCBORType,
4970 const uint64_t uTagNumber,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004971 QCBORTagContentCallBack *pfCB,
Laurence Lundblade68769332024-11-03 13:09:20 -08004972 const size_t uOffset)
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004973{
4974 uint8_t auQCBORType[2];
4975
4976 auQCBORType[0] = uQCBORType;
4977 auQCBORType[1] = QCBOR_TYPE_NONE;
4978
4979 QCBORDecode_Private_ProcessTagItem(pMe,
4980 pItem,
4981 uTagRequirement,
4982 auQCBORType,
4983 uTagNumber,
4984 pfCB,
4985 uOffset);
4986}
4987
4988
4989
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004990
4991/*
4992 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4993 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004994void
4995QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
4996 uint8_t uTagRequirement,
4997 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004998{
Laurence Lundbladec7114722020-08-13 05:11:40 -07004999 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005000 size_t uOffset;
5001
5002 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
5003 QCBORDecode_Private_ProcessTagOne(pMe,
5004 &Item,
5005 uTagRequirement,
5006 QCBOR_TYPE_DATE_EPOCH,
5007 CBOR_TAG_DATE_EPOCH,
5008 QCBORDecode_DateEpochTagCB,
5009 uOffset);
5010 *pnTime = Item.val.epochDate.nSeconds;
Laurence Lundbladec7114722020-08-13 05:11:40 -07005011}
5012
5013
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005014/*
5015 * Public function, see header qcbor/qcbor_spiffy_decode.h file
5016 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07005017void
5018QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
5019 int64_t nLabel,
5020 uint8_t uTagRequirement,
5021 int64_t *pnTime)
5022{
5023 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005024 size_t uOffset;
5025
5026 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
5027 QCBORDecode_Private_ProcessTagOne(pMe,
5028 &Item,
5029 uTagRequirement,
5030 QCBOR_TYPE_DATE_EPOCH,
5031 CBOR_TAG_DATE_EPOCH,
5032 QCBORDecode_DateEpochTagCB,
5033 uOffset);
5034 *pnTime = Item.val.epochDate.nSeconds;
Laurence Lundbladec7114722020-08-13 05:11:40 -07005035}
5036
5037
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005038/*
5039 * Public function, see header qcbor/qcbor_spiffy_decode.h file
5040 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07005041void
5042QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
5043 const char *szLabel,
5044 uint8_t uTagRequirement,
5045 int64_t *pnTime)
5046{
5047 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005048 size_t uOffset;
Laurence Lundbladec7114722020-08-13 05:11:40 -07005049
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005050 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
5051 QCBORDecode_Private_ProcessTagOne(pMe,
5052 &Item,
5053 uTagRequirement,
5054 QCBOR_TYPE_DATE_EPOCH,
5055 CBOR_TAG_DATE_EPOCH,
5056 QCBORDecode_DateEpochTagCB,
5057 uOffset);
5058 *pnTime = Item.val.epochDate.nSeconds;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005059}
5060
5061
5062/*
5063 * Public function, see header qcbor/qcbor_decode.h
5064 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005065void
5066QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe,
5067 uint8_t uTagRequirement,
5068 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005069{
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005070 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005071 size_t uOffset;
5072
5073 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
5074 QCBORDecode_Private_ProcessTagOne(pMe,
5075 &Item,
5076 uTagRequirement,
5077 QCBOR_TYPE_DAYS_EPOCH,
5078 CBOR_TAG_DAYS_EPOCH,
5079 QCBORDecode_DaysEpochTagCB,
5080 uOffset);
5081 *pnDays = Item.val.epochDays;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005082}
5083
5084
5085/*
5086 * Public function, see header qcbor/qcbor_decode.h
5087 */
5088void
5089QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe,
5090 int64_t nLabel,
5091 uint8_t uTagRequirement,
5092 int64_t *pnDays)
5093{
5094 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005095 size_t uOffset;
5096
5097 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
5098 QCBORDecode_Private_ProcessTagOne(pMe,
5099 &Item,
5100 uTagRequirement,
5101 QCBOR_TYPE_DAYS_EPOCH,
5102 CBOR_TAG_DAYS_EPOCH,
5103 QCBORDecode_DaysEpochTagCB,
5104 uOffset);
5105 *pnDays = Item.val.epochDays;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005106}
5107
5108
5109/*
5110 * Public function, see header qcbor/qcbor_decode.h
5111 */
5112void
5113QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe,
5114 const char *szLabel,
5115 uint8_t uTagRequirement,
5116 int64_t *pnDays)
5117{
5118 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005119 size_t uOffset;
5120
5121 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
5122 QCBORDecode_Private_ProcessTagOne(pMe,
5123 &Item,
5124 uTagRequirement,
5125 QCBOR_TYPE_DAYS_EPOCH,
5126 CBOR_TAG_DAYS_EPOCH,
5127 QCBORDecode_DaysEpochTagCB,
5128 uOffset);
5129 *pnDays = Item.val.epochDays;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005130}
5131
5132
5133
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005134
Laurence Lundblade37286c02022-09-03 10:05:02 -07005135void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005136QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
5137 const uint8_t uTagRequirement,
5138 const uint8_t uQCBOR_Type,
5139 const uint64_t uTagNumber,
5140 UsefulBufC *pStr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005141{
Laurence Lundbladec4537442020-04-14 18:53:22 -07005142 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005143 size_t uOffset;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005144
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005145 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
5146 QCBORDecode_Private_ProcessTagOne(pMe,
5147 &Item,
5148 uTagRequirement,
5149 uQCBOR_Type,
5150 uTagNumber,
5151 QCBORDecode_StringsTagCB,
5152 uOffset);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005153
5154 if(pMe->uLastError == QCBOR_SUCCESS) {
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005155 *pStr = Item.val.string;
Laurence Lundbladeab40c6f2020-08-28 11:24:58 -07005156 } else {
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005157 *pStr = NULLUsefulBufC;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005158 }
5159}
5160
Laurence Lundbladec4537442020-04-14 18:53:22 -07005161
5162
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005163static void
5164QCBORDecode_Private_GetMIME(QCBORDecodeContext *pMe,
5165 const uint8_t uTagRequirement,
5166 QCBORItem *pItem,
5167 UsefulBufC *pValue,
5168 bool *pbIsTag257,
5169 size_t uOffset)
5170{
5171 QCBORError uErr;
5172
5173 const uint8_t puTypes[] = {QCBOR_TYPE_MIME, QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE};
5174
5175 const uint64_t puTNs[] = {CBOR_TAG_MIME, CBOR_TAG_BINARY_MIME, CBOR_TAG_INVALID64};
5176
5177 QCBORDecode_Private_ProcessTagItemMulti(pMe,
5178 pItem,
5179 uTagRequirement,
5180 puTypes,
5181 puTNs,
5182 QCBORDecode_MIMETagCB,
5183 uOffset);
5184 if(pMe->uLastError) {
5185 return;
5186 }
5187
5188 if(pItem->uDataType == QCBOR_TYPE_MIME) {
5189 *pbIsTag257 = false;
5190 } else if(pItem->uDataType == QCBOR_TYPE_BINARY_MIME) {
5191 *pbIsTag257 = true;
5192 }
5193 *pValue = pItem->val.string;
5194
5195
5196 uErr = QCBOR_SUCCESS;
5197
5198 pMe->uLastError = (uint8_t)uErr;
5199}
5200
5201
5202void
5203QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pMe,
5204 const uint8_t uTagRequirement,
5205 UsefulBufC *pMessage,
5206 bool *pbIsTag257)
5207{
5208 QCBORItem Item;
5209 size_t uOffset;
5210
5211 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
5212 QCBORDecode_Private_GetMIME(pMe,
5213 uTagRequirement,
5214 &Item,
5215 pMessage,
5216 pbIsTag257,
5217 uOffset);
5218}
5219
5220void
5221QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pMe,
5222 const int64_t nLabel,
5223 const uint8_t uTagRequirement,
5224 UsefulBufC *pMessage,
5225 bool *pbIsTag257)
5226{
5227 QCBORItem Item;
5228 size_t uOffset;
5229
5230 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
5231 QCBORDecode_Private_GetMIME(pMe,
5232 uTagRequirement,
5233 &Item,
5234 pMessage,
5235 pbIsTag257,
5236 uOffset);
5237}
5238
5239void
5240QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pMe,
5241 const char *szLabel,
5242 const uint8_t uTagRequirement,
5243 UsefulBufC *pMessage,
5244 bool *pbIsTag257)
5245{
5246 QCBORItem Item;
5247 size_t uOffset;
5248
5249 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
5250 QCBORDecode_Private_GetMIME(pMe,
5251 uTagRequirement,
5252 &Item,
5253 pMessage,
5254 pbIsTag257,
5255 uOffset);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005256}
5257
5258
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005259
Laurence Lundblade93d89472020-10-03 22:30:50 -07005260// Improvement: add methods for wrapped CBOR, a simple alternate
5261// to EnterBstrWrapped
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005262
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005263
Laurence Lundbladedd6e76e2021-03-10 01:54:01 -07005264#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
Laurence Lundbladee6430642020-03-14 21:15:44 -07005265
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005266/**
5267 * @brief Prototype for conversion of exponent and mantissa to unsigned integer.
5268 *
5269 * @param[in] uMantissa The mantissa.
5270 * @param[in] nExponent The exponent.
5271 * @param[out] puResult The resulting integer.
5272 *
5273 * Concrete implementations of this are for exponent base 10 and 2 supporting
5274 * decimal fractions and big floats.
5275 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005276typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005277
5278
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005279/**
5280 * @brief Base 10 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5281 *
5282 * @param[in] uMantissa The unsigned integer mantissa.
5283 * @param[in] nExponent The signed integer exponent.
5284 * @param[out] puResult Place to return the unsigned integer result.
5285 *
5286 * This computes: mantissa * 10 ^^ exponent as for a decimal fraction. The output is a 64-bit
5287 * unsigned integer.
5288 *
5289 * There are many inputs for which the result will not fit in the
Laurence Lundblade88ba5662024-11-03 02:10:24 -08005290 * 64-bit integer and @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005291 * be returned.
5292 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005293static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005294QCBOR_Private_Exponentitate10(const uint64_t uMantissa,
5295 int64_t nExponent,
5296 uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005297{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005298 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005299
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005300 if(uResult != 0) {
5301 /* This loop will run a maximum of 19 times because
5302 * UINT64_MAX < 10 ^^ 19. More than that will cause
5303 * exit with the overflow error
5304 */
5305 for(; nExponent > 0; nExponent--) {
5306 if(uResult > UINT64_MAX / 10) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005307 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005308 }
5309 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005310 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005311
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005312 for(; nExponent < 0; nExponent++) {
5313 uResult = uResult / 10;
5314 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005315 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005316 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005317 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07005318 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005319 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07005320
5321 *puResult = uResult;
5322
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005323 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005324}
5325
5326
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005327/**
5328 * @brief Base 2 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
5329 *
5330 * @param[in] uMantissa The unsigned integer mantissa.
5331 * @param[in] nExponent The signed integer exponent.
5332 * @param[out] puResult Place to return the unsigned integer result.
5333 *
5334 * This computes: mantissa * 2 ^^ exponent as for a big float. The
5335 * output is a 64-bit unsigned integer.
5336 *
5337 * There are many inputs for which the result will not fit in the
Laurence Lundblade88ba5662024-11-03 02:10:24 -08005338 * 64-bit integer and @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005339 * be returned.
5340 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005341static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005342QCBOR_Private_Exponentitate2(const uint64_t uMantissa,
5343 int64_t nExponent,
5344 uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005345{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005346 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005347
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005348 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005349
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005350 /* This loop will run a maximum of 64 times because INT64_MAX <
5351 * 2^31. More than that will cause exit with the overflow error
Laurence Lundbladee6430642020-03-14 21:15:44 -07005352 */
5353 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005354 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005355 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005356 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005357 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005358 nExponent--;
5359 }
5360
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005361 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005362 if(uResult == 0) {
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005363 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005364 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005365 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005366 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005367 }
5368
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005369 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005370
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005371 return QCBOR_SUCCESS;
5372}
5373
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005374
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005375/**
5376 * @brief Exponentiate a signed mantissa and signed exponent to produce a signed result.
5377 *
5378 * @param[in] nMantissa Signed integer mantissa.
5379 * @param[in] nExponent Signed integer exponent.
5380 * @param[out] pnResult Place to put the signed integer result.
5381 * @param[in] pfExp Exponentiation function.
5382 *
5383 * @returns Error code
5384 *
Laurence Lundblade88ba5662024-11-03 02:10:24 -08005385 * @c pfExp performs exponentiation on and unsigned mantissa and
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005386 * produces an unsigned result. This converts the mantissa from signed
5387 * and converts the result to signed. The exponentiation function is
5388 * either for base 2 or base 10 (and could be other if needed).
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005389 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005390static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005391QCBOR_Private_ExponentiateNN(const int64_t nMantissa,
5392 const int64_t nExponent,
5393 int64_t *pnResult,
5394 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005395{
5396 uint64_t uResult;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005397 uint64_t uMantissa;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005398
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005399 /* Take the absolute value and put it into an unsigned. */
5400 if(nMantissa >= 0) {
5401 /* Positive case is straightforward */
5402 uMantissa = (uint64_t)nMantissa;
5403 } else if(nMantissa != INT64_MIN) {
5404 /* The common negative case. See next. */
5405 uMantissa = (uint64_t)-nMantissa;
5406 } else {
5407 /* int64_t and uint64_t are always two's complement per the
5408 * C standard (and since QCBOR uses these it only works with
5409 * two's complement, which is pretty much universal these
5410 * days). The range of a negative two's complement integer is
5411 * one more that than a positive, so the simple code above might
5412 * not work all the time because you can't simply negate the
5413 * value INT64_MIN because it can't be represented in an
5414 * int64_t. -INT64_MIN can however be represented in a
5415 * uint64_t. Some compilers seem to recognize this case for the
5416 * above code and put the correct value in uMantissa, however
5417 * they are not required to do this by the C standard. This next
5418 * line does however work for all compilers.
5419 *
5420 * This does assume two's complement where -INT64_MIN ==
5421 * INT64_MAX + 1 (which wouldn't be true for one's complement or
5422 * sign and magnitude (but we know we're using two's complement
5423 * because int64_t requires it)).
5424 *
5425 * See these, particularly the detailed commentary:
5426 * https://stackoverflow.com/questions/54915742/does-c99-mandate-a-int64-t-type-be-available-always
5427 * https://stackoverflow.com/questions/37301078/is-negating-int-min-undefined-behaviour
5428 */
5429 uMantissa = (uint64_t)INT64_MAX+1;
5430 }
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005431
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005432 /* Call the exponentiator passed for either base 2 or base 10.
5433 * Here is where most of the overflow errors are caught. */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005434 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
5435 if(uReturn) {
5436 return uReturn;
5437 }
5438
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005439 /* Convert back to the sign of the original mantissa */
5440 if(nMantissa >= 0) {
5441 if(uResult > INT64_MAX) {
5442 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5443 }
5444 *pnResult = (int64_t)uResult;
5445 } else {
5446 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
5447 * of INT64_MIN. This assumes two's compliment representation
5448 * where INT64_MIN is one increment farther from 0 than
5449 * INT64_MAX. Trying to write -INT64_MIN doesn't work to get
5450 * this because the compiler makes it an int64_t which can't
5451 * represent -INT64_MIN. Also see above.
5452 */
5453 if(uResult > (uint64_t)INT64_MAX+1) {
5454 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5455 }
5456 *pnResult = -(int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005457 }
5458
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005459 return QCBOR_SUCCESS;
5460}
5461
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005462
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005463/**
5464 * @brief Exponentiate an unsigned mantissa and signed exponent to produce an unsigned result.
5465 *
5466 * @param[in] nMantissa Signed integer mantissa.
5467 * @param[in] nExponent Signed integer exponent.
5468 * @param[out] puResult Place to put the signed integer result.
5469 * @param[in] pfExp Exponentiation function.
5470 *
5471 * @returns Error code
5472 *
Laurence Lundblade88ba5662024-11-03 02:10:24 -08005473 * @c pfExp performs exponentiation on and unsigned mantissa and
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005474 * produces an unsigned result. This errors out if the mantissa
5475 * is negative because the output is unsigned.
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07005476 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005477static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005478QCBOR_Private_ExponentitateNU(const int64_t nMantissa,
5479 const int64_t nExponent,
5480 uint64_t *puResult,
5481 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005482{
5483 if(nMantissa < 0) {
5484 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
5485 }
5486
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005487 /* Cast to unsigned is OK because of check for negative.
5488 * Cast to unsigned is OK because UINT64_MAX > INT64_MAX.
5489 * Exponentiation is straight forward
5490 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005491 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
5492}
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005493
5494
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005495/**
5496 * @brief Exponentiate an usnigned mantissa and unsigned exponent to produce an unsigned result.
5497 *
5498 * @param[in] uMantissa Unsigned integer mantissa.
5499 * @param[in] nExponent Unsigned integer exponent.
5500 * @param[out] puResult Place to put the unsigned integer result.
5501 * @param[in] pfExp Exponentiation function.
5502 *
5503 * @returns Error code
5504 *
Laurence Lundblade88ba5662024-11-03 02:10:24 -08005505 * @c pfExp performs exponentiation on and unsigned mantissa and
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005506 * produces an unsigned result so this is just a wrapper that does
5507 * nothing (and is likely inlined).
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005508 */
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005509static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005510QCBOR_Private_ExponentitateUU(const uint64_t uMantissa,
5511 const int64_t nExponent,
5512 uint64_t *puResult,
5513 fExponentiator pfExp)
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005514{
5515 return (*pfExp)(uMantissa, nExponent, puResult);
5516}
5517
Laurence Lundblade6658c952024-11-14 05:04:37 -08005518#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005519
5520
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005521
5522
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005523/**
5524 * @brief Convert a CBOR big number to a uint64_t.
5525 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005526 * @param[in] BigNumber Bytes of the big number to convert.
5527 * @param[in] uMax Maximum value allowed for the result.
5528 * @param[out] pResult Place to put the unsigned integer result.
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005529 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005530 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW When the bignumber is
5531 * too large to fit
5532 * @retval QCBOR_SUCCESS The conversion succeeded.
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005533 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005534 * Many values will overflow because a big number can represent a much
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005535 * larger range than uint64_t.
5536 */
5537static QCBORError
Laurence Lundblade05369de2024-11-17 17:00:28 -08005538QCBORDecode_Private_BigNumberToUInt(const UsefulBufC BigNumber,
5539 const uint64_t uMax,
5540 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005541{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005542 uint64_t uResult;
Laurence Lundblade05369de2024-11-17 17:00:28 -08005543 size_t uLen;
5544
5545 const uint8_t *pByte = BigNumber.ptr;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005546
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005547 uResult = 0;
Laurence Lundblade05369de2024-11-17 17:00:28 -08005548 for(uLen = BigNumber.len; uLen > 0; uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07005549 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07005550 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005551 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07005552 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005553 }
5554
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005555 *pResult = uResult;
5556 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005557}
5558
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005559
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005560/**
5561 * @brief Convert a CBOR postive big number to a uint64_t.
5562 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005563 * @param[in] BigNumber Bytes of the big number to convert.
5564 * @param[out] pResult Place to put the unsigned integer result.
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005565 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005566 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW When the bignumber is
5567 * too large to fit
5568 * @retval QCBOR_SUCCESS The conversion succeeded.
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005569 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005570 * Many values will overflow because a big num can represent a much
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005571 * larger range than uint64_t.
5572 */
5573static QCBORError
Laurence Lundblade05369de2024-11-17 17:00:28 -08005574QCBORDecode_Private_PositiveBigNumberToUInt(const UsefulBufC BigNumber,
5575 uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005576{
Laurence Lundblade05369de2024-11-17 17:00:28 -08005577 return QCBORDecode_Private_BigNumberToUInt(BigNumber, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07005578}
5579
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005580
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005581/**
5582 * @brief Convert a CBOR positive big number to an int64_t.
5583 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005584 * @param[in] BigNumber Bytes of the big number to convert.
5585 * @param[out] pResult Place to put the signed integer result.
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005586 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005587 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW When the bignumber is
5588 * too large to fit
5589 * @retval QCBOR_SUCCESS The conversion succeeded.
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005590 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005591 * Many values will overflow because a big num can represent a much
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005592 * larger range than int64_t.
5593 */
5594static QCBORError
Laurence Lundblade05369de2024-11-17 17:00:28 -08005595QCBORDecode_Private_PositiveBigNumberToInt(const UsefulBufC BigNumber,
5596 int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005597{
Laurence Lundblade05369de2024-11-17 17:00:28 -08005598 uint64_t uResult;
5599 QCBORError uError;
5600
5601 uError = QCBORDecode_Private_BigNumberToUInt(BigNumber, INT64_MAX, &uResult);
5602 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005603 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005604 }
Laurence Lundblade05369de2024-11-17 17:00:28 -08005605 /* Cast safe because QCBORDecode_Private_BigNumberToUInt() limits to INT64_MAX */
Laurence Lundbladee6430642020-03-14 21:15:44 -07005606 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07005607 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005608}
5609
5610
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005611/**
5612 * @brief Convert a CBOR negative big number to an int64_t.
5613 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005614 * @param[in] BigNumber Bytes of the big number to convert.
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005615 * @param[out] pnResult Place to put the signed integer result.
5616 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005617 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW When the bignumber is
5618 * too large to fit
5619 * @retval QCBOR_SUCCESS The conversion succeeded.
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005620 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005621 * Many values will overflow because a big num can represent a much
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005622 * larger range than int64_t.
5623 */
5624static QCBORError
Laurence Lundblade05369de2024-11-17 17:00:28 -08005625QCBORDecode_Private_NegativeBigNumberToInt(const UsefulBufC BigNumber,
5626 int64_t *pnResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005627{
Laurence Lundblade05369de2024-11-17 17:00:28 -08005628 uint64_t uResult;
5629 QCBORError uError;
Laurence Lundblade68769332024-11-03 13:09:20 -08005630
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005631 /* The negative integer furthest from zero for a C int64_t is
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005632 * INT64_MIN which is expressed as -INT64_MAX - 1. The value of a
5633 * negative number in CBOR is computed as -n - 1 where n is the
5634 * encoded integer, where n is what is in the variable BigNum. When
5635 * converting BigNum to a uint64_t, the maximum value is thus
5636 * INT64_MAX, so that when it -n - 1 is applied to it the result
5637 * will never be further from 0 than INT64_MIN.
5638 *
5639 * -n - 1 <= INT64_MIN.
5640 * -n - 1 <= -INT64_MAX - 1
5641 * n <= INT64_MAX.
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005642 */
Laurence Lundblade05369de2024-11-17 17:00:28 -08005643 uError = QCBORDecode_Private_BigNumberToUInt(BigNumber, INT64_MAX, &uResult);
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005644 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005645 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005646 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005647
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07005648 /* Now apply -n - 1. The cast is safe because
5649 * ConvertBigNumToUnsigned() is limited to INT64_MAX which does fit
5650 * is the largest positive integer that an int64_t can
5651 * represent. */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005652 *pnResult = -(int64_t)uResult - 1;
5653
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07005654 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005655}
5656
Laurence Lundblade05369de2024-11-17 17:00:28 -08005657/**
5658 * @brief Convert an integer to a big number.
5659 *
5660 * @param[in] uNum The integer to convert.
5661 * @param[in] BigNumberBuf The buffer to output the big number to.
5662 *
5663 * @returns The big number or NULLUsefulBufC is the buffer is to small.
5664 *
5665 * This always succeeds unless the buffer is too small.
5666 */
5667static UsefulBufC
5668QCBORDecode_Private_UIntToBigNumber(uint64_t uNum, const UsefulBuf BigNumberBuf)
5669{
5670 UsefulOutBuf UOB;
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005671
Laurence Lundblade05369de2024-11-17 17:00:28 -08005672 /* With a UsefulOutBuf, there's no pointer math */
5673 UsefulOutBuf_Init(&UOB, BigNumberBuf);
5674
5675 /* Must copy one byte even if zero. The loop, mask and shift
5676 * algorithm provides endian conversion.
5677 */
5678 do {
5679 UsefulOutBuf_InsertByte(&UOB, uNum & 0xff, 0);
5680 uNum >>= 8;
5681 } while(uNum);
5682
5683 return UsefulOutBuf_OutUBuf(&UOB);
5684}
5685
5686#ifndef QCBOR_DISABLE_FLOAT_HW_USE
5687/**
5688 * @brief Convert a big number to double-precision float.
5689 *
5690 * @param[in] BigNumber The big number to convert.
5691 *
5692 * @returns The double value.
5693 *
5694 * This will always succeed. It will lose precision for larger
5695 * numbers. If the big number is too large to fit (more than
5696 * 1.7976931348623157E+308) infinity will be returned. NaN is never
5697 * returned.
5698 */
5699static double
5700QCBORDecode_Private_BigNumberToDouble(const UsefulBufC BigNumber)
5701{
5702 double dResult;
5703 size_t uLen;
5704
5705 const uint8_t *pByte = BigNumber.ptr;
5706
5707 dResult = 0.0;
5708 /* This will overflow and become the float value INFINITY if the number
5709 * is too large to fit. */
5710 for(uLen = BigNumber.len; uLen > 0; uLen--){
5711 dResult = (dResult * 256.0) + (double)*pByte++;
5712 }
5713
5714 return dResult;
5715}
5716#endif /* ! QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005717
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005718
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005719/**
5720 * @brief Convert integers and floats to an int64_t.
5721 *
5722 * @param[in] pItem The item to convert.
5723 * @param[in] uConvertTypes Bit mask list of conversion options.
5724 * @param[out] pnValue The resulting converted value.
5725 *
5726 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
5727 * in uConvertTypes.
5728 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
5729 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
5730 * or too small.
5731 */
Laurence Lundblade93d89472020-10-03 22:30:50 -07005732static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005733QCBOR_Private_ConvertInt64(const QCBORItem *pItem,
5734 const uint32_t uConvertTypes,
5735 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005736{
5737 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005738 case QCBOR_TYPE_FLOAT:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005739 case QCBOR_TYPE_DOUBLE:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005740#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005741 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005742 /* https://pubs.opengroup.org/onlinepubs/009695399/functions/llround.html
5743 http://www.cplusplus.com/reference/cmath/llround/
5744 */
5745 // Not interested in FE_INEXACT
5746 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005747 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
5748 *pnValue = llround(pItem->val.dfnum);
5749 } else {
5750 *pnValue = lroundf(pItem->val.fnum);
5751 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07005752 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
5753 // llround() shouldn't result in divide by zero, but catch
5754 // it here in case it unexpectedly does. Don't try to
5755 // distinguish between the various exceptions because it seems
5756 // they vary by CPU, compiler and OS.
5757 return QCBOR_ERR_FLOAT_EXCEPTION;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005758 }
5759 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005760 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005761 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005762#else
5763 return QCBOR_ERR_HW_FLOAT_DISABLED;
5764#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005765 break;
5766
5767 case QCBOR_TYPE_INT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005768 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005769 *pnValue = pItem->val.int64;
5770 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005771 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005772 }
5773 break;
5774
5775 case QCBOR_TYPE_UINT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005776 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005777 if(pItem->val.uint64 < INT64_MAX) {
5778 *pnValue = pItem->val.int64;
5779 } else {
5780 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5781 }
5782 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07005783 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005784 }
5785 break;
5786
Laurence Lundblade2d493002024-02-01 11:09:17 -07005787 case QCBOR_TYPE_65BIT_NEG_INT:
5788 /* This type occurs if the value won't fit into int64_t
5789 * so this is always an error. */
5790 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
5791 break;
5792
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005793 default:
5794 return QCBOR_ERR_UNEXPECTED_TYPE;
5795 }
5796 return QCBOR_SUCCESS;
5797}
5798
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005799
Laurence Lundblade05369de2024-11-17 17:00:28 -08005800
5801#if !defined(USEFULBUF_DISABLE_ALL_FLOAT) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
5802/*
5803 * Public function, see header qcbor/qcbor_spiffy_decode.h file
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005804 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005805void
Laurence Lundblade05369de2024-11-17 17:00:28 -08005806QCBORDecode_GetNumberConvertPrecisely(QCBORDecodeContext *pMe,
5807 QCBORItem *pNumber)
Laurence Lundbladee6430642020-03-14 21:15:44 -07005808{
Laurence Lundblade05369de2024-11-17 17:00:28 -08005809 QCBORItem Item;
5810 struct IEEE754_ToInt ToInt;
5811 double dNum;
5812 QCBORError uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07005813
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005814 if(pMe->uLastError != QCBOR_SUCCESS) {
5815 return;
5816 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005817
Laurence Lundblade05369de2024-11-17 17:00:28 -08005818 // TODO:VGetNext?
5819 uError = QCBORDecode_GetNext(pMe, &Item);
5820 if(uError != QCBOR_SUCCESS) {
5821 *pNumber = Item;
5822 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07005823 return;
5824 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005825
Laurence Lundblade05369de2024-11-17 17:00:28 -08005826 switch(Item.uDataType) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005827 case QCBOR_TYPE_INT64:
Laurence Lundblade05369de2024-11-17 17:00:28 -08005828 case QCBOR_TYPE_UINT64:
5829 *pNumber = Item;
5830 break;
5831
5832 case QCBOR_TYPE_DOUBLE:
5833 ToInt = IEEE754_DoubleToInt(Item.val.dfnum);
5834 if(ToInt.type == IEEE754_ToInt_IS_INT) {
5835 pNumber->uDataType = QCBOR_TYPE_INT64;
5836 pNumber->val.int64 = ToInt.integer.is_signed;
5837 } else if(ToInt.type == IEEE754_ToInt_IS_UINT) {
5838 if(ToInt.integer.un_signed <= INT64_MAX) {
5839 /* Do the same as base QCBOR integer decoding */
5840 pNumber->uDataType = QCBOR_TYPE_INT64;
5841 pNumber->val.int64 = (int64_t)ToInt.integer.un_signed;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005842 } else {
Laurence Lundblade05369de2024-11-17 17:00:28 -08005843 pNumber->uDataType = QCBOR_TYPE_UINT64;
5844 pNumber->val.uint64 = ToInt.integer.un_signed;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005845 }
5846 } else {
Laurence Lundblade05369de2024-11-17 17:00:28 -08005847 *pNumber = Item;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005848 }
5849 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005850
Laurence Lundblade05369de2024-11-17 17:00:28 -08005851 case QCBOR_TYPE_FLOAT:
5852 ToInt = IEEE754_SingleToInt(Item.val.fnum);
5853 if(ToInt.type == IEEE754_ToInt_IS_INT) {
5854 pNumber->uDataType = QCBOR_TYPE_INT64;
5855 pNumber->val.int64 = ToInt.integer.is_signed;
5856 } else if(ToInt.type == IEEE754_ToInt_IS_UINT) {
5857 if(ToInt.integer.un_signed <= INT64_MAX) {
5858 /* Do the same as base QCBOR integer decoding */
5859 pNumber->uDataType = QCBOR_TYPE_INT64;
5860 pNumber->val.int64 = (int64_t)ToInt.integer.un_signed;
5861 } else {
5862 pNumber->uDataType = QCBOR_TYPE_UINT64;
5863 pNumber->val.uint64 = ToInt.integer.un_signed;
5864 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005865 } else {
Laurence Lundblade05369de2024-11-17 17:00:28 -08005866 *pNumber = Item;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07005867 }
5868 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005869
Laurence Lundblade2d493002024-02-01 11:09:17 -07005870 case QCBOR_TYPE_65BIT_NEG_INT:
Laurence Lundblade05369de2024-11-17 17:00:28 -08005871 if(Item.val.uint64 == UINT64_MAX) {
5872 /* The value -18446744073709551616 is encoded as an
5873 * unsigned 18446744073709551615. It's a whole number that
5874 * needs to be returned as a double. It can't be handled
5875 * by IEEE754_UintToDouble because 18446744073709551616
5876 * doesn't fit into a uint64_t. You can't get it by adding
5877 * 1 to 18446744073709551615.
5878 */
5879 pNumber->val.dfnum = -18446744073709551616.0;
5880 pNumber->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005881 } else {
Laurence Lundblade05369de2024-11-17 17:00:28 -08005882 dNum = IEEE754_UintToDouble(Item.val.uint64 + 1, 1);
5883 if(dNum == IEEE754_UINT_TO_DOUBLE_OOB) {
5884 *pNumber = Item;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005885 } else {
Laurence Lundblade05369de2024-11-17 17:00:28 -08005886 pNumber->val.dfnum = dNum;
5887 pNumber->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005888 }
5889 }
5890 break;
5891
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005892 default:
Laurence Lundblade05369de2024-11-17 17:00:28 -08005893 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
5894 pNumber->uDataType = QCBOR_TYPE_NONE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005895 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005896 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005897}
5898
Laurence Lundblade05369de2024-11-17 17:00:28 -08005899#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT && ! QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundbladee6430642020-03-14 21:15:44 -07005900
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07005901
Laurence Lundblade05369de2024-11-17 17:00:28 -08005902/* Add one to the big number and put the result in a new UsefulBufC
5903 * from storage in UsefulBuf.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005904 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005905 * Leading zeros must be removed before calling this.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005906 *
Laurence Lundblade05369de2024-11-17 17:00:28 -08005907 * Code Reviewers: THIS FUNCTION DOES POINTER MATH
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005908 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005909static UsefulBufC
Laurence Lundblade05369de2024-11-17 17:00:28 -08005910QCBORDecode_BigNumberCopyPlusOne(UsefulBufC BigNumber, UsefulBuf BigNumberBuf)
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005911{
Laurence Lundblade05369de2024-11-17 17:00:28 -08005912 uint8_t uCarry;
5913 uint8_t uSourceValue;
5914 const uint8_t *pSource;
5915 uint8_t *pDest;
5916 ptrdiff_t uDestBytesLeft;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005917
Laurence Lundblade05369de2024-11-17 17:00:28 -08005918 /* Start adding at the LSB */
5919 pSource = &((const uint8_t *)BigNumber.ptr)[BigNumber.len-1];
5920 pDest = &((uint8_t *)BigNumberBuf.ptr)[BigNumberBuf.len-1];
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005921
Laurence Lundblade05369de2024-11-17 17:00:28 -08005922 uCarry = 1; /* Gets set back to zero if add the next line doesn't wrap */
5923 *pDest = *pSource + 1;
5924 while(1) {
5925 /* Wrap around from 0xff to 0 is a defined operation for
5926 * unsigned addition in C.*/
5927 if(*pDest != 0) {
5928 /* The add operation didn't wrap so no more carry. This
5929 * funciton only adds one, so when there is no more carry,
5930 * carrying is over to the end.
5931 */
5932 uCarry = 0;
5933 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005934
Laurence Lundblade05369de2024-11-17 17:00:28 -08005935 uDestBytesLeft = pDest - (uint8_t *)BigNumberBuf.ptr;
5936 if(pSource <= (const uint8_t *)BigNumber.ptr && uCarry == 0) {
5937 break; /* Successful exit */
5938 }
5939 if(pSource > (const uint8_t *)BigNumber.ptr) {
5940 uSourceValue = *--pSource;
5941 } else {
5942 /* All source bytes processed, but not the last carry */
5943 uSourceValue = 0;
5944 }
5945
5946 pDest--;
5947 if(uDestBytesLeft < 0) {
5948 return NULLUsefulBufC; /* Not enough space in destination buffer */
5949 }
5950
5951 *pDest = uSourceValue + uCarry;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005952 }
5953
Laurence Lundblade05369de2024-11-17 17:00:28 -08005954 return (UsefulBufC){pDest, BigNumberBuf.len - (size_t)uDestBytesLeft};
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07005955}
5956
Laurence Lundblade05369de2024-11-17 17:00:28 -08005957
5958/* This returns 1 when uNum is 0 */
5959static size_t
5960QCBORDecode_Private_CountNonZeroBytes(uint64_t uNum)
5961{
5962 size_t uCount = 0;
5963 do {
5964 uCount++;
5965 uNum >>= 8;
5966 } while(uNum);
5967
5968 return uCount;
5969}
5970
5971
5972/*
5973 * Public function, see header qcbor/qcbor_decode.h
5974 */
5975QCBORError
5976QCBORDecode_ProcessBigNumberNoPreferred(const QCBORItem Item,
5977 const UsefulBuf BigNumberBuf,
5978 UsefulBufC *pBigNumber,
5979 bool *pbIsNegative)
5980{
5981 size_t uLen;
5982 UsefulBufC BigNumber;
5983 int uType;
5984
5985 uType = Item.uDataType;
5986 if(uType == QCBOR_TYPE_BYTE_STRING) {
5987 uType = *pbIsNegative ? QCBOR_TYPE_NEGBIGNUM : QCBOR_TYPE_POSBIGNUM;
5988 }
5989
5990 static const uint8_t Zero[] = {0x00};
5991 BigNumber = UsefulBuf_SkipLeading(Item.val.bigNum, 0);
5992 if(BigNumber.len == 0) {
5993 BigNumber = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(Zero);
5994 }
5995
5996 /* Compute required length so it can be returned if buffer is too small */
5997 switch(uType) {
5998
5999 case QCBOR_TYPE_POSBIGNUM:
6000 uLen = BigNumber.len;
6001 break;
6002
6003 case QCBOR_TYPE_NEGBIGNUM:
6004 uLen = BigNumber.len;
6005 if(UsefulBuf_IsValue(UsefulBuf_SkipLeading(BigNumber, 0), 0xff) == SIZE_MAX) {
6006 uLen++;
6007 }
6008 break;
6009
6010 default:
6011 return QCBOR_ERR_UNEXPECTED_TYPE;
6012 }
6013
6014 *pBigNumber = (UsefulBufC){NULL, uLen};
6015
6016 if(BigNumberBuf.len < uLen || uLen == 0 || BigNumberBuf.ptr == NULL) {
6017 return BigNumberBuf.ptr == NULL ? QCBOR_SUCCESS : QCBOR_ERR_BUFFER_TOO_SMALL;
6018 /* Buffer is too short or type is wrong */
6019 }
6020
6021
6022 if(uType == QCBOR_TYPE_POSBIGNUM) {
6023 *pBigNumber = UsefulBuf_Copy(BigNumberBuf, BigNumber);
6024 *pbIsNegative = false;
6025 } else if(uType == QCBOR_TYPE_NEGBIGNUM) {
6026 /* The messy one. Take the stuff in the buffer and copy it to
6027 * the new buffer, adding one to it. This might be one byte
6028 * bigger than the original because of the carry from adding
6029 * one.*/
6030 *pbIsNegative = true;
6031 *pBigNumber = QCBORDecode_BigNumberCopyPlusOne(BigNumber, BigNumberBuf);
6032 }
6033
6034 return QCBOR_SUCCESS;
6035}
6036
6037
6038/*
6039 * Public function, see header qcbor/qcbor_decode.h
6040 */
6041QCBORError
6042QCBORDecode_ProcessBigNumber(const QCBORItem Item,
6043 UsefulBuf BigNumberBuf,
6044 UsefulBufC *pBigNumber,
6045 bool *pbIsNegative)
6046{
6047 QCBORError uResult;
6048 size_t uLen;
6049 int uType;
6050
6051 uType = Item.uDataType;
6052
6053 switch(uType) {
6054 case QCBOR_TYPE_POSBIGNUM:
6055 case QCBOR_TYPE_NEGBIGNUM:
6056 case QCBOR_TYPE_BYTE_STRING:
6057 return QCBORDecode_ProcessBigNumberNoPreferred(Item, BigNumberBuf, pBigNumber, pbIsNegative);
6058 break;
6059
6060 case QCBOR_TYPE_INT64:
6061 uLen = QCBORDecode_Private_CountNonZeroBytes((uint64_t)ABSOLUTE_VALUE(Item.val.int64));
6062 break;
6063
6064 case QCBOR_TYPE_UINT64:
6065 uLen = QCBORDecode_Private_CountNonZeroBytes(Item.val.uint64);
6066 break;
6067
6068 case QCBOR_TYPE_65BIT_NEG_INT:
6069 uLen = Item.val.uint64 == UINT64_MAX ? 9 : QCBORDecode_Private_CountNonZeroBytes(Item.val.uint64);
6070 break;
6071
6072 default:
6073 return QCBOR_ERR_UNEXPECTED_TYPE;
6074 }
6075
6076
6077 *pBigNumber = (UsefulBufC){NULL, uLen};
6078
6079 if(BigNumberBuf.len < uLen || uLen == 0 || BigNumberBuf.ptr == NULL) {
6080 return BigNumberBuf.ptr == NULL ? QCBOR_SUCCESS : QCBOR_ERR_BUFFER_TOO_SMALL;
6081 /* Buffer is too short or type is wrong */
6082 }
6083
6084 uResult = QCBOR_SUCCESS;
6085
6086 if(uType == QCBOR_TYPE_UINT64) {
6087 *pBigNumber = QCBORDecode_Private_UIntToBigNumber(Item.val.uint64, BigNumberBuf);
6088 *pbIsNegative = false;
6089 } else if(uType == QCBOR_TYPE_INT64) {
6090 /* Offset of 1 for negative numbers already performed */
6091 *pbIsNegative = Item.val.int64 < 0;
6092 *pBigNumber = QCBORDecode_Private_UIntToBigNumber((uint64_t)(*pbIsNegative ? -Item.val.int64 : Item.val.int64), BigNumberBuf);
6093 } else if(uType == QCBOR_TYPE_65BIT_NEG_INT) {
6094 /* Offset of 1 for negative numbers NOT already performed */
6095 *pbIsNegative = true;
6096 if(Item.val.uint64 == UINT64_MAX) {
6097 /* The one value that can't be done with a computation
6098 * because it would overflow a uint64_t */
6099 static const uint8_t TwoToThe64[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
6100 *pBigNumber = UsefulBuf_Copy(BigNumberBuf, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(TwoToThe64));
6101 } else {
6102 /* +1 because negative big numbers are encoded one less than actual */
6103 *pBigNumber = QCBORDecode_Private_UIntToBigNumber(Item.val.uint64 + 1, BigNumberBuf);
6104 }
6105 }
6106
6107 return uResult;
6108}
6109
6110
6111
6112static const uint64_t QCBORDecode_Private_BigNumberTagNumbers[] = {
6113 CBOR_TAG_POS_BIGNUM,
6114 CBOR_TAG_NEG_BIGNUM,
6115 CBOR_TAG_INVALID64};
6116
6117static const uint8_t QCBORDecode_Private_BigNumberTypes[] = {
6118 QCBOR_TYPE_INT64,
6119 QCBOR_TYPE_UINT64,
6120 QCBOR_TYPE_65BIT_NEG_INT,
6121 QCBOR_TYPE_POSBIGNUM,
6122 QCBOR_TYPE_NEGBIGNUM,
6123 QCBOR_TYPE_NONE};
6124
6125#define QCBORDecode_Private_BigNumberTypesNoPreferred &QCBORDecode_Private_BigNumberTypes[3]
6126
6127/**
6128 * @brief Common processing for a big number tag.
6129 *
6130 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
6131 * @param[in] pItem The item with the date.
6132 * @param[out] pBignumber The returned big number
6133 * @param[out] pbIsNegative The returned sign of the big number.
6134 *
6135 * Common processing for the big number tag. Mostly make sure
6136 * the tag content is correct and copy forward any further other tag
6137 * numbers.
6138 */
6139static void
6140QCBORDecode_Private_BigNumberRawMain(QCBORDecodeContext *pMe,
6141 const uint8_t uTagRequirement,
6142 QCBORItem *pItem,
6143 UsefulBufC *pBignumber,
6144 bool *pbIsNegative,
6145 size_t uOffset)
6146{
6147 QCBORDecode_Private_ProcessTagItemMulti(pMe,
6148 pItem,
6149 uTagRequirement,
6150 QCBORDecode_Private_BigNumberTypesNoPreferred,
6151 QCBORDecode_Private_BigNumberTagNumbers,
6152 QCBORDecode_StringsTagCB,
6153 uOffset);
6154 if(pMe->uLastError) {
6155 return;
6156 }
6157
6158 if(pItem->uDataType == QCBOR_TYPE_POSBIGNUM) {
6159 *pbIsNegative = false;
6160 } else if(pItem->uDataType == QCBOR_TYPE_NEGBIGNUM) {
6161 *pbIsNegative = true;
6162 }
6163 *pBignumber = pItem->val.bigNum;
6164}
6165
6166
6167static void
6168QCBORDecode_Private_BigNumberNoPreferredMain(QCBORDecodeContext *pMe,
6169 const uint8_t uTagRequirement,
6170 QCBORItem *pItem,
6171 const size_t uOffset,
6172 UsefulBuf BigNumberBuf,
6173 UsefulBufC *pBigNumber,
6174 bool *pbIsNegative)
6175{
6176 QCBORDecode_Private_ProcessTagItemMulti(pMe,
6177 pItem,
6178 uTagRequirement,
6179 QCBORDecode_Private_BigNumberTypesNoPreferred,
6180 QCBORDecode_Private_BigNumberTagNumbers,
6181 QCBORDecode_StringsTagCB,
6182 uOffset);
6183 if(pMe->uLastError) {
6184 return;
6185 }
6186
6187 pMe->uLastError = (uint8_t)QCBORDecode_ProcessBigNumberNoPreferred(*pItem, BigNumberBuf, pBigNumber, pbIsNegative);
6188}
6189
6190
6191static void
6192QCBORDecode_Private_BigNumberMain(QCBORDecodeContext *pMe,
6193 const uint8_t uTagRequirement,
6194 QCBORItem *pItem,
6195 const size_t uOffset,
6196 UsefulBuf BigNumberBuf,
6197 UsefulBufC *pBigNumber,
6198 bool *pbIsNegative)
6199{
6200 QCBORDecode_Private_ProcessTagItemMulti(pMe,
6201 pItem,
6202 uTagRequirement,
6203 QCBORDecode_Private_BigNumberTypes,
6204 QCBORDecode_Private_BigNumberTagNumbers,
6205 QCBORDecode_StringsTagCB,
6206 uOffset);
6207 if(pMe->uLastError) {
6208 return;
6209 }
6210
6211 pMe->uLastError = (uint8_t)QCBORDecode_ProcessBigNumber(*pItem, BigNumberBuf, pBigNumber, pbIsNegative);
6212}
6213
6214
6215/*
6216 * Public function, see header qcbor/qcbor_decode.h
6217 */
6218void
6219QCBORDecode_GetTBigNumber(QCBORDecodeContext *pMe,
6220 const uint8_t uTagRequirement,
6221 UsefulBuf BigNumberBuf,
6222 UsefulBufC *pBigNumber,
6223 bool *pbIsNegative)
6224{
6225 QCBORItem Item;
6226 size_t uOffset;
6227
6228 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
6229 QCBORDecode_Private_BigNumberMain(pMe, uTagRequirement, &Item, uOffset, BigNumberBuf, pBigNumber, pbIsNegative);
6230}
6231
6232/*
6233 * Public function, see header qcbor/qcbor_decode.h
6234 */
6235void
6236QCBORDecode_GetTBigNumberInMapN(QCBORDecodeContext *pMe,
6237 const int64_t nLabel,
6238 const uint8_t uTagRequirement,
6239 UsefulBuf BigNumberBuf,
6240 UsefulBufC *pBigNumber,
6241 bool *pbIsNegative)
6242{
6243 QCBORItem Item;
6244 size_t uOffset;
6245
6246 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
6247 QCBORDecode_Private_BigNumberMain(pMe,
6248 uTagRequirement,
6249 &Item,
6250 uOffset,
6251 BigNumberBuf,
6252 pBigNumber,
6253 pbIsNegative);
6254}
6255
6256/*
6257 * Public function, see header qcbor/qcbor_decode.h
6258 */
6259void
6260QCBORDecode_GetTBigNumberInMapSZ(QCBORDecodeContext *pMe,
6261 const char *szLabel,
6262 const uint8_t uTagRequirement,
6263 UsefulBuf BigNumberBuf,
6264 UsefulBufC *pBigNumber,
6265 bool *pbIsNegative)
6266{
6267 QCBORItem Item;
6268 size_t uOffset;
6269
6270 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
6271 QCBORDecode_Private_BigNumberMain(pMe,
6272 uTagRequirement,
6273 &Item,
6274 uOffset,
6275 BigNumberBuf,
6276 pBigNumber,
6277 pbIsNegative);
6278}
6279
6280
6281/*
6282 * Public function, see header qcbor/qcbor_decode.h
6283 */
6284void
6285QCBORDecode_GetTBigNumberNoPreferred(QCBORDecodeContext *pMe,
6286 const uint8_t uTagRequirement,
6287 UsefulBuf BigNumberBuf,
6288 UsefulBufC *pBigNumber,
6289 bool *pbIsNegative)
6290{
6291 QCBORItem Item;
6292 size_t uOffset;
6293
6294 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
6295 QCBORDecode_Private_BigNumberNoPreferredMain(pMe, uTagRequirement, &Item, uOffset, BigNumberBuf, pBigNumber, pbIsNegative);
6296}
6297
6298/*
6299 * Public function, see header qcbor/qcbor_decode.h
6300 */
6301void
6302QCBORDecode_GetTBigNumberNoPreferredInMapN(QCBORDecodeContext *pMe,
6303 const int64_t nLabel,
6304 const uint8_t uTagRequirement,
6305 UsefulBuf BigNumberBuf,
6306 UsefulBufC *pBigNumber,
6307 bool *pbIsNegative)
6308{
6309 QCBORItem Item;
6310 size_t uOffset;
6311
6312 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
6313 QCBORDecode_Private_BigNumberNoPreferredMain(pMe, uTagRequirement, &Item, uOffset, BigNumberBuf, pBigNumber, pbIsNegative);
6314
6315}
6316
6317/*
6318 * Public function, see header qcbor/qcbor_decode.h
6319 */
6320void
6321QCBORDecode_GetTBigNumberNoPreferredInMapSZ(QCBORDecodeContext *pMe,
6322 const char *szLabel,
6323 const uint8_t uTagRequirement,
6324 UsefulBuf BigNumberBuf,
6325 UsefulBufC *pBigNumber,
6326 bool *pbIsNegative)
6327{
6328 QCBORItem Item;
6329 size_t uOffset;
6330
6331 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
6332 QCBORDecode_Private_BigNumberNoPreferredMain(pMe, uTagRequirement, &Item, uOffset, BigNumberBuf, pBigNumber, pbIsNegative);
6333}
6334
6335
6336
6337/*
6338 * Public function, see header qcbor/qcbor_spiffy_decode.h
6339 */
6340void
6341QCBORDecode_GetTBigNumberRaw(QCBORDecodeContext *pMe,
6342 const uint8_t uTagRequirement,
6343 UsefulBufC *pBignumber,
6344 bool *pbIsNegative)
6345{
6346 QCBORItem Item;
6347 size_t uOffset;
6348
6349 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
6350 QCBORDecode_Private_BigNumberRawMain(pMe,
6351 uTagRequirement,
6352 &Item,
6353 pBignumber,
6354 pbIsNegative,
6355 uOffset);
6356}
6357
6358/*
6359 * Public function, see header qcbor/qcbor_spiffy_decode.h
6360 */
6361void
6362QCBORDecode_GetTBigNumberRawInMapN(QCBORDecodeContext *pMe,
6363 const int64_t nLabel,
6364 const uint8_t uTagRequirement,
6365 UsefulBufC *pBigNumber,
6366 bool *pbIsNegative)
6367{
6368 QCBORItem Item;
6369 size_t uOffset;
6370
6371 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
6372 QCBORDecode_Private_BigNumberRawMain(pMe,
6373 uTagRequirement,
6374 &Item,
6375 pBigNumber,
6376 pbIsNegative,
6377 uOffset);
6378}
6379
6380/*
6381 * Public function, see header qcbor/qcbor_spiffy_decode.h
6382 */
6383void
6384QCBORDecode_GetTBigNumberRawInMapSZ(QCBORDecodeContext *pMe,
6385 const char *szLabel,
6386 const uint8_t uTagRequirement,
6387 UsefulBufC *pBigNumber,
6388 bool *pbIsNegative)
6389{
6390 QCBORItem Item;
6391 size_t uOffset;
6392
6393 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
6394 QCBORDecode_Private_BigNumberRawMain(pMe,
6395 uTagRequirement,
6396 &Item,
6397 pBigNumber,
6398 pbIsNegative,
6399 uOffset);
6400}
6401
6402
6403#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
6404
6405
6406// TODO: relocate these notes?
Laurence Lundblade37286c02022-09-03 10:05:02 -07006407/* Some notes from the work to disable tags.
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006408 * Some are out of date since tag refactoring.
Laurence Lundblade37286c02022-09-03 10:05:02 -07006409 *
6410 * The API for big floats and decimal fractions seems good.
6411 * If there's any issue with it it's that the code size to
6412 * implement is a bit large because of the conversion
6413 * to/from int and bignum that is required. There is no API
6414 * that doesn't do the conversion so dead stripping will never
6415 * leave that code out.
6416 *
6417 * The implementation itself seems correct, but not as clean
6418 * and neat as it could be. It could probably be smaller too.
6419 *
6420 * The implementation has three main parts / functions
6421 * - The decoding of the array of two
6422 * - All the tag and type checking for the various API functions
6423 * - Conversion to/from bignum and int
6424 *
6425 * The type checking seems like it wastes the most code for
6426 * what it needs to do.
6427 *
6428 * The inlining for the conversion is probably making the
6429 * overall code base larger.
6430 *
6431 * The tests cases could be organized a lot better and be
6432 * more thorough.
6433 *
6434 * Seems also like there could be more common code in the
6435 * first tier part of the public API. Some functions only
6436 * vary by a TagSpec.
6437 */
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006438
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006439
6440static const uint8_t QCBORDecode_Private_DecimalFractionTypes[] = {
6441 QCBOR_TYPE_DECIMAL_FRACTION,
6442 QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
6443 QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM,
Laurence Lundblade68769332024-11-03 13:09:20 -08006444 QCBOR_TYPE_DECIMAL_FRACTION_POS_U64,
6445 QCBOR_TYPE_DECIMAL_FRACTION_NEG_U64,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006446 QCBOR_TYPE_NONE};
6447
6448static const uint8_t QCBORDecode_Private_BigFloatTypes[] = {
6449 QCBOR_TYPE_BIGFLOAT,
6450 QCBOR_TYPE_BIGFLOAT_POS_BIGNUM,
6451 QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM,
Laurence Lundblade68769332024-11-03 13:09:20 -08006452 QCBOR_TYPE_BIGFLOAT_POS_U64,
6453 QCBOR_TYPE_BIGFLOAT_NEG_U64,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006454 QCBOR_TYPE_NONE};
6455
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006456/**
Laurence Lundblade68769332024-11-03 13:09:20 -08006457 * @brief Common processor for exponent and int64_t mantissa.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006458 *
6459 * @param[in] pMe The decode context.
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006460 * @param[in] uTagRequirement Whether tag number must be present or not.
6461 * @param[in] uTagNumber The tag number for which content is expected.
6462 * @param[in] uOffset Cursor offset for tag number consumption checking.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006463 * @param[in] pItem The data item to process.
6464 * @param[out] pnMantissa The returned mantissa as an int64_t.
6465 * @param[out] pnExponent The returned exponent as an int64_t.
6466 *
6467 * This handles exponent and mantissa for base 2 and 10. This
6468 * is limited to a mantissa that is an int64_t. See also
6469 * QCBORDecode_Private_ProcessExpMantissaBig().
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006470 *
6471 * On output, the item is always a fully decoded decimal fraction or
6472 * big float.
6473 *
Laurence Lundblade68769332024-11-03 13:09:20 -08006474 * This errors out if the input tag and type aren't as required.
6475 *
6476 * This always provides the correctly offset mantissa, even when the
6477 * input CBOR is a negative big number. This works the
6478 * same in QCBOR v1 and v2.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006479 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006480static void
Laurence Lundblade68769332024-11-03 13:09:20 -08006481QCBORDecode_Private_ExpIntMantissaMain(QCBORDecodeContext *pMe,
6482 const uint8_t uTagRequirement,
6483 const uint64_t uTagNumber,
6484 const size_t uOffset,
6485 QCBORItem *pItem,
6486 int64_t *pnMantissa,
6487 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006488{
Laurence Lundblade68769332024-11-03 13:09:20 -08006489 QCBORError uErr;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006490 const uint8_t *qTypes;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006491
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07006492 if(pMe->uLastError) {
6493 return;
6494 }
6495
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006496 if(uTagNumber == CBOR_TAG_BIGFLOAT) {
6497 qTypes = QCBORDecode_Private_BigFloatTypes;
6498 } else {
6499 qTypes = QCBORDecode_Private_DecimalFractionTypes;
6500 }
6501
6502 QCBORDecode_Private_ProcessTagItem(pMe,
6503 pItem,
6504 uTagRequirement,
6505 qTypes,
6506 uTagNumber,
6507 QCBORDecode_ExpMantissaTagCB,
6508 uOffset);
6509
6510 if(pMe->uLastError != QCBOR_SUCCESS) {
6511 return;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006512 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006513
Laurence Lundblade68769332024-11-03 13:09:20 -08006514 uErr = QCBOR_SUCCESS;
Laurence Lundblade9b334962020-08-27 10:55:53 -07006515 switch (pItem->uDataType) {
6516
6517 case QCBOR_TYPE_DECIMAL_FRACTION:
6518 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade9b334962020-08-27 10:55:53 -07006519 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006520 *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
Laurence Lundblade9b334962020-08-27 10:55:53 -07006521 break;
6522
Laurence Lundblade37286c02022-09-03 10:05:02 -07006523#ifndef QCBOR_DISABLE_TAGS
6524 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006525 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
6526 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
6527 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade05369de2024-11-17 17:00:28 -08006528 uErr = QCBORDecode_Private_PositiveBigNumberToInt(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006529 break;
6530
6531 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
6532 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
6533 *pnExponent = pItem->val.expAndMantissa.nExponent;
Laurence Lundblade05369de2024-11-17 17:00:28 -08006534 uErr = QCBORDecode_Private_NegativeBigNumberToInt(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
Laurence Lundblade9b334962020-08-27 10:55:53 -07006535 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006536#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundblade9b334962020-08-27 10:55:53 -07006537
Laurence Lundblade68769332024-11-03 13:09:20 -08006538 case QCBOR_TYPE_BIGFLOAT_NEG_U64:
6539 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_U64:
6540 case QCBOR_TYPE_BIGFLOAT_POS_U64:
6541 case QCBOR_TYPE_DECIMAL_FRACTION_POS_U64:
6542 uErr = QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
6543 break;
6544
Laurence Lundblade9b334962020-08-27 10:55:53 -07006545 default:
6546 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
6547 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006548
Laurence Lundblade68769332024-11-03 13:09:20 -08006549 pMe->uLastError = (uint8_t)uErr;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006550}
6551
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006552static void
Laurence Lundblade68769332024-11-03 13:09:20 -08006553QCBORDecode_Private_ExpBigMantissaRawMain(QCBORDecodeContext *pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006554 const uint8_t uTagRequirement,
6555 const uint64_t uTagNumber,
6556 const size_t uOffset,
6557 QCBORItem *pItem,
6558 const UsefulBuf BufferForMantissa,
6559 UsefulBufC *pMantissa,
6560 bool *pbIsNegative,
6561 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006562{
Laurence Lundblade033574f2024-11-03 17:42:35 -08006563 QCBORError uErr;
6564 uint64_t uMantissa;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006565 const uint8_t *qTypes;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006566
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006567 if(pMe->uLastError) {
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07006568 return;
6569 }
6570
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006571 if(uTagNumber == CBOR_TAG_BIGFLOAT) {
6572 qTypes = QCBORDecode_Private_BigFloatTypes;
6573 } else {
6574 qTypes = QCBORDecode_Private_DecimalFractionTypes;
6575 }
6576
6577 QCBORDecode_Private_ProcessTagItem(pMe,
6578 pItem,
6579 uTagRequirement,
6580 qTypes,
6581 uTagNumber,
6582 QCBORDecode_ExpMantissaTagCB,
6583 uOffset);
6584
6585 if(pMe->uLastError != QCBOR_SUCCESS) {
6586 return;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006587 }
6588
Laurence Lundblade68769332024-11-03 13:09:20 -08006589 uErr = QCBOR_SUCCESS;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006590
6591 switch (pItem->uDataType) {
6592
6593 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006594 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006595 if(pItem->val.expAndMantissa.Mantissa.nInt >= 0) {
6596 uMantissa = (uint64_t)pItem->val.expAndMantissa.Mantissa.nInt;
6597 *pbIsNegative = false;
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006598 } else {
Laurence Lundblade68769332024-11-03 13:09:20 -08006599 if(pItem->val.expAndMantissa.Mantissa.nInt != INT64_MIN) {
6600 uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt;
6601 } else {
6602 /* Can't negate like above when int64_t is INT64_MIN because it
6603 * will overflow. See ExponentNN() */
6604 uMantissa = (uint64_t)INT64_MAX+1;
6605 }
Laurence Lundblade4e808ba2022-12-29 12:45:20 -07006606 *pbIsNegative = true;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006607 }
Laurence Lundblade68769332024-11-03 13:09:20 -08006608 /* Reverse the offset by 1 for type 1 negative value to be consistent
6609 * with big num case below which don't offset because it requires
6610 * big number arithmetic. This is a bug fix for QCBOR v1.5.
6611 */
6612 uMantissa--;
Laurence Lundblade05369de2024-11-17 17:00:28 -08006613 *pMantissa = QCBORDecode_Private_UIntToBigNumber(uMantissa, BufferForMantissa);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006614 *pnExponent = pItem->val.expAndMantissa.nExponent;
6615 break;
6616
Laurence Lundblade37286c02022-09-03 10:05:02 -07006617#ifndef QCBOR_DISABLE_TAGS
6618 /* If tags are disabled, mantissas can never be big nums */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006619 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006620 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006621 *pnExponent = pItem->val.expAndMantissa.nExponent;
6622 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6623 *pbIsNegative = false;
6624 break;
6625
6626 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006627 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006628 *pnExponent = pItem->val.expAndMantissa.nExponent;
6629 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
6630 *pbIsNegative = true;
6631 break;
Laurence Lundblade37286c02022-09-03 10:05:02 -07006632#endif /* QCBOR_DISABLE_TAGS */
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006633
6634 default:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006635 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006636 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006637
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006638 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006639}
6640
6641
Laurence Lundblade68769332024-11-03 13:09:20 -08006642/**
6643 * @brief Decode exponent and mantissa into a big number with negative offset of 1.
6644 *
6645 * @param[in] pMe The decode context.
6646 * @param[in] uTagRequirement Whether a tag number must be present or not.
6647 * @param[in] pItem Item to decode and convert.
6648 * @param[in] BufferForMantissa Buffer to output mantissa into.
6649 * @param[out] pMantissa The output mantissa.
6650 * @param[out] pbIsNegative The sign of the output.
6651 * @param[out] pnExponent The mantissa of the output.
6652 *
6653 * This is the common processing of a decimal fraction or a big float
6654 * into a big number. This will decode and consume all the CBOR items
6655 * that make up the decimal fraction or big float.
6656 *
6657 * This performs the subtraction of 1 from the negative value so the
6658 * caller doesn't need to. This links more object code than QCBORDecode_Private_ProcessExpMantissaBig().
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006659 */
Laurence Lundblade68769332024-11-03 13:09:20 -08006660static void
6661QCBORDecode_Private_ExpBigMantissaMain(QCBORDecodeContext *pMe,
6662 const uint8_t uTagRequirement,
6663 const uint64_t uTagNumber,
6664 const size_t uOffset,
6665 QCBORItem *pItem,
6666 const UsefulBuf BufferForMantissa,
6667 UsefulBufC *pMantissa,
6668 bool *pbIsNegative,
6669 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006670{
Laurence Lundblade68769332024-11-03 13:09:20 -08006671 QCBORError uErr;
6672 QCBORItem TempMantissa;
6673 const uint8_t *qTypes;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006674
Laurence Lundblade68769332024-11-03 13:09:20 -08006675 if(pMe->uLastError) {
6676 return;
6677 }
6678
6679 if(uTagNumber == CBOR_TAG_BIGFLOAT) {
6680 qTypes = QCBORDecode_Private_BigFloatTypes;
6681 } else {
6682 qTypes = QCBORDecode_Private_DecimalFractionTypes;
6683 }
6684
6685 QCBORDecode_Private_ProcessTagItem(pMe,
6686 pItem,
6687 uTagRequirement,
6688 qTypes,
6689 uTagNumber,
6690 QCBORDecode_ExpMantissaTagCB,
6691 uOffset);
6692
6693 if(pMe->uLastError != QCBOR_SUCCESS) {
6694 return;
6695 }
6696
6697 memset(&TempMantissa, 0, sizeof(TempMantissa));
6698
6699 switch (pItem->uDataType) {
6700
6701 case QCBOR_TYPE_DECIMAL_FRACTION:
6702 case QCBOR_TYPE_BIGFLOAT:
6703 TempMantissa.uDataType = QCBOR_TYPE_INT64;
6704 TempMantissa.val.int64 = pItem->val.expAndMantissa.Mantissa.nInt;
6705 break;
6706
6707 case QCBOR_TYPE_DECIMAL_FRACTION_POS_U64:
6708 case QCBOR_TYPE_BIGFLOAT_POS_U64:
6709 TempMantissa.uDataType = QCBOR_TYPE_UINT64;
6710 TempMantissa.val.uint64 = pItem->val.expAndMantissa.Mantissa.uInt;
6711 break;
6712
6713 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_U64:
6714 case QCBOR_TYPE_BIGFLOAT_NEG_U64:
6715 TempMantissa.uDataType = QCBOR_TYPE_65BIT_NEG_INT;
6716 TempMantissa.val.uint64 = pItem->val.expAndMantissa.Mantissa.uInt;
6717 break;
6718
6719#ifndef QCBOR_DISABLE_TAGS
6720 /* If tags are disabled, mantissas can never be big nums */
6721 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
6722 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
6723 TempMantissa.uDataType = QCBOR_TYPE_BYTE_STRING;
6724 TempMantissa.val.bigNum = pItem->val.expAndMantissa.Mantissa.bigNum;
6725 *pbIsNegative = false;
6726 break;
6727
6728 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
6729 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
6730 TempMantissa.uDataType = QCBOR_TYPE_BYTE_STRING;
6731 TempMantissa.val.bigNum = pItem->val.expAndMantissa.Mantissa.bigNum;
6732 *pbIsNegative = true;
6733 break;
6734#endif /* ! QCBOR_DISABLE_TAGS */
6735 }
6736
6737 *pnExponent = pItem->val.expAndMantissa.nExponent;
6738 uErr = QCBORDecode_ProcessBigNumber(TempMantissa, BufferForMantissa, pMantissa, pbIsNegative);
6739
6740 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006741}
6742
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006743
6744/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006745 * Public function, see header qcbor/qcbor_decode.h file
6746 */
6747void
Laurence Lundblade68769332024-11-03 13:09:20 -08006748QCBORDecode_GetTDecimalFraction(QCBORDecodeContext *pMe,
6749 const uint8_t uTagRequirement,
6750 int64_t *pnMantissa,
6751 int64_t *pnExponent)
6752{
6753 QCBORItem Item;
6754 size_t uOffset;
6755
6756 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
6757 QCBORDecode_Private_ExpIntMantissaMain(pMe,
6758 uTagRequirement,
6759 CBOR_TAG_DECIMAL_FRACTION,
6760 uOffset,
6761 &Item,
6762 pnMantissa,
6763 pnExponent);
6764}
6765
6766
6767/*
6768 * Public function, see header qcbor/qcbor_decode.h file
6769 */
6770void
6771QCBORDecode_GetTDecimalFractionInMapN(QCBORDecodeContext *pMe,
6772 const int64_t nLabel,
6773 const uint8_t uTagRequirement,
6774 int64_t *pnMantissa,
6775 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006776{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006777 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006778 size_t uOffset;
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006779
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006780 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade68769332024-11-03 13:09:20 -08006781 QCBORDecode_Private_ExpIntMantissaMain(pMe,
6782 uTagRequirement,
6783 CBOR_TAG_DECIMAL_FRACTION,
6784 uOffset,
6785 &Item,
6786 pnMantissa,
6787 pnExponent);
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006788
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006789}
6790
6791
6792/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006793 * Public function, see header qcbor/qcbor_decode.h file
6794 */
6795void
Laurence Lundblade68769332024-11-03 13:09:20 -08006796QCBORDecode_GetTDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
6797 const char *szLabel,
6798 const uint8_t uTagRequirement,
6799 int64_t *pnMantissa,
6800 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006801{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006802 QCBORItem Item;
6803 size_t uOffset;
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006804
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006805 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade68769332024-11-03 13:09:20 -08006806 QCBORDecode_Private_ExpIntMantissaMain(pMe,
6807 uTagRequirement,
6808 CBOR_TAG_DECIMAL_FRACTION,
6809 uOffset,
6810 &Item,
6811 pnMantissa,
6812 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006813}
6814
6815
6816/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006817 * Public function, see header qcbor/qcbor_decode.h file
6818 */
6819void
Laurence Lundblade68769332024-11-03 13:09:20 -08006820QCBORDecode_GetTDecimalFractionBigMantissa(QCBORDecodeContext *pMe,
6821 const uint8_t uTagRequirement,
6822 const UsefulBuf MantissaBuffer,
6823 UsefulBufC *pMantissa,
6824 bool *pbMantissaIsNegative,
6825 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006826{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006827 QCBORItem Item;
6828 size_t uOffset;
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006829
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006830 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
Laurence Lundblade68769332024-11-03 13:09:20 -08006831 QCBORDecode_Private_ExpBigMantissaMain(pMe,
6832 uTagRequirement,
6833 CBOR_TAG_DECIMAL_FRACTION,
6834 uOffset,
6835 &Item,
6836 MantissaBuffer,
6837 pMantissa,
6838 pbMantissaIsNegative,
6839 pnExponent);
6840}
6841
6842
6843/*
6844 * Public function, see header qcbor/qcbor_decode.h file
6845 */
6846void
6847QCBORDecode_GetTDecimalFractionBigMantissaInMapN(QCBORDecodeContext *pMe,
6848 const int64_t nLabel,
6849 const uint8_t uTagRequirement,
6850 const UsefulBuf BufferForMantissa,
6851 UsefulBufC *pMantissa,
6852 bool *pbIsNegative,
6853 int64_t *pnExponent)
6854{
6855 QCBORItem Item;
6856 size_t uOffset;
6857
6858 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
6859 QCBORDecode_Private_ExpBigMantissaMain(pMe,
6860 uTagRequirement,
6861 CBOR_TAG_DECIMAL_FRACTION,
6862 uOffset,
6863 &Item,
6864 BufferForMantissa,
6865 pMantissa,
6866 pbIsNegative,
6867 pnExponent);
6868}
6869
6870
6871/*
6872 * Public function, see header qcbor/qcbor_decode.h file
6873 */
6874void
6875QCBORDecode_GetTDecimalFractionBigMantissaInMapSZ(QCBORDecodeContext *pMe,
6876 const char *szLabel,
6877 const uint8_t uTagRequirement,
6878 const UsefulBuf BufferForMantissa,
6879 UsefulBufC *pMantissa,
6880 bool *pbIsNegative,
6881 int64_t *pnExponent)
6882{
6883 QCBORItem Item;
6884 size_t uOffset;
6885
6886 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
6887 QCBORDecode_Private_ExpBigMantissaMain(pMe,
6888 uTagRequirement,
6889 CBOR_TAG_DECIMAL_FRACTION,
6890 uOffset,
6891 &Item,
6892 BufferForMantissa,
6893 pMantissa,
6894 pbIsNegative,
6895 pnExponent);
6896}
6897
6898/*
6899 * Public function, see header qcbor/qcbor_decode.h file
6900 */
6901void
6902QCBORDecode_GetTDecimalFractionBigMantissaRaw(QCBORDecodeContext *pMe,
6903 const uint8_t uTagRequirement,
6904 const UsefulBuf MantissaBuffer,
6905 UsefulBufC *pMantissa,
6906 bool *pbMantissaIsNegative,
6907 int64_t *pnExponent)
6908{
6909 QCBORItem Item;
6910 size_t uOffset;
6911
6912 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
6913 QCBORDecode_Private_ExpBigMantissaRawMain(pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006914 uTagRequirement,
6915 CBOR_TAG_DECIMAL_FRACTION,
6916 uOffset,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006917 &Item,
6918 MantissaBuffer,
6919 pMantissa,
6920 pbMantissaIsNegative,
6921 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006922}
6923
6924
6925/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006926 * Public function, see header qcbor/qcbor_decode.h file
6927 */
6928void
Laurence Lundblade68769332024-11-03 13:09:20 -08006929QCBORDecode_GetTDecimalFractionBigMantissaRawInMapN(QCBORDecodeContext *pMe,
6930 const int64_t nLabel,
6931 const uint8_t uTagRequirement,
6932 const UsefulBuf BufferForMantissa,
6933 UsefulBufC *pMantissa,
6934 bool *pbIsNegative,
6935 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07006936{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006937 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006938 size_t uOffset;
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006939
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006940 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade68769332024-11-03 13:09:20 -08006941 QCBORDecode_Private_ExpBigMantissaRawMain(pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006942 uTagRequirement,
6943 CBOR_TAG_DECIMAL_FRACTION,
6944 uOffset,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006945 &Item,
6946 BufferForMantissa,
6947 pMantissa,
6948 pbIsNegative,
6949 pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006950}
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07006951
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07006952
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006953/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006954 * Public function, see header qcbor/qcbor_decode.h file
6955 */
6956void
Laurence Lundblade68769332024-11-03 13:09:20 -08006957QCBORDecode_GetTDecimalFractionBigMantissaRawInMapSZ(QCBORDecodeContext *pMe,
6958 const char *szLabel,
6959 const uint8_t uTagRequirement,
6960 const UsefulBuf BufferForMantissa,
6961 UsefulBufC *pMantissa,
6962 bool *pbIsNegative,
6963 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006964{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006965 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006966 size_t uOffset;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006967
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006968 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade68769332024-11-03 13:09:20 -08006969 QCBORDecode_Private_ExpBigMantissaRawMain(pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006970 uTagRequirement,
6971 CBOR_TAG_DECIMAL_FRACTION,
6972 uOffset,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07006973 &Item,
6974 BufferForMantissa,
6975 pMantissa,
6976 pbIsNegative,
6977 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07006978}
6979
6980
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006981/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07006982 * Public function, see header qcbor/qcbor_decode.h file
6983 */
6984void
Laurence Lundblade68769332024-11-03 13:09:20 -08006985QCBORDecode_GetTBigFloat(QCBORDecodeContext *pMe,
6986 const uint8_t uTagRequirement,
6987 int64_t *pnMantissa,
6988 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07006989{
Laurence Lundblade68769332024-11-03 13:09:20 -08006990 QCBORItem Item;
6991 size_t uOffset;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07006992
Laurence Lundblade721b56e2024-10-22 03:02:04 -07006993 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
Laurence Lundblade68769332024-11-03 13:09:20 -08006994 QCBORDecode_Private_ExpIntMantissaMain(pMe,
6995 uTagRequirement,
6996 CBOR_TAG_BIGFLOAT,
6997 uOffset,
6998 &Item,
6999 pnMantissa,
7000 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007001}
7002
7003
7004/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007005 * Public function, see header qcbor/qcbor_decode.h file
7006 */
7007void
Laurence Lundblade68769332024-11-03 13:09:20 -08007008QCBORDecode_GetTBigFloatInMapN(QCBORDecodeContext *pMe,
7009 const int64_t nLabel,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007010 const uint8_t uTagRequirement,
7011 int64_t *pnMantissa,
7012 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007013{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007014 QCBORItem Item;
7015 size_t uOffset;
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007016
Laurence Lundblade68769332024-11-03 13:09:20 -08007017 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
7018 QCBORDecode_Private_ExpIntMantissaMain(pMe,
7019 uTagRequirement,
7020 CBOR_TAG_BIGFLOAT,
7021 uOffset,
7022 &Item,
7023 pnMantissa,
7024 pnExponent);
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007025}
7026
7027
7028/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007029 * Public function, see header qcbor/qcbor_decode.h file
7030 */
7031void
Laurence Lundblade68769332024-11-03 13:09:20 -08007032QCBORDecode_GetTBigFloatInMapSZ(QCBORDecodeContext *pMe,
7033 const char *szLabel,
7034 const uint8_t uTagRequirement,
7035 int64_t *pnMantissa,
7036 int64_t *pnExponent)
7037{
7038 QCBORItem Item;
7039 size_t uOffset;
7040
7041 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
7042 QCBORDecode_Private_ExpIntMantissaMain(pMe,
7043 uTagRequirement,
7044 CBOR_TAG_BIGFLOAT,
7045 uOffset,
7046 &Item,
7047 pnMantissa,
7048 pnExponent);
7049}
7050
7051
7052/*
7053 * Public function, see header qcbor/qcbor_decode.h file
7054 */
7055void
7056QCBORDecode_GetTBigFloatBigMantissa(QCBORDecodeContext *pMe,
7057 const uint8_t uTagRequirement,
7058 const UsefulBuf MantissaBuffer,
7059 UsefulBufC *pMantissa,
7060 bool *pbMantissaIsNegative,
7061 int64_t *pnExponent)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007062{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007063 QCBORItem Item;
7064 size_t uOffset;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007065
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007066 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
Laurence Lundblade68769332024-11-03 13:09:20 -08007067 QCBORDecode_Private_ExpBigMantissaMain(pMe,
7068 uTagRequirement,
7069 CBOR_TAG_BIGFLOAT,
7070 uOffset,
7071 &Item,
7072 MantissaBuffer,
7073 pMantissa,
7074 pbMantissaIsNegative,
7075 pnExponent);
7076}
7077
7078
7079
7080/*
7081 * Public function, see header qcbor/qcbor_decode.h file
7082 */
7083void
7084QCBORDecode_GetTBigFloatBigMantissaInMapN(QCBORDecodeContext *pMe,
7085 const int64_t nLabel,
7086 const uint8_t uTagRequirement,
7087 const UsefulBuf BufferForMantissa,
7088 UsefulBufC *pMantissa,
7089 bool *pbIsNegative,
7090 int64_t *pnExponent)
7091{
7092 QCBORItem Item;
7093 size_t uOffset;
7094
7095 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
7096 QCBORDecode_Private_ExpBigMantissaMain(pMe,
7097 uTagRequirement,
7098 CBOR_TAG_BIGFLOAT,
7099 uOffset,
7100 &Item,
7101 BufferForMantissa,
7102 pMantissa,
7103 pbIsNegative,
7104 pnExponent);
7105}
7106
7107
7108/*
7109 * Public function, see header qcbor/qcbor_decode.h file
7110 */
7111void
7112QCBORDecode_GetTBigFloatBigMantissaInMapSZ(QCBORDecodeContext *pMe,
7113 const char *szLabel,
7114 const uint8_t uTagRequirement,
7115 const UsefulBuf BufferForMantissa,
7116 UsefulBufC *pMantissa,
7117 bool *pbIsNegative,
7118 int64_t *pnExponent)
7119{
7120 QCBORItem Item;
7121 size_t uOffset;
7122
7123 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
7124 QCBORDecode_Private_ExpBigMantissaMain(pMe,
7125 uTagRequirement,
7126 CBOR_TAG_BIGFLOAT,
7127 uOffset,
7128 &Item,
7129 BufferForMantissa,
7130 pMantissa,
7131 pbIsNegative,
7132 pnExponent);
7133}
7134
7135
Laurence Lundblade05369de2024-11-17 17:00:28 -08007136/*
7137 * Public function, see header qcbor/qcbor_decode.h file
7138 */
Laurence Lundblade68769332024-11-03 13:09:20 -08007139void
7140QCBORDecode_GetTBigFloatBigMantissaRaw(QCBORDecodeContext *pMe,
7141 const uint8_t uTagRequirement,
7142 const UsefulBuf MantissaBuffer,
7143 UsefulBufC *pMantissa,
7144 bool *pbMantissaIsNegative,
7145 int64_t *pnExponent)
7146{
7147 QCBORItem Item;
7148 size_t uOffset;
7149
7150 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
7151 QCBORDecode_Private_ExpBigMantissaRawMain(pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007152 uTagRequirement,
7153 CBOR_TAG_BIGFLOAT,
7154 uOffset,
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07007155 &Item,
7156 MantissaBuffer,
7157 pMantissa,
7158 pbMantissaIsNegative,
7159 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007160}
7161
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007162/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007163 * Public function, see header qcbor/qcbor_decode.h file
7164 */
7165void
Laurence Lundblade68769332024-11-03 13:09:20 -08007166QCBORDecode_GetTBigFloatBigMantissaRawInMapN(QCBORDecodeContext *pMe,
7167 const int64_t nLabel,
7168 const uint8_t uTagRequirement,
7169 const UsefulBuf BufferForMantissa,
7170 UsefulBufC *pMantissa,
7171 bool *pbIsNegative,
7172 int64_t *pnExponent)
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007173{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007174 QCBORItem Item;
7175 size_t uOffset;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007176
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007177 QCBORDecode_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade68769332024-11-03 13:09:20 -08007178 QCBORDecode_Private_ExpBigMantissaRawMain(pMe,
7179 uTagRequirement,
7180 CBOR_TAG_BIGFLOAT,
7181 uOffset,
7182 &Item,
7183 BufferForMantissa,
7184 pMantissa,
7185 pbIsNegative,
7186 pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07007187}
7188
7189
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007190/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07007191 * Public function, see header qcbor/qcbor_decode.h file
7192 */
7193void
Laurence Lundblade68769332024-11-03 13:09:20 -08007194QCBORDecode_GetTBigFloatBigMantissaRawInMapSZ(QCBORDecodeContext *pMe,
7195 const char *szLabel,
7196 const uint8_t uTagRequirement,
7197 const UsefulBuf BufferForMantissa,
7198 UsefulBufC *pMantissa,
7199 bool *pbIsNegative,
7200 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007201{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07007202 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007203 size_t uOffset;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007204
Laurence Lundblade721b56e2024-10-22 03:02:04 -07007205 QCBORDecode_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade68769332024-11-03 13:09:20 -08007206 QCBORDecode_Private_ExpBigMantissaRawMain(pMe,
7207 uTagRequirement,
7208 CBOR_TAG_BIGFLOAT,
7209 uOffset,
7210 &Item,
7211 BufferForMantissa,
7212 pMantissa,
7213 pbIsNegative,
7214 pnExponent);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07007215}
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07007216
Laurence Lundblade68769332024-11-03 13:09:20 -08007217#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007218
7219
Laurence Lundblade05369de2024-11-17 17:00:28 -08007220
7221
7222/**
7223 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
7224 *
7225 * @param[in] pMe The decode context.
7226 * @param[in] uConvertTypes Bit mask list of conversion options.
7227 * @param[out] pnValue Result of the conversion.
7228 * @param[in,out] pItem Temporary space to store Item, returned item.
7229 *
7230 * See QCBORDecode_GetInt64Convert().
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007231 */
7232void
Laurence Lundblade05369de2024-11-17 17:00:28 -08007233QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pMe,
7234 uint32_t uConvertTypes,
7235 int64_t *pnValue,
7236 QCBORItem *pItem)
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007237{
Laurence Lundblade05369de2024-11-17 17:00:28 -08007238 QCBORDecode_VGetNext(pMe, pItem);
7239 if(pMe->uLastError) {
7240 return;
7241 }
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007242
Laurence Lundblade05369de2024-11-17 17:00:28 -08007243 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
7244 uConvertTypes,
7245 pnValue);
7246}
7247
7248/**
7249 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
7250 *
7251 * @param[in] pMe The decode context.
7252 * @param[in] nLabel Label to find in map.
7253 * @param[in] uConvertTypes Bit mask list of conversion options.
7254 * @param[out] pnValue Result of the conversion.
7255 * @param[in,out] pItem Temporary space to store Item, returned item.
7256 *
7257 * See QCBORDecode_GetInt64ConvertInMapN().
7258 */
7259void
7260QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pMe,
7261 int64_t nLabel,
7262 uint32_t uConvertTypes,
7263 int64_t *pnValue,
7264 QCBORItem *pItem)
7265{
7266 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007267 if(pMe->uLastError != QCBOR_SUCCESS) {
7268 return;
7269 }
7270
Laurence Lundblade05369de2024-11-17 17:00:28 -08007271 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
7272 uConvertTypes,
7273 pnValue);
7274}
7275
7276/**
7277 * @brief Almost-public method to decode a number and convert to int64_t (semi-private).
7278 *
7279 * @param[in] pMe The decode context.
7280 * @param[in] szLabel Label to find in map.
7281 * @param[in] uConvertTypes Bit mask list of conversion options.
7282 * @param[out] pnValue Result of the conversion.
7283 * @param[in,out] pItem Temporary space to store Item, returned item.
7284 *
7285 * See QCBORDecode_GetInt64ConvertInMapSZ().
7286 */
7287void
7288QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
7289 const char * szLabel,
7290 uint32_t uConvertTypes,
7291 int64_t *pnValue,
7292 QCBORItem *pItem)
7293{
7294 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
7295 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007296 return;
7297 }
7298
Laurence Lundblade05369de2024-11-17 17:00:28 -08007299 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
7300 uConvertTypes,
7301 pnValue);
7302}
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007303
Laurence Lundblade05369de2024-11-17 17:00:28 -08007304
7305/**
7306 * @brief Convert many number types to an int64_t.
7307 *
7308 * @param[in] pItem The item to convert.
7309 * @param[in] uConvertTypes Bit mask list of conversion options.
7310 * @param[out] pnValue The resulting converted value.
7311 *
7312 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
7313 * in uConvertTypes.
7314 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
7315 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
7316 * or too small.
7317 */
7318static QCBORError
7319QCBOR_Private_Int64ConvertAll(const QCBORItem *pItem,
7320 const uint32_t uConvertTypes,
7321 int64_t *pnValue)
7322{
7323 switch(pItem->uDataType) {
7324
7325 case QCBOR_TYPE_POSBIGNUM:
7326 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
7327 return QCBORDecode_Private_PositiveBigNumberToInt(pItem->val.bigNum, pnValue);
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007328 } else {
Laurence Lundblade05369de2024-11-17 17:00:28 -08007329 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007330 }
7331 break;
7332
Laurence Lundblade05369de2024-11-17 17:00:28 -08007333 case QCBOR_TYPE_NEGBIGNUM:
7334 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
7335 return QCBORDecode_Private_NegativeBigNumberToInt(pItem->val.bigNum, pnValue);
7336 } else {
7337 return QCBOR_ERR_UNEXPECTED_TYPE;
7338 }
7339 break;
7340
7341#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
7342 case QCBOR_TYPE_DECIMAL_FRACTION:
7343 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
7344 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
7345 pItem->val.expAndMantissa.nExponent,
7346 pnValue,
7347 &QCBOR_Private_Exponentitate10);
7348 } else {
7349 return QCBOR_ERR_UNEXPECTED_TYPE;
7350 }
7351 break;
7352
7353 case QCBOR_TYPE_BIGFLOAT:
7354 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
7355 return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
7356 pItem->val.expAndMantissa.nExponent,
7357 pnValue,
7358 QCBOR_Private_Exponentitate2);
7359 } else {
7360 return QCBOR_ERR_UNEXPECTED_TYPE;
7361 }
7362 break;
7363
7364 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
7365 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
7366 int64_t nMantissa;
7367 QCBORError uErr;
7368 uErr = QCBORDecode_Private_PositiveBigNumberToInt(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
7369 if(uErr) {
7370 return uErr;
7371 }
7372 return QCBOR_Private_ExponentiateNN(nMantissa,
7373 pItem->val.expAndMantissa.nExponent,
7374 pnValue,
7375 QCBOR_Private_Exponentitate10);
7376 } else {
7377 return QCBOR_ERR_UNEXPECTED_TYPE;
7378 }
7379 break;
7380
7381 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
7382 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
7383 int64_t nMantissa;
7384 QCBORError uErr;
7385 uErr = QCBORDecode_Private_NegativeBigNumberToInt(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
7386 if(uErr) {
7387 return uErr;
7388 }
7389 return QCBOR_Private_ExponentiateNN(nMantissa,
7390 pItem->val.expAndMantissa.nExponent,
7391 pnValue,
7392 QCBOR_Private_Exponentitate10);
7393 } else {
7394 return QCBOR_ERR_UNEXPECTED_TYPE;
7395 }
7396 break;
7397
7398 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
7399 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
7400 int64_t nMantissa;
7401 QCBORError uErr;
7402 uErr = QCBORDecode_Private_PositiveBigNumberToInt(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
7403 if(uErr) {
7404 return uErr;
7405 }
7406 return QCBOR_Private_ExponentiateNN(nMantissa,
7407 pItem->val.expAndMantissa.nExponent,
7408 pnValue,
7409 QCBOR_Private_Exponentitate2);
7410 } else {
7411 return QCBOR_ERR_UNEXPECTED_TYPE;
7412 }
7413 break;
7414
7415 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
7416 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
7417 int64_t nMantissa;
7418 QCBORError uErr;
7419 uErr = QCBORDecode_Private_NegativeBigNumberToInt(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
7420 if(uErr) {
7421 return uErr;
7422 }
7423 return QCBOR_Private_ExponentiateNN(nMantissa,
7424 pItem->val.expAndMantissa.nExponent,
7425 pnValue,
7426 QCBOR_Private_Exponentitate2);
7427 } else {
7428 return QCBOR_ERR_UNEXPECTED_TYPE;
7429 }
7430 break;
7431#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
7432
7433
7434 default:
7435 return QCBOR_ERR_UNEXPECTED_TYPE; }
7436}
7437
7438
7439/*
7440 * Public function, see header qcbor/qcbor_decode.h file
7441 */
7442void
7443QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe,
7444 const uint32_t uConvertTypes,
7445 int64_t *pnValue)
7446{
7447 QCBORItem Item;
7448
7449 QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item);
7450
7451 if(pMe->uLastError == QCBOR_SUCCESS) {
7452 // The above conversion succeeded
7453 return;
7454 }
7455
7456 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
7457 // The above conversion failed in a way that code below can't correct
7458 return;
7459 }
7460
7461 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
7462 uConvertTypes,
7463 pnValue);
7464}
7465
7466
7467/*
7468 * Public function, see header qcbor/qcbor_decode.h file
7469 */
7470void
7471QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
7472 const int64_t nLabel,
7473 const uint32_t uConvertTypes,
7474 int64_t *pnValue)
7475{
7476 QCBORItem Item;
7477
7478 QCBORDecode_Private_GetInt64ConvertInMapN(pMe,
7479 nLabel,
7480 uConvertTypes,
7481 pnValue,
7482 &Item);
7483
7484 if(pMe->uLastError == QCBOR_SUCCESS) {
7485 // The above conversion succeeded
7486 return;
7487 }
7488
7489 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
7490 // The above conversion failed in a way that code below can't correct
7491 return;
7492 }
7493
7494 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
7495 uConvertTypes,
7496 pnValue);
7497}
7498
7499
7500/*
7501 * Public function, see header qcbor/qcbor_decode.h file
7502 */
7503void
7504QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
7505 const char *szLabel,
7506 const uint32_t uConvertTypes,
7507 int64_t *pnValue)
7508{
7509 QCBORItem Item;
7510 QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe,
7511 szLabel,
7512 uConvertTypes,
7513 pnValue,
7514 &Item);
7515
7516 if(pMe->uLastError == QCBOR_SUCCESS) {
7517 // The above conversion succeeded
7518 return;
7519 }
7520
7521 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
7522 // The above conversion failed in a way that code below can't correct
7523 return;
7524 }
7525
7526 pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
7527 uConvertTypes,
7528 pnValue);
7529}
7530
7531
7532/**
7533 * @brief Convert many number types to an uint64_t.
7534 *
7535 * @param[in] pItem The item to convert.
7536 * @param[in] uConvertTypes Bit mask list of conversion options.
7537 * @param[out] puValue The resulting converted value.
7538 *
7539 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
7540 * in uConvertTypes.
7541 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
7542 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
7543 * or too small.
7544 */
7545static QCBORError
7546QCBOR_Private_ConvertUInt64(const QCBORItem *pItem,
7547 const uint32_t uConvertTypes,
7548 uint64_t *puValue)
7549{
7550 switch(pItem->uDataType) {
7551 case QCBOR_TYPE_DOUBLE:
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007552 case QCBOR_TYPE_FLOAT:
Laurence Lundblade05369de2024-11-17 17:00:28 -08007553#ifndef QCBOR_DISABLE_FLOAT_HW_USE
7554 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
7555 // Can't use llround here because it will not convert values
7556 // greater than INT64_MAX and less than UINT64_MAX that
7557 // need to be converted so it is more complicated.
7558 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
7559 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
7560 if(isnan(pItem->val.dfnum)) {
7561 return QCBOR_ERR_FLOAT_EXCEPTION;
7562 } else if(pItem->val.dfnum < 0) {
7563 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
7564 } else {
7565 double dRounded = round(pItem->val.dfnum);
7566 // See discussion in DecodeDateEpoch() for
7567 // explanation of - 0x7ff
7568 if(dRounded > (double)(UINT64_MAX- 0x7ff)) {
7569 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
7570 }
7571 *puValue = (uint64_t)dRounded;
7572 }
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007573 } else {
Laurence Lundblade05369de2024-11-17 17:00:28 -08007574 if(isnan(pItem->val.fnum)) {
7575 return QCBOR_ERR_FLOAT_EXCEPTION;
7576 } else if(pItem->val.fnum < 0) {
7577 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
7578 } else {
7579 float fRounded = roundf(pItem->val.fnum);
7580 // See discussion in DecodeDateEpoch() for
7581 // explanation of - 0x7ff
7582 if(fRounded > (float)(UINT64_MAX- 0x7ff)) {
7583 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
7584 }
7585 *puValue = (uint64_t)fRounded;
7586 }
7587 }
7588 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
7589 // round() and roundf() shouldn't result in exceptions here, but
7590 // catch them to be robust and thorough. Don't try to
7591 // distinguish between the various exceptions because it seems
7592 // they vary by CPU, compiler and OS.
7593 return QCBOR_ERR_FLOAT_EXCEPTION;
7594 }
7595
7596 } else {
7597 return QCBOR_ERR_UNEXPECTED_TYPE;
7598 }
7599#else
7600 return QCBOR_ERR_HW_FLOAT_DISABLED;
7601#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
7602 break;
7603
7604 case QCBOR_TYPE_INT64:
7605 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
7606 if(pItem->val.int64 >= 0) {
7607 *puValue = (uint64_t)pItem->val.int64;
7608 } else {
7609 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007610 }
7611 } else {
Laurence Lundblade05369de2024-11-17 17:00:28 -08007612 return QCBOR_ERR_UNEXPECTED_TYPE;
7613 }
7614 break;
7615
7616 case QCBOR_TYPE_UINT64:
7617 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
7618 *puValue = pItem->val.uint64;
7619 } else {
7620 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007621 }
7622 break;
7623
Laurence Lundbladed883ad32024-03-23 22:37:37 -07007624 case QCBOR_TYPE_65BIT_NEG_INT:
Laurence Lundblade05369de2024-11-17 17:00:28 -08007625 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
Laurence Lundblade68769332024-11-03 13:09:20 -08007626
7627 default:
7628 return QCBOR_ERR_UNEXPECTED_TYPE;
7629 }
7630
Laurence Lundblade68769332024-11-03 13:09:20 -08007631 return QCBOR_SUCCESS;
7632}
7633
7634
Laurence Lundblade05369de2024-11-17 17:00:28 -08007635/**
7636 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
7637 *
7638 * @param[in] pMe The decode context.
7639 * @param[in] uConvertTypes Bit mask list of conversion options.
7640 * @param[out] puValue Result of the conversion.
7641 * @param[in,out] pItem Temporary space to store Item, returned item.
7642 *
7643 * See QCBORDecode_GetUInt64Convert().
Laurence Lundblade68769332024-11-03 13:09:20 -08007644 */
Laurence Lundblade05369de2024-11-17 17:00:28 -08007645void
7646QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pMe,
7647 const uint32_t uConvertTypes,
7648 uint64_t *puValue,
7649 QCBORItem *pItem)
Laurence Lundblade68769332024-11-03 13:09:20 -08007650{
Laurence Lundblade05369de2024-11-17 17:00:28 -08007651 QCBORDecode_VGetNext(pMe, pItem);
7652 if(pMe->uLastError) {
7653 return;
7654 }
Laurence Lundblade68769332024-11-03 13:09:20 -08007655
Laurence Lundblade05369de2024-11-17 17:00:28 -08007656 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
7657 uConvertTypes,
7658 puValue);
7659}
Laurence Lundblade68769332024-11-03 13:09:20 -08007660
Laurence Lundblade05369de2024-11-17 17:00:28 -08007661
7662/**
7663 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
7664 *
7665 * @param[in] pMe The decode context.
7666 * @param[in] nLabel Label to find in map.
7667 * @param[in] uConvertTypes Bit mask list of conversion options.
7668 * @param[out] puValue Result of the conversion.
7669 * @param[in,out] pItem Temporary space to store Item, returned item.
7670 *
7671 * See QCBORDecode_GetUInt64ConvertInMapN().
7672 */
7673void
7674QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe,
7675 const int64_t nLabel,
7676 const uint32_t uConvertTypes,
7677 uint64_t *puValue,
7678 QCBORItem *pItem)
7679{
7680 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
7681 if(pMe->uLastError != QCBOR_SUCCESS) {
7682 return;
7683 }
7684
7685 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
7686 uConvertTypes,
7687 puValue);
7688}
7689
7690
7691/**
7692 * @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
7693 *
7694 * @param[in] pMe The decode context.
7695 * @param[in] szLabel Label to find in map.
7696 * @param[in] uConvertTypes Bit mask list of conversion options.
7697 * @param[out] puValue Result of the conversion.
7698 * @param[in,out] pItem Temporary space to store Item, returned item.
7699 *
7700 * See QCBORDecode_GetUInt64ConvertInMapSZ().
7701 */
7702void
7703QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
7704 const char *szLabel,
7705 const uint32_t uConvertTypes,
7706 uint64_t *puValue,
7707 QCBORItem *pItem)
7708{
7709 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
7710 if(pMe->uLastError != QCBOR_SUCCESS) {
7711 return;
7712 }
7713
7714 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
7715 uConvertTypes,
7716 puValue);
7717}
7718
7719
7720/**
7721 * @brief Convert many number types to an unt64_t.
7722 *
7723 * @param[in] pItem The item to convert.
7724 * @param[in] uConvertTypes Bit mask list of conversion options.
7725 * @param[out] puValue The resulting converted value.
7726 *
7727 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
7728 * in uConvertTypes.
7729 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
7730 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
7731 * or too small.
7732 */
7733static QCBORError
7734QCBOR_Private_UInt64ConvertAll(const QCBORItem *pItem,
7735 const uint32_t uConvertTypes,
7736 uint64_t *puValue)
7737{
7738 switch(pItem->uDataType) { /* -Wmaybe-uninitialized falsly warns here */
7739
Laurence Lundblade68769332024-11-03 13:09:20 -08007740 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade05369de2024-11-17 17:00:28 -08007741 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
7742 return QCBORDecode_Private_PositiveBigNumberToUInt(pItem->val.bigNum, puValue);
7743 } else {
7744 return QCBOR_ERR_UNEXPECTED_TYPE;
7745 }
7746 break;
7747
Laurence Lundblade68769332024-11-03 13:09:20 -08007748 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade05369de2024-11-17 17:00:28 -08007749 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
7750 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
7751 } else {
7752 return QCBOR_ERR_UNEXPECTED_TYPE;
7753 }
7754 break;
7755
7756#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
7757
7758 case QCBOR_TYPE_DECIMAL_FRACTION:
7759 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
7760 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
7761 pItem->val.expAndMantissa.nExponent,
7762 puValue,
7763 QCBOR_Private_Exponentitate10);
7764 } else {
7765 return QCBOR_ERR_UNEXPECTED_TYPE;
7766 }
7767 break;
7768
7769 case QCBOR_TYPE_BIGFLOAT:
7770 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
7771 return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
7772 pItem->val.expAndMantissa.nExponent,
7773 puValue,
7774 QCBOR_Private_Exponentitate2);
7775 } else {
7776 return QCBOR_ERR_UNEXPECTED_TYPE;
7777 }
7778 break;
7779
7780 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
7781 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
7782 uint64_t uMantissa;
7783 QCBORError uErr;
7784 uErr = QCBORDecode_Private_PositiveBigNumberToUInt(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa);
7785 if(uErr != QCBOR_SUCCESS) {
7786 return uErr;
7787 }
7788 return QCBOR_Private_ExponentitateUU(uMantissa,
7789 pItem->val.expAndMantissa.nExponent,
7790 puValue,
7791 QCBOR_Private_Exponentitate10);
7792 } else {
7793 return QCBOR_ERR_UNEXPECTED_TYPE;
7794 }
7795 break;
7796
7797 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
7798 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
7799 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
7800 } else {
7801 return QCBOR_ERR_UNEXPECTED_TYPE;
7802 }
7803 break;
7804
7805 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
7806 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
7807 uint64_t uMantissa;
7808 QCBORError uErr;
7809 uErr = QCBORDecode_Private_PositiveBigNumberToUInt(pItem->val.expAndMantissa.Mantissa.bigNum,
7810 &uMantissa);
7811 if(uErr != QCBOR_SUCCESS) {
7812 return uErr;
7813 }
7814 return QCBOR_Private_ExponentitateUU(uMantissa,
7815 pItem->val.expAndMantissa.nExponent,
7816 puValue,
7817 QCBOR_Private_Exponentitate2);
7818 } else {
7819 return QCBOR_ERR_UNEXPECTED_TYPE;
7820 }
7821 break;
7822
7823 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
7824 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
7825 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
7826 } else {
7827 return QCBOR_ERR_UNEXPECTED_TYPE;
7828 }
7829 break;
7830#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
7831 default:
7832 return QCBOR_ERR_UNEXPECTED_TYPE;
7833 }
7834}
7835
7836
7837/*
7838 * Public function, see header qcbor/qcbor_decode.h file
7839 */
7840void
7841QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe,
7842 const uint32_t uConvertTypes,
7843 uint64_t *puValue)
7844{
7845 QCBORItem Item;
7846
7847 QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item);
7848
7849 if(pMe->uLastError == QCBOR_SUCCESS) {
7850 // The above conversion succeeded
7851 return;
7852 }
7853
7854 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
7855 // The above conversion failed in a way that code below can't correct
7856 return;
7857 }
7858
7859 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
7860 uConvertTypes,
7861 puValue);
7862}
7863
7864
7865/*
7866 * Public function, see header qcbor/qcbor_decode.h file
7867 */
7868void
7869QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
7870 const int64_t nLabel,
7871 const uint32_t uConvertTypes,
7872 uint64_t *puValue)
7873{
7874 QCBORItem Item;
7875
7876 QCBORDecode_Private_GetUInt64ConvertInMapN(pMe,
7877 nLabel,
7878 uConvertTypes,
7879 puValue,
7880 &Item);
7881
7882 if(pMe->uLastError == QCBOR_SUCCESS) {
7883 // The above conversion succeeded
7884 return;
7885 }
7886
7887 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
7888 // The above conversion failed in a way that code below can't correct
7889 return;
7890 }
7891
7892 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
7893 uConvertTypes,
7894 puValue);
7895}
7896
7897
7898/*
7899 * Public function, see header qcbor/qcbor_decode.h file
7900 */
7901void
7902QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
7903 const char *szLabel,
7904 const uint32_t uConvertTypes,
7905 uint64_t *puValue)
7906{
7907 QCBORItem Item;
7908 QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe,
7909 szLabel,
7910 uConvertTypes,
7911 puValue,
7912 &Item);
7913
7914 if(pMe->uLastError == QCBOR_SUCCESS) {
7915 // The above conversion succeeded
7916 return;
7917 }
7918
7919 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
7920 // The above conversion failed in a way that code below can't correct
7921 return;
7922 }
7923
7924 pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
7925 uConvertTypes,
7926 puValue);
7927}
7928
7929
7930
7931
7932#ifndef USEFULBUF_DISABLE_ALL_FLOAT
7933/**
7934 * @brief Basic conversions to a double.
7935 *
7936 * @param[in] pItem The item to convert
7937 * @param[in] uConvertTypes Bit flags indicating source types for conversion
7938 * @param[out] pdValue The value converted to a double
7939 *
7940 * This does the conversions that don't need much object code,
7941 * the conversions from int, uint and float to double.
7942 *
7943 * See QCBOR_Private_DoubleConvertAll() for the full set
7944 * of conversions.
7945 */
7946static QCBORError
7947QCBOR_Private_ConvertDouble(const QCBORItem *pItem,
7948 const uint32_t uConvertTypes,
7949 double *pdValue)
7950{
7951 switch(pItem->uDataType) {
7952 case QCBOR_TYPE_FLOAT:
7953#ifndef QCBOR_DISABLE_FLOAT_HW_USE
7954 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
7955 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
7956 // Simple cast does the job.
7957 *pdValue = (double)pItem->val.fnum;
7958 } else {
7959 return QCBOR_ERR_UNEXPECTED_TYPE;
7960 }
7961 }
7962#else /* QCBOR_DISABLE_FLOAT_HW_USE */
7963 return QCBOR_ERR_HW_FLOAT_DISABLED;
7964#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
7965 break;
7966
7967 case QCBOR_TYPE_DOUBLE:
7968 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
7969 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
7970 *pdValue = pItem->val.dfnum;
7971 } else {
7972 return QCBOR_ERR_UNEXPECTED_TYPE;
7973 }
7974 }
Laurence Lundblade68769332024-11-03 13:09:20 -08007975 break;
7976
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007977 case QCBOR_TYPE_INT64:
Laurence Lundblade05369de2024-11-17 17:00:28 -08007978#ifndef QCBOR_DISABLE_FLOAT_HW_USE
7979 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
7980 // A simple cast seems to do the job with no worry of exceptions.
7981 // There will be precision loss for some values.
7982 *pdValue = (double)pItem->val.int64;
7983
7984 } else {
7985 return QCBOR_ERR_UNEXPECTED_TYPE;
7986 }
7987#else
7988 return QCBOR_ERR_HW_FLOAT_DISABLED;
7989#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade14ce2282024-07-24 22:13:35 -07007990 break;
7991
7992 case QCBOR_TYPE_UINT64:
Laurence Lundblade05369de2024-11-17 17:00:28 -08007993#ifndef QCBOR_DISABLE_FLOAT_HW_USE
7994 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
7995 // A simple cast seems to do the job with no worry of exceptions.
7996 // There will be precision loss for some values.
7997 *pdValue = (double)pItem->val.uint64;
7998 } else {
7999 return QCBOR_ERR_UNEXPECTED_TYPE;
8000 }
Laurence Lundblade14ce2282024-07-24 22:13:35 -07008001 break;
Laurence Lundblade05369de2024-11-17 17:00:28 -08008002#else
8003 return QCBOR_ERR_HW_FLOAT_DISABLED;
8004#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade14ce2282024-07-24 22:13:35 -07008005
8006 case QCBOR_TYPE_65BIT_NEG_INT:
Laurence Lundblade05369de2024-11-17 17:00:28 -08008007#ifndef QCBOR_DISABLE_FLOAT_HW_USE
8008 // TODO: don't use float HW. We have the function to do it.
8009 *pdValue = -(double)pItem->val.uint64 - 1;
Laurence Lundblade14ce2282024-07-24 22:13:35 -07008010 break;
Laurence Lundblade05369de2024-11-17 17:00:28 -08008011#else
8012 return QCBOR_ERR_HW_FLOAT_DISABLED;
8013#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade14ce2282024-07-24 22:13:35 -07008014
8015 default:
Laurence Lundblade68769332024-11-03 13:09:20 -08008016 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade14ce2282024-07-24 22:13:35 -07008017 }
8018
Laurence Lundblade05369de2024-11-17 17:00:28 -08008019 return QCBOR_SUCCESS;
Laurence Lundblade14ce2282024-07-24 22:13:35 -07008020}
8021
8022
Laurence Lundblade05369de2024-11-17 17:00:28 -08008023/**
8024 * @brief Almost-public method to decode a number and convert to double (semi-private).
8025 *
8026 * @param[in] pMe The decode context.
8027 * @param[in] uConvertTypes Bit mask list of conversion options
8028 * @param[out] pdValue The output of the conversion.
8029 * @param[in,out] pItem Temporary space to store Item, returned item.
8030 *
8031 * See QCBORDecode_GetDoubleConvert().
8032 */
8033void
8034QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pMe,
8035 const uint32_t uConvertTypes,
8036 double *pdValue,
8037 QCBORItem *pItem)
Laurence Lundblade14ce2282024-07-24 22:13:35 -07008038{
Laurence Lundblade05369de2024-11-17 17:00:28 -08008039 QCBORDecode_VGetNext(pMe, pItem);
Laurence Lundblade721b56e2024-10-22 03:02:04 -07008040 if(pMe->uLastError) {
8041 return;
8042 }
8043
Laurence Lundblade05369de2024-11-17 17:00:28 -08008044 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
8045 uConvertTypes,
8046 pdValue);
Laurence Lundblade68769332024-11-03 13:09:20 -08008047}
8048
8049
Laurence Lundblade05369de2024-11-17 17:00:28 -08008050/**
8051 * @brief Almost-public method to decode a number and convert to double (semi-private).
8052 *
8053 * @param[in] pMe The decode context.
8054 * @param[in] nLabel Label to find in map.
8055 * @param[in] uConvertTypes Bit mask list of conversion options
8056 * @param[out] pdValue The output of the conversion.
8057 * @param[in,out] pItem Temporary space to store Item, returned item.
8058 *
8059 * See QCBORDecode_GetDoubleConvertInMapN().
Laurence Lundblade14ce2282024-07-24 22:13:35 -07008060 */
8061void
Laurence Lundblade05369de2024-11-17 17:00:28 -08008062QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pMe,
Laurence Lundblade68769332024-11-03 13:09:20 -08008063 const int64_t nLabel,
Laurence Lundblade05369de2024-11-17 17:00:28 -08008064 const uint32_t uConvertTypes,
8065 double *pdValue,
8066 QCBORItem *pItem)
Laurence Lundblade68769332024-11-03 13:09:20 -08008067{
Laurence Lundblade05369de2024-11-17 17:00:28 -08008068 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
8069 if(pMe->uLastError != QCBOR_SUCCESS) {
8070 return;
8071 }
Laurence Lundblade68769332024-11-03 13:09:20 -08008072
Laurence Lundblade05369de2024-11-17 17:00:28 -08008073 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
8074 uConvertTypes,
8075 pdValue);
Laurence Lundblade68769332024-11-03 13:09:20 -08008076}
8077
Laurence Lundblade05369de2024-11-17 17:00:28 -08008078
8079/**
8080 * @brief Almost-public method to decode a number and convert to double (semi-private).
8081 *
8082 * @param[in] pMe The decode context.
8083 * @param[in] szLabel Label to find in map.
8084 * @param[in] uConvertTypes Bit mask list of conversion options
8085 * @param[out] pdValue The output of the conversion.
8086 * @param[in,out] pItem Temporary space to store Item, returned item.
8087 *
8088 * See QCBORDecode_GetDoubleConvertInMapSZ().
Laurence Lundblade68769332024-11-03 13:09:20 -08008089 */
8090void
Laurence Lundblade05369de2024-11-17 17:00:28 -08008091QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe,
Laurence Lundblade68769332024-11-03 13:09:20 -08008092 const char *szLabel,
Laurence Lundblade05369de2024-11-17 17:00:28 -08008093 const uint32_t uConvertTypes,
8094 double *pdValue,
8095 QCBORItem *pItem)
Laurence Lundblade68769332024-11-03 13:09:20 -08008096{
Laurence Lundblade05369de2024-11-17 17:00:28 -08008097 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
8098 if(pMe->uLastError != QCBOR_SUCCESS) {
8099 return;
8100 }
Laurence Lundblade68769332024-11-03 13:09:20 -08008101
Laurence Lundblade05369de2024-11-17 17:00:28 -08008102 pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
8103 uConvertTypes,
8104 pdValue);
Laurence Lundblade14ce2282024-07-24 22:13:35 -07008105}
8106
Laurence Lundblade05369de2024-11-17 17:00:28 -08008107
8108/**
8109 * @brief Convert many number types to a double.
8110 *
8111 * @param[in] pItem The item to convert.
8112 * @param[in] uConvertTypes Bit mask list of conversion options.
8113 * @param[out] pdValue The resulting converted value.
8114 *
8115 * @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
8116 * in uConvertTypes.
8117 * @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
8118 * @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
8119 * or too small.
8120 */
8121static QCBORError
8122QCBOR_Private_DoubleConvertAll(const QCBORItem *pItem,
8123 const uint32_t uConvertTypes,
8124 double *pdValue)
8125{
8126#ifndef QCBOR_DISABLE_FLOAT_HW_USE
8127 /*
8128 * What Every Computer Scientist Should Know About Floating-Point Arithmetic
8129 * https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
8130 */
8131 switch(pItem->uDataType) {
8132
8133#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
8134 case QCBOR_TYPE_DECIMAL_FRACTION:
8135 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
8136 // Underflow gives 0, overflow gives infinity
8137 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
8138 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
8139 } else {
8140 return QCBOR_ERR_UNEXPECTED_TYPE;
8141 }
8142 break;
8143
8144 case QCBOR_TYPE_BIGFLOAT:
8145 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
8146 // Underflow gives 0, overflow gives infinity
8147 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
8148 exp2((double)pItem->val.expAndMantissa.nExponent);
8149 } else {
8150 return QCBOR_ERR_UNEXPECTED_TYPE;
8151 }
8152 break;
8153#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
8154
8155 case QCBOR_TYPE_POSBIGNUM:
8156 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
8157 *pdValue = QCBORDecode_Private_BigNumberToDouble(pItem->val.bigNum);
8158 } else {
8159 return QCBOR_ERR_UNEXPECTED_TYPE;
8160 }
8161 break;
8162
8163 case QCBOR_TYPE_NEGBIGNUM:
8164 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
8165 *pdValue = -1-QCBORDecode_Private_BigNumberToDouble(pItem->val.bigNum);
8166 } else {
8167 return QCBOR_ERR_UNEXPECTED_TYPE;
8168 }
8169 break;
8170
8171#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
8172 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
8173 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
8174 double dMantissa = QCBORDecode_Private_BigNumberToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
8175 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
8176 } else {
8177 return QCBOR_ERR_UNEXPECTED_TYPE;
8178 }
8179 break;
8180
8181 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
8182 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
8183 /* Must subtract 1 for CBOR negative integer offset */
8184 double dMantissa = -1-QCBORDecode_Private_BigNumberToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
8185 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
8186 } else {
8187 return QCBOR_ERR_UNEXPECTED_TYPE;
8188 }
8189 break;
8190
8191 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
8192 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
8193 double dMantissa = QCBORDecode_Private_BigNumberToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
8194 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
8195 } else {
8196 return QCBOR_ERR_UNEXPECTED_TYPE;
8197 }
8198 break;
8199
8200 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
8201 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
8202 double dMantissa = -1-QCBORDecode_Private_BigNumberToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
8203 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
8204 } else {
8205 return QCBOR_ERR_UNEXPECTED_TYPE;
8206 }
8207 break;
8208#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
8209
8210 default:
8211 return QCBOR_ERR_UNEXPECTED_TYPE;
8212 }
8213
8214 return QCBOR_SUCCESS;
8215
8216#else
8217 (void)pItem;
8218 (void)uConvertTypes;
8219 (void)pdValue;
8220 return QCBOR_ERR_HW_FLOAT_DISABLED;
8221#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
8222
8223}
8224
8225
8226/*
8227 * Public function, see header qcbor/qcbor_decode.h file
8228 */
8229void
8230QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe,
8231 const uint32_t uConvertTypes,
8232 double *pdValue)
8233{
8234
8235 QCBORItem Item;
8236
8237 QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item);
8238
8239 if(pMe->uLastError == QCBOR_SUCCESS) {
8240 // The above conversion succeeded
8241 return;
8242 }
8243
8244 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
8245 // The above conversion failed in a way that code below can't correct
8246 return;
8247 }
8248
8249 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
8250 uConvertTypes,
8251 pdValue);
8252}
8253
8254
8255/*
8256 * Public function, see header qcbor/qcbor_decode.h file
8257 */
8258void
8259QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe,
8260 const int64_t nLabel,
8261 const uint32_t uConvertTypes,
8262 double *pdValue)
8263{
8264 QCBORItem Item;
8265
8266 QCBORDecode_Private_GetDoubleConvertInMapN(pMe,
8267 nLabel,
8268 uConvertTypes,
8269 pdValue,
8270 &Item);
8271
8272 if(pMe->uLastError == QCBOR_SUCCESS) {
8273 // The above conversion succeeded
8274 return;
8275 }
8276
8277 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
8278 // The above conversion failed in a way that code below can't correct
8279 return;
8280 }
8281
8282 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
8283 uConvertTypes,
8284 pdValue);
8285}
8286
8287
8288/*
8289 * Public function, see header qcbor/qcbor_decode.h file
8290 */
8291void
8292QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe,
8293 const char *szLabel,
8294 const uint32_t uConvertTypes,
8295 double *pdValue)
8296{
8297 QCBORItem Item;
8298 QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe,
8299 szLabel,
8300 uConvertTypes,
8301 pdValue,
8302 &Item);
8303
8304 if(pMe->uLastError == QCBOR_SUCCESS) {
8305 // The above conversion succeeded
8306 return;
8307 }
8308
8309 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
8310 // The above conversion failed in a way that code below can't correct
8311 return;
8312 }
8313
8314 pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
8315 uConvertTypes,
8316 pdValue);
8317}
8318#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
8319
8320
Laurence Lundblade721b56e2024-10-22 03:02:04 -07008321// TODO: re order above functions in tag number order