blob: 7e2abad8b871d8231c854e53adc75d551ab9c6e5 [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
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070040
Laurence Lundblade68cb61c2023-02-12 13:21:44 -080041#if (defined(__GNUC__) && !defined(__clang__))
Laurence Lundblade8e36f812024-01-26 10:59:29 -070042/*
Laurence Lundblade68cb61c2023-02-12 13:21:44 -080043 * This is how the -Wmaybe-uninitialized compiler warning is
44 * handled. It can’t be ignored because some version of gcc enable it
45 * with -Wall which is a common and useful gcc warning option. It also
46 * can’t be ignored because it is the goal of QCBOR to compile clean
47 * out of the box in all environments.
48 *
49 * The big problem with -Wmaybe-uninitialized is that it generates
50 * false positives. It complains things are uninitialized when they
51 * are not. This is because it is not a thorough static analyzer. This
52 * is why “maybe” is in its name. The problem is it is just not
53 * thorough enough to understand all the code (and someone saw fit to
54 * put it in gcc and worse to enable it with -Wall).
55 *
56 * One solution would be to change the code so -Wmaybe-uninitialized
57 * doesn’t get confused, for example adding an unnecessary extra
58 * initialization to zero. (If variables were truly uninitialized, the
59 * correct path is to understand the code thoroughly and set them to
60 * the correct value at the correct time; in essence this is already
61 * done; -Wmaybe-uninitialized just can’t tell). This path is not
62 * taken because it makes the code bigger and is kind of the tail
63 * wagging the dog.
64 *
65 * The solution here is to just use a pragma to disable it for the
66 * whole file. Disabling it for each line makes the code fairly ugly
67 * requiring #pragma to push, pop and ignore. Another reason is the
68 * warnings issues vary by version of gcc and which optimization
69 * optimizations are selected. Another reason is that compilers other
70 * than gcc don’t have -Wmaybe-uninitialized.
71 *
72 * One may ask how to be sure these warnings are false positives and
73 * not real issues. 1) The code has been read carefully to check. 2)
74 * Testing is pretty thorough. 3) This code has been run through
75 * thorough high-quality static analyzers.
76 *
77 * In particularly, most of the warnings are about
78 * Item.Item->uDataType being uninitialized. QCBORDecode_GetNext()
79 * *always* sets this value and test case confirm
80 * this. -Wmaybe-uninitialized just can't tell.
81 *
82 * https://stackoverflow.com/questions/5080848/disable-gcc-may-be-used-uninitialized-on-a-particular-variable
83 */
84#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
Laurence Lundblade8e36f812024-01-26 10:59:29 -070085#endif
Laurence Lundblade68cb61c2023-02-12 13:21:44 -080086
87
Laurence Lundblade8e36f812024-01-26 10:59:29 -070088static bool
89QCBORItem_IsMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -070090{
Laurence Lundblade8e36f812024-01-26 10:59:29 -070091 const uint8_t uDataType = Item.uDataType;
Laurence Lundblade02625d42020-06-25 14:41:41 -070092 return uDataType == QCBOR_TYPE_MAP ||
Laurence Lundbladeec290b82024-06-10 11:10:54 -070093#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
94 uDataType == QCBOR_TYPE_MAP_AS_ARRAY ||
95#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
96 uDataType == QCBOR_TYPE_ARRAY;
Laurence Lundblade02625d42020-06-25 14:41:41 -070097}
98
Laurence Lundblade8e36f812024-01-26 10:59:29 -070099static bool
100QCBORItem_IsEmptyDefiniteLengthMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700101{
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700102 if(!QCBORItem_IsMapOrArray(Item)){
Laurence Lundblade02625d42020-06-25 14:41:41 -0700103 return false;
104 }
105
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700106 if(Item.val.uCount != 0) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700107 return false;
108 }
109 return true;
110}
111
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700112static bool
113QCBORItem_IsIndefiniteLengthMapOrArray(const QCBORItem Item)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700114{
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800115#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700116 if(!QCBORItem_IsMapOrArray(Item)){
Laurence Lundblade02625d42020-06-25 14:41:41 -0700117 return false;
118 }
119
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700120 if(Item.val.uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700121 return false;
122 }
123 return true;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800124#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700125 (void)Item;
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800126 return false;
127#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700128}
129
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700130/* Return true if the labels in Item1 and Item2 are the same.
131 Works only for integer and string labels. Returns false
132 for any other type. */
133static bool
134QCBORItem_MatchLabel(const QCBORItem Item1, const QCBORItem Item2)
135{
136 if(Item1.uLabelType == QCBOR_TYPE_INT64) {
137 if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
138 return true;
139 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700140#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700141 } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
142 if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
143 return true;
144 }
145 } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
146 if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
147 return true;
148 }
149 } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
150 if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
151 return true;
152 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700153#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700154 }
155
156 /* Other label types are never matched */
157 return false;
158}
159
160
161/*
162 Returns true if Item1 and Item2 are the same type
163 or if either are of QCBOR_TYPE_ANY.
164 */
165static bool
166QCBORItem_MatchType(const QCBORItem Item1, const QCBORItem Item2)
167{
168 if(Item1.uDataType == Item2.uDataType) {
169 return true;
170 } else if(Item1.uDataType == QCBOR_TYPE_ANY) {
171 return true;
172 } else if(Item2.uDataType == QCBOR_TYPE_ANY) {
173 return true;
174 }
175 return false;
176}
177
Laurence Lundblade02625d42020-06-25 14:41:41 -0700178
Laurence Lundbladeee851742020-01-08 08:37:05 -0800179/*===========================================================================
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700180 DecodeNesting -- Tracking array/map/sequence/bstr-wrapped nesting
Laurence Lundbladeee851742020-01-08 08:37:05 -0800181 ===========================================================================*/
182
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700183/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800184 * See comments about and typedef of QCBORDecodeNesting in qcbor_private.h,
185 * the data structure all these functions work on.
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700186 */
187
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700188
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700189static uint8_t
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700190DecodeNesting_GetCurrentLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700191{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700192 const ptrdiff_t nLevel = pNesting->pCurrent - &(pNesting->pLevels[0]);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800193 /* Limit in DecodeNesting_Descend against more than
194 * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
Laurence Lundblade02625d42020-06-25 14:41:41 -0700195 */
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700196 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700197}
198
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700199
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700200static uint8_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700201DecodeNesting_GetBoundedModeLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700202{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700203 const ptrdiff_t nLevel = pNesting->pCurrentBounded - &(pNesting->pLevels[0]);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800204 /* Limit in DecodeNesting_Descend against more than
205 * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
Laurence Lundblade02625d42020-06-25 14:41:41 -0700206 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700207 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700208}
209
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700210
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700211static uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700212DecodeNesting_GetMapOrArrayStart(const QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700213{
214 return pNesting->pCurrentBounded->u.ma.uStartOffset;
215}
216
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700217
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700218static bool
Laurence Lundblade085d7952020-07-24 10:26:30 -0700219DecodeNesting_IsBoundedEmpty(const QCBORDecodeNesting *pNesting)
220{
221 if(pNesting->pCurrentBounded->u.ma.uCountCursor == QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
222 return true;
223 } else {
224 return false;
225 }
226}
227
228
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700229static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700230DecodeNesting_IsCurrentAtTop(const QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700231{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700232 if(pNesting->pCurrent == &(pNesting->pLevels[0])) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700233 return true;
234 } else {
235 return false;
236 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700237}
238
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700239
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700240static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700241DecodeNesting_IsCurrentDefiniteLength(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700242{
243 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800244 /* Not a map or array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700245 return false;
246 }
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800247
248#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700249 if(pNesting->pCurrent->u.ma.uCountTotal == QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800250 /* Is indefinite */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700251 return false;
252 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800253
Laurence Lundbladee2c893c2020-12-26 17:41:53 -0800254#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
255
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800256 /* All checks passed; is a definte length map or array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700257 return true;
258}
259
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700260static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700261DecodeNesting_IsCurrentBstrWrapped(const QCBORDecodeNesting *pNesting)
Laurence Lundblade642282a2020-06-23 12:00:33 -0700262{
263 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800264 /* is a byte string */
Laurence Lundblade642282a2020-06-23 12:00:33 -0700265 return true;
266 }
267 return false;
268}
269
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700270
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700271static bool
272DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700273{
274 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
275 return true;
276 }
Laurence Lundblade02625d42020-06-25 14:41:41 -0700277 if(pNesting->pCurrent->u.ma.uStartOffset != QCBOR_NON_BOUNDED_OFFSET) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700278 return true;
279 }
280 return false;
281}
282
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700283
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700284static void
285DecodeNesting_SetMapOrArrayBoundedMode(QCBORDecodeNesting *pNesting, bool bIsEmpty, size_t uStart)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700286{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800287 /* Should be only called on maps and arrays */
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700288 /*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800289 * DecodeNesting_EnterBoundedMode() checks to be sure uStart is not
290 * larger than DecodeNesting_EnterBoundedMode which keeps it less than
291 * uin32_t so the cast is safe.
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700292 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700293 pNesting->pCurrent->u.ma.uStartOffset = (uint32_t)uStart;
Laurence Lundblade085d7952020-07-24 10:26:30 -0700294
295 if(bIsEmpty) {
296 pNesting->pCurrent->u.ma.uCountCursor = QCBOR_COUNT_INDICATES_ZERO_LENGTH;
297 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700298}
299
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700300
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700301static void
302DecodeNesting_ClearBoundedMode(QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700303{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700304 pNesting->pCurrent->u.ma.uStartOffset = QCBOR_NON_BOUNDED_OFFSET;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700305}
306
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700307
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700308static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700309DecodeNesting_IsAtEndOfBoundedLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700310{
311 if(pNesting->pCurrentBounded == NULL) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800312 /* No bounded map or array set up */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700313 return false;
314 }
315 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800316 /* Not a map or array; end of those is by byte count */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700317 return false;
318 }
Laurence Lundblade6ab01fb2020-10-01 13:04:49 -0700319 if(!DecodeNesting_IsCurrentBounded(pNesting)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800320 /* In a traveral at a level deeper than the bounded level */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700321 return false;
322 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800323 /* Works for both definite- and indefinitelength maps/arrays */
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800324 if(pNesting->pCurrentBounded->u.ma.uCountCursor != 0 &&
325 pNesting->pCurrentBounded->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800326 /* Count is not zero, still unconsumed item */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700327 return false;
328 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800329 /* All checks passed, got to the end of an array or map*/
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700330 return true;
331}
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700332
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700333
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700334static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700335DecodeNesting_IsEndOfDefiniteLengthMapOrArray(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700336{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800337 /* Must only be called on map / array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700338 if(pNesting->pCurrent->u.ma.uCountCursor == 0) {
339 return true;
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700340 } else {
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700341 return false;
342 }
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700343}
344
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700345
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700346static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700347DecodeNesting_IsCurrentTypeMap(const QCBORDecodeNesting *pNesting)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700348{
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700349 if(pNesting->pCurrent->uLevelType == CBOR_MAJOR_TYPE_MAP) {
350 return true;
351 } else {
352 return false;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700353 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700354}
355
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700356
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700357static bool
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700358DecodeNesting_IsBoundedType(const QCBORDecodeNesting *pNesting, uint8_t uType)
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700359{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700360 if(pNesting->pCurrentBounded == NULL) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700361 return false;
362 }
Laurence Lundblade02625d42020-06-25 14:41:41 -0700363
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700364 uint8_t uItemDataType = pNesting->pCurrentBounded->uLevelType;
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700365#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700366 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
367 uItemDataType = QCBOR_TYPE_ARRAY;
368 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700369#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade5db34da2024-05-30 03:14:35 -0700370
371 if(uItemDataType != uType) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700372 return false;
373 }
374
375 return true;
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700376}
377
Laurence Lundblade02625d42020-06-25 14:41:41 -0700378
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700379static void
Laurence Lundblade6c8a4442020-06-22 22:16:11 -0700380DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700381{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800382 /* Only call on a definite-length array / map */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700383 pNesting->pCurrent->u.ma.uCountCursor--;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700384}
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700385
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700386
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700387static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700388DecodeNesting_ReverseDecrement(QCBORDecodeNesting *pNesting)
389{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800390 /* Only call on a definite-length array / map */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700391 pNesting->pCurrent->u.ma.uCountCursor++;
392}
393
394
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700395static void
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700396DecodeNesting_Ascend(QCBORDecodeNesting *pNesting)
397{
398 pNesting->pCurrent--;
399}
400
Laurence Lundblade02625d42020-06-25 14:41:41 -0700401
402static QCBORError
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700403DecodeNesting_Descend(QCBORDecodeNesting *pNesting, uint8_t uType)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700404{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800405 /* Error out if nesting is too deep */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700406 if(pNesting->pCurrent >= &(pNesting->pLevels[QCBOR_MAX_ARRAY_NESTING])) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700407 return QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP;
Laurence Lundblade02625d42020-06-25 14:41:41 -0700408 }
409
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800410 /* The actual descend */
Laurence Lundblade02625d42020-06-25 14:41:41 -0700411 pNesting->pCurrent++;
412
413 pNesting->pCurrent->uLevelType = uType;
414
415 return QCBOR_SUCCESS;
416}
417
418
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700419static QCBORError
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800420DecodeNesting_EnterBoundedMapOrArray(QCBORDecodeNesting *pNesting,
421 bool bIsEmpty,
422 size_t uOffset)
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700423{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700424 /*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800425 * Should only be called on map/array.
426 *
427 * Have descended into this before this is called. The job here is
428 * just to mark it in bounded mode.
429 *
430 * Check against QCBOR_MAX_DECODE_INPUT_SIZE make sure that
431 * uOffset doesn't collide with QCBOR_NON_BOUNDED_OFFSET.
432 *
433 * Cast of uOffset to uint32_t for cases where SIZE_MAX < UINT32_MAX.
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700434 */
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -0800435 if((uint32_t)uOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -0700436 return QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700437 }
438
Laurence Lundblade0750fc42020-06-20 21:02:34 -0700439 pNesting->pCurrentBounded = pNesting->pCurrent;
Laurence Lundblade085d7952020-07-24 10:26:30 -0700440
441 DecodeNesting_SetMapOrArrayBoundedMode(pNesting, bIsEmpty, uOffset);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700442
443 return QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700444}
445
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700446
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700447static QCBORError
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700448DecodeNesting_DescendMapOrArray(QCBORDecodeNesting *pNesting,
Laurence Lundbladeb95afec2024-08-26 10:51:28 -0700449 const uint8_t uQCBORType,
450 const uint16_t uCount)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700451{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700452 QCBORError uError = QCBOR_SUCCESS;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700453
454 if(uCount == 0) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800455 /* Nothing to do for empty definite-length arrays. They are just are
456 * effectively the same as an item that is not a map or array.
457 */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700458 goto Done;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800459 /* Empty indefinite-length maps and arrays are handled elsewhere */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700460 }
461
Laurence Lundbladeb95afec2024-08-26 10:51:28 -0700462 /* Rely on check in QCBOR_Private_DecodeArrayOrMap() for definite-length
463 * arrays and maps that are too long */
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700464
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700465 uError = DecodeNesting_Descend(pNesting, uQCBORType);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700466 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700467 goto Done;
468 }
469
Laurence Lundbladeb95afec2024-08-26 10:51:28 -0700470 pNesting->pCurrent->u.ma.uCountCursor = uCount;
471 pNesting->pCurrent->u.ma.uCountTotal = uCount;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700472
473 DecodeNesting_ClearBoundedMode(pNesting);
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700474
475Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700476 return uError;;
477}
478
479
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700480static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700481DecodeNesting_LevelUpCurrent(QCBORDecodeNesting *pNesting)
482{
483 pNesting->pCurrent = pNesting->pCurrentBounded - 1;
484}
485
486
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700487static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700488DecodeNesting_LevelUpBounded(QCBORDecodeNesting *pNesting)
489{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700490 while(pNesting->pCurrentBounded != &(pNesting->pLevels[0])) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700491 pNesting->pCurrentBounded--;
492 if(DecodeNesting_IsCurrentBounded(pNesting)) {
493 break;
494 }
495 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700496}
497
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800498
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700499static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700500DecodeNesting_SetCurrentToBoundedLevel(QCBORDecodeNesting *pNesting)
501{
502 pNesting->pCurrent = pNesting->pCurrentBounded;
503}
504
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700505
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700506static QCBORError
Laurence Lundblade02625d42020-06-25 14:41:41 -0700507DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting,
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700508 uint32_t uEndOffset,
509 uint32_t uStartOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700510{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700511 QCBORError uError;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700512
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700513 uError = DecodeNesting_Descend(pNesting, QCBOR_TYPE_BYTE_STRING);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700514 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700515 goto Done;
516 }
517
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800518 /* Fill in the new byte string level */
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700519 pNesting->pCurrent->u.bs.uSavedEndOffset = uEndOffset;
520 pNesting->pCurrent->u.bs.uBstrStartOffset = uStartOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700521
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800522 /* Bstr wrapped levels are always bounded */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700523 pNesting->pCurrentBounded = pNesting->pCurrent;
524
525Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700526 return uError;;
527}
528
Laurence Lundbladed0304932020-06-27 10:59:38 -0700529
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700530static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700531DecodeNesting_ZeroMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700532{
533 pNesting->pCurrent->u.ma.uCountCursor = 0;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700534}
535
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700536
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700537static void
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800538DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting)
539{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700540 if(pNesting->pCurrent->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
541 pNesting->pCurrentBounded->u.ma.uCountCursor = pNesting->pCurrentBounded->u.ma.uCountTotal;
542 }
Laurence Lundbladeddebabe2020-11-22 11:32:17 -0800543}
544
545
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700546static void
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700547DecodeNesting_Init(QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700548{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700549 /* Assumes that *pNesting has been zero'd before this call. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700550 pNesting->pLevels[0].uLevelType = QCBOR_TYPE_BYTE_STRING;
551 pNesting->pCurrent = &(pNesting->pLevels[0]);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700552}
553
554
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700555static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800556DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting,
557 QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700558{
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700559 *pSave = *pNesting;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700560}
561
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700562
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700563static void
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800564DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting,
565 const QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700566{
567 *pNesting = *pSave;
568}
569
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700570
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700571static uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700572DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700573{
Laurence Lundbladecf41c522021-02-20 10:19:07 -0700574 return pMe->pCurrentBounded->u.bs.uSavedEndOffset;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700575}
576
577
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800578
579
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800580#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladeee851742020-01-08 08:37:05 -0800581/*===========================================================================
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800582 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
583
584 The following four functions are pretty wrappers for invocation of
585 the string allocator supplied by the caller.
586
Laurence Lundbladeee851742020-01-08 08:37:05 -0800587 ===========================================================================*/
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800588
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700589static void
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800590StringAllocator_Free(const QCBORInternalAllocator *pMe, const void *pMem)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800591{
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300592 /* This cast to uintptr_t suppresses the "-Wcast-qual" warnings.
593 * This is the one place where the const needs to be cast away so const can
594 * be use in the rest of the code.
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800595 */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300596 (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, 0);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800597}
598
Laurence Lundbladeee851742020-01-08 08:37:05 -0800599// StringAllocator_Reallocate called with pMem NULL is
600// equal to StringAllocator_Allocate()
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700601static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800602StringAllocator_Reallocate(const QCBORInternalAllocator *pMe,
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800603 const void *pMem,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800604 size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800605{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800606 /* See comment in StringAllocator_Free() */
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300607 return (pMe->pfAllocator)(pMe->pAllocateCxt, (void *)(uintptr_t)pMem, uSize);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800608}
609
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700610static UsefulBuf
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800611StringAllocator_Allocate(const QCBORInternalAllocator *pMe, size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800612{
613 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
614}
615
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700616static void
Laurence Lundblade3a691a02020-12-28 04:15:16 -0800617StringAllocator_Destruct(const QCBORInternalAllocator *pMe)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800618{
Laurence Lundbladeb9702452021-03-08 21:02:57 -0800619 /* See comment in StringAllocator_Free() */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800620 if(pMe->pfAllocator) {
621 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
622 }
623}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800624#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800625
626
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800627
628
Laurence Lundbladeee851742020-01-08 08:37:05 -0800629/*===========================================================================
630 QCBORDecode -- The main implementation of CBOR decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700631
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800632 See qcbor/qcbor_decode.h for definition of the object
633 used here: QCBORDecodeContext
Laurence Lundbladeee851742020-01-08 08:37:05 -0800634 ===========================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700635/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800636 * Public function, see header file
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700637 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700638void
639QCBORDecode_Init(QCBORDecodeContext *pMe,
640 UsefulBufC EncodedCBOR,
Laurence Lundbladed595cb82024-11-22 12:03:13 -0800641 QCBORDecodeMode uConfigFlags)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700642{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800643 memset(pMe, 0, sizeof(QCBORDecodeContext));
644 UsefulInputBuf_Init(&(pMe->InBuf), EncodedCBOR);
645 /* Don't bother with error check on decode mode. If a bad value is
646 * passed it will just act as if the default normal mode of 0 was set.
647 */
Laurence Lundbladed595cb82024-11-22 12:03:13 -0800648 pMe->uDecodeMode = (uint32_t)uConfigFlags;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800649 DecodeNesting_Init(&(pMe->nesting));
650
651 /* Inialize me->auMappedTags to CBOR_TAG_INVALID16. See
652 * GetNext_TaggedItem() and MapTagNumber(). */
653 memset(pMe->auMappedTags, 0xff, sizeof(pMe->auMappedTags));
Laurence Lundblade721b56e2024-10-22 03:02:04 -0700654
655 pMe->uTagNumberCheckOffset = SIZE_MAX;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700656}
657
658
Laurence Lundblade721b56e2024-10-22 03:02:04 -0700659/*
660 * Public function, see header file
661 */
662void
663QCBORDecode_CompatibilityV1(QCBORDecodeContext *pMe)
664{
Laurence Lundbladed595cb82024-11-22 12:03:13 -0800665 pMe->uDecodeMode |= QCBOR_DECODE_ALLOW_UNPROCESSED_TAG_NUMBERS;
Laurence Lundblade721b56e2024-10-22 03:02:04 -0700666#ifndef QCBOR_DISABLE_TAGS
667 QCBORDecode_InstallTagDecoders(pMe, QCBORDecode_TagDecoderTablev1, NULL);
668#endif /* ! QCBOR_DISABLE_TAGS */
669}
670
671
672
673
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800674#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
675
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700676/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800677 * Public function, see header file
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700678 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700679void
680QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
681 QCBORStringAllocate pfAllocateFunction,
682 void *pAllocateContext,
683 bool bAllStrings)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700684{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800685 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
686 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
687 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700688}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -0800689#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700690
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800691
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800692
693
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800694
695
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700696/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800697 * Decoding items is done in six layers, one calling the next one
698 * down. If a layer has no work to do for a particular item, it
699 * returns quickly.
700 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700701 * 1. QCBORDecode_Private_GetNextTagContent - The top layer processes
702 * tagged data items, turning them into the local C representation.
703 * For the most simple it is just associating a QCBOR_TYPE with the
704 * data. For the complex ones that an aggregate of data items, there
705 * is some further decoding and some limited recursion.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800706 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700707 * 2. QCBORDecode_Private_GetNextMapOrArray - This manages the
708 * beginnings and ends of maps and arrays. It tracks descending into
709 * and ascending out of maps/arrays. It processes breaks that
710 * terminate indefinite-length maps and arrays.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800711 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700712 * 3. QCBORDecode_Private_GetNextMapEntry - This handles the combining
713 * of two items, the label and the data, that make up a map entry. It
714 * only does work on maps. It combines the label and data items into
715 * one labeled item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800716 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700717 * 4. QCBORDecode_Private_GetNextTagNumber - This decodes type 6 tag
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800718 * numbers. It turns the tag numbers into bit flags associated with
719 * the data item. No actual decoding of the contents of the tag is
720 * performed here.
721 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700722 * 5. QCBORDecode_Private_GetNextFullString - This assembles the
723 * sub-items that make up an indefinite-length string into one string
724 * item. It uses the string allocator to create contiguous space for
725 * the item. It processes all breaks that are part of
726 * indefinite-length strings.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800727 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700728 * 6. QCBOR_Private_DecodeAtomicDataItem - This decodes the atomic
729 * data items in CBOR. Each atomic data item has a "major type", an
730 * integer "argument" and optionally some content. For text and byte
731 * strings, the content is the bytes that make up the string. These
732 * are the smallest data items that are considered to be well-formed.
733 * The content may also be other data items in the case of aggregate
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800734 * types. They are not handled in this layer.
735 *
Laurence Lundblade0f01ac62024-02-18 23:07:07 -0700736 * This uses about 350 bytes of stack. This number comes from
737 * instrumenting (printf address of stack variables) the code on x86
738 * compiled for size optimization.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700739 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800740
741
742/*
743 * Note about use of int and unsigned variables.
744 *
745 * See http://www.unix.org/whitepapers/64bit.html for reasons int is
746 * used carefully here, and in particular why it isn't used in the
747 * public interface. Also see
748 * https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers
749 *
750 * Int is used for values that need less than 16-bits and would be
751 * subject to integer promotion and result in complaining from static
752 * analyzers.
753 */
754
755
756/**
757 * @brief Decode the CBOR head, the type and argument.
758 *
759 * @param[in] pUInBuf The input buffer to read from.
Laurence Lundbladed595cb82024-11-22 12:03:13 -0800760 * @param[in] uConfigFlags Decode mode flags.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800761 * @param[out] pnMajorType The decoded major type.
762 * @param[out] puArgument The decoded argument.
763 * @param[out] pnAdditionalInfo The decoded Lower 5 bits of initial byte.
764 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -0700765 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved features
766 * @retval QCBOR_ERR_HIT_END Unexpected end of input
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800767 *
768 * This decodes the CBOR "head" that every CBOR data item has. See
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700769 * longer description in QCBOREncode_EncodeHead().
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800770 *
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700771 * This does the network to host byte order conversion. The conversion
772 * here also provides the conversion for floats in addition to that
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800773 * for lengths, tags and integer values.
774 *
775 * The int type is preferred to uint8_t for some variables as this
776 * avoids integer promotions, can reduce code size and makes static
777 * analyzers happier.
778 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700779static QCBORError
Laurence Lundbladed595cb82024-11-22 12:03:13 -0800780QCBOR_Private_DecodeHead(UsefulInputBuf *pUInBuf,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700781#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
Laurence Lundbladed595cb82024-11-22 12:03:13 -0800782 QCBORDecodeMode uConfigFlags,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700783#endif
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700784 int *pnMajorType,
785 uint64_t *puArgument,
786 int *pnAdditionalInfo)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700787{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800788 QCBORError uReturn;
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700789 uint64_t uArgument;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800790
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700791 /* Get and break down initial byte that every CBOR data item has */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800792 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800793 const int nTmpMajorType = nInitialByte >> 5;
794 const int nAdditionalInfo = nInitialByte & 0x1f;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800795
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800796 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800797 /* Need to get 1,2,4 or 8 additional argument bytes. Map
798 * LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length.
799 */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800800 static const uint8_t aIterate[] = {1,2,4,8};
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800801
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800802 /* Loop getting all the bytes in the argument */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800803 uArgument = 0;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800804 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700805 /* This shift-and-add gives the endian conversion. */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800806 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
807 }
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700808
809#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
810 /* If requested, check that argument is in preferred form */
Laurence Lundbladed595cb82024-11-22 12:03:13 -0800811 if(uConfigFlags & QCBOR_DECODE_ONLY_PREFERRED_NUMBERS) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700812 uint64_t uMinArgument;
813
814 if(nAdditionalInfo == LEN_IS_ONE_BYTE) {
815 if(uArgument < 24) {
816 uReturn = QCBOR_ERR_PREFERRED_CONFORMANCE;
817 goto Done;
818 }
819 } else {
820 if(nTmpMajorType != CBOR_MAJOR_TYPE_SIMPLE) {
821 /* Check only if not a floating-point number */
822 int nArgLen = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE - 1];
823 uMinArgument = UINT64_MAX >> ((int)sizeof(uint64_t) - nArgLen) * 8;
824 if(uArgument <= uMinArgument) {
825 uReturn = QCBOR_ERR_PREFERRED_CONFORMANCE;
826 goto Done;
827 }
828 }
829 }
830 }
831#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
832
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800833 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800834 /* The reserved and thus-far unused additional info values */
835 uReturn = QCBOR_ERR_UNSUPPORTED;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800836 goto Done;
837 } else {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700838#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
Laurence Lundbladed595cb82024-11-22 12:03:13 -0800839 if(uConfigFlags & QCBOR_DECODE_NO_INDEF_LENGTH && nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -0700840 uReturn = QCBOR_ERR_PREFERRED_CONFORMANCE;
841 goto Done;
842 }
843#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
844
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800845 /* Less than 24, additional info is argument or 31, an
846 * indefinite-length. No more bytes to get.
847 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800848 uArgument = (uint64_t)nAdditionalInfo;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700849 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800850
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700851 if(UsefulInputBuf_GetError(pUInBuf)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800852 uReturn = QCBOR_ERR_HIT_END;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700853 goto Done;
854 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800855
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800856 /* All successful if arrived here. */
857 uReturn = QCBOR_SUCCESS;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800858 *pnMajorType = nTmpMajorType;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800859 *puArgument = uArgument;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800860 *pnAdditionalInfo = nAdditionalInfo;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800861
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700862Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800863 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700864}
865
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800866
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800867/**
868 * @brief Decode integer types, major types 0 and 1.
869 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700870 * @param[in] nMajorType The CBOR major type (0 or 1).
871 * @param[in] uArgument The argument from the head.
872 * @param[in] nAdditionalInfo So it can be error-checked.
873 * @param[out] pDecodedItem The filled in decoded item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800874 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700875 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered.
876 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800877 *
878 * Must only be called when major type is 0 or 1.
879 *
880 * CBOR doesn't explicitly specify two's compliment for integers but
881 * all CPUs use it these days and the test vectors in the RFC are
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700882 * so. All integers in encoded CBOR are unsigned and the CBOR major
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800883 * type indicates positive or negative. CBOR can express positive
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700884 * integers up to 2^64 - 1 negative integers down to -2^64. Note that
885 * negative numbers can be one more
886 * away from zero than positive because there is no negative zero.
887 *
888 * The "65-bit negs" are values CBOR can encode that can't fit
889 * into an int64_t or uint64_t. They decoded as a special type
890 * QCBOR_TYPE_65BIT_NEG_INT. Not that this type does NOT
891 * take into account the offset of one for CBOR negative integers.
892 * It must be applied to get the correct value. Applying this offset
893 * would overflow a uint64_t.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700894 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700895static QCBORError
896QCBOR_Private_DecodeInteger(const int nMajorType,
897 const uint64_t uArgument,
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700898 const int nAdditionalInfo,
Laurence Lundblade8e36f812024-01-26 10:59:29 -0700899 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700900{
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800901 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800902
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700903 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
904 uReturn = QCBOR_ERR_BAD_INT;
905 goto Done;
906 }
907
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700908 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800909 if (uArgument <= INT64_MAX) {
910 pDecodedItem->val.int64 = (int64_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700911 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800912
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700913 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800914 pDecodedItem->val.uint64 = uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700915 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700916 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800917
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700918 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800919 if(uArgument <= INT64_MAX) {
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700920 /* INT64_MIN is one further away from 0 than INT64_MAX
921 * so the -1 here doesn't overflow. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800922 pDecodedItem->val.int64 = (-(int64_t)uArgument) - 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700923 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800924
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700925 } else {
Laurence Lundblade2d493002024-02-01 11:09:17 -0700926 pDecodedItem->val.uint64 = uArgument;
927 pDecodedItem->uDataType = QCBOR_TYPE_65BIT_NEG_INT;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700928 }
929 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800930
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700931Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800932 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700933}
934
Laurence Lundblade3f1318a2021-01-04 18:26:44 -0800935
Laurence Lundbladeec290b82024-06-10 11:10:54 -0700936/**
937 * @brief Decode text and byte strings
938 *
939 * @param[in] pMe Decoder context.
940 * @param[in] bAllocate Whether to allocate and copy string.
941 * @param[in] nMajorType Whether it is a byte or text string.
942 * @param[in] uStrLen The length of the string.
943 * @param[in] nAdditionalInfo Whether it is an indefinite-length string.
944 * @param[out] pDecodedItem The filled-in decoded item.
945 *
946 * @retval QCBOR_ERR_HIT_END Unexpected end of input.
947 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
948 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
949 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator
950 *
951 * This reads @c uStrlen bytes from the input and fills in @c
952 * pDecodedItem. If @c bAllocate is true, then memory for the string
953 * is allocated.
954 */
955static QCBORError
956QCBOR_Private_DecodeString(QCBORDecodeContext *pMe,
957 const bool bAllocate,
958 const int nMajorType,
959 const uint64_t uStrLen,
960 const int nAdditionalInfo,
961 QCBORItem *pDecodedItem)
962{
963 QCBORError uReturn = QCBOR_SUCCESS;
964
965 /* ---- Figure out the major type ---- */
966 #if CBOR_MAJOR_TYPE_BYTE_STRING + 4 != QCBOR_TYPE_BYTE_STRING
967 #error QCBOR_TYPE_BYTE_STRING not lined up with major type
968 #endif
969
970 #if CBOR_MAJOR_TYPE_TEXT_STRING + 4 != QCBOR_TYPE_TEXT_STRING
971 #error QCBOR_TYPE_TEXT_STRING not lined up with major type
972 #endif
973 pDecodedItem->uDataType = (uint8_t)(nMajorType + 4);
974
975 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
976 /* --- Just the head of an indefinite-length string --- */
977 pDecodedItem->val.string = (UsefulBufC){NULL, QCBOR_STRING_LENGTH_INDEFINITE};
978
979 } else {
980 /* --- A definite-length string --- */
981 /* --- (which might be a chunk of an indefinte-length string) --- */
982
983 /* CBOR lengths can be 64 bits, but size_t is not 64 bits on all
984 * CPUs. This check makes the casts to size_t below safe.
985 *
986 * The max is 4 bytes less than the largest sizeof() so this can be
987 * tested by putting a SIZE_MAX length in the CBOR test input (no
988 * one will care the limit on strings is 4 bytes shorter).
989 */
990 if(uStrLen > SIZE_MAX-4) {
991 uReturn = QCBOR_ERR_STRING_TOO_LONG;
992 goto Done;
993 }
994
995 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(&(pMe->InBuf), (size_t)uStrLen);
996 if(UsefulBuf_IsNULLC(Bytes)) {
997 /* Failed to get the bytes for this string item */
998 uReturn = QCBOR_ERR_HIT_END;
999 goto Done;
1000 }
1001
1002 if(bAllocate) {
1003#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
1004 /* --- Put string in allocated memory --- */
1005
1006 /* Note that this is not where allocation to coalesce
1007 * indefinite-length strings is done. This is for when the
1008 * caller has requested all strings be allocated. Disabling
1009 * indefinite length strings also disables this allocate-all
1010 * option.
1011 */
1012
1013 if(pMe->StringAllocator.pfAllocator == NULL) {
1014 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1015 goto Done;
1016 }
1017 UsefulBuf NewMem = StringAllocator_Allocate(&(pMe->StringAllocator), (size_t)uStrLen);
1018 if(UsefulBuf_IsNULL(NewMem)) {
1019 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1020 goto Done;
1021 }
1022 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
1023 pDecodedItem->uDataAlloc = 1;
1024#else
1025 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1026#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1027 } else {
1028 /* --- Normal case with no string allocator --- */
1029 pDecodedItem->val.string = Bytes;
1030 }
1031 }
1032
1033Done:
1034 return uReturn;
1035}
1036
1037
1038/**
1039 * @brief Decode array or map.
1040 *
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001041 * @param[in] uConfigFlags Decoder mode.
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001042 * @param[in] nMajorType Whether it is a byte or text string.
1043 * @param[in] uItemCount The length of the string.
1044 * @param[in] nAdditionalInfo Whether it is an indefinite-length.
1045 * @param[out] pDecodedItem The filled-in decoded item.
1046 *
1047 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinites disabled.
1048 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map.
1049 *
1050 * Not much to do for arrays and maps. Just the type item count (but a
1051 * little messy because of ifdefs for indefinite-lengths and
1052 * map-as-array decoding).
1053 *
1054 * This also does the bulk of the work for @ref
1055 * QCBOR_DECODE_MODE_MAP_AS_ARRAY, a special mode to handle
1056 * arbitrarily complex map labels. This ifdefs out with
1057 * QCBOR_DISABLE_NON_INTEGER_LABELS.
1058 */
1059static QCBORError
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001060QCBOR_Private_DecodeArrayOrMap(const QCBORDecodeMode uConfigFlags,
1061 const int nMajorType,
1062 uint64_t uItemCount,
1063 const int nAdditionalInfo,
1064 QCBORItem *pDecodedItem)
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001065{
1066 QCBORError uReturn;
1067
1068 /* ------ Sort out the data type ------ */
1069 #if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
1070 #error QCBOR_TYPE_ARRAY value not lined up with major type
1071 #endif
1072
1073 #if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
1074 #error QCBOR_TYPE_MAP value not lined up with major type
1075 #endif
1076 pDecodedItem->uDataType = (uint8_t)nMajorType;
1077#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001078 if((uConfigFlags & QCBOR_DECODE_MODE_MAP_AS_ARRAY) && nMajorType == QCBOR_TYPE_MAP) {
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001079 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
1080 }
1081#else
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001082 (void)uConfigFlags;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001083#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
1084
1085 uReturn = QCBOR_SUCCESS;
1086
1087 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1088 /* ------ Indefinite-length array/map ----- */
1089#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
1090 pDecodedItem->val.uCount = QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH;
1091#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1092 uReturn = QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED;
1093#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
1094 } else {
Laurence Lundbladeb95afec2024-08-26 10:51:28 -07001095 /* ----- Definite-length array/map ----- */
1096 if(uItemCount > (nMajorType == QCBOR_TYPE_MAP ? QCBOR_MAX_ITEMS_IN_MAP : QCBOR_MAX_ITEMS_IN_ARRAY)) {
1097 uReturn = QCBOR_ERR_ARRAY_DECODE_TOO_LONG;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001098
Laurence Lundbladeb95afec2024-08-26 10:51:28 -07001099 } else {
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001100#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001101 if((uConfigFlags & QCBOR_DECODE_MODE_MAP_AS_ARRAY) && nMajorType == QCBOR_TYPE_MAP) {
Laurence Lundbladeb95afec2024-08-26 10:51:28 -07001102 /* ------ Map as array ------ */
1103 uItemCount *= 2;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001104 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001105#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundbladeb95afec2024-08-26 10:51:28 -07001106
1107 /* cast OK because of check above */
1108 pDecodedItem->val.uCount = (uint16_t)uItemCount;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001109 }
1110 }
1111
1112 return uReturn;
1113}
1114
1115
1116/**
1117 * @brief Decode a tag number.
1118 *
1119 * @param[in] uTagNumber The length of the string.
1120 * @param[in] nAdditionalInfo So this can be error-checked.
1121 * @param[out] pDecodedItem The filled-in decoded item.
1122 *
1123 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo is LEN_IS_INDEFINITE.
1124 * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined.
1125 *
1126 * Not much to do for tags, but fill in pDecodedItem and check for
1127 * error in nAdditionalInfo.
1128 */
1129static QCBORError
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001130QCBOR_Private_DecodeTagNumber(const uint64_t uTagNumber,
1131 const int nAdditionalInfo,
1132 QCBORItem *pDecodedItem)
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001133{
1134#ifndef QCBOR_DISABLE_TAGS
1135 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1136 return QCBOR_ERR_BAD_INT;
1137 } else {
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001138 pDecodedItem->val.uTagNumber = uTagNumber;
1139 pDecodedItem->uDataType = QCBOR_TYPE_TAG_NUMBER;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001140 return QCBOR_SUCCESS;
1141 }
1142#else /* QCBOR_DISABLE_TAGS */
1143 (void)nAdditionalInfo;
Laurence Lundblade6c9a8242024-06-12 20:34:52 -07001144 (void)uTagNumber;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001145 (void)pDecodedItem;
1146 return QCBOR_ERR_TAGS_DISABLED;
1147#endif /* QCBOR_DISABLE_TAGS */
1148}
1149
1150
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001151#ifndef USEFULBUF_DISABLE_ALL_FLOAT
1152
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001153#if !defined(QCBOR_DISABLE_DECODE_CONFORMANCE) && !defined(QCBOR_DISABLE_PREFERRED_FLOAT)
1154
1155static QCBORError
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001156QCBORDecode_Private_HalfConformance(const double d, const QCBORDecodeMode uConfigFlags)
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001157{
1158 struct IEEE754_ToInt ToInt;
1159
1160 /* Only need to check for conversion to integer because
1161 * half-precision is always preferred serialization. Don't
1162 * need special checker for half-precision because whole
1163 * numbers always convert perfectly from half to double.
1164 *
1165 * This catches half-precision with NaN payload too.
1166 *
1167 * The only thing allowed here is a double/half-precision that
1168 * can't be converted to anything but a double.
1169 */
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001170 if(uConfigFlags & QCBOR_DECODE_ONLY_REDUCED_FLOATS) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001171 ToInt = IEEE754_DoubleToInt(d);
1172 if(ToInt.type != QCBOR_TYPE_DOUBLE) {
1173 return QCBOR_ERR_DCBOR_CONFORMANCE;
1174 }
1175 }
1176
1177 return QCBOR_SUCCESS;
1178}
1179
1180
1181static QCBORError
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001182QCBORDecode_Private_SingleConformance(const float f, const QCBORDecodeMode uconfigFlags)
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001183{
1184 struct IEEE754_ToInt ToInt;
1185 IEEE754_union ToSmaller;
1186
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001187 if(uconfigFlags & QCBOR_DECODE_ONLY_REDUCED_FLOATS) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001188 /* See if it could have been encoded as an integer */
1189 ToInt = IEEE754_SingleToInt(f);
1190 if(ToInt.type == IEEE754_ToInt_IS_INT || ToInt.type == IEEE754_ToInt_IS_UINT) {
1191 return QCBOR_ERR_DCBOR_CONFORMANCE;
1192 }
1193
1194 /* Make sure there is no NaN payload */
1195 if(IEEE754_SingleHasNaNPayload(f)) {
1196 return QCBOR_ERR_DCBOR_CONFORMANCE;
1197 }
1198 }
1199
1200 /* See if it could have been encoded shorter */
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001201 if(uconfigFlags & QCBOR_DECODE_ONLY_PREFERRED_NUMBERS) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001202 ToSmaller = IEEE754_SingleToHalf(f, true);
1203 if(ToSmaller.uSize != sizeof(float)) {
1204 return QCBOR_ERR_PREFERRED_CONFORMANCE;
1205 }
1206 }
1207
1208 return QCBOR_SUCCESS;
1209}
1210
1211
1212static QCBORError
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001213QCBORDecode_Private_DoubleConformance(const double d, QCBORDecodeMode uConfigFlags)
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001214{
1215 struct IEEE754_ToInt ToInt;
1216 IEEE754_union ToSmaller;
1217
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001218 if(uConfigFlags & QCBOR_DECODE_ONLY_REDUCED_FLOATS) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001219 /* See if it could have been encoded as an integer */
1220 ToInt = IEEE754_DoubleToInt(d);
1221 if(ToInt.type == IEEE754_ToInt_IS_INT || ToInt.type == IEEE754_ToInt_IS_UINT) {
1222 return QCBOR_ERR_DCBOR_CONFORMANCE;
1223 }
1224 /* Make sure there is no NaN payload */
1225 if(IEEE754_DoubleHasNaNPayload(d)) {
1226 return QCBOR_ERR_DCBOR_CONFORMANCE;
1227 }
1228 }
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001229
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001230 /* See if it could have been encoded shorter */
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001231 if(uConfigFlags & QCBOR_DECODE_ONLY_PREFERRED_NUMBERS) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001232 ToSmaller = IEEE754_DoubleToSmaller(d, true, true);
1233 if(ToSmaller.uSize != sizeof(double)) {
1234 return QCBOR_ERR_PREFERRED_CONFORMANCE;
1235 }
1236 }
1237
1238 return QCBOR_SUCCESS;
1239}
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001240#else /* ! QCBOR_DISABLE_DECODE_CONFORMANCE && ! QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001241
1242static QCBORError
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001243QCBORDecode_Private_SingleConformance(const float f, const QCBORDecodeMode uConfigFlags)
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001244{
1245 (void)f;
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001246 if(uConfigFlags & (QCBOR_DECODE_ONLY_REDUCED_FLOATS | QCBOR_DECODE_ONLY_PREFERRED_NUMBERS)) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001247 return QCBOR_ERR_CANT_CHECK_FLOAT_CONFORMANCE;
1248 } else {
1249 return QCBOR_SUCCESS;
1250 }
1251}
1252
1253static QCBORError
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001254QCBORDecode_Private_DoubleConformance(const double d, const QCBORDecodeMode uConfigFlags)
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001255{
1256 (void)d;
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001257 if(uConfigFlags & (QCBOR_DECODE_ONLY_REDUCED_FLOATS | QCBOR_DECODE_ONLY_PREFERRED_NUMBERS)) {
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001258 return QCBOR_ERR_CANT_CHECK_FLOAT_CONFORMANCE;
1259 } else {
1260 return QCBOR_SUCCESS;
1261 }
1262}
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001263#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE && ! QCBOR_DISABLE_PREFERRED_FLOAT */
1264
1265
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001266/*
1267 * Decode a float
1268 */
1269static QCBORError
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001270QCBOR_Private_DecodeFloat(const QCBORDecodeMode uConfigFlags,
1271 const int nAdditionalInfo,
1272 const uint64_t uArgument,
1273 QCBORItem *pDecodedItem)
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001274{
1275 QCBORError uReturn = QCBOR_SUCCESS;
1276 float single;
1277
1278 (void)single; /* Avoid unused error from various #ifndefs */
1279
1280 switch(nAdditionalInfo) {
1281 case HALF_PREC_FLOAT: /* 25 */
1282#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
1283 /* Half-precision is returned as a double. The cast to
1284 * uint16_t is safe because the encoded value was 16 bits. It
1285 * was widened to 64 bits to be passed in here.
1286 */
1287 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uArgument);
1288 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
1289
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001290 uReturn = QCBORDecode_Private_HalfConformance(pDecodedItem->val.dfnum, uConfigFlags);
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001291 if(uReturn != QCBOR_SUCCESS) {
1292 break;
1293 }
1294#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
1295 uReturn = FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS);
1296 break;
1297
1298 case SINGLE_PREC_FLOAT: /* 26 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001299 /* Single precision is normally returned as a double since
1300 * double is widely supported, there is no loss of precision,
1301 * it makes it easy for the caller in most cases and it can
1302 * be converted back to single with no loss of precision
1303 *
1304 * The cast to uint32_t is safe because the encoded value was
1305 * 32 bits. It was widened to 64 bits to be passed in here.
1306 */
1307 single = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uArgument);
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001308 uReturn = QCBORDecode_Private_SingleConformance(single, uConfigFlags);
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001309 if(uReturn != QCBOR_SUCCESS) {
1310 break;
1311 }
1312
1313#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1314 /* In the normal case, use HW to convert float to
1315 * double. */
1316 pDecodedItem->val.dfnum = (double)single;
1317 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
1318#else /* QCBOR_DISABLE_FLOAT_HW_USE */
1319 /* Use of float HW is disabled, return as a float. */
1320 pDecodedItem->val.fnum = single;
1321 pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
1322
1323 /* IEEE754_FloatToDouble() could be used here to return as
1324 * a double, but it adds object code and most likely
1325 * anyone disabling FLOAT HW use doesn't care about floats
1326 * and wants to save object code.
1327 */
1328#endif /* ! QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001329 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
1330 break;
1331
1332 case DOUBLE_PREC_FLOAT: /* 27 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001333 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uArgument);
1334 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
1335
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001336 uReturn = QCBORDecode_Private_DoubleConformance(pDecodedItem->val.dfnum, uConfigFlags);
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001337 if(uReturn != QCBOR_SUCCESS) {
1338 break;
1339 }
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001340 uReturn = FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS);
1341 break;
1342 }
1343
1344 return uReturn;
1345}
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001346#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */
1347
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001348
1349
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001350/* Make sure #define value line up as DecodeSimple counts on this. */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001351#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
1352#error QCBOR_TYPE_FALSE macro value wrong
1353#endif
1354
1355#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
1356#error QCBOR_TYPE_TRUE macro value wrong
1357#endif
1358
1359#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
1360#error QCBOR_TYPE_NULL macro value wrong
1361#endif
1362
1363#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
1364#error QCBOR_TYPE_UNDEF macro value wrong
1365#endif
1366
Laurence Lundblade0f99d692018-09-26 14:39:28 -07001367#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
1368#error QCBOR_TYPE_BREAK macro value wrong
1369#endif
1370
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001371#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
1372#error QCBOR_TYPE_DOUBLE macro value wrong
1373#endif
1374
1375#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
1376#error QCBOR_TYPE_FLOAT macro value wrong
1377#endif
1378
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001379/**
1380 * @brief Decode major type 7 -- true, false, floating-point, break...
1381 *
1382 * @param[in] nAdditionalInfo The lower five bits from the initial byte.
1383 * @param[in] uArgument The argument from the head.
1384 * @param[out] pDecodedItem The filled in decoded item.
1385 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001386 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1387 * of half-precision disabled
1388 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all float
1389 * decode is disabled.
1390 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of simple
1391 * type in input.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001392 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001393static QCBORError
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001394QCBOR_Private_DecodeType7(const QCBORDecodeMode uConfigFlags,
1395 const int nAdditionalInfo,
1396 const uint64_t uArgument,
1397 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001398{
1399 QCBORError uReturn = QCBOR_SUCCESS;
1400
1401 /* uAdditionalInfo is 5 bits from the initial byte. Compile time
1402 * checks above make sure uAdditionalInfo values line up with
1403 * uDataType values. DecodeHead() never returns an AdditionalInfo
1404 * > 0x1f so cast is safe.
1405 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001406 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001407
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001408 switch(nAdditionalInfo) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001409 /* No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they
1410 * are caught before this is called.
1411 */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001412
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001413 case HALF_PREC_FLOAT: /* 25 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001414 case SINGLE_PREC_FLOAT: /* 26 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001415 case DOUBLE_PREC_FLOAT: /* 27 */
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001416#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001417 uReturn = QCBOR_Private_DecodeFloat(uConfigFlags, nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001418#else
1419 uReturn = QCBOR_ERR_ALL_FLOAT_DISABLED;
1420#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001421 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001422
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001423 case CBOR_SIMPLEV_FALSE: /* 20 */
1424 case CBOR_SIMPLEV_TRUE: /* 21 */
1425 case CBOR_SIMPLEV_NULL: /* 22 */
1426 case CBOR_SIMPLEV_UNDEF: /* 23 */
1427 case CBOR_SIMPLE_BREAK: /* 31 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001428#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001429 if((uConfigFlags & QCBOR_DECODE_DISALLOW_DCBOR_SIMPLES) &&
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001430 nAdditionalInfo == CBOR_SIMPLEV_UNDEF) {
1431 uReturn = QCBOR_ERR_DCBOR_CONFORMANCE;
1432 goto Done;
1433 }
1434#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001435 break; /* nothing to do */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001436
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001437 case CBOR_SIMPLEV_ONEBYTE: /* 24 */
1438 if(uArgument <= CBOR_SIMPLE_BREAK) {
1439 /* This takes out f8 00 ... f8 1f which should be encoded
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001440 * as e0 … f7 -- preferred serialization check for simple values.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001441 */
1442 uReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001443 goto Done;
1444 }
Laurence Lundblade5e390822019-01-06 12:35:01 -08001445 /* FALLTHROUGH */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001446
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001447 default: /* 0-19 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001448#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001449 if((uConfigFlags & QCBOR_DECODE_DISALLOW_DCBOR_SIMPLES) &&
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001450 (uArgument < CBOR_SIMPLEV_FALSE || uArgument > CBOR_SIMPLEV_NULL)) {
1451 uReturn = QCBOR_ERR_DCBOR_CONFORMANCE;
1452 goto Done;
1453 }
1454#endif /* !QCBOR_DISABLE_DECODE_CONFORMANCE */
1455
1456 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
1457 /* QCBOR_Private_DecodeHead() will make uArgument equal to
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001458 * nAdditionalInfo when nAdditionalInfo is < 24. This cast is
1459 * safe because the 2, 4 and 8 byte lengths of uNumber are in
1460 * the double/float cases above
Laurence Lundbladeee851742020-01-08 08:37:05 -08001461 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001462 pDecodedItem->val.uSimple = (uint8_t)uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001463 break;
1464 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001465
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001466Done:
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001467 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001468}
1469
1470
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001471/**
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001472 * @brief Decode a single primitive data item (decode layer 6).
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001473 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001474 * @param[in] pMe Decoder context.
1475 * @param[in] bAllocateStrings If true, use allocator for strings.
1476 * @param[out] pDecodedItem The filled-in decoded item.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001477 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001478 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1479 * features
1480 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1481 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1482 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1483 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001484 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Allocation requested, but no allocator
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001485 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1486 * of half-precision disabled
1487 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1488 * float decode is disabled.
1489 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1490 * simple type in input.
1491 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1492 * in input, but indefinite
1493 * lengths disabled.
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001494 * @retval QCBOR_ERR_BAD_INT nAdditionalInfo indicated indefinte.
1495 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array/map.
1496 * @retval QCBOR_ERR_TAGS_DISABLED QCBOR_DISABLE_TAGS is defined.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001497 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001498 * This decodes the most primitive/atomic data item. It does no
1499 * combining of data items.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001500 */
1501static QCBORError
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001502QCBOR_Private_DecodeAtomicDataItem(QCBORDecodeContext *pMe,
1503 const bool bAllocateStrings,
1504 QCBORItem *pDecodedItem)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001505{
1506 QCBORError uReturn;
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001507 int nMajorType = 0;
1508 uint64_t uArgument = 0;
1509 int nAdditionalInfo = 0;
1510
1511 const QCBORDecodeMode uDecodeMode = pMe->uDecodeMode;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001512
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001513 memset(pDecodedItem, 0, sizeof(QCBORItem));
1514
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001515 /* Decode the "head" that every CBOR item has into the major type,
1516 * argument and the additional info.
1517 */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001518 uReturn = QCBOR_Private_DecodeHead(&(pMe->InBuf),
1519#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
1520 // TODO: make this prettier; will optimizer take out stuff without ifdef?
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001521 uDecodeMode,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001522#endif /* !QCBOR_DISABLE_DECODE_CONFORMANCE */
1523 &nMajorType,
1524 &uArgument,
1525 &nAdditionalInfo);
Laurence Lundblade14ce2282024-07-24 22:13:35 -07001526
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001527 if(uReturn != QCBOR_SUCCESS) {
1528 return uReturn;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001529 }
1530
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001531 /* All the functions below get inlined by the optimizer. This code
1532 * is easier to read with them all being similar functions, even if
1533 * some functions don't do much.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001534 */
1535 switch (nMajorType) {
1536 case CBOR_MAJOR_TYPE_POSITIVE_INT: /* Major type 0 */
1537 case CBOR_MAJOR_TYPE_NEGATIVE_INT: /* Major type 1 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001538 return QCBOR_Private_DecodeInteger(nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001539 break;
1540
1541 case CBOR_MAJOR_TYPE_BYTE_STRING: /* Major type 2 */
1542 case CBOR_MAJOR_TYPE_TEXT_STRING: /* Major type 3 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001543 return QCBOR_Private_DecodeString(pMe, bAllocateStrings, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001544 break;
1545
1546 case CBOR_MAJOR_TYPE_ARRAY: /* Major type 4 */
1547 case CBOR_MAJOR_TYPE_MAP: /* Major type 5 */
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001548 return QCBOR_Private_DecodeArrayOrMap(uDecodeMode, nMajorType, uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001549 break;
1550
1551 case CBOR_MAJOR_TYPE_TAG: /* Major type 6, tag numbers */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001552 return QCBOR_Private_DecodeTagNumber(uArgument, nAdditionalInfo, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001553 break;
1554
1555 case CBOR_MAJOR_TYPE_SIMPLE:
1556 /* Major type 7: float, double, true, false, null... */
Laurence Lundbladed595cb82024-11-22 12:03:13 -08001557 return QCBOR_Private_DecodeType7(uDecodeMode, nAdditionalInfo, uArgument, pDecodedItem);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001558 break;
1559
1560 default:
1561 /* Never happens because DecodeHead() should never return > 7 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001562 return QCBOR_ERR_UNSUPPORTED;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001563 break;
1564 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001565}
1566
1567
1568/**
1569 * @brief Process indefinite-length strings (decode layer 5).
1570 *
1571 * @param[in] pMe Decoder context
1572 * @param[out] pDecodedItem The decoded item that work is done on.
1573 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001574 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1575 * features
1576 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1577 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1578 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1579 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1580 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1581 * of half-precision disabled
1582 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1583 * float decode is disabled.
1584 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1585 * simple type in input.
1586 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1587 * in input, but indefinite
1588 * lengths disabled.
1589 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1590 * but no string allocator.
1591 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1592 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1593 * input, but indefinite-length
1594 * strings are disabled.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001595 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001596 * If @c pDecodedItem is not an indefinite-length string, this does nothing.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001597 *
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001598 * If it is, this loops getting the subsequent chunk data items that
1599 * make up the string. The string allocator is used to make a
1600 * contiguous buffer for the chunks. When this completes @c
1601 * pDecodedItem contains the put-together string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001602 *
1603 * Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001604 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001605static QCBORError
1606QCBORDecode_Private_GetNextFullString(QCBORDecodeContext *pMe,
1607 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001608{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001609 /* Aproximate stack usage
1610 * 64-bit 32-bit
1611 * local vars 32 16
1612 * 2 UsefulBufs 32 16
1613 * QCBORItem 56 52
1614 * TOTAL 120 74
1615 */
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001616 QCBORError uReturn;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001617
1618 /* A note about string allocation -- Memory for strings is
1619 * allocated either because 1) indefinte-length string chunks are
1620 * being coalecsed or 2) caller has requested all strings be
1621 * allocated. The first case is handed below here. The second case
1622 * is handled in DecodeString if the bAllocate is true. That
1623 * boolean originates here with pMe->bStringAllocateAll immediately
1624 * below. That is, QCBOR_Private_DecodeAtomicDataItem() is called
1625 * in two different contexts here 1) main-line processing which is
1626 * where definite-length strings need to be allocated if
1627 * bStringAllocateAll is true and 2) processing chunks of
1628 * indefinite-lengths strings in in which case there must be no
1629 * allocation.
1630 */
1631
1632
1633 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, pMe->bStringAllocateAll, pDecodedItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001634 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001635 goto Done;
1636 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001637
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001638 /* This is where out-of-place break is detected for the whole
1639 * decoding stack. Break is an error for everything that calls
1640 * QCBORDecode_Private_GetNextFullString(), so the check is
1641 * centralized here.
1642 */
1643 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
1644 uReturn = QCBOR_ERR_BAD_BREAK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001645 goto Done;
1646 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001647
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001648
1649 /* Skip out if not an indefinite-length string */
1650 const uint8_t uStringType = pDecodedItem->uDataType;
1651 if(uStringType != QCBOR_TYPE_BYTE_STRING &&
1652 uStringType != QCBOR_TYPE_TEXT_STRING) {
1653 goto Done;
1654 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001655 if(pDecodedItem->val.string.len != QCBOR_STRING_LENGTH_INDEFINITE) {
1656 goto Done;
1657 }
1658
1659#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001660 /* Can't decode indefinite-length strings without a string allocator */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001661 if(!pMe->StringAllocator.pfAllocator) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001662 uReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1663 goto Done;
1664 }
1665
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001666 /* Loop getting chunks of the indefinite-length string */
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001667 UsefulBufC FullString = NULLUsefulBufC;
1668
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001669 for(;;) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001670 /* Get QCBORItem for next chunk */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001671 QCBORItem StringChunkItem;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001672 /* Pass false to DecodeAtomicDataItem() because the individual
1673 * string chunks in an indefinite-length must not be
1674 * allocated. They are always copied into the allocated
1675 * contiguous buffer allocated here.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001676 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001677 uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &StringChunkItem);
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001678 if(uReturn) {
1679 break;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001680 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001681
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001682 /* Is item is the marker for end of the indefinite-length string? */
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001683 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001684 /* String is complete */
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001685 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301686 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001687 break;
1688 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001689
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001690 /* All chunks must be of the same type, the type of the item
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001691 * that introduces the indefinite-length string. This also
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001692 * catches errors where the chunk is not a string at all and an
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001693 * indefinite-length string inside an indefinite-length string.
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001694 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001695 if(StringChunkItem.uDataType != uStringType ||
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001696 StringChunkItem.val.string.len == QCBOR_STRING_LENGTH_INDEFINITE) {
1697 uReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001698 break;
1699 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001700
David Navarro9123e5b2022-03-28 16:04:03 +02001701 if (StringChunkItem.val.string.len > 0) {
1702 /* The first time throurgh FullString.ptr is NULL and this is
1703 * equivalent to StringAllocator_Allocate(). Subsequently it is
1704 * not NULL and a reallocation happens.
1705 */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001706 UsefulBuf NewMem = StringAllocator_Reallocate(&(pMe->StringAllocator),
David Navarro9123e5b2022-03-28 16:04:03 +02001707 FullString.ptr,
1708 FullString.len + StringChunkItem.val.string.len);
David Navarro9123e5b2022-03-28 16:04:03 +02001709 if(UsefulBuf_IsNULL(NewMem)) {
1710 uReturn = QCBOR_ERR_STRING_ALLOCATE;
1711 break;
1712 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001713
David Navarro9123e5b2022-03-28 16:04:03 +02001714 /* Copy new string chunk to the end of accumulated string */
1715 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001716 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001717 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001718
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001719 if(uReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
1720 /* Getting the item failed, clean up the allocated memory */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001721 StringAllocator_Free(&(pMe->StringAllocator), FullString.ptr);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001722 }
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001723#else /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
1724 uReturn = QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED;
1725#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001726
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001727Done:
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001728 return uReturn;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001729}
1730
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08001731
Laurence Lundblade37286c02022-09-03 10:05:02 -07001732#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001733/**
1734 * @brief This converts a tag number to a shorter mapped value for storage.
1735 *
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001736 * @param[in] pMe The decode context.
1737 * @param[in] uUnMappedTag The tag number to map
1738 * @param[out] puMappedTagNumber The stored tag number.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001739 *
1740 * @return error code.
1741 *
1742 * The main point of mapping tag numbers is make QCBORItem
1743 * smaller. With this mapping storage of 4 tags takes up 8
1744 * bytes. Without, it would take up 32 bytes.
1745 *
1746 * This maps tag numbers greater than QCBOR_LAST_UNMAPPED_TAG.
1747 * QCBOR_LAST_UNMAPPED_TAG is a little smaller than MAX_UINT16.
1748 *
1749 * See also UnMapTagNumber() and @ref QCBORItem.
1750 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001751static QCBORError
1752QCBORDecode_Private_MapTagNumber(QCBORDecodeContext *pMe,
1753 const uint64_t uUnMappedTag,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001754 uint16_t *puMappedTagNumber)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001755{
1756 if(uUnMappedTag > QCBOR_LAST_UNMAPPED_TAG) {
1757 unsigned uTagMapIndex;
1758 /* Is there room in the tag map, or is it in it already? */
1759 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
1760 if(pMe->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID64) {
1761 break;
1762 }
1763 if(pMe->auMappedTags[uTagMapIndex] == uUnMappedTag) {
1764 break;
1765 }
1766 }
1767 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
1768 return QCBOR_ERR_TOO_MANY_TAGS;
1769 }
1770
1771 /* Covers the cases where tag is new and were it is already in the map */
1772 pMe->auMappedTags[uTagMapIndex] = uUnMappedTag;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001773 *puMappedTagNumber = (uint16_t)(uTagMapIndex + QCBOR_LAST_UNMAPPED_TAG + 1);
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001774
1775 } else {
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001776 *puMappedTagNumber = (uint16_t)uUnMappedTag;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001777 }
1778
1779 return QCBOR_SUCCESS;
1780}
1781
1782
1783/**
1784 * @brief This converts a mapped tag number to the actual tag number.
1785 *
1786 * @param[in] pMe The decode context.
1787 * @param[in] uMappedTagNumber The stored tag number.
1788 *
1789 * @return The actual tag number is returned or
1790 * @ref CBOR_TAG_INVALID64 on error.
1791 *
1792 * This is the reverse of MapTagNumber()
1793 */
1794static uint64_t
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001795QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe,
1796 const uint16_t uMappedTagNumber)
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001797{
1798 if(uMappedTagNumber <= QCBOR_LAST_UNMAPPED_TAG) {
1799 return uMappedTagNumber;
1800 } else if(uMappedTagNumber == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07001801 return CBOR_TAG_INVALID64;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001802 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001803 /* This won't be negative because of code below in
1804 * MapTagNumber()
1805 */
1806 const unsigned uIndex = uMappedTagNumber - (QCBOR_LAST_UNMAPPED_TAG + 1);
1807 return pMe->auMappedTags[uIndex];
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001808 }
1809}
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001810
1811
1812static const struct QCBORTagDecoderEntry *
1813QCBORDecode_Private_LookUpTagDecoder(const struct QCBORTagDecoderEntry *pTagContentTable,
1814 const uint64_t uTagNumber)
1815{
1816 const struct QCBORTagDecoderEntry *pTE;
1817
1818 if(pTagContentTable == NULL) {
1819 return NULL;
1820 }
1821
1822 for(pTE = pTagContentTable; pTE->uTagNumber != CBOR_TAG_INVALID64; pTE++) {
1823 if(pTE->uTagNumber == uTagNumber || pTE->uTagNumber == CBOR_TAG_ANY) {
1824 break;
1825 }
1826 }
1827
1828 if(pTE->uTagNumber == CBOR_TAG_INVALID64) {
1829 return NULL;
1830 }
1831
1832 return pTE;
1833}
1834#endif /* ! QCBOR_DISABLE_TAGS */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001835
Laurence Lundblade9b334962020-08-27 10:55:53 -07001836
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001837/**
1838 * @brief Aggregate all tags wrapping a data item (decode layer 4).
1839 *
1840 * @param[in] pMe Decoder context
1841 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001842 *
1843 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1844 * features
1845 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1846 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1847 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1848 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1849 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1850 * of half-precision disabled
1851 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1852 * float decode is disabled.
1853 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1854 * simple type in input.
1855 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1856 * in input, but indefinite
1857 * lengths disabled.
1858 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1859 * but no string allocator.
1860 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1861 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1862 * input, but indefinite-length
1863 * strings are disabled.
1864 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001865 *
1866 * This loops getting atomic data items until one is not a tag
1867 * number. Usually this is largely pass-through because most
1868 * item are not tag numbers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001869 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001870static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001871QCBORDecode_Private_GetNextTagNumber(QCBORDecodeContext *pMe,
1872 QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001873{
Laurence Lundblade37286c02022-09-03 10:05:02 -07001874#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001875 int nIndex;
1876 QCBORError uErr;
1877 uint16_t uMappedTagNumber;
1878 QCBORError uReturn;
1879
1880 /* Accummulate the tag numbers from multiple items here and then
1881 * copy them into the last item, the non-tag-number item.
Laurence Lundbladea9e7ab92022-03-23 10:28:48 +01001882 */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001883 QCBORMappedTagNumbers auTagNumbers;;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001884
1885 /* Initialize to CBOR_TAG_INVALID16 */
1886 #if CBOR_TAG_INVALID16 != 0xffff
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001887 /* Be sure the memset is initializing to CBOR_TAG_INVALID16 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001888 #err CBOR_TAG_INVALID16 tag not defined as expected
1889 #endif
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001890 memset(auTagNumbers, 0xff, sizeof(auTagNumbers));
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001891
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001892 /* Loop fetching data items until the item fetched is not a tag number */
1893 uReturn = QCBOR_SUCCESS;
1894 for(nIndex = 0; ; nIndex++) {
1895 uErr = QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade9b334962020-08-27 10:55:53 -07001896 if(uErr != QCBOR_SUCCESS) {
1897 uReturn = uErr;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001898 break;
1899 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001900
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001901 if(pDecodedItem->uDataType != QCBOR_TYPE_TAG_NUMBER) {
1902 /* Successful exit from loop; maybe got some tags, maybe not */
1903 memcpy(pDecodedItem->auTagNumbers, auTagNumbers, sizeof(auTagNumbers));
1904 break;
1905 }
1906
1907 if(nIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
1908 /* No room in the item's tag number array */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001909 uReturn = QCBOR_ERR_TOO_MANY_TAGS;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001910 /* Continue on to get all tag numbers wrapping this item even
1911 * though it is erroring out in the end. This allows decoding
1912 * to continue. This is a QCBOR resource limit error, not a
1913 * problem with being well-formed CBOR.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001914 */
Laurence Lundblade9b334962020-08-27 10:55:53 -07001915 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001916 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001917
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001918 /* Map the tag number */
1919 uMappedTagNumber = 0;
1920 uReturn = QCBORDecode_Private_MapTagNumber(pMe, pDecodedItem->val.uTagNumber, &uMappedTagNumber);
1921 /* Continue even on error so as to consume all tag numbers
1922 * wrapping this data item so decoding can go on. If
1923 * QCBORDecode_Private_MapTagNumber() errors once it will
1924 * continue to error.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001925 */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001926
1927 auTagNumbers[nIndex] = uMappedTagNumber;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001928 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001929
Laurence Lundblade9b334962020-08-27 10:55:53 -07001930 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001931
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001932#else /* ! QCBOR_DISABLE_TAGS */
Laurence Lundblade37286c02022-09-03 10:05:02 -07001933
Laurence Lundblade0f01ac62024-02-18 23:07:07 -07001934 return QCBORDecode_Private_GetNextFullString(pMe, pDecodedItem);
Laurence Lundblade37286c02022-09-03 10:05:02 -07001935
Laurence Lundblade721b56e2024-10-22 03:02:04 -07001936#endif /* ! QCBOR_DISABLE_TAGS */
Laurence Lundblade37286c02022-09-03 10:05:02 -07001937}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001938
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001939
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001940/**
1941 * @brief Combine a map entry label and value into one item (decode layer 3).
1942 *
1943 * @param[in] pMe Decoder context
1944 * @param[out] pDecodedItem The decoded item that work is done on.
1945 *
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07001946 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
1947 * features
1948 * @retval QCBOR_ERR_HIT_END Unexpected end of input
1949 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
1950 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
1951 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
1952 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
1953 * of half-precision disabled
1954 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
1955 * float decode is disabled.
1956 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
1957 * simple type in input.
1958 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
1959 * in input, but indefinite
1960 * lengths disabled.
1961 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
1962 * but no string allocator.
1963 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
1964 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
1965 * input, but indefinite-length
1966 * strings are disabled.
1967 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
1968 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
1969 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001970 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001971 * If the current nesting level is a map, then this combines pairs of
1972 * items into one data item with a label and value.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001973 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001974 * This is passthrough if the current nesting level is not a map.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001975 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001976 * This also implements maps-as-array mode where a map is treated like
1977 * an array to allow caller to do their own label processing.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001978 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07001979static QCBORError
1980QCBORDecode_Private_GetNextMapEntry(QCBORDecodeContext *pMe,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001981 QCBORItem *pDecodedItem,
1982 uint32_t *puLabelEndOffset)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001983{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001984 QCBORItem LabelItem;
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07001985 QCBORError uErr, uErr2;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001986
1987 uErr = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
1988 if(QCBORDecode_IsUnrecoverableError(uErr)) {
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001989 goto Done;
1990 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001991
Laurence Lundbladeec290b82024-06-10 11:10:54 -07001992 if(!DecodeNesting_IsCurrentTypeMap(&(pMe->nesting))) {
1993 /* Not decoding a map. Nothing to do. */
1994 /* When decoding maps-as-arrays, the type will be
1995 * QCBOR_TYPE_MAP_AS_ARRAY and this function will exit
1996 * here. This is now map processing for maps-as-arrays is not
1997 * done. */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08001998 goto Done;
1999 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08002000
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002001 /* Decoding a map entry, so the item decoded above was the label */
2002 LabelItem = *pDecodedItem;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002003
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002004 if(puLabelEndOffset != NULL) {
2005 /* Cast is OK because lengths are all 32-bit in QCBOR */
2006 *puLabelEndOffset = (uint32_t)UsefulInputBuf_Tell(&(pMe->InBuf));
2007 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08002008
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002009 /* Get the value of the map item */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002010 uErr2 = QCBORDecode_Private_GetNextTagNumber(pMe, pDecodedItem);
2011 if(QCBORDecode_IsUnrecoverableError(uErr2)) {
2012 uErr = uErr2;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002013 goto Done;
2014 }
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002015 if(uErr2 != QCBOR_SUCCESS) {
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002016 /* The recoverable error for the value overrides the recoverable
2017 * error for the label, if there was an error for the label */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002018 uErr = uErr2;
2019 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002020
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002021 /* Combine the label item and value item into one */
2022 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
2023 pDecodedItem->uLabelType = LabelItem.uDataType;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09002024
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002025#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002026 /* TODO: QCBOR_DECODE_MODE_MAP_STRINGS_ONLY might have been a bad idea. Maybe
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002027 * get rid of it in QCBOR 2.0
2028 */
Laurence Lundbladed595cb82024-11-22 12:03:13 -08002029 if(pMe->uDecodeMode & QCBOR_DECODE_MODE_MAP_STRINGS_ONLY &&
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002030 LabelItem.uDataType != QCBOR_TYPE_TEXT_STRING) {
2031 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
2032 goto Done;
2033 }
2034#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
2035
2036 switch(LabelItem.uDataType) {
2037 case QCBOR_TYPE_INT64:
2038 pDecodedItem->label.int64 = LabelItem.val.int64;
2039 break;
2040
2041#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
2042 case QCBOR_TYPE_UINT64:
2043 pDecodedItem->label.uint64 = LabelItem.val.uint64;
2044 break;
2045
2046 case QCBOR_TYPE_TEXT_STRING:
2047 case QCBOR_TYPE_BYTE_STRING:
2048 pDecodedItem->label.string = LabelItem.val.string;
2049 break;
2050#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
2051
2052 default:
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002053 /* It is possible to skip over labels that are non-aggregate
2054 * types like floats, but not to skip over labels that are
2055 * arrays or maps. We might eventually handle more label
2056 * types like floats as they are not too hard and we now
2057 * have QCBOR_DISABLE_NON_INTEGER_LABELS */
2058 if(!pMe->bAllowAllLabels || QCBORItem_IsMapOrArray(LabelItem)) {
2059 uErr = QCBOR_ERR_MAP_LABEL_TYPE;
2060 goto Done;
2061 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002062 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002063
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002064Done:
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002065 return uErr;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002066}
2067
2068
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002069#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002070/**
2071 * @brief Peek and see if next data item is a break;
2072 *
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002073 * param[in] pUIB UsefulInputBuf to read from.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002074 * @param[out] pbNextIsBreak Indicate if next was a break or not.
2075 *
2076 * @return Any decoding error.
2077 *
2078 * See if next item is a CBOR break. If it is, it is consumed,
2079 * if not it is not consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07002080*/
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002081static QCBORError
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002082QCBOR_Private_NextIsBreak(QCBORDecodeContext *pMe, bool *pbNextIsBreak)
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002083{
2084 *pbNextIsBreak = false;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002085 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) != 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002086 QCBORItem Peek;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002087 size_t uPeek = UsefulInputBuf_Tell(&(pMe->InBuf));
2088 QCBORError uReturn = QCBOR_Private_DecodeAtomicDataItem(pMe, false, &Peek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002089 if(uReturn != QCBOR_SUCCESS) {
2090 return uReturn;
2091 }
2092 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002093 /* It is not a break, rewind so it can be processed normally. */
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002094 UsefulInputBuf_Seek(&(pMe->InBuf), uPeek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002095 } else {
2096 *pbNextIsBreak = true;
2097 }
2098 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002099
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002100 return QCBOR_SUCCESS;
2101}
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002102#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002103
2104
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002105/**
2106 * @brief Ascend up nesting levels if all items in them have been consumed.
2107 *
2108 * @param[in] pMe The decode context.
2109 * @param[in] bMarkEnd If true mark end of maps/arrays with count of zero.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002110 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002111 *
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002112 * An item was just consumed, now figure out if it was the
2113 * end of an array/map map that can be closed out. That
2114 * may in turn close out the above array/map...
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002115 *
2116 * When ascending indefinite-length arrays and maps, this will correctly
2117 * consume the break for the level above. This is a problem for the
2118 * implementation of QCBORDecode_GetArray() that must not return
2119 * that break. @c pbBreak is set to true to indicate that one
2120 * byte should be removed.
2121 *
2122 * Improvement: this could reduced further if indef is disabled
2123 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002124static QCBORError
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002125QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd, bool *pbBreak)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002126{
2127 QCBORError uReturn;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002128
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002129 /* Loop ascending nesting levels as long as there is ascending to do */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002130 while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002131 if(pbBreak) {
2132 *pbBreak = false;
2133 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002134
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002135 if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) {
2136 /* Nesting level is bstr-wrapped CBOR */
2137
2138 /* Ascent for bstr-wrapped CBOR is always by explicit call
2139 * so no further ascending can happen.
2140 */
2141 break;
2142
2143 } else if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
2144 /* Level is a definite-length array/map */
2145
2146 /* Decrement the item count the definite-length array/map */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002147 DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(&(pMe->nesting));
2148 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002149 /* Didn't close out array/map, so all work here is done */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002150 break;
2151 }
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002152 /* All items in a definite-length array were consumed so it
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002153 * is time to ascend one level. This happens below.
2154 */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002155
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002156#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002157 } else {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002158 /* Level is an indefinite-length array/map. */
2159
2160 /* Check for a break which is what ends indefinite-length arrays/maps */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002161 bool bIsBreak = false;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07002162 uReturn = QCBOR_Private_NextIsBreak(pMe, &bIsBreak);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002163 if(uReturn != QCBOR_SUCCESS) {
2164 goto Done;
2165 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002166
2167 if(!bIsBreak) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002168 /* Not a break so array/map does not close out. All work is done */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002169 break;
2170 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002171
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002172 /* It was a break in an indefinitelength map / array so
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002173 * it is time to ascend one level.
2174 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002175 if(pbBreak) {
2176 *pbBreak = true;
2177 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002178
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002179#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002180 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002181
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002182
2183 /* All items in the array/map have been consumed. */
Laurence Lundblade642282a2020-06-23 12:00:33 -07002184
Laurence Lundblade93d89472020-10-03 22:30:50 -07002185 /* But ascent in bounded mode is only by explicit call to
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002186 * QCBORDecode_ExitBoundedMode().
2187 */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07002188 if(DecodeNesting_IsCurrentBounded(&(pMe->nesting))) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002189 /* Set the count to zero for definite-length arrays to indicate
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002190 * cursor is at end of bounded array/map */
Laurence Lundbladed0304932020-06-27 10:59:38 -07002191 if(bMarkEnd) {
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002192 /* Used for definite and indefinite to signal end */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07002193 DecodeNesting_ZeroMapOrArrayCount(&(pMe->nesting));
Laurence Lundbladed0304932020-06-27 10:59:38 -07002194
Laurence Lundblade2c1faf92020-06-26 22:43:56 -07002195 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002196 break;
2197 }
2198
2199 /* Finally, actually ascend one level. */
2200 DecodeNesting_Ascend(&(pMe->nesting));
2201 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07002202
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002203 uReturn = QCBOR_SUCCESS;
2204
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002205#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002206Done:
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002207#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
2208
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002209 return uReturn;
2210}
2211
2212
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002213/**
2214 * @brief Ascending & Descending out of nesting levels (decode layer 2).
2215 *
2216 * @param[in] pMe Decoder context
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002217 * @param[out] pbBreak Set to true if extra break was consumed.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002218 * @param[out] pDecodedItem The decoded item that work is done on.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07002219
2220 * @retval QCBOR_ERR_UNSUPPORTED Encountered unsupported/reserved
2221 * features
2222 * @retval QCBOR_ERR_HIT_END Unexpected end of input
2223 * @retval QCBOR_ERR_INT_OVERFLOW Too-large negative encountered
2224 * @retval QCBOR_ERR_STRING_ALLOCATE Out of memory.
2225 * @retval QCBOR_ERR_STRING_TOO_LONG String longer than SIZE_MAX - 4.
2226 * @retval QCBOR_ERR_HALF_PRECISION_DISABLED Half-precision in input, but decode
2227 * of half-precision disabled
2228 * @retval QCBOR_ERR_ALL_FLOAT_DISABLED Float-point in input, but all
2229 * float decode is disabled.
2230 * @retval QCBOR_ERR_BAD_TYPE_7 Not-allowed representation of
2231 * simple type in input.
2232 * @retval QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED Indefinite length map/array
2233 * in input, but indefinite
2234 * lengths disabled.
2235 * @retval QCBOR_ERR_NO_STRING_ALLOCATOR Indefinite-length string in input,
2236 * but no string allocator.
2237 * @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK Error in indefinite-length string.
2238 * @retval QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED Indefinite-length string in
2239 * input, but indefinite-length
2240 * strings are disabled.
2241 * @retval QCBOR_ERR_TOO_MANY_TAGS Too many tag numbers on item.
2242 * @retval QCBOR_ERR_ARRAY_DECODE_TOO_LONG Too many items in array.
2243 * @retval QCBOR_ERR_MAP_LABEL_TYPE Map label not string or integer.
2244 * @retval QCBOR_ERR_NO_MORE_ITEMS Need more items for map or array.
2245 * @retval QCBOR_ERR_BAD_BREAK Indefinite-length break in wrong
2246 * place.
2247 * @retval QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP Nesting deeper than QCBOR
2248 * can handle.
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002249 *
2250 * This handles the traversal descending into and asecnding out of
2251 * maps, arrays and bstr-wrapped CBOR. It figures out the ends of
2252 * definite- and indefinte-length maps and arrays by looking at the
2253 * item count or finding CBOR breaks. It detects the ends of the
2254 * top-level sequence and of bstr-wrapped CBOR by byte count.
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002255 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002256static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002257QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002258 bool *pbBreak,
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002259 QCBORItem *pDecodedItem,
2260 uint32_t *puLabelEndOffset)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002261{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002262 QCBORError uReturn;
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002263 /* ==== First: figure out if at the end of a traversal ==== */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002264
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002265 /* If out of bytes to consume, it is either the end of the
2266 * top-level sequence of some bstr-wrapped CBOR that was entered.
2267 *
2268 * In the case of bstr-wrapped CBOR, the length of the
2269 * UsefulInputBuf was set to that of the bstr-wrapped CBOR. When
2270 * the bstr-wrapped CBOR is exited, the length is set back to the
2271 * top-level's length or to the next highest bstr-wrapped CBOR.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002272 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002273 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf)) == 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002274 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002275 goto Done;
2276 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07002277
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002278 /* Check to see if at the end of a bounded definite-length map or
2279 * array. The check for a break ending indefinite-length array is
2280 * later in QCBORDecode_NestLevelAscender().
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002281 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002282 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002283 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002284 goto Done;
2285 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07002286
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08002287 /* ==== Next: not at the end, so get another item ==== */
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002288 uReturn = QCBORDecode_Private_GetNextMapEntry(pMe, pDecodedItem, puLabelEndOffset);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002289 if(QCBORDecode_IsUnrecoverableError(uReturn)) {
2290 /* Error is so bad that traversal is not possible. */
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002291 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002292 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05302293
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002294 /* Record the nesting level for this data item before processing
2295 * any of decrementing and descending.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002296 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002297 pDecodedItem->uNestingLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002298
Laurence Lundblade642282a2020-06-23 12:00:33 -07002299
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002300 /* ==== Next: Process the item for descent, ascent, decrement... ==== */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002301 if(QCBORItem_IsMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002302 /* If the new item is a map or array, descend.
2303 *
2304 * Empty indefinite-length maps and arrays are descended into,
2305 * but then ascended out of in the next chunk of code.
2306 *
2307 * Maps and arrays do count as items in the map/array that
2308 * encloses them so a decrement needs to be done for them too,
2309 * but that is done only when all the items in them have been
2310 * processed, not when they are opened with the exception of an
2311 * empty map or array.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002312 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002313 QCBORError uDescendErr;
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002314 uDescendErr = DecodeNesting_DescendMapOrArray(&(pMe->nesting),
Laurence Lundbladeb95afec2024-08-26 10:51:28 -07002315 pDecodedItem->uDataType,
2316 pDecodedItem->val.uCount);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002317 if(uDescendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002318 /* This error is probably a traversal error and it overrides
2319 * the non-traversal error.
2320 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002321 uReturn = uDescendErr;
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002322 goto Done;
2323 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002324 }
2325
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002326 if(!QCBORItem_IsMapOrArray(*pDecodedItem) ||
2327 QCBORItem_IsEmptyDefiniteLengthMapOrArray(*pDecodedItem) ||
2328 QCBORItem_IsIndefiniteLengthMapOrArray(*pDecodedItem)) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002329 /* The following cases are handled here:
2330 * - A non-aggregate item like an integer or string
2331 * - An empty definite-length map or array
2332 * - An indefinite-length map or array that might be empty or might not.
2333 *
2334 * QCBORDecode_NestLevelAscender() does the work of decrementing the count
2335 * for an definite-length map/array and break detection for an
2336 * indefinite-0length map/array. If the end of the map/array was
2337 * reached, then it ascends nesting levels, possibly all the way
2338 * to the top level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002339 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002340 QCBORError uAscendErr;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07002341 uAscendErr = QCBORDecode_Private_NestLevelAscender(pMe, true, pbBreak);
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002342 if(uAscendErr != QCBOR_SUCCESS) {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002343 /* This error is probably a traversal error and it overrides
2344 * the non-traversal error.
2345 */
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002346 uReturn = uAscendErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002347 goto Done;
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002348 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05302349 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002350
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07002351 /* ==== Last: tell the caller the nest level of the next item ==== */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002352 /* Tell the caller what level is next. This tells them what
2353 * maps/arrays were closed out and makes it possible for them to
2354 * reconstruct the tree with just the information returned in a
2355 * QCBORItem.
Laurence Lundblade642282a2020-06-23 12:00:33 -07002356 */
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002357 if(DecodeNesting_IsAtEndOfBoundedLevel(&(pMe->nesting))) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07002358 /* At end of a bounded map/array; uNextNestLevel 0 to indicate this */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002359 pDecodedItem->uNextNestLevel = 0;
2360 } else {
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002361 pDecodedItem->uNextNestLevel = DecodeNesting_GetCurrentLevel(&(pMe->nesting));
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002362 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002363
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002364Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002365 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002366}
2367
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002368
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002369/**
2370 * @brief Decode tag content for select tags (decoding layer 1).
2371 *
2372 * @param[in] pMe The decode context.
2373 * @param[out] pDecodedItem The decoded item.
2374 *
2375 * @return Decoding error code.
2376 *
Laurence Lundblade99615302020-11-29 11:19:47 -08002377 * CBOR tag numbers for the item were decoded in GetNext_TaggedItem(),
2378 * but the whole tag was not decoded. Here, the whole tags (tag number
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002379 * and tag content) are decoded. This is a
Laurence Lundblade99615302020-11-29 11:19:47 -08002380 * quick pass through for items that are not tags.
Laurence Lundblade59289e52019-12-30 13:44:37 -08002381 */
Laurence Lundblade33ed26f2024-11-24 10:26:43 -08002382QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002383QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
2384 QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08002385{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002386 QCBORError uErr;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002387
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002388 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pDecodedItem, NULL);
2389
2390#ifndef QCBOR_DISABLE_TAGS
2391 uint64_t uTagNumber;
2392 int nTagIndex;
2393 const struct QCBORTagDecoderEntry *pTagDecoder;
2394
2395 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002396 goto Done;
2397 }
2398
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002399 /* Loop over tag numbers in reverse, those closest to content first */
2400 for(nTagIndex = QCBOR_MAX_TAGS_PER_ITEM-1; nTagIndex >= 0; nTagIndex--) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08002401
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002402 if(pDecodedItem->auTagNumbers[nTagIndex] == CBOR_TAG_INVALID16) {
2403 continue; /* Empty slot, skip to next */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002404 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002405
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002406 /* See if there's a content decoder for it */
2407 uTagNumber = QCBORDecode_Private_UnMapTagNumber(pMe, pDecodedItem->auTagNumbers[nTagIndex]);
2408 pTagDecoder = QCBORDecode_Private_LookUpTagDecoder(pMe->pTagDecoderTable, uTagNumber);
2409 if(pTagDecoder == NULL) {
2410 break; /* Successful exist -- a tag that we can't decode */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002411 }
Laurence Lundblade99615302020-11-29 11:19:47 -08002412
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002413 /* Call the content decoder */
2414 uErr = pTagDecoder->pfContentDecoder(pMe, pMe->pTagDecodersContext, pTagDecoder->uTagNumber, pDecodedItem);
2415 if(uErr != QCBOR_SUCCESS) {
2416 break; /* Error exit from the loop */
2417 }
2418
2419 /* Remove tag number from list since its content was decoded */
2420 pDecodedItem->auTagNumbers[nTagIndex] = CBOR_TAG_INVALID16;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002421 }
2422
2423Done:
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002424#endif /* ! QCBOR_DISABLE_TAGS */
2425
2426 return uErr;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002427}
2428
2429
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002430/**
2431 * @brief Consume an entire map or array including its contents.
2432 *
2433 * @param[in] pMe The decoder context.
2434 * @param[in] pItemToConsume The array/map whose contents are to be
2435 * consumed.
2436 * @param[out] puNextNestLevel The next nesting level after the item was
2437 * fully consumed.
2438 *
2439 * This may be called when @c pItemToConsume is not an array or
2440 * map. In that case, this is just a pass through for @c puNextNestLevel
2441 * since there is nothing to do.
2442 */
2443static QCBORError
2444QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
2445 const QCBORItem *pItemToConsume,
2446 bool *pbBreak,
2447 uint8_t *puNextNestLevel)
2448{
2449 QCBORError uReturn;
2450 QCBORItem Item;
2451
2452 /* If it is a map or array, this will tell if it is empty. */
2453 const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel);
2454
2455 if(QCBORItem_IsMapOrArray(*pItemToConsume) && !bIsEmpty) {
2456 /* There is only real work to do for non-empty maps and arrays */
2457
2458 /* This works for definite- and indefinite-length maps and
2459 * arrays by using the nesting level
2460 */
2461 do {
2462 uReturn = QCBORDecode_Private_GetNextMapOrArray(pMe, pbBreak, &Item, NULL);
2463 if(QCBORDecode_IsUnrecoverableError(uReturn) ||
2464 uReturn == QCBOR_ERR_NO_MORE_ITEMS) {
2465 goto Done;
2466 }
2467 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
2468
2469 *puNextNestLevel = Item.uNextNestLevel;
2470
2471 uReturn = QCBOR_SUCCESS;
2472
2473 } else {
2474 /* pItemToConsume is not a map or array. Just pass the nesting
2475 * level through. */
2476 *puNextNestLevel = pItemToConsume->uNextNestLevel;
2477
2478 uReturn = QCBOR_SUCCESS;
2479 }
2480
2481Done:
2482 return uReturn;
2483}
2484
2485
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002486#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002487/*
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002488 * This consumes the next item. It returns the starting position of
2489 * the label and the length of the label. It also returns the nest
2490 * level of the item consumed.
2491 */
2492static QCBORError
2493QCBORDecode_Private_GetLabelAndConsume(QCBORDecodeContext *pMe,
2494 uint8_t *puNestLevel,
2495 size_t *puLabelStart,
2496 size_t *puLabelLen)
2497{
2498 QCBORError uErr;
2499 QCBORItem Item;
2500 uint8_t uLevel;
2501 uint32_t uLabelOffset;
2502
2503 /* Get the label and consume it should it be complex */
2504 *puLabelStart = UsefulInputBuf_Tell(&(pMe->InBuf));
2505
2506 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, &Item, &uLabelOffset);
2507 if(uErr != QCBOR_SUCCESS) {
2508 goto Done;
2509 }
2510 *puLabelLen = uLabelOffset - *puLabelStart;
2511 *puNestLevel = Item.uNestingLevel;
2512 uErr = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uLevel);
2513
2514Done:
2515 return uErr;
2516}
2517
2518
2519/* Loop over items in a map until the end of the map looking for
2520 * duplicates. This starts at the current position in the map, not at
2521 * the beginning of the map.
2522 *
2523 * This saves and restores the traversal cursor and nest tracking so
2524 * they are the same on exit as they were on entry.
2525 */
2526static QCBORError
2527QCBORDecode_Private_CheckDups(QCBORDecodeContext *pMe,
2528 const uint8_t uNestLevel,
2529 const size_t uCompareLabelStart,
2530 const size_t uCompareLabelLen)
2531{
2532 QCBORError uErr;
2533 size_t uLabelStart;
2534 size_t uLabelLen;
2535 uint8_t uLevel;
2536 int nCompare;
2537
2538 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2539 const UsefulInputBuf Save = pMe->InBuf;
2540
2541 do {
2542 uErr = QCBORDecode_Private_GetLabelAndConsume(pMe, &uLevel, &uLabelStart, &uLabelLen);
2543 if(uErr != QCBOR_SUCCESS) {
2544 if(uErr == QCBOR_ERR_NO_MORE_ITEMS) {
2545 uErr = QCBOR_SUCCESS; /* Successful end */
2546 }
2547 break;
2548 }
2549
2550 if(uLevel != uNestLevel) {
2551 break; /* Successful end of loop */
2552 }
2553
2554 /* This check for dups works for labels that are preferred
2555 * serialization and are not maps. If the labels are not in
2556 * preferred serialization, then the check has to be more
2557 * complicated and is type-specific because it uses the decoded
2558 * value, not the encoded CBOR. It is further complicated for
2559 * maps because the order of items in a map that is a label
2560 * doesn't matter when checking that is is the duplicate of
2561 * another map that is a label. QCBOR so far only turns on this
2562 * dup checking as part of CDE checking which requires preferred
2563 * serialization. See 5.6 in RFC 8949.
2564 */
2565 nCompare = UsefulInputBuf_Compare(&(pMe->InBuf),
2566 uCompareLabelStart, uCompareLabelLen,
2567 uLabelStart, uLabelLen);
2568 if(nCompare == 0) {
2569 uErr = QCBOR_ERR_DUPLICATE_LABEL;
2570 break;
2571 }
2572 } while (1);
2573
2574 pMe->nesting = SaveNesting;
2575 pMe->InBuf = Save;
2576
2577 return uErr;
2578}
2579
2580
2581/* This does sort order and duplicate detection on a map. The and all
2582 * it's members must be in preferred serialization so the comparisons
2583 * work correctly.
2584 */
2585static QCBORError
2586QCBORDecode_Private_CheckMap(QCBORDecodeContext *pMe, const QCBORItem *pMapToCheck)
2587{
2588 QCBORError uErr;
2589 uint8_t uNestLevel;
2590 size_t offset2, offset1, length2, length1;
2591
2592 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2593 const UsefulInputBuf Save = pMe->InBuf;
2594 pMe->bAllowAllLabels = 1;
2595
2596 /* This loop runs over all the items in the map once, comparing
2597 * each adjacent pair for correct ordering. It also calls CheckDup
2598 * on each one which also runs over the remaining items in the map
2599 * checking for duplicates. So duplicate checking runs in n^2.
2600 */
2601
2602 offset2 = SIZE_MAX;
2603 length2 = SIZE_MAX; // To avoid uninitialized warning
2604 while(1) {
2605 uErr = QCBORDecode_Private_GetLabelAndConsume(pMe, &uNestLevel, &offset1, &length1);
2606 if(uErr != QCBOR_SUCCESS) {
2607 if(uErr == QCBOR_ERR_NO_MORE_ITEMS) {
2608 uErr = QCBOR_SUCCESS; /* Successful exit from loop */
2609 }
2610 break;
2611 }
2612
2613 if(uNestLevel < pMapToCheck->uNextNestLevel) {
2614 break; /* Successful exit from loop */
2615 }
2616
2617 if(offset2 != SIZE_MAX) {
2618 /* Check that the labels are ordered. Check is not done the
2619 * first time through the loop when offset2 is unset. Since
2620 * this does comparison of the items in encoded form they
2621 * must be preferred serialization encoded. See RFC 8949
2622 * 4.2.1.
2623 */
2624 if(UsefulInputBuf_Compare(&(pMe->InBuf), offset2, length2, offset1, length1) > 0) {
2625 uErr = QCBOR_ERR_UNSORTED;
2626 break;
2627 }
2628 }
2629
2630 uErr = QCBORDecode_Private_CheckDups(pMe, pMapToCheck->uNextNestLevel, offset1, length1);
2631 if(uErr != QCBOR_SUCCESS) {
2632 break;
2633 }
2634
2635 offset2 = offset1;
2636 length2 = length1;
2637 }
2638
2639 pMe->bAllowAllLabels = 0;
2640 pMe->nesting = SaveNesting;
2641 pMe->InBuf = Save;
2642
2643 return uErr;
2644}
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002645#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
2646
2647static QCBORError
2648QCBORDecode_Private_GetItemChecks(QCBORDecodeContext *pMe,
2649 QCBORError uErr,
2650 const size_t uOffset,
2651 QCBORItem *pDecodedItem)
2652{
2653 (void)pMe; /* Avoid warning for next two ifdefs */
2654 (void)uOffset;
2655
2656#ifndef QCBOR_DISABLE_DECODE_CONFORMANCE
2657 if(uErr == QCBOR_SUCCESS &&
Laurence Lundbladed595cb82024-11-22 12:03:13 -08002658 pMe->uDecodeMode & QCBOR_DECODE_ONLY_SORTED_MAPS &&
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002659 pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
2660 /* Traverse map checking sort order and for duplicates */
2661 uErr = QCBORDecode_Private_CheckMap(pMe, pDecodedItem);
2662 }
2663#endif /* ! QCBOR_DISABLE_CONFORMANCE */
2664
2665#ifndef QCBOR_DISABLE_TAGS
2666 if(uErr == QCBOR_SUCCESS &&
Laurence Lundbladed595cb82024-11-22 12:03:13 -08002667 !(pMe->uDecodeMode & QCBOR_DECODE_ALLOW_UNPROCESSED_TAG_NUMBERS) &&
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002668 pDecodedItem->auTagNumbers[0] != CBOR_TAG_INVALID16) {
2669 /* Not QCBOR v1; there are tag numbers -- check they were consumed */
2670 if(uOffset != pMe->uTagNumberCheckOffset || pMe->uTagNumberIndex != 255) {
2671 uErr = QCBOR_ERR_UNPROCESSED_TAG_NUMBER;
2672 }
2673 }
2674#endif /* ! QCBOR_DISABLE_TAGS */
2675
2676 if(uErr != QCBOR_SUCCESS) {
2677 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2678 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
2679 }
2680
2681 return uErr;
2682}
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002683
2684
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002685/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002686 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002687 */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002688QCBORError
2689QCBORDecode_GetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2690{
2691 QCBORError uErr;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002692 size_t uOffset;
2693
2694 uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07002695 uErr = QCBORDecode_Private_GetNextTagContent(pMe, pDecodedItem);
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002696 uErr = QCBORDecode_Private_GetItemChecks(pMe, uErr, uOffset, pDecodedItem);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07002697 return uErr;
Laurence Lundblade59289e52019-12-30 13:44:37 -08002698}
2699
2700
2701/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002702 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08002703 */
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002704QCBORError
2705QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2706{
2707 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2708 const UsefulInputBuf Save = pMe->InBuf;
2709
2710 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
2711
2712 pMe->nesting = SaveNesting;
2713 pMe->InBuf = Save;
2714
2715 return uErr;
2716}
2717
2718
2719/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002720 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade2a26abb2020-11-05 19:06:54 -08002721 */
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002722void
2723QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2724{
2725 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002726 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2727 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002728 return;
2729 }
2730
2731 pMe->uLastError = (uint8_t)QCBORDecode_PeekNext(pMe, pDecodedItem);
2732}
2733
2734
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002735static void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002736QCBORDecode_Private_SaveTagNumbers(QCBORDecodeContext *pMe, const QCBORItem *pItem)
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002737{
2738#ifndef QCBOR_DISABLE_TAGS
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002739 memcpy(pMe->auLastTags, pItem->auTagNumbers, sizeof(pItem->auTagNumbers));
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07002740#else
2741 (void)pMe;
2742 (void)pItem;
2743#endif
2744}
2745
Laurence Lundblade3427dee2021-06-20 11:11:24 -07002746/*
2747 * Public function, see header qcbor/qcbor_decode.h file
2748 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002749void
2750QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002751{
2752 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladef00b8be2024-03-08 10:34:33 -08002753 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2754 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002755 return;
2756 }
2757
2758 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem);
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002759 QCBORDecode_Private_SaveTagNumbers(pMe, pDecodedItem);
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002760}
2761
2762
2763/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002764 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002765 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002766QCBORError
2767QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002768{
Laurence Lundblade87495732021-02-26 10:05:55 -07002769 if(puConsumed != NULL) {
2770 *puConsumed = pMe->InBuf.cursor;
2771 }
2772
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002773 QCBORError uReturn = pMe->uLastError;
Laurence Lundblade085d7952020-07-24 10:26:30 -07002774
2775 if(uReturn != QCBOR_SUCCESS) {
2776 goto Done;
2777 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002778
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002779 /* Error out if all the maps/arrays are not closed out */
2780 if(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07002781 uReturn = QCBOR_ERR_ARRAY_OR_MAP_UNCONSUMED;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002782 goto Done;
2783 }
2784
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002785 /* Error out if not all the bytes are consumed */
2786 if(UsefulInputBuf_BytesUnconsumed(&(pMe->InBuf))) {
Laurence Lundblade085d7952020-07-24 10:26:30 -07002787 uReturn = QCBOR_ERR_EXTRA_BYTES;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002788 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002789
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002790Done:
Laurence Lundblade87495732021-02-26 10:05:55 -07002791 return uReturn;
2792}
2793
2794
2795/*
2796 * Public function, see header qcbor/qcbor_decode.h file
2797 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002798QCBORError
2799QCBORDecode_Finish(QCBORDecodeContext *pMe)
Laurence Lundblade87495732021-02-26 10:05:55 -07002800{
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002801#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002802 /* Call the destructor for the string allocator if there is one.
2803 * Always called, even if there are errors; always have to clean up.
2804 */
2805 StringAllocator_Destruct(&(pMe->StringAllocator));
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002806#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002807
Laurence Lundblade87495732021-02-26 10:05:55 -07002808 return QCBORDecode_PartialFinish(pMe, NULL);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002809}
2810
2811
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002812#ifndef QCBOR_DISABLE_TAGS
2813/*
2814 * Public function, see header qcbor/qcbor_decode.h file
2815 */
2816uint64_t
2817QCBORDecode_GetNthTagNumber(const QCBORDecodeContext *pMe,
2818 const QCBORItem *pItem,
2819 uint8_t uIndex)
2820{
2821 if(pItem->uDataType == QCBOR_TYPE_NONE) {
2822 return CBOR_TAG_INVALID64;
2823 }
2824 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2825 return CBOR_TAG_INVALID64;
2826 }
2827
2828 return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->auTagNumbers[uIndex]);
2829}
2830
2831
2832/*
2833 * Public function, see header qcbor/qcbor_decode.h file
2834 */
2835uint64_t
2836QCBORDecode_GetNthTagNumberOfLast(QCBORDecodeContext *pMe,
2837 uint8_t uIndex)
2838{
2839 if(pMe->uLastError != QCBOR_SUCCESS) {
2840 return CBOR_TAG_INVALID64;
2841 }
2842 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2843 return CBOR_TAG_INVALID64;
2844 }
2845
2846 return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->auLastTags[uIndex]);
2847}
2848
2849
2850/*
2851 * Public function, see header qcbor/qcbor_decode.h file
2852 */
2853static uint64_t
2854QCBORDecode_Private_GetNthTagNumberReverse(const QCBORDecodeContext *pMe,
2855 const uint16_t puTagNumbers[],
2856 const uint32_t uIndex)
2857{
2858 uint32_t uArrayIndex;
2859
2860 /* Find number of tag numbers */
2861 for(uArrayIndex = QCBOR_MAX_TAGS_PER_ITEM-1; uArrayIndex > 0; uArrayIndex--) {
2862 if(puTagNumbers[uArrayIndex] != CBOR_TAG_INVALID16) {
2863 break;
2864 }
2865 }
2866 if(uIndex > uArrayIndex) {
2867 return CBOR_TAG_INVALID64;
2868 }
2869
2870 return QCBORDecode_Private_UnMapTagNumber(pMe, puTagNumbers[uArrayIndex - uIndex]);
2871}
2872
2873
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002874/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002875 * Public function, see header qcbor/qcbor_decode.h file
2876 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002877uint64_t
2878QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
2879 const QCBORItem *pItem,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002880 const uint32_t uIndex)
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002881{
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002882 if(pItem->uDataType == QCBOR_TYPE_NONE) {
2883 return CBOR_TAG_INVALID64;
2884 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002885
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002886 return QCBORDecode_Private_GetNthTagNumberReverse(pMe, pItem->auTagNumbers, uIndex);
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002887}
2888
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002889
Laurence Lundblade9b334962020-08-27 10:55:53 -07002890/*
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002891 * Public function, see header qcbor/qcbor_decode.h file
2892 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002893uint64_t
2894QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe,
2895 uint32_t uIndex)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002896{
Laurence Lundblade88e9db22020-11-02 03:56:33 -08002897 if(pMe->uLastError != QCBOR_SUCCESS) {
2898 return CBOR_TAG_INVALID64;
2899 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002900 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2901 return CBOR_TAG_INVALID64;
Laurence Lundblade9b334962020-08-27 10:55:53 -07002902 }
Laurence Lundblade37286c02022-09-03 10:05:02 -07002903
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002904 return QCBORDecode_Private_GetNthTagNumberReverse(pMe, pMe->auLastTags, uIndex);
Laurence Lundblade9b334962020-08-27 10:55:53 -07002905}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002906
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002907
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002908/*
2909 * Public function, see header qcbor/qcbor_decode.h file
2910 */
2911QCBORError
2912QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pMe, uint64_t *puTagNumber)
2913{
2914 QCBORItem Item;
2915 size_t uOffset;
2916 QCBORError uErr;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002917
Laurence Lundblade721b56e2024-10-22 03:02:04 -07002918 const QCBORDecodeNesting SaveNesting = pMe->nesting;
2919 const UsefulInputBuf Save = pMe->InBuf;
2920
2921 uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
2922 if(uOffset == pMe->uTagNumberCheckOffset) {
2923 pMe->uTagNumberIndex++;
2924 } else {
2925 pMe->uTagNumberIndex = 0;
2926 }
2927
2928 *puTagNumber = CBOR_TAG_INVALID64;
2929 uErr = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
2930 if(uErr) {
2931 return uErr;
2932 }
2933
2934 *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &Item, pMe->uTagNumberIndex);
2935 if(*puTagNumber == CBOR_TAG_INVALID64 ||
2936 QCBORDecode_GetNthTagNumber(pMe, &Item, pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
2937 pMe->uTagNumberIndex = QCBOR_ALL_TAGS_PROCESSED;
2938 }
2939 pMe->uTagNumberCheckOffset = uOffset;
2940
2941 pMe->nesting = SaveNesting;
2942 pMe->InBuf = Save;
2943
2944 return QCBOR_SUCCESS;
2945}
2946
2947
2948/*
2949 * Public function, see header qcbor/qcbor_decode.h file
2950 */
2951void
2952QCBORDecode_VGetNextTagNumber(QCBORDecodeContext *pMe, uint64_t *puTagNumber)
2953{
2954 pMe->uLastError = (uint8_t)QCBORDecode_GetNextTagNumber(pMe, puTagNumber);
2955}
2956
2957#endif /* ! QCBOR_DISABLE_TAGS */
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002958
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08002959#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
Laurence Lundbladef6531662018-12-04 10:42:22 +09002960
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002961/* ===========================================================================
2962 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002963
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08002964 This implements a simple sting allocator for indefinite-length
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002965 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
2966 implements the function type QCBORStringAllocate and allows easy
2967 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09002968
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002969 This particular allocator is built-in for convenience. The caller
2970 can implement their own. All of this following code will get
2971 dead-stripped if QCBORDecode_SetMemPool() is not called.
2972
2973 This is a very primitive memory allocator. It does not track
2974 individual allocations, only a high-water mark. A free or
2975 reallocation must be of the last chunk allocated.
2976
2977 The size of the pool and offset to free memory are packed into the
2978 first 8 bytes of the memory pool so we don't have to keep them in
2979 the decode context. Since the address of the pool may not be
2980 aligned, they have to be packed and unpacked as if they were
2981 serialized data of the wire or such.
2982
2983 The sizes packed in are uint32_t to be the same on all CPU types
2984 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08002985 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002986
2987
Laurence Lundblade8e36f812024-01-26 10:59:29 -07002988static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08002989MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002990{
2991 // Use of UsefulInputBuf is overkill, but it is convenient.
2992 UsefulInputBuf UIB;
2993
Laurence Lundbladeee851742020-01-08 08:37:05 -08002994 // Just assume the size here. It was checked during SetUp so
2995 // the assumption is safe.
Laurence Lundblade93d89472020-10-03 22:30:50 -07002996 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem,QCBOR_DECODE_MIN_MEM_POOL_SIZE});
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002997 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
2998 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
2999 return UsefulInputBuf_GetError(&UIB);
3000}
3001
3002
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003003static int
Laurence Lundbladeee851742020-01-08 08:37:05 -08003004MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003005{
3006 // Use of UsefulOutBuf is overkill, but convenient. The
3007 // length check performed here is useful.
3008 UsefulOutBuf UOB;
3009
3010 UsefulOutBuf_Init(&UOB, Pool);
3011 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
3012 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
3013 return UsefulOutBuf_GetError(&UOB);
3014}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003015
3016
3017/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003018 Internal function for an allocation, reallocation free and destuct.
3019
3020 Having only one function rather than one each per mode saves space in
3021 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003022
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003023 Code Reviewers: THIS FUNCTION DOES POINTER MATH
3024 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08003025static UsefulBuf
3026MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003027{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003028 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003029
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003030 uint32_t uPoolSize;
3031 uint32_t uFreeOffset;
3032
3033 if(uNewSize > UINT32_MAX) {
3034 // This allocator is only good up to 4GB. This check should
3035 // optimize out if sizeof(size_t) == sizeof(uint32_t)
3036 goto Done;
3037 }
3038 const uint32_t uNewSize32 = (uint32_t)uNewSize;
3039
3040 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
3041 goto Done;
3042 }
3043
3044 if(uNewSize) {
3045 if(pMem) {
3046 // REALLOCATION MODE
3047 // Calculate pointer to the end of the memory pool. It is
3048 // assumed that pPool + uPoolSize won't wrap around by
3049 // assuming the caller won't pass a pool buffer in that is
3050 // not in legitimate memory space.
3051 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
3052
3053 // Check that the pointer for reallocation is in the range of the
3054 // pool. This also makes sure that pointer math further down
3055 // doesn't wrap under or over.
3056 if(pMem >= pPool && pMem < pPoolEnd) {
3057 // Offset to start of chunk for reallocation. This won't
3058 // wrap under because of check that pMem >= pPool. Cast
3059 // is safe because the pool is always less than UINT32_MAX
3060 // because of check in QCBORDecode_SetMemPool().
3061 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3062
3063 // Check to see if the allocation will fit. uPoolSize -
3064 // uMemOffset will not wrap under because of check that
3065 // pMem is in the range of the uPoolSize by check above.
3066 if(uNewSize <= uPoolSize - uMemOffset) {
3067 ReturnValue.ptr = pMem;
3068 ReturnValue.len = uNewSize;
3069
3070 // Addition won't wrap around over because uNewSize was
3071 // checked to be sure it is less than the pool size.
3072 uFreeOffset = uMemOffset + uNewSize32;
3073 }
3074 }
3075 } else {
3076 // ALLOCATION MODE
3077 // uPoolSize - uFreeOffset will not underflow because this
3078 // pool implementation makes sure uFreeOffset is always
3079 // smaller than uPoolSize through this check here and
3080 // reallocation case.
3081 if(uNewSize <= uPoolSize - uFreeOffset) {
3082 ReturnValue.len = uNewSize;
3083 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08003084 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003085 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003086 }
3087 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003088 if(pMem) {
3089 // FREE MODE
3090 // Cast is safe because of limit on pool size in
3091 // QCBORDecode_SetMemPool()
3092 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
3093 } else {
3094 // DESTRUCT MODE
3095 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003096 }
3097 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003098
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003099 UsefulBuf Pool = {pPool, uPoolSize};
3100 MemPool_Pack(Pool, uFreeOffset);
3101
3102Done:
3103 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003104}
3105
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003106
Laurence Lundbladef6531662018-12-04 10:42:22 +09003107/*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003108 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09003109 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003110QCBORError
3111QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
3112 UsefulBuf Pool,
3113 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003114{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003115 // The pool size and free mem offset are packed into the beginning
Dave Thaler93c01182022-08-06 15:08:35 -04003116 // of the pool memory. This compile time check makes sure the
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003117 // constant in the header is correct. This check should optimize
3118 // down to nothing.
Dave Thaler93c01182022-08-06 15:08:35 -04003119#ifdef _MSC_VER
3120#pragma warning(push)
3121#pragma warning(disable:4127) // conditional expression is constant
3122#endif
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003123 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003124 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003125 }
Dave Thaler93c01182022-08-06 15:08:35 -04003126#ifdef _MSC_VER
3127#pragma warning(pop)
3128#endif
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003129
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003130 // The pool size and free offset packed in to the beginning of pool
3131 // memory are only 32-bits. This check will optimize out on 32-bit
3132 // machines.
3133 if(Pool.len > UINT32_MAX) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003134 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003135 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003136
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003137 // This checks that the pool buffer given is big enough.
3138 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003139 return QCBOR_ERR_MEM_POOL_SIZE;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08003140 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003141
Laurence Lundblade3427dee2021-06-20 11:11:24 -07003142 QCBORDecode_SetUpAllocator(pMe, MemPool_Function, Pool.ptr, bAllStrings);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08003143
Laurence Lundblade30816f22018-11-10 13:40:22 +07003144 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07003145}
Laurence Lundbladef6da33c2020-11-26 18:15:05 -08003146#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003147
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003148
3149
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003150/*
3151 * Public function, see header qcbor/qcbor_decode.h file
3152 */
3153void
3154QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003155{
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003156 QCBORDecode_VGetNext(pMe, pDecodedItem);
3157
3158 if(pMe->uLastError == QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003159 pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL,
Máté Tóth-Pálc6d59682021-05-26 18:55:30 +02003160 &pDecodedItem->uNextNestLevel);
Laurence Lundblade732e52d2021-02-22 20:11:01 -07003161 }
3162}
3163
3164
Laurence Lundblade11654912024-05-09 11:49:24 -07003165/*
3166 * Public function, see header qcbor/qcbor_decode.h file
3167 */
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003168QCBORError
3169QCBORDecode_EndCheck(QCBORDecodeContext *pMe)
Laurence Lundblade11654912024-05-09 11:49:24 -07003170{
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003171 size_t uCursorOffset;
3172 QCBORError uErr;
Laurence Lundblade11654912024-05-09 11:49:24 -07003173
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003174 uErr = QCBORDecode_GetError(pMe);
3175 if(uErr != QCBOR_SUCCESS) {
3176 return uErr;
Laurence Lundblade11654912024-05-09 11:49:24 -07003177 }
3178
3179 uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
3180
3181 if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003182 return QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade11654912024-05-09 11:49:24 -07003183 }
Laurence Lundblade535bb5e2024-06-16 12:06:32 -07003184
3185 return QCBOR_SUCCESS;
Laurence Lundblade11654912024-05-09 11:49:24 -07003186}
3187
3188
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003189/**
3190 * @brief Rewind cursor to start as if map or array were just entered.
3191 *
3192 * @param[in] pMe The decoding context
3193 *
3194 * This affects the nesting tracking and the UsefulInputBuf.
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003195 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003196static void
3197QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003198{
3199 /* Reset nesting tracking to the deepest bounded level */
3200 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3201
3202 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3203
3204 /* Reposition traversal cursor to the start of the map/array */
3205 UsefulInputBuf_Seek(&(pMe->InBuf),
3206 DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
3207}
3208
3209
3210/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003211 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003212 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003213void
3214QCBORDecode_Rewind(QCBORDecodeContext *pMe)
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003215{
3216 if(pMe->nesting.pCurrentBounded != NULL) {
3217 /* In a bounded map, array or bstr-wrapped CBOR */
3218
3219 if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
3220 /* In bstr-wrapped CBOR. */
3221
3222 /* Reposition traversal cursor to start of wrapping byte string */
3223 UsefulInputBuf_Seek(&(pMe->InBuf),
3224 pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
3225 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
3226
3227 } else {
3228 /* In a map or array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003229 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundbladecf41c522021-02-20 10:19:07 -07003230 }
3231
3232 } else {
3233 /* Not in anything bounded */
3234
3235 /* Reposition traversal cursor to the start of input CBOR */
3236 UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
3237
3238 /* Reset nesting tracking to beginning of input. */
3239 DecodeNesting_Init(&(pMe->nesting));
3240 }
3241
3242 pMe->uLastError = QCBOR_SUCCESS;
3243}
3244
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003245
Laurence Lundblade9b334962020-08-27 10:55:53 -07003246
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003247
3248
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003249typedef struct {
3250 void *pCBContext;
3251 QCBORItemCallback pfCallback;
3252} MapSearchCallBack;
3253
3254typedef struct {
3255 size_t uStartOffset;
3256 uint16_t uItemCount;
3257} MapSearchInfo;
3258
3259
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003260/**
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003261 * @brief Search a map for a set of items.
3262 *
3263 * @param[in] pMe The decode context to search.
3264 * @param[in,out] pItemArray The items to search for and the items found.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003265 * @param[out] pInfo Several bits of meta-info returned by search.
3266 * @param[in] pCallBack Callback object or @c NULL.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003267 *
3268 * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map.
3269 *
3270 * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label)
3271 * were found for one of the labels being
3272 * search for. This duplicate detection is
3273 * only performed for items in pItemArray,
3274 * not every item in the map.
3275 *
3276 * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was
3277 * wrong for the matchd label.
3278 *
3279 * @retval Also errors returned by QCBORDecode_GetNext().
3280 *
Laurence Lundblade88ba5662024-11-03 02:10:24 -08003281 * On input, @c pItemArray contains a list of labels and data types of
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003282 * items to be found.
3283 *
3284 * On output, the fully retrieved items are filled in with values and
3285 * such. The label was matched, so it never changes.
3286 *
3287 * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE.
3288 *
3289 * This also finds the ends of maps and arrays when they are exited.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003290 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003291static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003292QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
3293 QCBORItem *pItemArray,
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003294 MapSearchInfo *pInfo,
3295 MapSearchCallBack *pCallBack)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003296{
Laurence Lundbladee6f15112020-07-23 18:44:16 -07003297 QCBORError uReturn;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003298 uint64_t uFoundItemBitMap = 0;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07003299
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003300 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003301 uReturn = pMe->uLastError;
3302 goto Done2;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003303 }
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003304
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003305 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) &&
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003306 pItemArray->uLabelType != QCBOR_TYPE_NONE) {
3307 /* QCBOR_TYPE_NONE as first item indicates just looking
3308 for the end of an array, so don't give error. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003309 uReturn = QCBOR_ERR_MAP_NOT_ENTERED;
3310 goto Done2;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003311 }
3312
Laurence Lundblade085d7952020-07-24 10:26:30 -07003313 if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) {
3314 // It is an empty bounded array or map
3315 if(pItemArray->uLabelType == QCBOR_TYPE_NONE) {
3316 // Just trying to find the end of the map or array
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003317 pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003318 uReturn = QCBOR_SUCCESS;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003319 } else {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003320 // Nothing is ever found in an empty array or map. All items
3321 // are marked as not found below.
Laurence Lundblade085d7952020-07-24 10:26:30 -07003322 uReturn = QCBOR_SUCCESS;
3323 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003324 goto Done2;
Laurence Lundblade085d7952020-07-24 10:26:30 -07003325 }
3326
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003327 QCBORDecodeNesting SaveNesting;
Laurence Lundblade11654912024-05-09 11:49:24 -07003328 size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade085d7952020-07-24 10:26:30 -07003329 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3330
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003331 /* Reposition to search from the start of the map / array */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003332 QCBORDecode_Private_RewindMapOrArray(pMe);
Laurence Lundblade1341c592020-04-11 14:19:05 -07003333
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003334 /*
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003335 Loop over all the items in the map or array. Each item
3336 could be a map or array, but label matching is only at
Laurence Lundblade3f1318a2021-01-04 18:26:44 -08003337 the main level. This handles definite- and indefinite-
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003338 length maps and arrays. The only reason this is ever
3339 called on arrays is to find their end position.
3340
3341 This will always run over all items in order to do
3342 duplicate detection.
3343
3344 This will exit with failure if it encounters an
3345 unrecoverable error, but continue on for recoverable
3346 errors.
3347
3348 If a recoverable error occurs on a matched item, then
3349 that error code is returned.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003350 */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07003351 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003352 if(pInfo) {
3353 pInfo->uItemCount = 0;
3354 }
Máté Tóth-Pál2f2aa5f2021-05-17 21:35:09 +02003355 uint8_t uNextNestLevel;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003356 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003357 /* Remember offset of the item because sometimes it has to be returned */
Laurence Lundblade1341c592020-04-11 14:19:05 -07003358 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003359
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003360 /* Get the item */
3361 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003362 /* QCBORDecode_Private_GetNextTagContent() rather than GetNext()
3363 * because a label match is performed on recoverable errors to
3364 * be able to return the the error code for the found item. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003365 QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003366 if(QCBORDecode_IsUnrecoverableError(uResult)) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003367 /* The map/array can't be decoded when unrecoverable errors occur */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003368 uReturn = uResult;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003369 goto Done;
3370 }
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003371 if(uResult == QCBOR_ERR_NO_MORE_ITEMS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003372 /* Unexpected end of map or array. */
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003373 uReturn = uResult;
Laurence Lundbladea9489f82020-09-12 13:50:56 -07003374 goto Done;
3375 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003376
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003377 /* See if item has one of the labels that are of interest */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003378 bool bMatched = false;
3379 for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) {
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003380 if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003381 /* A label match has been found */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003382 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
3383 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003384 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003385 }
Laurence Lundblade63926052021-03-29 16:05:51 -07003386 if(uResult != QCBOR_SUCCESS) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003387 /* The label matches, but the data item is in error.
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003388 * It is OK to have recoverable errors on items that
3389 * are not matched. */
Laurence Lundblade63926052021-03-29 16:05:51 -07003390 uReturn = uResult;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003391 goto Done;
3392 }
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003393 if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) {
Laurence Lundblade63926052021-03-29 16:05:51 -07003394 /* The data item is not of the type(s) requested */
3395 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003396 goto Done;
3397 }
3398
Laurence Lundblade1341c592020-04-11 14:19:05 -07003399 /* Successful match. Return the item. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003400 pItemArray[nIndex] = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003401 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003402 if(pInfo) {
3403 pInfo->uStartOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003404 }
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003405 bMatched = true;
3406 }
3407 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003408
3409
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003410 if(!bMatched && pCallBack != NULL) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003411 /*
3412 Call the callback on unmatched labels.
3413 (It is tempting to do duplicate detection here, but that would
3414 require dynamic memory allocation because the number of labels
3415 that might be encountered is unbounded.)
3416 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003417 uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item);
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003418 if(uReturn != QCBOR_SUCCESS) {
3419 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003420 }
3421 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003422
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003423 /*
3424 Consume the item whether matched or not. This
3425 does the work of traversing maps and array and
3426 everything in them. In this loop only the
3427 items at the current nesting level are examined
3428 to match the labels.
3429 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003430 uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel);
Laurence Lundbladec7114722020-08-13 05:11:40 -07003431 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07003432 goto Done;
3433 }
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003434
3435 if(pInfo) {
3436 pInfo->uItemCount++;
3437 }
3438
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003439 } while (uNextNestLevel >= uMapNestLevel);
Laurence Lundblade9b334962020-08-27 10:55:53 -07003440
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003441 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003442
3443 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003444
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003445 // Check here makes sure that this won't accidentally be
3446 // QCBOR_MAP_OFFSET_CACHE_INVALID which is larger than
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003447 // QCBOR_MAX_DECODE_INPUT_SIZE.
Laurence Lundblade9c1b7b42020-12-12 11:44:16 -08003448 // Cast to uint32_t to possibly address cases where SIZE_MAX < UINT32_MAX
3449 if((uint32_t)uEndOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07003450 uReturn = QCBOR_ERR_INPUT_TOO_LARGE;
3451 goto Done;
3452 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003453 /* Cast OK because encoded CBOR is limited to UINT32_MAX */
3454 pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003455
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003456 Done:
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003457 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade11654912024-05-09 11:49:24 -07003458 UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos);
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003459
3460 Done2:
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003461 /* For all items not found, set the data and label type to QCBOR_TYPE_NONE */
Laurence Lundbladec7114722020-08-13 05:11:40 -07003462 for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003463 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003464 pItemArray[i].uDataType = QCBOR_TYPE_NONE;
3465 pItemArray[i].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003466 }
3467 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003468
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003469 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003470}
3471
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003472
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003473/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003474 * Public function, see header qcbor/qcbor_decode.h file
3475 */
3476void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003477QCBORDecode_SeekToLabelN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003478{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003479 MapSearchInfo Info;
3480 QCBORItem OneItemSeach[2];
3481
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003482 if(pMe->uLastError != QCBOR_SUCCESS) {
3483 return;
3484 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003485
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003486 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3487 OneItemSeach[0].label.int64 = nLabel;
3488 OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
3489 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
3490
3491 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
3492 if(pMe->uLastError == QCBOR_SUCCESS) {
3493 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
3494 }
3495}
3496
3497
3498void
3499QCBORDecode_SeekToLabelSZ(QCBORDecodeContext *pMe, const char *szLabel)
3500{
3501#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
3502 MapSearchInfo Info;
3503 QCBORItem OneItemSeach[2];
3504
3505 if(pMe->uLastError != QCBOR_SUCCESS) {
3506 return;
3507 }
3508
3509 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3510 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3511 OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
3512 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
3513
3514 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
3515 if(pMe->uLastError == QCBOR_SUCCESS) {
3516 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
3517 }
3518#else
3519 (void)pMe;
3520 (void)szLabel;
3521 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
3522#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
3523}
3524
3525
3526void
3527QCBORDecode_Private_GetItemInMapNoCheck(QCBORDecodeContext *pMe,
3528 QCBORItem *OneItemSeach,
3529 QCBORItem *pItem,
3530 size_t *puOffset)
3531{
3532 QCBORError uErr;
3533 MapSearchInfo SearchInfo;
3534
3535 if(pMe->uLastError != QCBOR_SUCCESS) {
3536 return;
3537 }
3538
3539 uErr = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &SearchInfo, NULL);
3540
3541 if(uErr == QCBOR_SUCCESS && OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
3542 uErr = QCBOR_ERR_LABEL_NOT_FOUND;
3543 }
3544 *pItem = OneItemSeach[0];
3545 *puOffset = SearchInfo.uStartOffset;
3546
3547 if(uErr == QCBOR_SUCCESS) {
3548 QCBORDecode_Private_SaveTagNumbers(pMe, pItem);
3549 }
3550
3551 pMe->uLastError = (uint8_t)uErr;
3552}
3553
3554
3555static void
3556QCBORDecode_Private_GetItemInMap(QCBORDecodeContext *pMe, QCBORItem *OneItemSeach, QCBORItem *pItem)
3557{
3558 QCBORError uErr;
3559 size_t uOffset;
3560
3561 QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, &uOffset);
3562
3563 uErr = QCBORDecode_Private_GetItemChecks(pMe, pMe->uLastError, uOffset, pItem);
3564 if(uErr != QCBOR_SUCCESS) {
3565 goto Done;
3566 }
3567
3568 QCBORDecode_Private_SaveTagNumbers(pMe, pItem);
3569
3570Done:
3571 pMe->uLastError = (uint8_t)uErr;
3572}
3573
3574
3575/*
3576 * Public function, see header qcbor/qcbor_decode.h file
3577 */
3578void
3579QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
3580 const int64_t nLabel,
3581 const uint8_t uQcborType,
3582 QCBORItem *pItem)
3583{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003584 QCBORItem OneItemSeach[2];
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003585
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003586 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3587 OneItemSeach[0].label.int64 = nLabel;
3588 OneItemSeach[0].uDataType = uQcborType;
3589 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003590
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003591 QCBORDecode_Private_GetItemInMap(pMe, OneItemSeach, pItem);
3592}
Laurence Lundblade93d3f532020-09-28 21:09:12 -07003593
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003594
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003595/**
3596 * @brief Get an item by label by type.
3597 *
3598 * @param[in] pMe The decode context.
3599 * @param[in] nLabel The label to search map for.
3600 * @param[in] uQcborType The QCBOR type to look for.
3601 * @param[out] pItem The item found.
3602 * @param[out] puOffset The offset of item for tag consumption check.
3603 *
3604 * This finds the item with the given label in currently open
3605 * map. This does not call QCBORDecode_Private_GetItemChecks()
3606 * to check tag number consumption or decode conformance.
3607 */
Laurence Lundblade33ed26f2024-11-24 10:26:43 -08003608void
3609QCBORDecode_Private_GetItemInMapNoCheckN(QCBORDecodeContext *pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003610 const int64_t nLabel,
3611 const uint8_t uQcborType,
3612 QCBORItem *pItem,
3613 size_t *puOffset)
3614{
3615 QCBORItem OneItemSeach[2];
Laurence Lundblade1341c592020-04-11 14:19:05 -07003616
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003617 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3618 OneItemSeach[0].label.int64 = nLabel;
3619 OneItemSeach[0].uDataType = uQcborType;
3620 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07003621
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003622 QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, puOffset);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003623}
3624
3625
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003626/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003627 * Public function, see header qcbor/qcbor_decode.h file
3628 */
3629void
3630QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
3631 const char *szLabel,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003632 const uint8_t uQcborType,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003633 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003634{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003635#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003636 QCBORItem OneItemSeach[2];
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003637
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003638 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3639 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3640 OneItemSeach[0].uDataType = uQcborType;
3641 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07003642
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003643 QCBORDecode_Private_GetItemInMap(pMe, OneItemSeach, pItem);
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003644
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003645#else
3646 (void)pMe;
3647 (void)szLabel;
3648 (void)uQcborType;
3649 (void)pItem;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003650 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003651#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003652}
3653
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003654/**
3655 * @brief Get an item by string label of a particular type
3656 *
3657 * @param[in] pMe The decode context.
3658 * @param[in] szLabel The label to search map for.
3659 * @param[in] uQcborType The QCBOR type to look for.
3660 * @param[out] pItem The item found.
3661 * @param[out] puOffset The offset of item for tag consumption check.
3662 *
3663 * This finds the item with the given label in currently open
3664 * map. This does not call QCBORDecode_Private_GetItemChecks()
3665 * to check tag number consumption or decode conformance.
3666 */
Laurence Lundblade33ed26f2024-11-24 10:26:43 -08003667void
3668QCBORDecode_Private_GetItemInMapNoCheckSZ(QCBORDecodeContext *pMe,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003669 const char *szLabel,
3670 const uint8_t uQcborType,
3671 QCBORItem *pItem,
3672 size_t *puOffset)
3673{
3674#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
3675 QCBORItem OneItemSeach[2];
3676
3677 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3678 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3679 OneItemSeach[0].uDataType = uQcborType;
3680 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
3681
3682 QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, puOffset);
3683
3684#else
3685 (void)pMe;
3686 (void)szLabel;
3687 (void)uQcborType;
3688 (void)pItem;
3689 (void)puOffset;
3690 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
3691#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
3692}
3693
3694
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003695
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003696
3697/**
3698 * @brief Semi-private. Get pointer, length and item for an array or map.
3699 *
3700 * @param[in] pMe The decode context.
3701 * @param[in] uType CBOR major type, either array/map.
3702 * @param[out] pItem The item for the array/map.
3703 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3704 *
Laurence Lundblade88ba5662024-11-03 02:10:24 -08003705 * The next item to be decoded must be a map or array as specified by @c uType.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003706 *
Laurence Lundblade88ba5662024-11-03 02:10:24 -08003707 * @c pItem will be filled in with the label and tags of the array or map
3708 * in addition to @c pEncodedCBOR giving the pointer and length of the
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003709 * encoded CBOR.
3710 *
3711 * When this is complete, the traversal cursor is at the end of the array or
3712 * map that was retrieved.
3713 */
3714void
3715QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe,
3716 const uint8_t uType,
3717 QCBORItem *pItem,
3718 UsefulBufC *pEncodedCBOR)
3719{
3720 QCBORError uErr;
3721 uint8_t uNestLevel;
3722 size_t uStartingCursor;
3723 size_t uStartOfReturned;
3724 size_t uEndOfReturned;
3725 size_t uTempSaveCursor;
3726 bool bInMap;
3727 QCBORItem LabelItem;
3728 bool EndedByBreak;
3729
3730 uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3731 bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting));
3732
3733 /* Could call GetNext here, but don't need to because this
Laurence Lundblade9b2ae8a2024-07-12 11:00:20 -07003734 * is only interested in arrays and maps. TODO: switch to GetNext()? */
3735 uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem, NULL);
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003736 if(uErr != QCBOR_SUCCESS) {
3737 pMe->uLastError = (uint8_t)uErr;
3738 return;
3739 }
3740
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003741 uint8_t uItemDataType = pItem->uDataType;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003742#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003743 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
3744 uItemDataType = QCBOR_TYPE_ARRAY;
3745 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -07003746#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade5db34da2024-05-30 03:14:35 -07003747
3748 if(uItemDataType != uType) {
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003749 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
3750 return;
3751 }
3752
3753 if(bInMap) {
3754 /* If the item is in a map, the start of the array/map
3755 * itself, not the label, must be found. Do this by
3756 * rewinding to the starting position and fetching
3757 * just the label data item. QCBORDecode_Private_GetNextTagNumber()
3758 * doesn't do any of the array/map item counting or nesting
3759 * level tracking. Used here it will just fetech the label
3760 * data item.
3761 *
3762 * Have to save the cursor and put it back to the position
3763 * after the full item once the label as been fetched by
3764 * itself.
3765 */
3766 uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3767 UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor);
3768
3769 /* Item has been fetched once so safe to ignore error */
3770 (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem);
3771
3772 uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3773 UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor);
3774 } else {
3775 uStartOfReturned = uStartingCursor;
3776 }
3777
3778 /* Consume the entire array/map to find the end */
3779 uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel);
3780 if(uErr != QCBOR_SUCCESS) {
3781 pMe->uLastError = (uint8_t)uErr;
3782 goto Done;
3783 }
3784
3785 /* Fill in returned values */
3786 uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
3787 if(EndedByBreak) {
3788 /* When ascending nesting levels, a break for the level above
3789 * was consumed. That break is not a part of what is consumed here. */
3790 uEndOfReturned--;
3791 }
3792 pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned);
3793 pEncodedCBOR->len = uEndOfReturned - uStartOfReturned;
3794
3795Done:
3796 return;
3797}
3798
3799
3800/**
3801 * @brief Semi-private. Get pointer, length and item count of an array or map.
3802 *
3803 * @param[in] pMe The decode context.
3804 * @param[in] pTarget The label and type of the array or map to retrieve.
3805 * @param[out] pItem The item for the array/map.
3806 * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
3807 *
Laurence Lundblade88ba5662024-11-03 02:10:24 -08003808 * The next item to be decoded must be a map or array as specified by @c uType.
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003809 *
3810 * When this is complete, the traversal cursor is unchanged.
3811 */void
3812QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe,
3813 QCBORItem *pTarget,
3814 QCBORItem *pItem,
3815 UsefulBufC *pEncodedCBOR)
3816{
3817 MapSearchInfo Info;
3818 QCBORDecodeNesting SaveNesting;
3819 size_t uSaveCursor;
3820
3821 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL);
3822 if(pMe->uLastError != QCBOR_SUCCESS) {
3823 return;
3824 }
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003825 pMe->uLastError = (uint8_t)QCBORDecode_Private_GetItemChecks(pMe, pMe->uLastError, Info.uStartOffset, pItem);
3826 if(pMe->uLastError != QCBOR_SUCCESS) {
3827 return;
3828 }
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003829
3830 /* Save the whole position of things so they can be restored.
3831 * so the cursor position is unchanged by this operation, like
3832 * all the other GetXxxxInMap() operations. */
3833 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
3834 uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
3835
3836 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
3837 UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
3838 QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR);
3839
3840 UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor);
3841 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
3842}
3843
3844
3845
3846
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003847static void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003848QCBORDecode_Private_ProcessTagOne(QCBORDecodeContext *pMe,
3849 QCBORItem *pItem,
3850 const uint8_t uTagRequirement,
3851 const uint8_t uQCBORType,
3852 const uint64_t uTagNumber,
3853 QCBORTagContentCallBack *pfCB,
3854 size_t uOffset);
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003855
3856/**
3857 * @brief Semi-private to get an string by label to match a tag specification.
3858 *
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003859 * @param[in] pMe The decode context.
3860 * @param[in] nLabel Label to search map for.
3861 * @param[in] uTagRequirement Whether or not tag number is required.
3862 * See @ref QCBOR_TAG_REQUIREMENT_TAG.
3863 * @param[in] uQCBOR_Type QCBOR type to search for.
3864 * @param[in] uTagNumber Tag number to match.
3865 * @param[out] pString The string found.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003866 *
3867 * This finds the string with the given label in currently open
3868 * map. Then checks that its tag number and types matches the tag
3869 * specification. If not, an error is set in the decode context.
3870 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003871void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003872QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
3873 const int64_t nLabel,
3874 const uint8_t uTagRequirement,
3875 const uint8_t uQCBOR_Type,
3876 const uint64_t uTagNumber,
3877 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003878{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003879 QCBORItem Item;
3880 size_t uOffset;
3881
Laurence Lundblade33ed26f2024-11-24 10:26:43 -08003882 QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003883 QCBORDecode_Private_ProcessTagOne(pMe,
3884 &Item,
3885 uTagRequirement,
3886 uQCBOR_Type,
3887 uTagNumber,
3888 QCBORDecode_StringsTagCB,
3889 uOffset);
3890
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003891 if(pMe->uLastError == QCBOR_SUCCESS) {
3892 *pString = Item.val.string;
3893 }
3894}
3895
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003896
3897/**
3898 * @brief Semi-private to get an string by label to match a tag specification.
3899 *
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003900 * @param[in] pMe The decode context.
3901 * @param[in] szLabel Label to search map for.
3902 * @param[in] uTagRequirement Whether or not tag number is required.
3903 * See @ref QCBOR_TAG_REQUIREMENT_TAG.
3904 * @param[in] uQCBOR_Type QCBOR type to search for.
3905 * @param[in] uTagNumber Tag number to match.
3906 * @param[out] pString The string found.
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003907 *
3908 * This finds the string with the given label in currently open
3909 * map. Then checks that its tag number and types matches the tag
3910 * specification. If not, an error is set in the decode context.
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003911 */
3912void
3913QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
3914 const char *szLabel,
3915 uint8_t uTagRequirement,
3916 uint8_t uQCBOR_Type,
3917 uint64_t uTagNumber,
3918 UsefulBufC *pString)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003919{
3920 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003921 size_t uOffset;
3922
Laurence Lundblade33ed26f2024-11-24 10:26:43 -08003923 QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003924 QCBORDecode_Private_ProcessTagOne(pMe,
3925 &Item,
3926 uTagRequirement,
3927 uQCBOR_Type,
3928 uTagNumber,
3929 QCBORDecode_StringsTagCB,
3930 uOffset);
3931
3932
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003933 if(pMe->uLastError == QCBOR_SUCCESS) {
3934 *pString = Item.val.string;
3935 }
3936}
Laurence Lundblade1341c592020-04-11 14:19:05 -07003937
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07003938
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003939/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003940 * Public function, see header qcbor/qcbor_decode.h file
3941 */
3942void
3943QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003944{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003945 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003946}
3947
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003948/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07003949 * Public function, see header qcbor/qcbor_decode.h file
3950 */
3951void
3952QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe,
3953 QCBORItem *pItemList,
3954 void *pCallbackCtx,
3955 QCBORItemCallback pfCB)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003956{
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003957 MapSearchCallBack CallBack;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003958
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07003959 CallBack.pCBContext = pCallbackCtx;
3960 CallBack.pfCallback = pfCB;
3961
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003962 pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003963}
3964
3965
Laurence Lundblade721b56e2024-10-22 03:02:04 -07003966#ifndef QCBOR_DISABLE_TAGS
3967/*
3968 * Public function, see header qcbor/qcbor_decode.h file
3969 */
3970QCBORError
3971QCBORDecode_GetNextTagNumberInMapN(QCBORDecodeContext *pMe, const int64_t nLabel, uint64_t *puTagNumber)
3972{
3973 size_t uOffset;
3974 MapSearchInfo Info;
3975 QCBORItem OneItemSeach[2];
3976
3977 if(pMe->uLastError != QCBOR_SUCCESS) {
3978 return pMe->uLastError;
3979 }
3980
3981 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3982 OneItemSeach[0].label.int64 = nLabel;
3983 OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
3984 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
3985
3986 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
3987
3988 uOffset = Info.uStartOffset;
3989 if(uOffset == pMe->uTagNumberCheckOffset) {
3990 pMe->uTagNumberIndex++;
3991 } else {
3992 pMe->uTagNumberIndex = 0;
3993 }
3994
3995 *puTagNumber = CBOR_TAG_INVALID64;
3996
3997 *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex);
3998 if(*puTagNumber == CBOR_TAG_INVALID64 ||
3999 QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
4000 pMe->uTagNumberIndex = QCBOR_ALL_TAGS_PROCESSED;
4001 }
4002 pMe->uTagNumberCheckOffset = uOffset;
4003
4004 return uReturn;
4005}
4006
4007
4008/*
4009 * Public function, see header qcbor/qcbor_decode.h file
4010 */
4011QCBORError
4012QCBORDecode_GetNextTagNumberInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint64_t *puTagNumber)
4013{
4014#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
4015 size_t uOffset;
4016 MapSearchInfo Info;
4017 QCBORItem OneItemSeach[2];
4018
4019 if(pMe->uLastError != QCBOR_SUCCESS) {
4020 return pMe->uLastError;
4021 }
4022
4023 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4024 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4025 OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
4026 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
4027
4028 QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
4029
4030
4031 uOffset = Info.uStartOffset;
4032 if(uOffset == pMe->uTagNumberCheckOffset) {
4033 pMe->uTagNumberIndex++;
4034 } else {
4035 pMe->uTagNumberIndex = 0;
4036 }
4037
4038 *puTagNumber = CBOR_TAG_INVALID64;
4039
4040 *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex);
4041 if(*puTagNumber == CBOR_TAG_INVALID64 ||
4042 QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
4043 pMe->uTagNumberIndex = 255; /* All tags clear for this item */
4044 }
4045 pMe->uTagNumberCheckOffset = uOffset;
4046
4047 return uReturn;
4048#else
4049 (void)pMe;
4050 (void)szLabel;
4051 (void)puTagNumber;
4052 return QCBOR_ERR_LABEL_NOT_FOUND;
4053#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
4054}
4055#endif /* ! QCBOR_DISABLE_TAGS */
4056
4057
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004058/**
4059 * @brief Search for a map/array by label and enter it
4060 *
4061 * @param[in] pMe The decode context.
4062 * @param[in] pSearch The map/array to search for.
4063 *
4064 * @c pSearch is expected to contain one item of type map or array
4065 * with the label specified. The current bounded map will be searched for
4066 * this and if found will be entered.
4067 *
4068 * If the label is not found, or the item found is not a map or array,
4069 * the error state is set.
4070 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004071static void
4072QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07004073{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004074 QCBORError uErr;
4075 MapSearchInfo SearchInfo;
4076
Laurence Lundblade323f8a92020-09-06 19:43:09 -07004077 // The first item in pSearch is the one that is to be
4078 // entered. It should be the only one filled in. Any other
4079 // will be ignored unless it causes an error.
Laurence Lundblade34691b92020-05-18 22:25:25 -07004080 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07004081 return;
4082 }
4083
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004084 uErr = QCBORDecode_Private_MapSearch(pMe, pSearch, &SearchInfo, NULL);
4085
4086 pMe->uLastError = (uint8_t)QCBORDecode_Private_GetItemChecks(pMe, uErr, SearchInfo.uStartOffset, pSearch);
4087
Laurence Lundblade34691b92020-05-18 22:25:25 -07004088 if(pMe->uLastError != QCBOR_SUCCESS) {
4089 return;
4090 }
4091
Laurence Lundblade9b334962020-08-27 10:55:53 -07004092 if(pSearch->uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004093 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004094 return;
4095 }
4096
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004097
4098 /* The map or array was found. Now enter it.
4099 *
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004100 * QCBORDecode_EnterBoundedMapOrArray() used here, requires the
4101 * next item for the pre-order traversal cursor to be the map/array
4102 * found by MapSearch(). The next few lines of code force the
4103 * cursor to that.
4104 *
4105 * There is no need to retain the old cursor because
4106 * QCBORDecode_EnterBoundedMapOrArray() will set it to the
4107 * beginning of the map/array being entered.
4108 *
4109 * The cursor is forced by: 1) setting the input buffer position to
4110 * the item offset found by MapSearch(), 2) setting the map/array
4111 * counter to the total in the map/array, 3) setting the nesting
4112 * level. Setting the map/array counter to the total is not
4113 * strictly correct, but this is OK because this cursor only needs
4114 * to be used to get one item and MapSearch() has already found it
4115 * confirming it exists.
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004116 */
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004117 UsefulInputBuf_Seek(&(pMe->InBuf), SearchInfo.uStartOffset);
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004118
Laurence Lundbladeddebabe2020-11-22 11:32:17 -08004119 DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
4120
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004121 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07004122
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004123 QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004124}
4125
4126
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004127/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004128 * Public function, see header qcbor/qcbor_decode.h file
4129 */
4130void
4131QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004132{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004133 QCBORItem OneItemSeach[2];
4134 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4135 OneItemSeach[0].label.int64 = nLabel;
4136 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4137 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004138
Laurence Lundblade9b334962020-08-27 10:55:53 -07004139 /* The map to enter was found, now finish off entering it. */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004140 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004141}
4142
4143
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004144/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004145 * Public function, see header qcbor/qcbor_decode.h file
4146 */
4147void
4148QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004149{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004150#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004151 QCBORItem OneItemSeach[2];
4152 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4153 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4154 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
4155 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade9b334962020-08-27 10:55:53 -07004156
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004157 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004158#else
4159 (void)szLabel;
4160 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
4161#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004162}
4163
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004164/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004165 * Public function, see header qcbor/qcbor_decode.h file
4166 */
4167void
4168QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07004169{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004170 QCBORItem OneItemSeach[2];
4171 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
4172 OneItemSeach[0].label.int64 = nLabel;
4173 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4174 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004175
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004176 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07004177}
4178
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004179/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004180 * Public function, see header qcbor/qcbor_decode.h file
4181 */
4182void
4183QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundblade34691b92020-05-18 22:25:25 -07004184{
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004185#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07004186 QCBORItem OneItemSeach[2];
4187 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
4188 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
4189 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
4190 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004191
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004192 QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004193#else
4194 (void)szLabel;
4195 pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
4196#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
Laurence Lundblade1341c592020-04-11 14:19:05 -07004197}
4198
4199
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004200/**
4201 * @brief Semi-private to do the the work for EnterMap() and EnterArray().
4202 *
4203 * @param[in] pMe The decode context
4204 * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY.
4205 * @param[out] pItem The data item for the map or array entered.
4206 *
4207 * The next item in the traversal must be a map or array. This
4208 * consumes that item and does the book keeping to enter the map or
4209 * array.
4210 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004211void
4212QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe,
4213 const uint8_t uType,
4214 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004215{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004216 QCBORError uErr;
4217
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004218 /* Must only be called on maps and arrays. */
Laurence Lundblade34691b92020-05-18 22:25:25 -07004219 if(pMe->uLastError != QCBOR_SUCCESS) {
4220 // Already in error state; do nothing.
4221 return;
4222 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07004223
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004224 /* Get the data item that is the map or array being entered. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004225 QCBORItem Item;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004226 uErr = QCBORDecode_GetNext(pMe, &Item);
4227 if(uErr != QCBOR_SUCCESS) {
4228 goto Done;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07004229 }
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004230
4231 uint8_t uItemDataType = Item.uDataType;
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004232
4233#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004234 if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) {
4235 uItemDataType = QCBOR_TYPE_ARRAY;
4236 }
Laurence Lundbladeec290b82024-06-10 11:10:54 -07004237#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
4238
Laurence Lundblade5db34da2024-05-30 03:14:35 -07004239 if(uItemDataType != uType) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004240 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
4241 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07004242 }
4243
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004244 QCBORDecode_Private_SaveTagNumbers(pMe, &Item);
Laurence Lundbladed40951e2020-08-28 11:11:14 -07004245
4246
Laurence Lundbladef0499502020-08-01 11:55:57 -07004247 const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
Laurence Lundblade085d7952020-07-24 10:26:30 -07004248 if(bIsEmpty) {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004249 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
4250 // Undo decrement done by QCBORDecode_GetNext() so the the
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004251 // the decrement when exiting the map/array works correctly
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07004252 pMe->nesting.pCurrent->u.ma.uCountCursor++;
4253 }
Laurence Lundblade93d89472020-10-03 22:30:50 -07004254 // Special case to increment nesting level for zero-length maps
4255 // and arrays entered in bounded mode.
Laurence Lundbladee6f15112020-07-23 18:44:16 -07004256 DecodeNesting_Descend(&(pMe->nesting), uType);
4257 }
4258
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004259 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004260
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004261 uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty,
4262 UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004263
Laurence Lundblade6545d1b2020-10-14 11:13:13 -07004264 if(pItem != NULL) {
4265 *pItem = Item;
4266 }
4267
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004268Done:
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004269 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004270}
4271
Laurence Lundblade02625d42020-06-25 14:41:41 -07004272
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004273/**
4274 * @brief Exit a bounded map, array or bstr (semi-private).
4275 *
4276 * @param[in] pMe Decode context.
4277 * @param[in] uEndOffset The input buffer offset of the end of item exited.
4278 *
4279 * @returns QCBOR_SUCCESS or an error code.
4280 *
4281 * This is the common work for exiting a level that is a bounded map,
4282 * array or bstr wrapped CBOR.
4283 *
4284 * One chunk of work is to set up the pre-order traversal so it is at
4285 * the item just after the bounded map, array or bstr that is being
4286 * exited. This is somewhat complex.
4287 *
4288 * The other work is to level-up the bounded mode to next higest
4289 * bounded mode or the top level if there isn't one.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004290 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004291static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004292QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
4293 const uint32_t uEndOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004294{
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004295 QCBORError uErr;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004296
Laurence Lundblade02625d42020-06-25 14:41:41 -07004297 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004298 * First the pre-order-traversal byte offset is positioned to the
4299 * item just after the bounded mode item that was just consumed.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004300 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004301 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
4302
Laurence Lundblade02625d42020-06-25 14:41:41 -07004303 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004304 * Next, set the current nesting level to one above the bounded
4305 * level that was just exited.
4306 *
4307 * DecodeNesting_CheckBoundedType() is always called before this
4308 * and makes sure pCurrentBounded is valid.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004309 */
4310 DecodeNesting_LevelUpCurrent(&(pMe->nesting));
4311
4312 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004313 * This does the complex work of leveling up the pre-order
4314 * traversal when the end of a map or array or another bounded
4315 * level is reached. It may do nothing, or ascend all the way to
4316 * the top level.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004317 */
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004318 uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004319 if(uErr != QCBOR_SUCCESS) {
4320 goto Done;
4321 }
4322
Laurence Lundblade02625d42020-06-25 14:41:41 -07004323 /*
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004324 * This makes the next highest bounded level the current bounded
4325 * level. If there is no next highest level, then no bounded mode
4326 * is in effect.
Laurence Lundblade02625d42020-06-25 14:41:41 -07004327 */
4328 DecodeNesting_LevelUpBounded(&(pMe->nesting));
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004329
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004330 pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004331
4332Done:
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004333 return uErr;
4334}
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004335
Laurence Lundblade02625d42020-06-25 14:41:41 -07004336
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004337/**
4338 * @brief Get started exiting a map or array (semi-private)
4339 *
4340 * @param[in] pMe The decode context
4341 * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP
4342 *
4343 * This does some work for map and array exiting (but not
4344 * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel()
4345 * is called to do the rest.
4346 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004347void
4348QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe,
4349 const uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004350{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004351 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07004352 /* Already in error state; do nothing. */
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004353 return;
4354 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004355
Laurence Lundblade02625d42020-06-25 14:41:41 -07004356 QCBORError uErr;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004357
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004358 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004359 uErr = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004360 goto Done;
4361 }
4362
Laurence Lundblade02625d42020-06-25 14:41:41 -07004363 /*
4364 Have to set the offset to the end of the map/array
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004365 that is being exited. If there is no cached value,
Laurence Lundblade02625d42020-06-25 14:41:41 -07004366 from previous map search, then do a dummy search.
4367 */
Laurence Lundbladebfbf4942020-09-16 23:31:00 -07004368 if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004369 QCBORItem Dummy;
4370 Dummy.uLabelType = QCBOR_TYPE_NONE;
Laurence Lundbladea29f45a2024-05-14 15:55:19 -07004371 uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL);
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004372 if(uErr != QCBOR_SUCCESS) {
4373 goto Done;
4374 }
4375 }
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004376
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004377 uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004378
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004379Done:
Laurence Lundblade2b843b52020-06-16 20:51:03 -07004380 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07004381}
4382
4383
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004384// TODO: re order this file with tags stuff last. bstr is a tag thing
4385static QCBORError
4386QCBORDecode_Private_CheckTagNType(QCBORDecodeContext *pMe,
4387 const QCBORItem *pItem,
4388 const size_t uOffset,
4389 const uint8_t *uQCBORTypes,
4390 const uint64_t *uTagNumbers,
4391 const uint8_t uTagRequirement,
4392 bool *bTypeMatched);
4393
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004394/**
4395 * @brief The main work of entering some byte-string wrapped CBOR.
4396 *
4397 * @param[in] pMe The decode context.
4398 * @param[in] pItem The byte string item.
4399 * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX
4400 * @param[out] pBstr Pointer and length of byte string entered.
4401 *
4402 * This is called once the byte string item has been decoded to do all
4403 * the book keeping work for descending a nesting level into the
4404 * nested CBOR.
4405 *
4406 * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement.
4407 */
Laurence Lundblade37286c02022-09-03 10:05:02 -07004408static QCBORError
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004409QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe,
4410 const QCBORItem *pItem,
4411 const uint8_t uTagRequirement,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004412 const size_t uOffset,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004413 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004414{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004415 bool bTypeMatched;
4416 QCBORError uError;
4417
4418 const uint8_t uTypes[] = {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE};
4419 const uint64_t uTagNumbers[] = {CBOR_TAG_CBOR, CBOR_TAG_CBOR_SEQUENCE, CBOR_TAG_INVALID64};
4420
4421
Laurence Lundbladec45b5672020-07-25 23:16:36 -07004422 if(pBstr) {
4423 *pBstr = NULLUsefulBufC;
4424 }
4425
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004426 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004427 return pMe->uLastError;
4428 }
4429
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004430 if(pItem->uDataAlloc) {
4431 return QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004432 }
4433
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004434 uError = QCBORDecode_Private_CheckTagNType(pMe,
4435 pItem,
4436 uOffset,
4437 uTypes, // TODO: maybe this should be empty
4438 uTagNumbers,
4439 uTagRequirement,
4440 &bTypeMatched);
4441
4442 if(pItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
4443 uError = QCBOR_ERR_BAD_TAG_CONTENT; // TODO: error
4444 }
4445
4446
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004447 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004448 /* Reverse the decrement done by GetNext() for the bstr so the
4449 * increment in QCBORDecode_NestLevelAscender() called by
4450 * ExitBoundedLevel() will work right.
4451 */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07004452 DecodeNesting_ReverseDecrement(&(pMe->nesting));
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07004453 }
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004454
4455 if(pBstr) {
4456 *pBstr = pItem->val.string;
4457 }
4458
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004459 /* This saves the current length of the UsefulInputBuf and then
4460 * narrows the UsefulInputBuf to start and length of the wrapped
4461 * CBOR that is being entered.
4462 *
4463 * Most of these calls are simple inline accessors so this doesn't
4464 * amount to much code.
4465 */
4466
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004467 const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004468 /* This check makes the cast of uPreviousLength to uint32_t below safe. */
4469 if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004470 uError = QCBOR_ERR_INPUT_TOO_LARGE;
Laurence Lundbladef76a2622020-08-06 19:51:03 -07004471 goto Done;
4472 }
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004473
4474 const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
4475 pItem->val.string.ptr);
4476 /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
4477 if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
4478 /* This should never happen because pItem->val.string.ptr should
4479 * always be valid since it was just returned.
4480 */
4481 uError = QCBOR_ERR_INPUT_TOO_LARGE;
4482 goto Done;
4483 }
4484
4485 const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
4486
4487 UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004488 UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004489
Laurence Lundblade02625d42020-06-25 14:41:41 -07004490 uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
Laurence Lundbladea4308a82020-10-03 18:08:57 -07004491 (uint32_t)uPreviousLength,
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004492 (uint32_t)uStartOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004493Done:
4494 return uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004495}
4496
4497
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004498static void
4499QCBORDecode_Private_GetAndTell(QCBORDecodeContext *pMe, QCBORItem *Item, size_t *uOffset)
4500{
4501#ifndef QCBOR_DISABLE_TAGS
4502 if(pMe->uLastError != QCBOR_SUCCESS) {
4503 return;
4504 }
4505
4506 *uOffset = QCBORDecode_Tell(pMe);
4507#else
4508 *uOffset = SIZE_MAX;
4509
4510#endif /* ! QCBOR_DISABLE_TAGS */
4511 pMe->uLastError = (uint8_t)QCBORDecode_Private_GetNextTagContent(pMe, Item);
4512}
4513
4514
Laurence Lundblade02625d42020-06-25 14:41:41 -07004515/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004516 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004517 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004518void
4519QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe,
4520 const uint8_t uTagRequirement,
4521 UsefulBufC *pBstr)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004522{
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004523 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004524 size_t uOffset;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004525
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004526 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004527 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4528 &Item,
4529 uTagRequirement,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004530 uOffset,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004531 pBstr);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07004532}
4533
4534
Laurence Lundblade02625d42020-06-25 14:41:41 -07004535/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004536 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004537 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004538void
4539QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe,
4540 const int64_t nLabel,
4541 const uint8_t uTagRequirement,
4542 UsefulBufC *pBstr)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004543{
4544 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004545 size_t uOffset;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004546
Laurence Lundblade33ed26f2024-11-24 10:26:43 -08004547 QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_BYTE_STRING, &Item, &uOffset);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004548 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4549 &Item,
4550 uTagRequirement,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004551 uOffset,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004552 pBstr);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004553}
4554
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004555
Laurence Lundblade02625d42020-06-25 14:41:41 -07004556/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004557 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004558 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004559void
4560QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe,
4561 const char *szLabel,
4562 const uint8_t uTagRequirement,
4563 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004564{
4565 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004566 size_t uOffset;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004567
Laurence Lundblade33ed26f2024-11-24 10:26:43 -08004568 QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_BYTE_STRING, &Item, &uOffset);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004569 pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
4570 &Item,
4571 uTagRequirement,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004572 uOffset,
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004573 pBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07004574}
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004575
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004576
Laurence Lundblade02625d42020-06-25 14:41:41 -07004577/*
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004578 * Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade02625d42020-06-25 14:41:41 -07004579 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004580void
4581QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004582{
Laurence Lundblade02625d42020-06-25 14:41:41 -07004583 if(pMe->uLastError != QCBOR_SUCCESS) {
4584 // Already in error state; do nothing.
4585 return;
4586 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004587
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07004588 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
Laurence Lundbladea9489f82020-09-12 13:50:56 -07004589 pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH;
Laurence Lundblade02625d42020-06-25 14:41:41 -07004590 return;
4591 }
4592
Laurence Lundbladecf41c522021-02-20 10:19:07 -07004593 const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
4594
Laurence Lundblade02625d42020-06-25 14:41:41 -07004595 /*
4596 Reset the length of the UsefulInputBuf to what it was before
4597 the bstr wrapped CBOR was entered.
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004598 */
Laurence Lundblade1ba100d2020-09-19 21:41:02 -07004599 UsefulInputBuf_SetBufferLength(&(pMe->InBuf),
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004600 DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
Laurence Lundblade0750fc42020-06-20 21:02:34 -07004601
4602
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004603 QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07004604 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07004605}
4606
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004607
Laurence Lundbladee6430642020-03-14 21:15:44 -07004608
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004609/**
4610 * @brief Process simple type true and false, a boolean
4611 *
4612 * @param[in] pMe The decode context.
4613 * @param[in] pItem The item with either true or false.
4614 * @param[out] pBool The boolean value output.
4615 *
4616 * Sets the internal error if the item isn't a true or a false. Also
4617 * records any tag numbers as the tag numbers of the last item.
4618 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004619static void
4620QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe,
4621 const QCBORItem *pItem,
4622 bool *pBool)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004623{
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004624 if(pMe->uLastError != QCBOR_SUCCESS) {
4625 /* Already in error state, do nothing */
4626 return;
4627 }
4628
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004629 switch(pItem->uDataType) {
4630 case QCBOR_TYPE_TRUE:
4631 *pBool = true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004632 break;
4633
4634 case QCBOR_TYPE_FALSE:
4635 *pBool = false;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004636 break;
4637
4638 default:
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004639 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004640 break;
4641 }
4642}
Laurence Lundbladee6430642020-03-14 21:15:44 -07004643
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004644
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004645/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004646 * Public function, see header qcbor/qcbor_decode.h file
4647 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004648void
4649QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004650{
Laurence Lundbladec4537442020-04-14 18:53:22 -07004651 QCBORItem Item;
Laurence Lundbladecdbbc192024-06-28 15:13:04 -07004652 QCBORDecode_VGetNext(pMe, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004653 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004654}
4655
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004656
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004657/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004658 * Public function, see header qcbor/qcbor_decode.h file
4659 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004660void
4661QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe,
4662 const int64_t nLabel,
4663 bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004664{
4665 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004666 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004667 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004668}
4669
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07004670
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004671/*
Laurence Lundblade9f9c3732021-03-23 09:38:46 -07004672 * Public function, see header qcbor/qcbor_decode.h file
4673 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004674void
4675QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe,
4676 const char *szLabel,
4677 bool *pValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004678{
4679 QCBORItem Item;
4680 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004681 QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004682}
4683
4684
Laurence Lundblade3888f002024-06-12 21:20:56 -07004685/**
4686 * @brief Process simple values.
4687 *
4688 * @param[in] pMe The decode context.
4689 * @param[in] pItem The item with the simple value.
4690 * @param[out] puSimple The simple value output.
4691 *
4692 * Sets the internal error if the item isn't a true or a false. Also
4693 * records any tag numbers as the tag numbers of the last item.
4694 */
4695static void
4696QCBORDecode_Private_ProcessSimple(QCBORDecodeContext *pMe,
4697 const QCBORItem *pItem,
4698 uint8_t *puSimple)
4699{
4700 if(pMe->uLastError != QCBOR_SUCCESS) {
4701 return;
4702 }
4703
4704 /* It's kind of lame to remap true...undef back to simple values, but
4705 * this function isn't used much and to not do it would require
4706 * changing GetNext() behavior in an incompatible way.
4707 */
4708 switch(pItem->uDataType) {
4709 case QCBOR_TYPE_UKNOWN_SIMPLE:
4710 *puSimple = pItem->val.uSimple;
4711 break;
4712
4713 case QCBOR_TYPE_TRUE:
4714 *puSimple = CBOR_SIMPLEV_TRUE;
4715 break;
4716
4717 case QCBOR_TYPE_FALSE:
4718 *puSimple = CBOR_SIMPLEV_FALSE;
4719 break;
4720
4721 case QCBOR_TYPE_NULL:
4722 *puSimple = CBOR_SIMPLEV_NULL;
4723 break;
4724
4725 case QCBOR_TYPE_UNDEF:
4726 *puSimple = CBOR_SIMPLEV_UNDEF;
4727 break;
4728
4729 default:
4730 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4731 return;
4732 }
Laurence Lundblade3888f002024-06-12 21:20:56 -07004733}
4734
4735/*
4736 * Public function, see header qcbor/qcbor_decode.h file
4737 */
4738void
4739QCBORDecode_GetSimple(QCBORDecodeContext *pMe, uint8_t *puSimple)
4740{
4741 QCBORItem Item;
Laurence Lundblade3888f002024-06-12 21:20:56 -07004742 QCBORDecode_VGetNext(pMe, &Item);
4743 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimple);
4744}
4745
4746/*
4747 * Public function, see header qcbor/qcbor_decode.h file
4748 */
4749void
4750QCBORDecode_GetSimpleInMapN(QCBORDecodeContext *pMe,
4751 int64_t nLabel,
4752 uint8_t *puSimpleValue)
4753{
4754 QCBORItem Item;
4755 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3888f002024-06-12 21:20:56 -07004756 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
4757}
4758
4759/*
4760 * Public function, see header qcbor/qcbor_decode.h file
4761 */
4762void
4763QCBORDecode_GetSimpleInMapSZ(QCBORDecodeContext *pMe,
4764 const char *szLabel,
4765 uint8_t *puSimpleValue)
4766{
4767 QCBORItem Item;
4768 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3888f002024-06-12 21:20:56 -07004769 QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
4770}
4771
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004772
Laurence Lundbladec7114722020-08-13 05:11:40 -07004773
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004774
4775#ifndef QCBOR_DISABLE_TAGS
4776// TODO: uTagNumber might be better a list than calling this multiple times
4777static QCBORError
4778QCBORDecode_Private_Check1TagNumber(const QCBORDecodeContext *pMe,
4779 const QCBORItem *pItem,
4780 const uint64_t uTagNumber,
4781 const size_t uOffset)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004782{
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004783 if(pItem->auTagNumbers[0] == CBOR_TAG_INVALID16) {
4784 /* There are no tag numbers at all, so no unprocessed */
4785 return QCBOR_SUCCESS;
4786 }
4787
4788 /* There are some tag numbers, so keep checking. This check passes
4789 * if there is one and only one tag number that matches uTagNumber
4790 */
4791
4792 // TODO: behave different in v1 and v2?
4793
4794 const uint64_t uInnerTag = QCBORDecode_GetNthTagNumber(pMe, pItem, 0);
4795
4796 if(uInnerTag == uTagNumber && pItem->auTagNumbers[1] == CBOR_TAG_INVALID16 ) {
4797 /* The only tag number is the one we are processing so no unprocessed */
4798 return QCBOR_SUCCESS;
4799 }
4800
4801 if(uOffset != pMe->uTagNumberCheckOffset) {
4802 /* processed tag numbers are for some other item, not us */
4803 return QCBOR_ERR_UNPROCESSED_TAG_NUMBER;
4804 }
4805
4806 if(pMe->uTagNumberIndex != 1) {
4807 return QCBOR_ERR_UNPROCESSED_TAG_NUMBER;
4808 }
4809
4810 return QCBOR_SUCCESS;
4811}
4812#endif
4813
4814
4815static QCBORError
4816QCBORDecode_Private_CheckTagNType(QCBORDecodeContext *pMe,
4817 const QCBORItem *pItem,
4818 const size_t uOffset,
4819 const uint8_t *uQCBORTypes,
4820 const uint64_t *uTagNumbers,
4821 const uint8_t uTagRequirement,
4822 bool *bTypeMatched)
4823{
4824 const int nTagReq = uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
4825
4826 *bTypeMatched = false;
4827 for(const uint8_t *pTNum = uQCBORTypes; *pTNum != QCBOR_TYPE_NONE; pTNum++) {
4828 if(pItem->uDataType == *pTNum) {
4829 *bTypeMatched = true;
4830 break;
4831 }
4832 }
4833
4834#ifndef QCBOR_DISABLE_TAGS
4835 bool bTagNumberMatched;
4836 QCBORError uErr;
4837 const uint64_t uInnerTag = QCBORDecode_GetNthTagNumber(pMe, pItem, 0);
4838
4839 bTagNumberMatched = false;
4840 for(const uint64_t *pQType = uTagNumbers; *pQType != CBOR_TAG_INVALID64; pQType++) {
4841 if(uInnerTag == *pQType) {
4842 bTagNumberMatched = true;
4843 break;
4844 }
4845 }
4846
4847
4848 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
4849 /* There must be a tag number */
4850 if(!bTagNumberMatched && !*bTypeMatched) {
4851 return QCBOR_ERR_UNEXPECTED_TYPE; // TODO: error code
4852 }
4853
4854 } else if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
4855 if(bTagNumberMatched || *bTypeMatched) {
4856 return QCBOR_ERR_UNEXPECTED_TYPE; // TODO: error code
4857 }
4858
4859 } else if(nTagReq == QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG) {
4860 /* No check necessary */
4861 }
4862
4863 /* Now check if there are extra tags and if there's an error in them */
4864 if(!(uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS)) {
4865 /* The flag to ignore extra is not set, so keep checking */
4866 for(const uint64_t *pTNum = uTagNumbers; *pTNum != CBOR_TAG_INVALID64; pTNum++) {
4867 uErr = QCBORDecode_Private_Check1TagNumber(pMe, pItem, *pTNum, uOffset);
4868 if(uErr != QCBOR_SUCCESS) {
4869 return uErr;
4870 }
4871 }
4872 }
4873
4874 return QCBOR_SUCCESS;
4875#else
4876 (void)pMe;
4877 (void)uOffset;
4878 (void)uTagNumbers;
4879
4880 if(nTagReq != QCBOR_TAG_REQUIREMENT_TAG && bTypeMatched) {
4881 return QCBOR_SUCCESS;
4882 } else {
4883 return QCBOR_ERR_UNEXPECTED_TYPE;
4884 }
4885
4886#endif
4887
4888}
4889
4890
Laurence Lundblade33ed26f2024-11-24 10:26:43 -08004891void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004892QCBORDecode_Private_ProcessTagItemMulti(QCBORDecodeContext *pMe,
4893 QCBORItem *pItem,
4894 const uint8_t uTagRequirement,
4895 const uint8_t uQCBORTypes[],
4896 const uint64_t uTagNumbers[],
4897 QCBORTagContentCallBack *pfCB,
4898 size_t uOffset)
4899{
4900 QCBORError uErr;
4901 bool bTypeMatched;
4902
Laurence Lundbladec7114722020-08-13 05:11:40 -07004903 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec7114722020-08-13 05:11:40 -07004904 return;
4905 }
4906
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004907 uErr = QCBORDecode_Private_CheckTagNType(pMe,
4908 pItem,
4909 uOffset,
4910 uQCBORTypes,
4911 uTagNumbers,
4912 uTagRequirement,
4913 &bTypeMatched);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004914 if(uErr != QCBOR_SUCCESS) {
4915 goto Done;
4916 }
4917
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004918 if(!bTypeMatched) {
4919 /* Tag content wasn't previously processed, do it now */
4920 uErr = (*pfCB)(pMe, NULL, uTagNumbers[0], pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07004921 if(uErr != QCBOR_SUCCESS) {
4922 goto Done;
4923 }
4924 }
4925
Laurence Lundbladec7114722020-08-13 05:11:40 -07004926Done:
4927 pMe->uLastError = (uint8_t)uErr;
4928}
4929
4930
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004931/*
4932 **/
Laurence Lundblade33ed26f2024-11-24 10:26:43 -08004933void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004934QCBORDecode_Private_ProcessTagItem(QCBORDecodeContext *pMe,
4935 QCBORItem *pItem,
4936 const uint8_t uTagRequirement,
4937 const uint8_t uQCBORTypes[],
4938 const uint64_t uTagNumber,
4939 QCBORTagContentCallBack *pfCB,
4940 size_t uOffset)
4941{
4942 uint64_t auTagNumbers[2];
4943
4944 auTagNumbers[0] = uTagNumber;
4945 auTagNumbers[1] = CBOR_TAG_INVALID64;
4946
4947 QCBORDecode_Private_ProcessTagItemMulti(pMe,
4948 pItem,
4949 uTagRequirement,
4950 uQCBORTypes,
4951 auTagNumbers,
4952 pfCB,
4953 uOffset);
4954}
4955
4956
4957static void
Laurence Lundblade68769332024-11-03 13:09:20 -08004958QCBORDecode_Private_ProcessTagOne(QCBORDecodeContext *pMe,
4959 QCBORItem *pItem,
4960 const uint8_t uTagRequirement,
4961 const uint8_t uQCBORType,
4962 const uint64_t uTagNumber,
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004963 QCBORTagContentCallBack *pfCB,
Laurence Lundblade68769332024-11-03 13:09:20 -08004964 const size_t uOffset)
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004965{
4966 uint8_t auQCBORType[2];
4967
4968 auQCBORType[0] = uQCBORType;
4969 auQCBORType[1] = QCBOR_TYPE_NONE;
4970
4971 QCBORDecode_Private_ProcessTagItem(pMe,
4972 pItem,
4973 uTagRequirement,
4974 auQCBORType,
4975 uTagNumber,
4976 pfCB,
4977 uOffset);
4978}
4979
4980
4981
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07004982
4983/*
4984 * Public function, see header qcbor/qcbor_spiffy_decode.h file
4985 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07004986void
4987QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
4988 uint8_t uTagRequirement,
4989 int64_t *pnTime)
Laurence Lundbladec7114722020-08-13 05:11:40 -07004990{
Laurence Lundbladec7114722020-08-13 05:11:40 -07004991 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07004992 size_t uOffset;
4993
4994 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
4995 QCBORDecode_Private_ProcessTagOne(pMe,
4996 &Item,
4997 uTagRequirement,
4998 QCBOR_TYPE_DATE_EPOCH,
4999 CBOR_TAG_DATE_EPOCH,
5000 QCBORDecode_DateEpochTagCB,
5001 uOffset);
5002 *pnTime = Item.val.epochDate.nSeconds;
Laurence Lundbladec7114722020-08-13 05:11:40 -07005003}
5004
5005
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005006/*
5007 * Public function, see header qcbor/qcbor_spiffy_decode.h file
5008 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07005009void
5010QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
5011 int64_t nLabel,
5012 uint8_t uTagRequirement,
5013 int64_t *pnTime)
5014{
5015 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005016 size_t uOffset;
5017
Laurence Lundblade33ed26f2024-11-24 10:26:43 -08005018 QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005019 QCBORDecode_Private_ProcessTagOne(pMe,
5020 &Item,
5021 uTagRequirement,
5022 QCBOR_TYPE_DATE_EPOCH,
5023 CBOR_TAG_DATE_EPOCH,
5024 QCBORDecode_DateEpochTagCB,
5025 uOffset);
5026 *pnTime = Item.val.epochDate.nSeconds;
Laurence Lundbladec7114722020-08-13 05:11:40 -07005027}
5028
5029
Laurence Lundblade4ae4ef92024-02-05 19:21:31 -07005030/*
5031 * Public function, see header qcbor/qcbor_spiffy_decode.h file
5032 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07005033void
5034QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
5035 const char *szLabel,
5036 uint8_t uTagRequirement,
5037 int64_t *pnTime)
5038{
5039 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005040 size_t uOffset;
Laurence Lundbladec7114722020-08-13 05:11:40 -07005041
Laurence Lundblade33ed26f2024-11-24 10:26:43 -08005042 QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005043 QCBORDecode_Private_ProcessTagOne(pMe,
5044 &Item,
5045 uTagRequirement,
5046 QCBOR_TYPE_DATE_EPOCH,
5047 CBOR_TAG_DATE_EPOCH,
5048 QCBORDecode_DateEpochTagCB,
5049 uOffset);
5050 *pnTime = Item.val.epochDate.nSeconds;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005051}
5052
5053
5054/*
5055 * Public function, see header qcbor/qcbor_decode.h
5056 */
Laurence Lundblade8e36f812024-01-26 10:59:29 -07005057void
5058QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe,
5059 uint8_t uTagRequirement,
5060 int64_t *pnDays)
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005061{
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005062 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005063 size_t uOffset;
5064
5065 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
5066 QCBORDecode_Private_ProcessTagOne(pMe,
5067 &Item,
5068 uTagRequirement,
5069 QCBOR_TYPE_DAYS_EPOCH,
5070 CBOR_TAG_DAYS_EPOCH,
5071 QCBORDecode_DaysEpochTagCB,
5072 uOffset);
5073 *pnDays = Item.val.epochDays;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005074}
5075
5076
5077/*
5078 * Public function, see header qcbor/qcbor_decode.h
5079 */
5080void
5081QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe,
5082 int64_t nLabel,
5083 uint8_t uTagRequirement,
5084 int64_t *pnDays)
5085{
5086 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005087 size_t uOffset;
5088
Laurence Lundblade33ed26f2024-11-24 10:26:43 -08005089 QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005090 QCBORDecode_Private_ProcessTagOne(pMe,
5091 &Item,
5092 uTagRequirement,
5093 QCBOR_TYPE_DAYS_EPOCH,
5094 CBOR_TAG_DAYS_EPOCH,
5095 QCBORDecode_DaysEpochTagCB,
5096 uOffset);
5097 *pnDays = Item.val.epochDays;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005098}
5099
5100
5101/*
5102 * Public function, see header qcbor/qcbor_decode.h
5103 */
5104void
5105QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe,
5106 const char *szLabel,
5107 uint8_t uTagRequirement,
5108 int64_t *pnDays)
5109{
5110 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005111 size_t uOffset;
5112
Laurence Lundblade33ed26f2024-11-24 10:26:43 -08005113 QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005114 QCBORDecode_Private_ProcessTagOne(pMe,
5115 &Item,
5116 uTagRequirement,
5117 QCBOR_TYPE_DAYS_EPOCH,
5118 CBOR_TAG_DAYS_EPOCH,
5119 QCBORDecode_DaysEpochTagCB,
5120 uOffset);
5121 *pnDays = Item.val.epochDays;
Laurence Lundblade46d63e92021-05-13 11:37:10 -07005122}
5123
5124
5125
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005126
Laurence Lundblade37286c02022-09-03 10:05:02 -07005127void
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005128QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
5129 const uint8_t uTagRequirement,
5130 const uint8_t uQCBOR_Type,
5131 const uint64_t uTagNumber,
5132 UsefulBufC *pStr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07005133{
Laurence Lundbladec4537442020-04-14 18:53:22 -07005134 QCBORItem Item;
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005135 size_t uOffset;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005136
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005137 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
5138 QCBORDecode_Private_ProcessTagOne(pMe,
5139 &Item,
5140 uTagRequirement,
5141 uQCBOR_Type,
5142 uTagNumber,
5143 QCBORDecode_StringsTagCB,
5144 uOffset);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07005145
5146 if(pMe->uLastError == QCBOR_SUCCESS) {
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005147 *pStr = Item.val.string;
Laurence Lundbladeab40c6f2020-08-28 11:24:58 -07005148 } else {
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005149 *pStr = NULLUsefulBufC;
Laurence Lundbladec4537442020-04-14 18:53:22 -07005150 }
5151}
5152
Laurence Lundbladec4537442020-04-14 18:53:22 -07005153
5154
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005155static void
5156QCBORDecode_Private_GetMIME(QCBORDecodeContext *pMe,
5157 const uint8_t uTagRequirement,
5158 QCBORItem *pItem,
5159 UsefulBufC *pValue,
5160 bool *pbIsTag257,
5161 size_t uOffset)
5162{
5163 QCBORError uErr;
5164
5165 const uint8_t puTypes[] = {QCBOR_TYPE_MIME, QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE};
5166
5167 const uint64_t puTNs[] = {CBOR_TAG_MIME, CBOR_TAG_BINARY_MIME, CBOR_TAG_INVALID64};
5168
5169 QCBORDecode_Private_ProcessTagItemMulti(pMe,
5170 pItem,
5171 uTagRequirement,
5172 puTypes,
5173 puTNs,
5174 QCBORDecode_MIMETagCB,
5175 uOffset);
5176 if(pMe->uLastError) {
5177 return;
5178 }
5179
5180 if(pItem->uDataType == QCBOR_TYPE_MIME) {
5181 *pbIsTag257 = false;
5182 } else if(pItem->uDataType == QCBOR_TYPE_BINARY_MIME) {
5183 *pbIsTag257 = true;
5184 }
5185 *pValue = pItem->val.string;
5186
5187
5188 uErr = QCBOR_SUCCESS;
5189
5190 pMe->uLastError = (uint8_t)uErr;
5191}
5192
5193
5194void
5195QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pMe,
5196 const uint8_t uTagRequirement,
5197 UsefulBufC *pMessage,
5198 bool *pbIsTag257)
5199{
5200 QCBORItem Item;
5201 size_t uOffset;
5202
5203 QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
5204 QCBORDecode_Private_GetMIME(pMe,
5205 uTagRequirement,
5206 &Item,
5207 pMessage,
5208 pbIsTag257,
5209 uOffset);
5210}
5211
5212void
5213QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pMe,
5214 const int64_t nLabel,
5215 const uint8_t uTagRequirement,
5216 UsefulBufC *pMessage,
5217 bool *pbIsTag257)
5218{
5219 QCBORItem Item;
5220 size_t uOffset;
5221
Laurence Lundblade33ed26f2024-11-24 10:26:43 -08005222 QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005223 QCBORDecode_Private_GetMIME(pMe,
5224 uTagRequirement,
5225 &Item,
5226 pMessage,
5227 pbIsTag257,
5228 uOffset);
5229}
5230
5231void
5232QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pMe,
5233 const char *szLabel,
5234 const uint8_t uTagRequirement,
5235 UsefulBufC *pMessage,
5236 bool *pbIsTag257)
5237{
5238 QCBORItem Item;
5239 size_t uOffset;
5240
Laurence Lundblade33ed26f2024-11-24 10:26:43 -08005241 QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
Laurence Lundblade721b56e2024-10-22 03:02:04 -07005242 QCBORDecode_Private_GetMIME(pMe,
5243 uTagRequirement,
5244 &Item,
5245 pMessage,
5246 pbIsTag257,
5247 uOffset);
Laurence Lundbladec4537442020-04-14 18:53:22 -07005248}
5249
5250
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005251
Laurence Lundblade93d89472020-10-03 22:30:50 -07005252// Improvement: add methods for wrapped CBOR, a simple alternate
5253// to EnterBstrWrapped
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07005254