blob: ebbca4e23e8b0a79d61656330a1ff7033d2fb4a7 [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 Lundbladeee851742020-01-08 08:37:05 -08003 Copyright (c) 2018-2020, Laurence Lundblade.
Laurence Lundbladed92a6162018-11-01 11:38:35 +07004 All rights reserved.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08005
Laurence Lundblade0dbc9172018-11-01 14:17:21 +07006Redistribution and use in source and binary forms, with or without
7modification, are permitted provided that the following conditions are
8met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of The Linux Foundation nor the names of its
16 contributors, nor the name "Laurence Lundblade" may be used to
17 endorse or promote products derived from this software without
18 specific prior written permission.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080019
Laurence Lundblade0dbc9172018-11-01 14:17:21 +070020THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
21WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
23ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
24BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
30IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Laurence Lundbladeee851742020-01-08 08:37:05 -080031 =============================================================================*/
Laurence Lundblade624405d2018-09-18 20:10:47 -070032
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080033
Laurence Lundblade844bb5c2020-03-01 17:27:25 -080034#include "qcbor/qcbor_decode.h"
Laurence Lundblade12d32c52018-09-19 11:25:27 -070035#include "ieee754.h"
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070036
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070037
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +053038/*
39 This casts away the const-ness of a pointer, usually so it can be
40 freed or realloced.
41 */
42#define UNCONST_POINTER(ptr) ((void *)(ptr))
43
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070044
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070045
Laurence Lundbladeee851742020-01-08 08:37:05 -080046/*===========================================================================
47 DecodeNesting -- Functions for tracking array/map nesting when decoding
48
Laurence Lundblade844bb5c2020-03-01 17:27:25 -080049 See qcbor/qcbor_decode.h for definition of the object
50 used here: QCBORDecodeNesting
Laurence Lundbladeee851742020-01-08 08:37:05 -080051 ===========================================================================*/
52
Laurence Lundblade9c905e82020-04-25 11:31:38 -070053
54
55/*
56The main mode of decoding is a pre-order travesal of the tree of leaves (numbers, strings...)
57formed by intermediate nodes (arrays and maps). The cursor for the traversal
58 is the byte offset in the encoded input and a leaf counter for definite
59 length maps and arrays. Indefinite length maps and arrays are handled
60 by look ahead for the break.
61
62 The view presented to the caller has tags, labels and the chunks of
63 indefinite length strings aggregated into one decorated data item.
64
65The caller understands the nesting level in pre-order traversal by
66 the fact that a data item that is a map or array is presented to
67 the caller when it is first encountered in the pre-order traversal and that all data items are presented with its nesting level
68 and the nesting level of the next item.
69
70 The caller traverse maps and arrays in a special mode that often more convenient
71 that tracking by nesting level. When an array or map is expected or encountered
72 the EnterMap or EnteryArray can be called.
73
74 When entering a map or array like this, the cursor points to the first
75 item in the map or array. When exiting, it points to the item after
76 the map or array, regardless of whether the items in the map or array were
77 all traversed.
78
79 When in a map or array, the cursor functions as normal, but traversal
80 cannot go past the end of the map or array that was entered. If this
81 is attempted the QCBOR_ERR_NO_MORE_ITEMS error is returned. To
82 go past the end of the map or array ExitMap() or ExitArray() must
83 be called. It can be called any time regardless of the position
84 of the cursor.
85
86 When a map is entered, a special function allows fetching data items
87 by label. This call will traversal the whole map looking for the
88 labeled item. The whole map is traversed so as to detect duplicates.
89 This type of fetching items does not affect the normal traversal
90 cursor.
91
92
93
94
95
96
97
98
99
100
101When a data item is presented to the caller, the nesting level of the data
102 item is presented along with the nesting level of the item that would be
103 next consumed.
104
105
106
107
108
109
110
111
112
113 */
114
Laurence Lundblade6b249302020-04-30 12:38:12 -0700115inline static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700116// TODO: add more tests for QCBOR_TYPE_MAP_AS_ARRAY mode in qcbor_decode_tests.c
Laurence Lundbladeee851742020-01-08 08:37:05 -0800117IsMapOrArray(uint8_t uDataType)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700118{
Laurence Lundblade6b249302020-04-30 12:38:12 -0700119 return uDataType == QCBOR_TYPE_MAP ||
120 uDataType == QCBOR_TYPE_ARRAY ||
121 uDataType == QCBOR_TYPE_MAP_AS_ARRAY;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700122}
123
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700124
125inline static uint8_t
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700126DecodeNesting_GetCurrentLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700127{
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700128 const ptrdiff_t nLevel = pNesting->pCurrent - &(pNesting->pMapsAndArrays[0]);
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700129 // Check in DecodeNesting_Descend and never having
130 // QCBOR_MAX_ARRAY_NESTING > 255 gaurantees cast is safe
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700131 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700132}
133
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700134inline static uint8_t
135DecodeNesting_GetBoundedModeLevel(QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700136{
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700137 const ptrdiff_t nLevel = pNesting->pCurrentBounded - &(pNesting->pMapsAndArrays[0]);
138
139 // Check in DecodeNesting_Descend and never having
140 // QCBOR_MAX_ARRAY_NESTING > 255 gaurantees cast is safe
141 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700142}
143
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700144inline static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700145DecodeNesting_IsCurrentAtTop(const QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700146{
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700147 if(pNesting->pCurrent == &(pNesting->pMapsAndArrays[0])) {
148 return true;
149 } else {
150 return false;
151 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700152}
153
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700154inline static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700155DecodeNesting_IsIndefiniteLength(const QCBORDecodeNesting *pNesting)
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700156{
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700157 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
158 /* Not a map or array */
159 return false;
160 }
161 if(pNesting->pCurrent->u.ma.uCountCursor != UINT16_MAX) {
162 /* Not indefinte length */
163 return false;
164 }
165 /* All checks passed; is an indefinte length map or array */
166 return true;
167}
168
169inline static bool
170DecodeNesting_IsDefiniteLength(const QCBORDecodeNesting *pNesting)
171{
172 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
173 /* Not a map or array */
174 return false;
175 }
176 if(pNesting->pCurrent->u.ma.uCountCursor == UINT16_MAX) {
177 /* Is indefinite */
178 return false;
179 }
180 /* All checks passed; is a definte length map or array */
181 return true;
182}
183
Laurence Lundblade6c8a4442020-06-22 22:16:11 -0700184inline static bool DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700185{
186 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
187 return true;
188 }
189 if(pNesting->pCurrent->u.ma.uStartOffset != UINT32_MAX) {
190 return true;
191 }
192 return false;
193}
194
195inline static void DecodeNesting_SetBoundedMode(const QCBORDecodeNesting *pNesting, size_t uStart)
196{
197 // Should be only called on maps and arrays
198 // TODO: check this cast, maybe give an error?
199 pNesting->pCurrent->u.ma.uStartOffset = (uint32_t)uStart;
200}
201
202inline static void DecodeNesting_ClearBoundedMode(const QCBORDecodeNesting *pNesting)
203{
204 pNesting->pCurrent->u.ma.uStartOffset = UINT32_MAX;
205}
206
207inline static bool
208DecodeNesting_IsAtEndOfBoundedMapOrArray(const QCBORDecodeNesting *pNesting)
209{
210 if(pNesting->pCurrentBounded == NULL) {
211 /* No bounded map or array or... set up. */
212 return false;
213 }
214 if(pNesting->pCurrentBounded->uLevelType == QCBOR_TYPE_BYTE_STRING) {
215 /* Not a map or array */
216 return false;
217 }
Laurence Lundblade6c8a4442020-06-22 22:16:11 -0700218 if(!DecodeNesting_IsCurrentBounded(pNesting)) { // TODO: pCurrent vs pCurrentBounded
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700219 /* Not in bounded mode. */
220 return false;
221 }
222 if(pNesting->pCurrentBounded->u.ma.uCountCursor == UINT16_MAX) {
223 /* An indefinite length map or array */
224 return false;
225 }
226 if(pNesting->pCurrentBounded->u.ma.uCountCursor != 0) {
227 /* Count is not zero, still unconsumed items. */
228 return false;
229 }
230 /* All checks passed, got to the end of a definite length map or array */
231 return true;
232}
233
234inline static bool
235DecodeNesting_IsEndOfDefiniteLengthMapOrArray(QCBORDecodeNesting *pNesting)
236{
237 /* Must only be called on map / array; TODO: add checks? */
238 if(pNesting->pCurrent->u.ma.uCountCursor == 0) {
239 return true;
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700240 } else {
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700241 return false;
242 }
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700243}
244
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700245inline static bool
246DecodeNesting_IsCurrentTypeMap(const QCBORDecodeNesting *pNesting)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700247{
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700248 if(pNesting->pCurrent->uLevelType == CBOR_MAJOR_TYPE_MAP) {
249 return true;
250 } else {
251 return false;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700252 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700253 /* Seems to be unnecessary TODO: if(DecodeNesting_IsAtTop(pNesting)) {
254 return false;
255 } */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700256}
257
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700258inline static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700259DecodeNesting_CheckBoundedType(const QCBORDecodeNesting *pNesting, uint8_t uType)
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700260{
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700261 if(pNesting->pCurrentBounded->uLevelType == uType) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700262 return true;
263 } else {
264 return false;
265 }
266}
267
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700268inline static void
Laurence Lundblade6c8a4442020-06-22 22:16:11 -0700269DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700270{
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700271 /* Only call on array / map; TODO: add check?*/
272 pNesting->pCurrent->u.ma.uCountCursor--;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700273}
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700274
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700275
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700276inline static void
277DecodeNesting_Ascend(QCBORDecodeNesting *pNesting)
278{
279 pNesting->pCurrent--;
280}
281
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700282inline static void
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700283DecodeNesting_EnterBoundedMode(QCBORDecodeNesting *pNesting, size_t uOffset)
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700284{
Laurence Lundblade0750fc42020-06-20 21:02:34 -0700285 /* Have descended into this before this is called. The job here is just to mark it in bounded mode */
286 pNesting->pCurrentBounded = pNesting->pCurrent;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700287 DecodeNesting_SetBoundedMode(pNesting, uOffset);
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700288}
289
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700290
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700291
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700292
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700293inline static QCBORError
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700294DecodeNesting_DescendMapOrArray(QCBORDecodeNesting *pNesting,
295 uint8_t uQCBORType,
296 uint64_t uCount)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700297{
298 QCBORError nReturn = QCBOR_SUCCESS;
299
300 if(uCount == 0) {
301 // Nothing to do for empty definite lenth arrays. They are just are
302 // effectively the same as an item that is not a map or array
303 goto Done;
304 // Empty indefinite length maps and arrays are handled elsewhere
305 }
306
307 // Error out if arrays is too long to handle
308 if(uCount != UINT16_MAX && uCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
309 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
310 goto Done;
311 }
312
313 // Error out if nesting is too deep
314 if(pNesting->pCurrent >= &(pNesting->pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING])) {
315 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
316 goto Done;
317 }
318
319 // The actual descend
320 pNesting->pCurrent++;
321
322 // Fill in the new level fully
Laurence Lundblade6c8a4442020-06-22 22:16:11 -0700323 pNesting->pCurrent->uLevelType = uQCBORType;
324 pNesting->pCurrent->u.ma.uCountCursor = (uint16_t)uCount;
325 pNesting->pCurrent->u.ma.uCountTotal = (uint16_t)uCount;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700326
327 DecodeNesting_ClearBoundedMode(pNesting);
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700328
329Done:
330 return nReturn;;
331}
332
333
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700334inline static QCBORError
335DecodeNesting_DescendWrappedBstr(QCBORDecodeNesting *pNesting,
336 size_t uEndOffset,
337 size_t uEndOfBstr)
338{
339 QCBORError nReturn = QCBOR_SUCCESS;
340
341 // Error out if nesting is too deep
342 if(pNesting->pCurrent >= &(pNesting->pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING])) {
343 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
344 goto Done;
345 }
346
347 // The actual descend
348 pNesting->pCurrent++;
349
350 // Fill in the new level fully
351 pNesting->pCurrent->uLevelType = QCBOR_TYPE_BYTE_STRING;
352 pNesting->pCurrent->u.bs.uPreviousEndOffset = (uint32_t)uEndOffset;
353 pNesting->pCurrent->u.bs.uEndOfBstr = (uint32_t)uEndOfBstr;
354
355 pNesting->pCurrentBounded = pNesting->pCurrent;
356
357Done:
358 return nReturn;;
359}
360
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700361
Laurence Lundbladeee851742020-01-08 08:37:05 -0800362inline static void
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700363DecodeNesting_Init(QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700364{
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700365 pNesting->pMapsAndArrays[0].uLevelType = QCBOR_TYPE_BYTE_STRING;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700366 pNesting->pCurrent = &(pNesting->pMapsAndArrays[0]);
367}
368
369
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700370static void DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting, QCBORDecodeNesting *pSave)
371{
372 *pSave = *pNesting;
Laurence Lundblade0750fc42020-06-20 21:02:34 -0700373 pNesting->pCurrent = pNesting->pCurrentBounded;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700374
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700375 if(!DecodeNesting_IsIndefiniteLength(pNesting)) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700376 pNesting->pCurrent->u.ma.uCountCursor = pNesting->pCurrent->u.ma.uCountTotal;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700377 }
378}
379
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700380static inline void DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting, QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700381{
382 *pNesting = *pSave;
383}
384
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700385
386static inline uint32_t DecodeNesting_GetEndOfBstr(QCBORDecodeNesting *pMe)
387{
388 return pMe->pCurrentBounded->u.bs.uEndOfBstr;
389}
390
391
392static inline uint32_t DecodeNesting_GetPreviousBoundedEnd(QCBORDecodeNesting *pMe)
393{
394 return pMe->pCurrentBounded->u.bs.uPreviousEndOffset;
395}
396
397
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700398QCBORError DecodeNesting_EnterBstr(QCBORDecodeNesting *pNesting, uint32_t uEndOffset)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700399{
400 QCBORError uReturn ;
401
402 // Error out if nesting is too deep
403 if(pNesting->pCurrent >= &(pNesting->pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING])) {
404 uReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
405 goto Done;
406 }
407
408 // The actual descend
409 pNesting->pCurrent++;
410
411 // Record a few details for this nesting level
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700412 pNesting->pCurrent->uLevelType = QCBOR_TYPE_BYTE_STRING; // TODO the right value for a bstr
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700413
414 uReturn = QCBOR_SUCCESS;
415
416Done:
417 return uReturn;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700418}
419
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700420
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700421
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700422
Laurence Lundbladeee851742020-01-08 08:37:05 -0800423/*===========================================================================
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800424 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
425
426 The following four functions are pretty wrappers for invocation of
427 the string allocator supplied by the caller.
428
Laurence Lundbladeee851742020-01-08 08:37:05 -0800429 ===========================================================================*/
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800430
Laurence Lundbladeee851742020-01-08 08:37:05 -0800431static inline void
432StringAllocator_Free(const QCORInternalAllocator *pMe, void *pMem)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800433{
434 (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, 0);
435}
436
Laurence Lundbladeee851742020-01-08 08:37:05 -0800437// StringAllocator_Reallocate called with pMem NULL is
438// equal to StringAllocator_Allocate()
439static inline UsefulBuf
440StringAllocator_Reallocate(const QCORInternalAllocator *pMe,
441 void *pMem,
442 size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800443{
444 return (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, uSize);
445}
446
Laurence Lundbladeee851742020-01-08 08:37:05 -0800447static inline UsefulBuf
448StringAllocator_Allocate(const QCORInternalAllocator *pMe, size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800449{
450 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
451}
452
Laurence Lundbladeee851742020-01-08 08:37:05 -0800453static inline void
454StringAllocator_Destruct(const QCORInternalAllocator *pMe)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800455{
456 if(pMe->pfAllocator) {
457 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
458 }
459}
460
461
462
Laurence Lundbladeee851742020-01-08 08:37:05 -0800463/*===========================================================================
464 QCBORDecode -- The main implementation of CBOR decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700465
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800466 See qcbor/qcbor_decode.h for definition of the object
467 used here: QCBORDecodeContext
Laurence Lundbladeee851742020-01-08 08:37:05 -0800468 ===========================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700469/*
470 Public function, see header file
471 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800472void QCBORDecode_Init(QCBORDecodeContext *me,
473 UsefulBufC EncodedCBOR,
474 QCBORDecodeMode nDecodeMode)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700475{
476 memset(me, 0, sizeof(QCBORDecodeContext));
477 UsefulInputBuf_Init(&(me->InBuf), EncodedCBOR);
Laurence Lundbladeee851742020-01-08 08:37:05 -0800478 // Don't bother with error check on decode mode. If a bad value is
479 // passed it will just act as if the default normal mode of 0 was set.
Laurence Lundbladee6bcef12020-04-01 10:56:27 -0700480 me->uDecodeMode = (uint8_t)nDecodeMode;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700481 DecodeNesting_Init(&(me->nesting));
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700482 for(int i = 0; i < QCBOR_NUM_MAPPED_TAGS; i++) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -0700483 me->auMappedTags[i] = CBOR_TAG_INVALID16;
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700484 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700485}
486
487
488/*
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700489 Public function, see header file
490 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800491void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
492 QCBORStringAllocate pfAllocateFunction,
493 void *pAllocateContext,
494 bool bAllStrings)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700495{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800496 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
497 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
498 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700499}
500
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800501
502/*
503 Public function, see header file
504 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800505void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *me,
506 const QCBORTagListIn *pTagList)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700507{
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700508 // This does nothing now. It is retained for backwards compatibility
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700509}
510
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700511
512/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800513 This decodes the fundamental part of a CBOR data item, the type and
514 number
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800515
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700516 This is the Counterpart to InsertEncodedTypeAndNumber().
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800517
Laurence Lundbladeee851742020-01-08 08:37:05 -0800518 This does the network->host byte order conversion. The conversion
519 here also results in the conversion for floats in addition to that
520 for lengths, tags and integer values.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800521
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700522 This returns:
523 pnMajorType -- the major type for the item
Laurence Lundbladeee851742020-01-08 08:37:05 -0800524
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800525 puArgument -- the "number" which is used a the value for integers,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800526 tags and floats and length for strings and arrays
527
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800528 pnAdditionalInfo -- Pass this along to know what kind of float or
Laurence Lundbladeee851742020-01-08 08:37:05 -0800529 if length is indefinite
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800530
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800531 The int type is preferred to uint8_t for some variables as this
532 avoids integer promotions, can reduce code size and makes
533 static analyzers happier.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700534 */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800535inline static QCBORError DecodeTypeAndNumber(UsefulInputBuf *pUInBuf,
536 int *pnMajorType,
537 uint64_t *puArgument,
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800538 int *pnAdditionalInfo)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700539{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700540 QCBORError nReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800541
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700542 // Get the initial byte that every CBOR data item has
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800543 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800544
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700545 // Break down the initial byte
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800546 const int nTmpMajorType = nInitialByte >> 5;
547 const int nAdditionalInfo = nInitialByte & 0x1f;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800548
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800549 // Where the number or argument accumulates
550 uint64_t uArgument;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800551
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800552 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700553 // Need to get 1,2,4 or 8 additional argument bytes. Map
554 // LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800555 static const uint8_t aIterate[] = {1,2,4,8};
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800556
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800557 // Loop getting all the bytes in the argument
558 uArgument = 0;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800559 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800560 // This shift and add gives the endian conversion
561 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
562 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800563 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800564 // The reserved and thus-far unused additional info values
565 nReturn = QCBOR_ERR_UNSUPPORTED;
566 goto Done;
567 } else {
568 // Less than 24, additional info is argument or 31, an indefinite length
569 // No more bytes to get
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800570 uArgument = (uint64_t)nAdditionalInfo;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700571 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800572
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700573 if(UsefulInputBuf_GetError(pUInBuf)) {
574 nReturn = QCBOR_ERR_HIT_END;
575 goto Done;
576 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800577
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700578 // All successful if we got here.
579 nReturn = QCBOR_SUCCESS;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800580 *pnMajorType = nTmpMajorType;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800581 *puArgument = uArgument;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800582 *pnAdditionalInfo = nAdditionalInfo;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800583
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700584Done:
585 return nReturn;
586}
587
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800588
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700589/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800590 CBOR doesn't explicitly specify two's compliment for integers but all
591 CPUs use it these days and the test vectors in the RFC are so. All
592 integers in the CBOR structure are positive and the major type
593 indicates positive or negative. CBOR can express positive integers
594 up to 2^x - 1 where x is the number of bits and negative integers
595 down to 2^x. Note that negative numbers can be one more away from
596 zero than positive. Stdint, as far as I can tell, uses two's
597 compliment to represent negative integers.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800598
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700599 See http://www.unix.org/whitepapers/64bit.html for reasons int isn't
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800600 used carefully here, and in particular why it isn't used in the interface.
601 Also see
602 https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers
603
604 Int is used for values that need less than 16-bits and would be subject
605 to integer promotion and complaining by static analyzers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700606 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800607inline static QCBORError
608DecodeInteger(int nMajorType, uint64_t uNumber, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700609{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700610 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800611
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700612 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
613 if (uNumber <= INT64_MAX) {
614 pDecodedItem->val.int64 = (int64_t)uNumber;
615 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800616
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700617 } else {
618 pDecodedItem->val.uint64 = uNumber;
619 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800620
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700621 }
622 } else {
623 if(uNumber <= INT64_MAX) {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800624 // CBOR's representation of negative numbers lines up with the
625 // two-compliment representation. A negative integer has one
626 // more in range than a positive integer. INT64_MIN is
627 // equal to (-INT64_MAX) - 1.
628 pDecodedItem->val.int64 = (-(int64_t)uNumber) - 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700629 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800630
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700631 } else {
632 // C can't represent a negative integer in this range
Laurence Lundblade21d1d812019-09-28 22:47:49 -1000633 // so it is an error.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700634 nReturn = QCBOR_ERR_INT_OVERFLOW;
635 }
636 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800637
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700638 return nReturn;
639}
640
641// Make sure #define value line up as DecodeSimple counts on this.
642#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
643#error QCBOR_TYPE_FALSE macro value wrong
644#endif
645
646#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
647#error QCBOR_TYPE_TRUE macro value wrong
648#endif
649
650#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
651#error QCBOR_TYPE_NULL macro value wrong
652#endif
653
654#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
655#error QCBOR_TYPE_UNDEF macro value wrong
656#endif
657
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700658#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
659#error QCBOR_TYPE_BREAK macro value wrong
660#endif
661
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700662#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
663#error QCBOR_TYPE_DOUBLE macro value wrong
664#endif
665
666#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
667#error QCBOR_TYPE_FLOAT macro value wrong
668#endif
669
670/*
671 Decode true, false, floats, break...
672 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800673inline static QCBORError
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800674DecodeSimple(int nAdditionalInfo, uint64_t uNumber, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700675{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700676 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800677
Laurence Lundbladeee851742020-01-08 08:37:05 -0800678 // uAdditionalInfo is 5 bits from the initial byte compile time checks
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800679 // above make sure uAdditionalInfo values line up with uDataType values.
680 // DecodeTypeAndNumber never returns a major type > 1f so cast is safe
681 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800682
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800683 switch(nAdditionalInfo) {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800684 // No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they are
685 // caught before this is called.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800686
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700687 case HALF_PREC_FLOAT:
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700688 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uNumber);
689 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700690 break;
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700691 case SINGLE_PREC_FLOAT:
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700692 pDecodedItem->val.dfnum = (double)UsefulBufUtil_CopyUint32ToFloat((uint32_t)uNumber);
693 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700694 break;
695 case DOUBLE_PREC_FLOAT:
696 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uNumber);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700697 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700698 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800699
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700700 case CBOR_SIMPLEV_FALSE: // 20
701 case CBOR_SIMPLEV_TRUE: // 21
702 case CBOR_SIMPLEV_NULL: // 22
703 case CBOR_SIMPLEV_UNDEF: // 23
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700704 case CBOR_SIMPLE_BREAK: // 31
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700705 break; // nothing to do
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800706
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700707 case CBOR_SIMPLEV_ONEBYTE: // 24
708 if(uNumber <= CBOR_SIMPLE_BREAK) {
709 // This takes out f8 00 ... f8 1f which should be encoded as e0 … f7
Laurence Lundblade077475f2019-04-26 09:06:33 -0700710 nReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700711 goto Done;
712 }
Laurence Lundblade5e390822019-01-06 12:35:01 -0800713 /* FALLTHROUGH */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700714 // fall through intentionally
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800715
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700716 default: // 0-19
717 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
Laurence Lundbladeee851742020-01-08 08:37:05 -0800718 /*
719 DecodeTypeAndNumber will make uNumber equal to
720 uAdditionalInfo when uAdditionalInfo is < 24 This cast is
721 safe because the 2, 4 and 8 byte lengths of uNumber are in
722 the double/float cases above
723 */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700724 pDecodedItem->val.uSimple = (uint8_t)uNumber;
725 break;
726 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800727
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700728Done:
729 return nReturn;
730}
731
732
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700733/*
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530734 Decode text and byte strings. Call the string allocator if asked to.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700735 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800736inline static QCBORError DecodeBytes(const QCORInternalAllocator *pAllocator,
737 int nMajorType,
738 uint64_t uStrLen,
739 UsefulInputBuf *pUInBuf,
740 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700741{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700742 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800743
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800744 // CBOR lengths can be 64 bits, but size_t is not 64 bits on all CPUs.
745 // This check makes the casts to size_t below safe.
746
747 // 4 bytes less than the largest sizeof() so this can be tested by
748 // putting a SIZE_MAX length in the CBOR test input (no one will
749 // care the limit on strings is 4 bytes shorter).
750 if(uStrLen > SIZE_MAX-4) {
751 nReturn = QCBOR_ERR_STRING_TOO_LONG;
752 goto Done;
753 }
754
755 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, (size_t)uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530756 if(UsefulBuf_IsNULLC(Bytes)) {
757 // Failed to get the bytes for this string item
758 nReturn = QCBOR_ERR_HIT_END;
759 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700760 }
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530761
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800762 if(pAllocator) {
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530763 // We are asked to use string allocator to make a copy
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800764 UsefulBuf NewMem = StringAllocator_Allocate(pAllocator, (size_t)uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530765 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade30816f22018-11-10 13:40:22 +0700766 nReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530767 goto Done;
768 }
769 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800770 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530771 } else {
772 // Normal case with no string allocator
773 pDecodedItem->val.string = Bytes;
774 }
Laurence Lundbladeee851742020-01-08 08:37:05 -0800775 const bool bIsBstr = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING);
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800776 // Cast because ternary operator causes promotion to integer
777 pDecodedItem->uDataType = (uint8_t)(bIsBstr ? QCBOR_TYPE_BYTE_STRING
778 : QCBOR_TYPE_TEXT_STRING);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800779
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530780Done:
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700781 return nReturn;
782}
783
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700784
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800785
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700786
787
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700788
789
Laurence Lundbladeee851742020-01-08 08:37:05 -0800790// Make sure the constants align as this is assumed by
791// the GetAnItem() implementation
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700792#if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
793#error QCBOR_TYPE_ARRAY value not lined up with major type
794#endif
795#if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
796#error QCBOR_TYPE_MAP value not lined up with major type
797#endif
798
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700799/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800800 This gets a single data item and decodes it including preceding
801 optional tagging. This does not deal with arrays and maps and nesting
802 except to decode the data item introducing them. Arrays and maps are
803 handled at the next level up in GetNext().
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800804
Laurence Lundbladeee851742020-01-08 08:37:05 -0800805 Errors detected here include: an array that is too long to decode,
806 hit end of buffer unexpectedly, a few forms of invalid encoded CBOR
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700807 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800808static QCBORError GetNext_Item(UsefulInputBuf *pUInBuf,
809 QCBORItem *pDecodedItem,
810 const QCORInternalAllocator *pAllocator)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700811{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700812 QCBORError nReturn;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800813
Laurence Lundbladeee851742020-01-08 08:37:05 -0800814 /*
815 Get the major type and the number. Number could be length of more
816 bytes or the value depending on the major type nAdditionalInfo is
817 an encoding of the length of the uNumber and is needed to decode
818 floats and doubles
819 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800820 int nMajorType;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700821 uint64_t uNumber;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800822 int nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800823
Laurence Lundblade4b09f632019-10-09 14:34:59 -0700824 memset(pDecodedItem, 0, sizeof(QCBORItem));
825
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800826 nReturn = DecodeTypeAndNumber(pUInBuf, &nMajorType, &uNumber, &nAdditionalInfo);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800827
Laurence Lundbladeee851742020-01-08 08:37:05 -0800828 // Error out here if we got into trouble on the type and number. The
829 // code after this will not work if the type and number is not good.
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700830 if(nReturn) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700831 goto Done;
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700832 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800833
Laurence Lundbladeee851742020-01-08 08:37:05 -0800834 // At this point the major type and the value are valid. We've got
835 // the type and the number that starts every CBOR data item.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800836 switch (nMajorType) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700837 case CBOR_MAJOR_TYPE_POSITIVE_INT: // Major type 0
838 case CBOR_MAJOR_TYPE_NEGATIVE_INT: // Major type 1
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800839 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700840 nReturn = QCBOR_ERR_BAD_INT;
841 } else {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800842 nReturn = DecodeInteger(nMajorType, uNumber, pDecodedItem);
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700843 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700844 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800845
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700846 case CBOR_MAJOR_TYPE_BYTE_STRING: // Major type 2
847 case CBOR_MAJOR_TYPE_TEXT_STRING: // Major type 3
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800848 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
849 const bool bIsBstr = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING);
850 pDecodedItem->uDataType = (uint8_t)(bIsBstr ? QCBOR_TYPE_BYTE_STRING
851 : QCBOR_TYPE_TEXT_STRING);
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530852 pDecodedItem->val.string = (UsefulBufC){NULL, SIZE_MAX};
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700853 } else {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800854 nReturn = DecodeBytes(pAllocator, nMajorType, uNumber, pUInBuf, pDecodedItem);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700855 }
856 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800857
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700858 case CBOR_MAJOR_TYPE_ARRAY: // Major type 4
859 case CBOR_MAJOR_TYPE_MAP: // Major type 5
860 // Record the number of items in the array or map
861 if(uNumber > QCBOR_MAX_ITEMS_IN_ARRAY) {
862 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
863 goto Done;
864 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800865 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530866 pDecodedItem->val.uCount = UINT16_MAX; // Indicate indefinite length
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700867 } else {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800868 // type conversion OK because of check above
869 pDecodedItem->val.uCount = (uint16_t)uNumber;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700870 }
Laurence Lundbladeee851742020-01-08 08:37:05 -0800871 // C preproc #if above makes sure constants for major types align
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800872 // DecodeTypeAndNumber never returns a major type > 7 so cast is safe
873 pDecodedItem->uDataType = (uint8_t)nMajorType;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700874 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800875
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700876 case CBOR_MAJOR_TYPE_OPTIONAL: // Major type 6, optional prepended tags
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800877 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700878 nReturn = QCBOR_ERR_BAD_INT;
879 } else {
880 pDecodedItem->val.uTagV = uNumber;
881 pDecodedItem->uDataType = QCBOR_TYPE_OPTTAG;
882 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700883 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800884
Laurence Lundbladeee851742020-01-08 08:37:05 -0800885 case CBOR_MAJOR_TYPE_SIMPLE:
886 // Major type 7, float, double, true, false, null...
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800887 nReturn = DecodeSimple(nAdditionalInfo, uNumber, pDecodedItem);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700888 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800889
Laurence Lundbladeee851742020-01-08 08:37:05 -0800890 default:
891 // Never happens because DecodeTypeAndNumber() should never return > 7
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700892 nReturn = QCBOR_ERR_UNSUPPORTED;
893 break;
894 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800895
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700896Done:
897 return nReturn;
898}
899
900
901
902/*
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800903 This layer deals with indefinite length strings. It pulls all the
Laurence Lundbladeee851742020-01-08 08:37:05 -0800904 individual chunk items together into one QCBORItem using the string
905 allocator.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800906
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530907 Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700908 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800909static inline QCBORError
910GetNext_FullItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700911{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700912 // Stack usage; int/ptr 2 UsefulBuf 2 QCBORItem -- 96
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700913
914 // Get pointer to string allocator. First use is to pass it to
915 // GetNext_Item() when option is set to allocate for *every* string.
916 // Second use here is to allocate space to coallese indefinite
917 // length string items into one.
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800918 const QCORInternalAllocator *pAllocator = me->StringAllocator.pfAllocator ?
919 &(me->StringAllocator) :
920 NULL;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800921
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700922 QCBORError nReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800923 nReturn = GetNext_Item(&(me->InBuf),
924 pDecodedItem,
925 me->bStringAllocateAll ? pAllocator: NULL);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700926 if(nReturn) {
927 goto Done;
928 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800929
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700930 // To reduce code size by removing support for indefinite length strings, the
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530931 // code in this function from here down can be eliminated. Run tests, except
932 // indefinite length string tests, to be sure all is OK if this is removed.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800933
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800934 // Only do indefinite length processing on strings
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700935 const uint8_t uStringType = pDecodedItem->uDataType;
936 if(uStringType!= QCBOR_TYPE_BYTE_STRING && uStringType != QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700937 goto Done; // no need to do any work here on non-string types
938 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800939
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800940 // Is this a string with an indefinite length?
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530941 if(pDecodedItem->val.string.len != SIZE_MAX) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800942 goto Done; // length is not indefinite, so no work to do here
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700943 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800944
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530945 // Can't do indefinite length strings without a string allocator
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800946 if(pAllocator == NULL) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700947 nReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
948 goto Done;
949 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800950
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700951 // Loop getting chunk of indefinite string
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700952 UsefulBufC FullString = NULLUsefulBufC;
953
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700954 for(;;) {
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700955 // Get item for next chunk
956 QCBORItem StringChunkItem;
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700957 // NULL string allocator passed here. Do not need to allocate
958 // chunks even if bStringAllocateAll is set.
Laurence Lundbladefae26bf2019-02-18 11:15:43 -0800959 nReturn = GetNext_Item(&(me->InBuf), &StringChunkItem, NULL);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700960 if(nReturn) {
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700961 break; // Error getting the next chunk
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700962 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800963
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530964 // See if it is a marker at end of indefinite length string
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700965 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800966 // String is complete
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700967 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +0530968 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700969 break;
970 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800971
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700972 // Match data type of chunk to type at beginning.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530973 // Also catches error of other non-string types that don't belong.
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700974 // Also catches indefinite length strings inside indefinite length strings
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800975 if(StringChunkItem.uDataType != uStringType ||
976 StringChunkItem.val.string.len == SIZE_MAX) {
Laurence Lundblade30816f22018-11-10 13:40:22 +0700977 nReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700978 break;
979 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800980
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530981 // Alloc new buffer or expand previously allocated buffer so it can fit
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800982 // The first time throurgh FullString.ptr is NULL and this is
983 // equivalent to StringAllocator_Allocate()
984 UsefulBuf NewMem = StringAllocator_Reallocate(pAllocator,
985 UNCONST_POINTER(FullString.ptr),
986 FullString.len + StringChunkItem.val.string.len);
987
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700988 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530989 // Allocation of memory for the string failed
Laurence Lundblade30816f22018-11-10 13:40:22 +0700990 nReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700991 break;
992 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800993
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700994 // Copy new string chunk at the end of string so far.
995 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700996 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800997
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800998 if(nReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
999 // Getting the item failed, clean up the allocated memory
1000 StringAllocator_Free(pAllocator, UNCONST_POINTER(FullString.ptr));
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001001 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001002
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001003Done:
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001004 return nReturn;
1005}
1006
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001007
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001008uint64_t ConvertTag(QCBORDecodeContext *me, uint16_t uTagVal) {
1009 if(uTagVal < 0xfff0) {
1010 return uTagVal;
1011 } else {
1012 // TODO constant and error check
1013 int x = uTagVal - 0xfff0;
1014 return me->auMappedTags[x];
1015 }
1016}
1017
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001018/*
Laurence Lundblade59289e52019-12-30 13:44:37 -08001019 Gets all optional tag data items preceding a data item that is not an
1020 optional tag and records them as bits in the tag map.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001021 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001022static QCBORError
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001023GetNext_TaggedItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001024{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001025 // Stack usage: int/ptr: 3 -- 24
Laurence Lundblade30816f22018-11-10 13:40:22 +07001026 QCBORError nReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001027
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001028 uint16_t auTags[QCBOR_MAX_TAGS_PER_ITEM] = {CBOR_TAG_INVALID16,
1029 CBOR_TAG_INVALID16,
1030 CBOR_TAG_INVALID16,
1031 CBOR_TAG_INVALID16};
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001032
Laurence Lundblade59289e52019-12-30 13:44:37 -08001033 // Loop fetching items until the item fetched is not a tag
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001034 for(;;) {
1035 nReturn = GetNext_FullItem(me, pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001036 if(nReturn) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001037 goto Done; // Error out of the loop
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001038 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001039
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001040 if(pDecodedItem->uDataType != QCBOR_TYPE_OPTTAG) {
1041 // Successful exit from loop; maybe got some tags, maybe not
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001042 memcpy(pDecodedItem->uTags, auTags, sizeof(auTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001043 break;
1044 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001045
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001046 // Is there room for the tag in the tags list?
1047 size_t uTagIndex;
1048 for(uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001049 if(auTags[uTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001050 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001051 }
1052 }
1053 if(uTagIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001054 return QCBOR_ERR_TOO_MANY_TAGS;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001055 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001056
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001057 // Is the tag > 16 bits?
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001058 if(pDecodedItem->val.uTagV > CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001059 size_t uTagMapIndex;
1060 // Is there room in the tag map?
1061 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001062 if(me->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001063 break;
1064 }
1065 if(me->auMappedTags[uTagMapIndex] == pDecodedItem->val.uTagV) {
1066 break;
1067 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001068 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001069 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
1070 // No room for the tag
1071 return 97; // TODO error code
1072 }
1073
1074 // Cover the case where tag is new and were it is already in the map
1075 me->auMappedTags[uTagMapIndex] = pDecodedItem->val.uTagV;
1076 auTags[uTagIndex] = (uint16_t)(uTagMapIndex + 0xfff0); // TODO proper constant and cast
1077
1078 } else {
1079 auTags[uTagIndex] = (uint16_t)pDecodedItem->val.uTagV;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001080 }
1081 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001082
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001083Done:
1084 return nReturn;
1085}
1086
1087
1088/*
Laurence Lundbladeee851742020-01-08 08:37:05 -08001089 This layer takes care of map entries. It combines the label and data
1090 items into one QCBORItem.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001091 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001092static inline QCBORError
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001093GetNext_MapEntry(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001094{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001095 // Stack use: int/ptr 1, QCBORItem -- 56
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001096 QCBORError nReturn = GetNext_TaggedItem(me, pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001097 if(nReturn)
1098 goto Done;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001099
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001100 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001101 // Break can't be a map entry
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001102 goto Done;
1103 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001104
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001105 if(me->uDecodeMode != QCBOR_DECODE_MODE_MAP_AS_ARRAY) {
1106 // In a map and caller wants maps decoded, not treated as arrays
1107
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001108 if(DecodeNesting_IsCurrentTypeMap(&(me->nesting))) {
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001109 // If in a map and the right decoding mode, get the label
1110
Laurence Lundbladeee851742020-01-08 08:37:05 -08001111 // Save label in pDecodedItem and get the next which will
1112 // be the real data
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001113 QCBORItem LabelItem = *pDecodedItem;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001114 nReturn = GetNext_TaggedItem(me, pDecodedItem);
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001115 if(nReturn)
1116 goto Done;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001117
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301118 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001119
1120 if(LabelItem.uDataType == QCBOR_TYPE_TEXT_STRING) {
1121 // strings are always good labels
1122 pDecodedItem->label.string = LabelItem.val.string;
1123 pDecodedItem->uLabelType = QCBOR_TYPE_TEXT_STRING;
1124 } else if (QCBOR_DECODE_MODE_MAP_STRINGS_ONLY == me->uDecodeMode) {
Laurence Lundbladeee851742020-01-08 08:37:05 -08001125 // It's not a string and we only want strings
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001126 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
1127 goto Done;
1128 } else if(LabelItem.uDataType == QCBOR_TYPE_INT64) {
1129 pDecodedItem->label.int64 = LabelItem.val.int64;
1130 pDecodedItem->uLabelType = QCBOR_TYPE_INT64;
1131 } else if(LabelItem.uDataType == QCBOR_TYPE_UINT64) {
1132 pDecodedItem->label.uint64 = LabelItem.val.uint64;
1133 pDecodedItem->uLabelType = QCBOR_TYPE_UINT64;
1134 } else if(LabelItem.uDataType == QCBOR_TYPE_BYTE_STRING) {
1135 pDecodedItem->label.string = LabelItem.val.string;
1136 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
1137 pDecodedItem->uLabelType = QCBOR_TYPE_BYTE_STRING;
1138 } else {
1139 // label is not an int or a string. It is an arrray
1140 // or a float or such and this implementation doesn't handle that.
1141 // Also, tags on labels are ignored.
1142 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
1143 goto Done;
1144 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001145 }
1146 } else {
1147 if(pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001148 if(pDecodedItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
1149 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
1150 goto Done;
1151 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001152 // Decoding a map as an array
1153 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001154 // Cast is safe because of check against QCBOR_MAX_ITEMS_IN_ARRAY/2
1155 // Cast is needed because of integer promotion
1156 pDecodedItem->val.uCount = (uint16_t)(pDecodedItem->val.uCount * 2);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001157 }
1158 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001159
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001160Done:
1161 return nReturn;
1162}
1163
1164
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001165static QCBORError
1166NextIsBreak(UsefulInputBuf *pUIB, bool *pbNextIsBreak)
1167{
1168 *pbNextIsBreak = false;
1169 if(UsefulInputBuf_BytesUnconsumed(pUIB) != 0) {
1170 // TODO: use the Peek method?
1171 QCBORItem Peek;
1172 size_t uPeek = UsefulInputBuf_Tell(pUIB);
1173 QCBORError uReturn = GetNext_Item(pUIB, &Peek, NULL);
1174 if(uReturn != QCBOR_SUCCESS) {
1175 return uReturn;
1176 }
1177 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
1178 // It is not a break, rewind so it can be processed normally.
1179 UsefulInputBuf_Seek(pUIB, uPeek);
1180 } else {
1181 *pbNextIsBreak = true;
1182 }
1183 }
1184
1185 return QCBOR_SUCCESS;
1186}
1187
1188
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001189/*
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001190 An item was just consumed, now figure out if it was the
1191 end of an array or map that can be closed out. That
1192 may in turn close out another map or array.
1193 */
1194static QCBORError Ascender(QCBORDecodeContext *pMe)
1195{
1196 QCBORError uReturn;
1197
1198 /* This loops ascending nesting levels as long as there is ascending to do */
1199 while(1) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001200 if(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting)) && !DecodeNesting_IsIndefiniteLength(&(pMe->nesting))) {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001201 /* 1st Case: in a definite length array (not a CBOR sequence). Simply
1202 decrement the item count. If it doesn't go to zero, then all is done.
1203 If it does go to zero, the bottom of the loop ascends one nesting level
1204 and the loop continues.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001205
1206 // TODO: check this.
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001207 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001208 if(DecodeNesting_IsDefiniteLength(&(pMe->nesting))) {
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07001209 DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(&(pMe->nesting));
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001210 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
1211 /* Didn't close out map or array; all work here is done */
1212 break;
1213 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001214 }
1215
1216 } else {
1217 /* 2nd, 3rd, 4th and 5th cases where a check for a following CBOR break must be checked for */
1218 bool bIsBreak = false;
1219 uReturn = NextIsBreak(&(pMe->InBuf), &bIsBreak);
1220 if(uReturn != QCBOR_SUCCESS) {
1221 goto Done;
1222 }
1223
1224 if(bIsBreak) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001225 if(DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001226 /* 2nd case where a break occurs at the top level and thus
1227 in a CBOR sequence. Always an error because break is
1228 not inside an indefinite length map or array. */
1229 uReturn = QCBOR_ERR_BAD_BREAK;
1230 goto Done;
1231 } else {
1232 /* 3rd case, the normal end of an indefinite length map
1233 or array. The bottom of the loop ascends one nesting
1234 level and the loop continues. */
1235 }
1236 } else {
1237 /* 4th case where an indefinite length array is not closed out
1238 and 5th case which is just an item in a CBOR sequence. In either
1239 there is no close out so all work here is done.
1240 */
1241 break;
1242 }
1243 }
1244
1245 /* All items in the level have been consumed. */
1246
1247 /* But ascent in bounded mode is only by explicit call to QCBORDecode_ExitBoundedMode() */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07001248 if(DecodeNesting_IsCurrentBounded(&(pMe->nesting))) {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001249 /* Set the count to zero for indefinite length arrays to indicate cursor is at end of bounded map / array */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001250 pMe->nesting.pCurrent->u.ma.uCountCursor = 0;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001251 break;
1252 }
1253
1254 /* Finally, actually ascend one level. */
1255 DecodeNesting_Ascend(&(pMe->nesting));
1256 }
1257
1258 uReturn = QCBOR_SUCCESS;
1259
1260Done:
1261 return uReturn;
1262}
1263
1264
1265/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001266 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001267 TODO: correct this comment
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001268 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001269static QCBORError
1270QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001271{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001272 QCBORError uReturn;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001273 /* === First figure out if at the end of traversal === */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001274
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001275 /* Case 1. Out of bytes to consume.
1276
1277 This is either the end of the top-level CBOR that was give
1278 to QCBORDecode_Init() or the end of a tag 24 bstr wrapped CBOR.
1279 It is detected by all bytes being consumed from the UsefulInputBuf.
1280
1281 To go back out of the tag 24 bstr wrapped item, the caller must
1282 explicitly call Exit() which will reset the UsefulInputBuf
1283 to the next highest bstr wrapped or the top level.
1284
1285 This is always the end condition that QCBORDecode_Finish()
1286 considers complete.
1287
1288 TODO: can the DecodeNesting_IsAtTop be removed? QCBORDecode_Finish()
1289 will perform this check.
1290
1291 */
Laurence Lundblade937ea812020-05-08 11:38:23 -07001292 /* For a pre-order traversal a non-error end occurs when there
1293 are no more bytes to consume and the nesting level is at the top.
1294 If it's not at the top, then the CBOR is not well formed. This error
1295 is caught elsewhere.
1296
1297 This handles the end of CBOR sequences as well as non-sequences. */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001298 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf)) == 0 && DecodeNesting_IsCurrentAtTop(&(me->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001299 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001300 goto Done;
1301 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07001302
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001303
1304 /* Case 2. End of map or array in bounded mode
1305
1306 The caller is attempting traveral of a bounded map or array and
1307 has got to the end of it.
1308
1309 The caller must explicitly exit the bounded mode map or array
1310 to get past this condition.
1311
1312 To complete a decode of the full input CBOR, the caller must
1313 exit all maps and arrays in bounded mode and this is never
1314 the successful end of decoding.
1315
1316 */
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001317 /* It is also an end of the input when in map mode and the cursor
Laurence Lundblade937ea812020-05-08 11:38:23 -07001318 is at the end of the map */
1319
1320
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001321 // This is to handle bounded mode
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001322 if(DecodeNesting_IsAtEndOfBoundedMapOrArray(&(me->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001323 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07001324 goto Done;
1325 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001326
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001327 /* === Not at the end; get another item === */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001328 uReturn = GetNext_MapEntry(me, pDecodedItem);
1329 if(uReturn) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001330 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001331 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301332
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001333 // Breaks ending arrays/maps are always processed at the end of this function.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301334 // They should never show up here.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301335 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001336 uReturn = QCBOR_ERR_BAD_BREAK;
Laurence Lundblade6de37062018-10-15 12:22:42 +05301337 goto Done;
Laurence Lundblade5b8c5852018-10-14 21:11:42 +05301338 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001339
Laurence Lundblade6de37062018-10-15 12:22:42 +05301340 // Record the nesting level for this data item before processing any of
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301341 // decrementing and descending.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001342 pDecodedItem->uNestingLevel = DecodeNesting_GetCurrentLevel(&(me->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001343
Laurence Lundblade6de37062018-10-15 12:22:42 +05301344 // Process the item just received for descent or decrement, and
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001345 // ascend if decrements are enough to close out a definite length array/map
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001346 if(IsMapOrArray(pDecodedItem->uDataType) && pDecodedItem->val.uCount != 0) {
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001347 // If the new item is array or map, the nesting level descends
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001348 uReturn = DecodeNesting_DescendMapOrArray(&(me->nesting), pDecodedItem->uDataType, pDecodedItem->val.uCount);
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001349 // Maps and arrays do count in as items in the map/array that encloses
1350 // them so a decrement needs to be done for them too, but that is done
1351 // only when all the items in them have been processed, not when they
Laurence Lundblade9916b1b2019-09-07 22:33:25 -07001352 // are opened with the exception of an empty map or array.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001353 if(uReturn != QCBOR_SUCCESS) {
1354 goto Done;
1355 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001356 }
1357
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001358 if(!IsMapOrArray(pDecodedItem->uDataType) ||
1359 pDecodedItem->val.uCount == 0 || pDecodedItem->val.uCount == UINT16_MAX) {
1360 /* The following cases are handled here:
1361 - A non-aggregate like an integer or string
1362 - An empty definite length map or array
1363 - An indefinite length map or array that might be empty or might not.
1364 */
1365
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001366
1367
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001368 /* === Figure out if item got closed out maps or arrays === */
1369
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001370 /*
1371 This needs to decrement, check for end and ascend
1372 the tree until an an ascend is not possible or the bounded
1373 limit is reached or the end of the encoded CBOR input
1374 is reached. For
1375 definite length maps and arrays the end is by count. For
1376 indefinite it is by a break.
1377
1378 Also state needs to be set that can tell the code at the
1379 beginning of this function that the end was reached.
1380
1381 This is complicated...
1382
1383
1384 This will handle an indefinite length array
1385 inside a definte length array inside an indefinite
1386 length array...
1387
1388 */
1389
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001390 // Decrement the count of items in the enclosing map/array
1391 // If the count in the enclosing map/array goes to zero, that
Laurence Lundblade6de37062018-10-15 12:22:42 +05301392 // triggers a decrement in the map/array above that and
1393 // an ascend in nesting level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001394 /* If the just consumed item is at the end of a map or
1395 array ascend in the nesting tracking. That may
1396 in turn may be the end of the above nesting level
1397 and so on up to the end of the whole encoded CBOR.
1398
1399 Each level could be a definite or indefinte length
1400 map or array. These are handled very differently.
1401
1402 */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001403 uReturn = Ascender(me);
1404 if(uReturn) {
1405 goto Done;
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001406 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05301407 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001408
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001409
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001410
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001411 /* === Tell the caller the nest level of the next item === */
1412
Laurence Lundblade6de37062018-10-15 12:22:42 +05301413 // Tell the caller what level is next. This tells them what maps/arrays
1414 // were closed out and makes it possible for them to reconstruct
1415 // the tree with just the information returned by GetNext
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07001416 // TODO: pull this into DecodeNesting_GetLevel
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07001417 if(DecodeNesting_IsCurrentBounded(&(me->nesting)) && me->nesting.pCurrent->u.ma.uCountCursor == 0) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001418 // At end of a map / array in map mode, so next nest is 0 to
1419 // indicate this end.
1420 pDecodedItem->uNextNestLevel = 0;
1421 } else {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001422 pDecodedItem->uNextNestLevel = DecodeNesting_GetCurrentLevel(&(me->nesting));
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001423 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001424
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001425Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001426 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundbladee9482dd2019-10-11 12:58:46 -07001427 // Make sure uDataType and uLabelType are QCBOR_TYPE_NONE
1428 memset(pDecodedItem, 0, sizeof(QCBORItem));
1429 }
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001430 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001431}
1432
1433
Laurence Lundblade59289e52019-12-30 13:44:37 -08001434/*
1435 Mostly just assign the right data type for the date string.
1436 */
1437inline static QCBORError DecodeDateString(QCBORItem *pDecodedItem)
1438{
1439 // Stack Use: UsefulBuf 1 16
1440 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1441 return QCBOR_ERR_BAD_OPT_TAG;
1442 }
1443
1444 const UsefulBufC Temp = pDecodedItem->val.string;
1445 pDecodedItem->val.dateString = Temp;
1446 pDecodedItem->uDataType = QCBOR_TYPE_DATE_STRING;
1447 return QCBOR_SUCCESS;
1448}
1449
1450
1451/*
Laurence Lundbladeee851742020-01-08 08:37:05 -08001452 The epoch formatted date. Turns lots of different forms of encoding
1453 date into uniform one
Laurence Lundblade59289e52019-12-30 13:44:37 -08001454 */
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001455static QCBORError DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08001456{
1457 // Stack usage: 1
1458 QCBORError nReturn = QCBOR_SUCCESS;
1459
1460 pDecodedItem->val.epochDate.fSecondsFraction = 0;
1461
1462 switch (pDecodedItem->uDataType) {
1463
1464 case QCBOR_TYPE_INT64:
1465 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
1466 break;
1467
1468 case QCBOR_TYPE_UINT64:
1469 if(pDecodedItem->val.uint64 > INT64_MAX) {
1470 nReturn = QCBOR_ERR_DATE_OVERFLOW;
1471 goto Done;
1472 }
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001473 pDecodedItem->val.epochDate.nSeconds = (int64_t)pDecodedItem->val.uint64;
Laurence Lundblade59289e52019-12-30 13:44:37 -08001474 break;
1475
1476 case QCBOR_TYPE_DOUBLE:
1477 {
1478 // This comparison needs to be done as a float before
1479 // conversion to an int64_t to be able to detect doubles
1480 // that are too large to fit into an int64_t. A double
1481 // has 52 bits of preceision. An int64_t has 63. Casting
1482 // INT64_MAX to a double actually causes a round up which
1483 // is bad and wrong for the comparison because it will
1484 // allow conversion of doubles that can't fit into a
1485 // uint64_t. To remedy this INT64_MAX - 0x7ff is used as
1486 // the cutoff point as if that rounds up in conversion to
1487 // double it will still be less than INT64_MAX. 0x7ff is
1488 // picked because it has 11 bits set.
1489 //
1490 // INT64_MAX seconds is on the order of 10 billion years,
1491 // and the earth is less than 5 billion years old, so for
1492 // most uses this conversion error won't occur even though
1493 // doubles can go much larger.
1494 //
1495 // Without the 0x7ff there is a ~30 minute range of time
1496 // values 10 billion years in the past and in the future
1497 // where this this code would go wrong.
1498 const double d = pDecodedItem->val.dfnum;
1499 if(d > (double)(INT64_MAX - 0x7ff)) {
1500 nReturn = QCBOR_ERR_DATE_OVERFLOW;
1501 goto Done;
1502 }
1503 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
1504 pDecodedItem->val.epochDate.fSecondsFraction = d - (double)pDecodedItem->val.epochDate.nSeconds;
1505 }
1506 break;
1507
1508 default:
1509 nReturn = QCBOR_ERR_BAD_OPT_TAG;
1510 goto Done;
1511 }
1512 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
1513
1514Done:
1515 return nReturn;
1516}
1517
1518
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001519/*
1520 Mostly just assign the right data type for the bignum.
1521 */
1522inline static QCBORError DecodeBigNum(QCBORItem *pDecodedItem)
1523{
1524 // Stack Use: UsefulBuf 1 -- 16
1525 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1526 return QCBOR_ERR_BAD_OPT_TAG;
1527 }
1528 const UsefulBufC Temp = pDecodedItem->val.string;
1529 pDecodedItem->val.bigNum = Temp;
1530 const bool bIsPosBigNum = (bool)(pDecodedItem->uTags[0] == CBOR_TAG_POS_BIGNUM);
1531 pDecodedItem->uDataType = (uint8_t)(bIsPosBigNum ? QCBOR_TYPE_POSBIGNUM
1532 : QCBOR_TYPE_NEGBIGNUM);
1533 return QCBOR_SUCCESS;
1534}
1535
1536
Laurence Lundblade59289e52019-12-30 13:44:37 -08001537#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
1538/*
1539 Decode decimal fractions and big floats.
1540
1541 When called pDecodedItem must be the array that is tagged as a big
1542 float or decimal fraction, the array that has the two members, the
1543 exponent and mantissa.
1544
1545 This will fetch and decode the exponent and mantissa and put the
1546 result back into pDecodedItem.
1547 */
1548inline static QCBORError
1549QCBORDecode_MantissaAndExponent(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
1550{
1551 QCBORError nReturn;
1552
1553 // --- Make sure it is an array; track nesting level of members ---
1554 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
1555 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1556 goto Done;
1557 }
1558
1559 // A check for pDecodedItem->val.uCount == 2 would work for
Laurence Lundbladeee851742020-01-08 08:37:05 -08001560 // definite length arrays, but not for indefnite. Instead remember
1561 // the nesting level the two integers must be at, which is one
1562 // deeper than that of the array.
Laurence Lundblade59289e52019-12-30 13:44:37 -08001563 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
1564
1565 // --- Is it a decimal fraction or a bigfloat? ---
1566 const bool bIsTaggedDecimalFraction = QCBORDecode_IsTagged(me, pDecodedItem, CBOR_TAG_DECIMAL_FRACTION);
1567 pDecodedItem->uDataType = bIsTaggedDecimalFraction ? QCBOR_TYPE_DECIMAL_FRACTION : QCBOR_TYPE_BIGFLOAT;
1568
1569 // --- Get the exponent ---
1570 QCBORItem exponentItem;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001571 nReturn = QCBORDecode_GetNextMapOrArray(me, &exponentItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001572 if(nReturn != QCBOR_SUCCESS) {
1573 goto Done;
1574 }
1575 if(exponentItem.uNestingLevel != nNestLevel) {
1576 // Array is empty or a map/array encountered when expecting an int
1577 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1578 goto Done;
1579 }
1580 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
1581 // Data arriving as an unsigned int < INT64_MAX has been converted
1582 // to QCBOR_TYPE_INT64 and thus handled here. This is also means
1583 // that the only data arriving here of type QCBOR_TYPE_UINT64 data
1584 // will be too large for this to handle and thus an error that will
1585 // get handled in the next else.
1586 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
1587 } else {
1588 // Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX
1589 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1590 goto Done;
1591 }
1592
1593 // --- Get the mantissa ---
1594 QCBORItem mantissaItem;
1595 nReturn = QCBORDecode_GetNextWithTags(me, &mantissaItem, NULL);
1596 if(nReturn != QCBOR_SUCCESS) {
1597 goto Done;
1598 }
1599 if(mantissaItem.uNestingLevel != nNestLevel) {
1600 // Mantissa missing or map/array encountered when expecting number
1601 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1602 goto Done;
1603 }
1604 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
1605 // Data arriving as an unsigned int < INT64_MAX has been converted
1606 // to QCBOR_TYPE_INT64 and thus handled here. This is also means
1607 // that the only data arriving here of type QCBOR_TYPE_UINT64 data
1608 // will be too large for this to handle and thus an error that
1609 // will get handled in an else below.
1610 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
1611 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM || mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
1612 // Got a good big num mantissa
1613 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
1614 // Depends on numbering of QCBOR_TYPE_XXX
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001615 pDecodedItem->uDataType = (uint8_t)(pDecodedItem->uDataType +
1616 mantissaItem.uDataType - QCBOR_TYPE_POSBIGNUM +
1617 1);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001618 } else {
1619 // Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX
1620 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1621 goto Done;
1622 }
1623
1624 // --- Check that array only has the two numbers ---
1625 if(mantissaItem.uNextNestLevel == nNestLevel) {
1626 // Extra items in the decimal fraction / big num
1627 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1628 goto Done;
1629 }
1630
1631Done:
1632
1633 return nReturn;
1634}
1635#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
1636
1637
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001638
1639/*
1640 */
1641inline static QCBORError DecodeURI(QCBORItem *pDecodedItem)
1642{
1643 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1644 return QCBOR_ERR_BAD_OPT_TAG;
1645 }
1646 pDecodedItem->uDataType = QCBOR_TYPE_URI;
1647 return QCBOR_SUCCESS;
1648}
1649
1650
1651inline static QCBORError DecodeB64URL(QCBORItem *pDecodedItem)
1652{
1653 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1654 return QCBOR_ERR_BAD_OPT_TAG;
1655 }
1656 pDecodedItem->uDataType = QCBOR_TYPE_BASE64URL;
1657 return QCBOR_SUCCESS;
1658}
1659
1660
1661inline static QCBORError DecodeB64(QCBORItem *pDecodedItem)
1662{
1663 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1664 return QCBOR_ERR_BAD_OPT_TAG;
1665 }
1666 pDecodedItem->uDataType = QCBOR_TYPE_BASE64;
1667 return QCBOR_SUCCESS;
1668}
1669
1670
1671inline static QCBORError DecodeRegex(QCBORItem *pDecodedItem)
1672{
1673 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1674 return QCBOR_ERR_BAD_OPT_TAG;
1675 }
1676 pDecodedItem->uDataType = QCBOR_TYPE_REGEX;
1677 return QCBOR_SUCCESS;
1678}
1679
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07001680inline static QCBORError DecodeWrappedCBOR(QCBORItem *pDecodedItem)
1681{
1682 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1683 return QCBOR_ERR_BAD_OPT_TAG;
1684 }
1685 pDecodedItem->uDataType = QBCOR_TYPE_WRAPPED_CBOR;
1686 return QCBOR_SUCCESS;
1687}
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001688
1689inline static QCBORError DecodeMIME(QCBORItem *pDecodedItem)
1690{
1691 if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) {
1692 pDecodedItem->uDataType = QCBOR_TYPE_MIME;
1693 } else if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1694 pDecodedItem->uDataType = QCBOR_TYPE_BINARY_MIME;
1695 } else {
1696 return QCBOR_ERR_BAD_OPT_TAG;
1697 }
1698 return QCBOR_SUCCESS;
1699}
1700
1701
1702/*
1703 */
1704inline static QCBORError DecodeUUID(QCBORItem *pDecodedItem)
1705{
1706 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1707 return QCBOR_ERR_BAD_OPT_TAG;
1708 }
1709 pDecodedItem->uDataType = QCBOR_TYPE_UUID;
1710 return QCBOR_SUCCESS;
1711}
1712
1713
Laurence Lundblade59289e52019-12-30 13:44:37 -08001714/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001715 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08001716 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001717QCBORError
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001718QCBORDecode_GetNext(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08001719{
1720 QCBORError nReturn;
1721
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001722 nReturn = QCBORDecode_GetNextMapOrArray(me, pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001723 if(nReturn != QCBOR_SUCCESS) {
1724 goto Done;
1725 }
1726
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001727 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM; i++) {
1728 switch(pDecodedItem->uTags[i] ) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08001729
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001730 case CBOR_TAG_DATE_STRING:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001731 nReturn = DecodeDateString(pDecodedItem);
1732 break;
1733
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001734 case CBOR_TAG_DATE_EPOCH:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001735 nReturn = DecodeDateEpoch(pDecodedItem);
1736 break;
1737
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001738 case CBOR_TAG_POS_BIGNUM:
1739 case CBOR_TAG_NEG_BIGNUM:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001740 nReturn = DecodeBigNum(pDecodedItem);
1741 break;
1742
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001743 #ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
1744 case CBOR_TAG_DECIMAL_FRACTION:
1745 case CBOR_TAG_BIGFLOAT:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001746 // For aggregate tagged types, what goes into pTags is only collected
1747 // from the surrounding data item, not the contents, so pTags is not
1748 // passed on here.
1749
1750 nReturn = QCBORDecode_MantissaAndExponent(me, pDecodedItem);
1751 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001752 #endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08001753
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07001754 case CBOR_TAG_CBOR:
1755 nReturn = DecodeWrappedCBOR(pDecodedItem);
1756 break;
1757
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001758 case CBOR_TAG_URI:
1759 nReturn = DecodeURI(pDecodedItem);
1760 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001761
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001762 case CBOR_TAG_B64URL:
1763 nReturn = DecodeB64URL(pDecodedItem);
1764 break;
1765
1766 case CBOR_TAG_B64:
1767 nReturn = DecodeB64(pDecodedItem);
1768 break;
1769
1770 case CBOR_TAG_MIME:
1771 case CBOR_TAG_BINARY_MIME:
1772 nReturn = DecodeMIME(pDecodedItem);
1773 break;
1774
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001775 case CBOR_TAG_REGEX:
1776 nReturn = DecodeRegex(pDecodedItem);
1777 break;
1778
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001779 case CBOR_TAG_BIN_UUID:
1780 nReturn = DecodeUUID(pDecodedItem);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001781 break;
1782
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001783 case CBOR_TAG_INVALID16:
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001784 // The end of the tag list or no tags
1785 // Successful exit from the loop.
1786 goto Done;
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001787
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001788 default:
1789 // A tag that is not understood
1790 // A successful exit from the loop
1791 goto Done;
1792
1793 }
1794 if(nReturn != QCBOR_SUCCESS) {
1795 goto Done;
1796 }
Laurence Lundblade59289e52019-12-30 13:44:37 -08001797 }
1798
1799Done:
1800 if(nReturn != QCBOR_SUCCESS) {
1801 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
1802 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
1803 }
1804 return nReturn;
1805}
1806
1807
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001808QCBORError QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
1809{
1810 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
1811
1812 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
1813
1814 UsefulInputBuf_Seek(&(pMe->InBuf), uOffset);
1815
1816 return uErr;
1817}
1818
1819
Laurence Lundblade59289e52019-12-30 13:44:37 -08001820/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001821 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08001822 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001823QCBORError
1824QCBORDecode_GetNextWithTags(QCBORDecodeContext *me,
1825 QCBORItem *pDecodedItem,
1826 QCBORTagListOut *pTags)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001827{
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001828 QCBORError nReturn;
1829
1830 nReturn = QCBORDecode_GetNext(me, pDecodedItem);
1831 if(nReturn != QCBOR_SUCCESS) {
1832 return nReturn;
1833 }
1834
1835 if(pTags != NULL) {
1836 pTags->uNumUsed = 0;
1837 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM; i++) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001838 if(pDecodedItem->uTags[i] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001839 break;
1840 }
1841 if(pTags->uNumUsed >= pTags->uNumAllocated) {
1842 return QCBOR_ERR_TOO_MANY_TAGS;
1843 }
1844 pTags->puTags[pTags->uNumUsed] = ConvertTag(me, pDecodedItem->uTags[i]);
1845 pTags->uNumUsed++;
1846 }
1847 }
1848
1849 return QCBOR_SUCCESS;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001850}
1851
1852
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001853/*
Laurence Lundblade6de37062018-10-15 12:22:42 +05301854 Decoding items is done in 5 layered functions, one calling the
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301855 next one down. If a layer has no work to do for a particular item
1856 it returns quickly.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001857
Laurence Lundblade59289e52019-12-30 13:44:37 -08001858 - QCBORDecode_GetNext, GetNextWithTags -- The top layer processes
1859 tagged data items, turning them into the local C representation.
1860 For the most simple it is just associating a QCBOR_TYPE with the data. For
1861 the complex ones that an aggregate of data items, there is some further
1862 decoding and a little bit of recursion.
1863
1864 - QCBORDecode_GetNextMapOrArray - This manages the beginnings and
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301865 ends of maps and arrays. It tracks descending into and ascending
Laurence Lundblade6de37062018-10-15 12:22:42 +05301866 out of maps/arrays. It processes all breaks that terminate
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001867 indefinite length maps and arrays.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001868
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301869 - GetNext_MapEntry -- This handles the combining of two
1870 items, the label and the data, that make up a map entry.
1871 It only does work on maps. It combines the label and data
1872 items into one labeled item.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001873
Laurence Lundblade59289e52019-12-30 13:44:37 -08001874 - GetNext_TaggedItem -- This decodes type 6 tagging. It turns the
1875 tags into bit flags associated with the data item. No actual decoding
1876 of the contents of the tagged item is performed here.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001877
Laurence Lundblade59289e52019-12-30 13:44:37 -08001878 - GetNext_FullItem -- This assembles the sub-items that make up
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301879 an indefinte length string into one string item. It uses the
Laurence Lundblade6de37062018-10-15 12:22:42 +05301880 string allocater to create contiguous space for the item. It
1881 processes all breaks that are part of indefinite length strings.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001882
Laurence Lundblade59289e52019-12-30 13:44:37 -08001883 - GetNext_Item -- This decodes the atomic data items in CBOR. Each
1884 atomic data item has a "major type", an integer "argument" and optionally
1885 some content. For text and byte strings, the content is the bytes
1886 that make up the string. These are the smallest data items that are
1887 considered to be well-formed. The content may also be other data items in
1888 the case of aggregate types. They are not handled in this layer.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001889
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001890 Roughly this takes 300 bytes of stack for vars. Need to
1891 evaluate this more carefully and correctly.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001892
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301893 */
1894
1895
1896/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001897 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001898 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001899int QCBORDecode_IsTagged(QCBORDecodeContext *me,
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001900 const QCBORItem *pItem,
1901 uint64_t uTag)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001902{
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001903 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM; i++ ) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001904 if(pItem->uTags[i] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001905 break;
1906 }
1907 if(ConvertTag(me, pItem->uTags[i]) == uTag) {
1908 return 1;
1909 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001910 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001911
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001912 return 0;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001913}
1914
1915
1916/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001917 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001918 */
Laurence Lundblade30816f22018-11-10 13:40:22 +07001919QCBORError QCBORDecode_Finish(QCBORDecodeContext *me)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001920{
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001921 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001922
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001923 // Error out if all the maps/arrays are not closed out
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001924 if(!DecodeNesting_IsCurrentAtTop(&(me->nesting))) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001925 nReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
1926 goto Done;
1927 }
1928
1929 // Error out if not all the bytes are consumed
1930 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) {
1931 nReturn = QCBOR_ERR_EXTRA_BYTES;
1932 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001933
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001934Done:
Laurence Lundblade6de37062018-10-15 12:22:42 +05301935 // Call the destructor for the string allocator if there is one.
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001936 // Always called, even if there are errors; always have to clean up
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001937 StringAllocator_Destruct(&(me->StringAllocator));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001938
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001939 return nReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001940}
1941
1942
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001943/*
1944Public function, see header qcbor/qcbor_decode.h file
1945*/
Laurence Lundblade2b843b52020-06-16 20:51:03 -07001946uint64_t QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
1947 const QCBORItem *pItem,
1948 unsigned int uIndex)
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001949{
1950 if(uIndex > QCBOR_MAX_TAGS_PER_ITEM) {
1951 return CBOR_TAG_INVALID16;
1952 } else if(pItem->uTags[uIndex] <= QCBOR_LAST_UNMAPPED_TAG) {
1953 return pItem->uTags[uIndex];
1954 } else if(pItem->uTags[uIndex] < QCBOR_NUM_MAPPED_TAGS + QCBOR_LAST_UNMAPPED_TAG) {
1955 return pMe->auMappedTags[pItem->uTags[uIndex] - QCBOR_LAST_UNMAPPED_TAG];
1956 } else {
1957 return CBOR_TAG_INVALID16;
1958 }
1959}
1960
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001961
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001962/*
1963
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001964Decoder errors handled in this file
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001965
Laurence Lundbladeee851742020-01-08 08:37:05 -08001966 - Hit end of input before it was expected while decoding type and
1967 number QCBOR_ERR_HIT_END
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001968
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001969 - negative integer that is too large for C QCBOR_ERR_INT_OVERFLOW
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001970
Laurence Lundbladeee851742020-01-08 08:37:05 -08001971 - Hit end of input while decoding a text or byte string
1972 QCBOR_ERR_HIT_END
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001973
Laurence Lundbladeee851742020-01-08 08:37:05 -08001974 - Encountered conflicting tags -- e.g., an item is tagged both a date
1975 string and an epoch date QCBOR_ERR_UNSUPPORTED
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001976
Laurence Lundbladeee851742020-01-08 08:37:05 -08001977 - Encontered an array or mapp that has too many items
1978 QCBOR_ERR_ARRAY_TOO_LONG
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001979
Laurence Lundbladeee851742020-01-08 08:37:05 -08001980 - Encountered array/map nesting that is too deep
1981 QCBOR_ERR_ARRAY_NESTING_TOO_DEEP
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001982
Laurence Lundbladeee851742020-01-08 08:37:05 -08001983 - An epoch date > INT64_MAX or < INT64_MIN was encountered
1984 QCBOR_ERR_DATE_OVERFLOW
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001985
Laurence Lundbladeee851742020-01-08 08:37:05 -08001986 - The type of a map label is not a string or int
1987 QCBOR_ERR_MAP_LABEL_TYPE
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001988
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001989 - Hit end with arrays or maps still open -- QCBOR_ERR_EXTRA_BYTES
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001990
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001991 */
1992
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001993
1994
Laurence Lundbladef6531662018-12-04 10:42:22 +09001995
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001996/* ===========================================================================
1997 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001998
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001999 This implements a simple sting allocator for indefinite length
2000 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
2001 implements the function type QCBORStringAllocate and allows easy
2002 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09002003
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002004 This particular allocator is built-in for convenience. The caller
2005 can implement their own. All of this following code will get
2006 dead-stripped if QCBORDecode_SetMemPool() is not called.
2007
2008 This is a very primitive memory allocator. It does not track
2009 individual allocations, only a high-water mark. A free or
2010 reallocation must be of the last chunk allocated.
2011
2012 The size of the pool and offset to free memory are packed into the
2013 first 8 bytes of the memory pool so we don't have to keep them in
2014 the decode context. Since the address of the pool may not be
2015 aligned, they have to be packed and unpacked as if they were
2016 serialized data of the wire or such.
2017
2018 The sizes packed in are uint32_t to be the same on all CPU types
2019 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08002020 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002021
2022
Laurence Lundbladeee851742020-01-08 08:37:05 -08002023static inline int
2024MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002025{
2026 // Use of UsefulInputBuf is overkill, but it is convenient.
2027 UsefulInputBuf UIB;
2028
Laurence Lundbladeee851742020-01-08 08:37:05 -08002029 // Just assume the size here. It was checked during SetUp so
2030 // the assumption is safe.
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002031 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem, QCBOR_DECODE_MIN_MEM_POOL_SIZE});
2032 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
2033 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
2034 return UsefulInputBuf_GetError(&UIB);
2035}
2036
2037
Laurence Lundbladeee851742020-01-08 08:37:05 -08002038static inline int
2039MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002040{
2041 // Use of UsefulOutBuf is overkill, but convenient. The
2042 // length check performed here is useful.
2043 UsefulOutBuf UOB;
2044
2045 UsefulOutBuf_Init(&UOB, Pool);
2046 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
2047 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
2048 return UsefulOutBuf_GetError(&UOB);
2049}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002050
2051
2052/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002053 Internal function for an allocation, reallocation free and destuct.
2054
2055 Having only one function rather than one each per mode saves space in
2056 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002057
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002058 Code Reviewers: THIS FUNCTION DOES POINTER MATH
2059 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08002060static UsefulBuf
2061MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002062{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002063 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002064
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002065 uint32_t uPoolSize;
2066 uint32_t uFreeOffset;
2067
2068 if(uNewSize > UINT32_MAX) {
2069 // This allocator is only good up to 4GB. This check should
2070 // optimize out if sizeof(size_t) == sizeof(uint32_t)
2071 goto Done;
2072 }
2073 const uint32_t uNewSize32 = (uint32_t)uNewSize;
2074
2075 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
2076 goto Done;
2077 }
2078
2079 if(uNewSize) {
2080 if(pMem) {
2081 // REALLOCATION MODE
2082 // Calculate pointer to the end of the memory pool. It is
2083 // assumed that pPool + uPoolSize won't wrap around by
2084 // assuming the caller won't pass a pool buffer in that is
2085 // not in legitimate memory space.
2086 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
2087
2088 // Check that the pointer for reallocation is in the range of the
2089 // pool. This also makes sure that pointer math further down
2090 // doesn't wrap under or over.
2091 if(pMem >= pPool && pMem < pPoolEnd) {
2092 // Offset to start of chunk for reallocation. This won't
2093 // wrap under because of check that pMem >= pPool. Cast
2094 // is safe because the pool is always less than UINT32_MAX
2095 // because of check in QCBORDecode_SetMemPool().
2096 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
2097
2098 // Check to see if the allocation will fit. uPoolSize -
2099 // uMemOffset will not wrap under because of check that
2100 // pMem is in the range of the uPoolSize by check above.
2101 if(uNewSize <= uPoolSize - uMemOffset) {
2102 ReturnValue.ptr = pMem;
2103 ReturnValue.len = uNewSize;
2104
2105 // Addition won't wrap around over because uNewSize was
2106 // checked to be sure it is less than the pool size.
2107 uFreeOffset = uMemOffset + uNewSize32;
2108 }
2109 }
2110 } else {
2111 // ALLOCATION MODE
2112 // uPoolSize - uFreeOffset will not underflow because this
2113 // pool implementation makes sure uFreeOffset is always
2114 // smaller than uPoolSize through this check here and
2115 // reallocation case.
2116 if(uNewSize <= uPoolSize - uFreeOffset) {
2117 ReturnValue.len = uNewSize;
2118 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08002119 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002120 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002121 }
2122 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002123 if(pMem) {
2124 // FREE MODE
2125 // Cast is safe because of limit on pool size in
2126 // QCBORDecode_SetMemPool()
2127 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
2128 } else {
2129 // DESTRUCT MODE
2130 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002131 }
2132 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002133
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002134 UsefulBuf Pool = {pPool, uPoolSize};
2135 MemPool_Pack(Pool, uFreeOffset);
2136
2137Done:
2138 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002139}
2140
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002141
Laurence Lundbladef6531662018-12-04 10:42:22 +09002142/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08002143 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09002144 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08002145QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
2146 UsefulBuf Pool,
2147 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002148{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002149 // The pool size and free mem offset are packed into the beginning
2150 // of the pool memory. This compile time check make sure the
2151 // constant in the header is correct. This check should optimize
2152 // down to nothing.
2153 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundblade30816f22018-11-10 13:40:22 +07002154 return QCBOR_ERR_BUFFER_TOO_SMALL;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002155 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002156
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002157 // The pool size and free offset packed in to the beginning of pool
2158 // memory are only 32-bits. This check will optimize out on 32-bit
2159 // machines.
2160 if(Pool.len > UINT32_MAX) {
2161 return QCBOR_ERR_BUFFER_TOO_LARGE;
2162 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002163
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002164 // This checks that the pool buffer given is big enough.
2165 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
2166 return QCBOR_ERR_BUFFER_TOO_SMALL;
2167 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002168
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002169 pMe->StringAllocator.pfAllocator = MemPool_Function;
2170 pMe->StringAllocator.pAllocateCxt = Pool.ptr;
2171 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002172
Laurence Lundblade30816f22018-11-10 13:40:22 +07002173 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002174}
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002175
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002176
2177
Laurence Lundblade1341c592020-04-11 14:19:05 -07002178#include <stdio.h>
2179void printdecode(QCBORDecodeContext *pMe, const char *szName)
2180{
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002181 printf("---%s--%d--%d--\narrow is current bounded level\nLevel Count Type S-Offset SaveCount Bounded E-Offset\n",
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002182 szName,
2183 (uint32_t)pMe->InBuf.cursor,
2184 (uint32_t)pMe->InBuf.UB.len);
Laurence Lundblade64b607e2020-05-13 13:05:57 -07002185 for(int i = 0; i < QCBOR_MAX_ARRAY_NESTING; i++) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002186 if(&(pMe->nesting.pMapsAndArrays[i]) > pMe->nesting.pCurrent) {
2187 break;
2188 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002189
2190 // TODO: print different for BS and MA
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002191 printf("%2s %2d %5d %s %6u %5d %d %5d\n",
2192 pMe->nesting.pCurrentBounded == &(pMe->nesting.pMapsAndArrays[i]) ? "->": " ",
Laurence Lundblade1341c592020-04-11 14:19:05 -07002193 i,
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002194 pMe->nesting.pMapsAndArrays[i].u.ma.uCountCursor,
2195 pMe->nesting.pMapsAndArrays[i].uLevelType == QCBOR_TYPE_MAP ? "map " :
2196 (pMe->nesting.pMapsAndArrays[i].uLevelType == QCBOR_TYPE_ARRAY ? "array" :
2197 (pMe->nesting.pMapsAndArrays[i].uLevelType == QCBOR_TYPE_BYTE_STRING ? "bstr " :
2198 (pMe->nesting.pMapsAndArrays[i].uLevelType == QCBOR_TYPE_NONE ? "none " : "?????"))),
2199 pMe->nesting.pMapsAndArrays[i].u.ma.uStartOffset,
2200 pMe->nesting.pMapsAndArrays[i].u.ma.uCountTotal,
2201 0, // TODO: fix this
2202 pMe->nesting.pMapsAndArrays[i].u.bs.uPreviousEndOffset
Laurence Lundblade1341c592020-04-11 14:19:05 -07002203 );
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002204
Laurence Lundblade1341c592020-04-11 14:19:05 -07002205 }
Laurence Lundblade64b607e2020-05-13 13:05:57 -07002206 printf("\n");
Laurence Lundblade1341c592020-04-11 14:19:05 -07002207}
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002208
2209
2210/*
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002211 Consume an entire map or array (and do next to
2212 nothing for non-aggregate types).
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002213 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002214static inline QCBORError
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002215ConsumeItem(QCBORDecodeContext *pMe,
2216 const QCBORItem *pItemToConsume,
2217 uint_fast8_t *puNextNestLevel)
2218{
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002219 QCBORError uReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002220 QCBORItem Item;
2221
2222 printdecode(pMe, "ConsumeItem");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002223
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002224 if(IsMapOrArray(pItemToConsume->uDataType)) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002225 /* There is only real work to do for maps and arrays */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002226
Laurence Lundblade1341c592020-04-11 14:19:05 -07002227 /* This works for definite and indefinite length
2228 * maps and arrays by using the nesting level
2229 */
2230 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002231 uReturn = QCBORDecode_GetNext(pMe, &Item);
2232 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002233 goto Done;
2234 }
2235 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002236
Laurence Lundblade1341c592020-04-11 14:19:05 -07002237 if(puNextNestLevel != NULL) {
2238 *puNextNestLevel = Item.uNextNestLevel;
2239 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002240 uReturn = QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002241
Laurence Lundblade1341c592020-04-11 14:19:05 -07002242 } else {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002243 /* item_to_consume is not a map or array */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002244 if(puNextNestLevel != NULL) {
2245 /* Just pass the nesting level through */
2246 *puNextNestLevel = pItemToConsume->uNextNestLevel;
2247 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002248 uReturn = QCBOR_SUCCESS;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002249 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002250
2251Done:
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002252 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002253}
2254
2255
Laurence Lundblade1341c592020-04-11 14:19:05 -07002256/* Return true if the labels in Item1 and Item2 are the same.
2257 Works only for integer and string labels. Returns false
2258 for any other type. */
2259static inline bool
2260MatchLabel(QCBORItem Item1, QCBORItem Item2)
2261{
2262 if(Item1.uLabelType == QCBOR_TYPE_INT64) {
2263 if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
2264 return true;
2265 }
2266 } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002267 if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002268 return true;
2269 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002270 } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002271 if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
2272 return true;
2273 }
2274 } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
2275 if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
2276 return true;
2277 }
2278 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002279
Laurence Lundblade1341c592020-04-11 14:19:05 -07002280 /* Other label types are never matched */
2281 return false;
2282}
2283
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002284
2285/*
2286 Returns true if Item1 and Item2 are the same type
2287 or if either are of QCBOR_TYPE_ANY.
2288 */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002289static inline bool
2290MatchType(QCBORItem Item1, QCBORItem Item2)
2291{
2292 if(Item1.uDataType == Item2.uDataType) {
2293 return true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002294 } else if(Item1.uDataType == QCBOR_TYPE_ANY) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002295 return true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002296 } else if(Item2.uDataType == QCBOR_TYPE_ANY) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002297 return true;
2298 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002299 return false;
2300}
2301
2302
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002303/**
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002304 \brief Search a map for a set of items.
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002305
2306 @param[in] pMe The decode context to search.
2307 @param[in,out] pItemArray The items to search for and the items found.
2308 @param[in] pCBContext Context for the not-found item call back
2309 @param[in] pfCallback Function to call on items not matched in pItemArray
2310
2311 @retval QCBOR_ERR_NOT_ENTERED Trying to search without having entered a map
2312
2313 @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label) were found for one of the labels being search for. This duplicate detection is only performed for items in pItemArray, not every item in the map.
2314
2315 @retval QCBOR_ERR_UNEXPECTED_TYPE The label was matched, but not the type.
2316
2317 @retval Also errors returned by QCBORDecode_GetNext().
2318
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002319 On input pItemArray contains a list of labels and data types
2320 of items to be found.
2321
2322 On output the fully retrieved items are filled in with
2323 values and such. The label was matched, so it never changes.
2324
2325 If an item was not found, its data type is set to none.
2326
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002327 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002328static QCBORError
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002329MapSearch(QCBORDecodeContext *pMe,
2330 QCBORItem *pItemArray,
2331 size_t *puOffset,
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002332 void *pCBContext,
2333 QCBORItemCallback pfCallback)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002334{
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002335 QCBORError uReturn;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002336
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002337 QCBORDecodeNesting SaveNesting;
2338 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002339
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002340 /* Reposition to search from the start of the map / array */
2341 UsefulInputBuf_Seek(&(pMe->InBuf), pMe->nesting.pCurrentBounded->u.ma.uStartOffset);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002342
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002343 /*
2344 Loop over all the items in the map. They could be
2345 deeply nested and this should handle both definite
2346 and indefinite length maps and arrays, so this
2347 adds some complexity.
2348 */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002349 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Laurence Lundblade1341c592020-04-11 14:19:05 -07002350
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002351 uint_fast8_t uNextNestLevel;
2352
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002353 uint64_t uFoundItemBitMap = 0;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002354
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002355 /* Iterate over items in the map / array */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002356 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002357 /* Remember offset of the item because sometimes it has to be returned */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002358 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002359
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002360 /* Get the item */
2361 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002362 uReturn = QCBORDecode_GetNext(pMe, &Item);
2363 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002364 /* Got non-well-formed CBOR */
2365 goto Done;
2366 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002367
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002368 /* See if item has one of the labels that are of interest */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002369 int nIndex;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002370 QCBORItem *pIterator;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002371 for(pIterator = pItemArray, nIndex = 0; pIterator->uLabelType != 0; pIterator++, nIndex++) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002372 if(MatchLabel(Item, *pIterator)) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002373 /* A label match has been found */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002374 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
2375 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002376 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002377 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002378 /* Also try to match its type */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002379 if(!MatchType(Item, *pIterator)) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002380 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002381 goto Done;
2382 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002383
2384 /* Successful match. Return the item. */
2385 *pIterator = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002386 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002387 if(puOffset) {
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002388 *puOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002389 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002390 } else {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002391 /*
2392 Call the callback on unmatched labels.
2393 (It is tempting to do duplicate detection here, but that would
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002394 require dynamic memory allocation because the number of labels
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002395 that might be encountered is unbounded.)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002396 */
2397 if(pfCallback) {
2398 uReturn = (*pfCallback)(pCBContext, &Item);
2399 if(uReturn != QCBOR_SUCCESS) {
2400 goto Done;
2401 }
2402 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002403 }
2404 }
2405
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002406 /*
2407 Consume the item whether matched or not. This
2408 does the work of traversing maps and array and
2409 everything in them. In this loop only the
2410 items at the current nesting level are examined
2411 to match the labels.
2412 */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002413 uReturn = ConsumeItem(pMe, &Item, &uNextNestLevel);
2414 if(uReturn) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002415 goto Done;
2416 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002417
2418 } while (uNextNestLevel >= uMapNestLevel);
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002419
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002420 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002421
2422 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002423 /* Cast OK because encoded CBOR is limited to UINT32_MAX */
2424 pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002425
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002426 /* For all items not found, set the data type to QCBOR_TYPE_NONE */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002427 int i;
2428 QCBORItem *pIterator;
2429 for(pIterator = pItemArray, i = 0; pIterator->uLabelType != 0; pIterator++, i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002430 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002431 pIterator->uDataType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002432 }
2433 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002434
2435Done:
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002436 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002437
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002438 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002439}
2440
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002441
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002442/*
2443Public function, see header qcbor/qcbor_decode.h file
2444*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002445void QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
2446 int64_t nLabel,
2447 uint8_t uQcborType,
2448 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002449{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002450 if(pMe->uLastError != QCBOR_SUCCESS) {
2451 return;
2452 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002453
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002454 QCBORItem OneItemSeach[2];
2455 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
2456 OneItemSeach[0].label.int64 = nLabel;
2457 OneItemSeach[0].uDataType = uQcborType;
2458 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07002459
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002460 QCBORError nReturn = MapSearch(pMe, OneItemSeach, NULL, NULL, NULL);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002461 if(nReturn) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002462 pMe->uLastError = (uint8_t)nReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002463 }
2464
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002465 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
2466 pMe->uLastError = QCBOR_ERR_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002467 }
2468
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002469 *pItem = OneItemSeach[0];
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002470}
2471
2472
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002473/*
2474Public function, see header qcbor/qcbor_decode.h file
2475*/
Laurence Lundbladeda095972020-06-06 18:35:33 -07002476void QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
2477 const char *szLabel,
2478 uint8_t uQcborType,
2479 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002480{
Laurence Lundbladeda095972020-06-06 18:35:33 -07002481 if(pMe->uLastError != QCBOR_SUCCESS) {
2482 return;
2483 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002484
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002485 QCBORItem OneItemSeach[2];
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002486 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2487 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
2488 OneItemSeach[0].uDataType = uQcborType;
2489 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07002490
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002491 QCBORError nReturn = MapSearch(pMe, OneItemSeach, NULL, NULL, NULL);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002492 if(nReturn) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07002493 pMe->uLastError = (uint8_t)nReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002494 }
2495
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002496 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07002497 pMe->uLastError = QCBOR_ERR_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002498 }
2499
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002500 *pItem = OneItemSeach[0];
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002501}
2502
2503
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002504/**
2505 @param[in] TagSpec Specification for matching tags.
2506 @param[in] uDataType A QCBOR data type
2507
2508 @retval QCBOR_SUCCESS \c uDataType is allowed by @c TagSpec
2509 @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec
2510
2511 The data type must be one of the QCBOR_TYPEs, not the IETF CBOR Registered tag value.
2512 */
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002513static QCBORError CheckTagRequirement(const TagSpecification TagSpec, uint8_t uDataType)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002514{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002515 if(TagSpec.uTagRequirement == QCBOR_TAGSPEC_MATCH_TAG) {
2516 /* Must match the tag */
2517 if(uDataType == TagSpec.uTaggedType) {
2518 return QCBOR_SUCCESS;
2519 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002520 } else {
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002521 /* QCBOR_TAGSPEC_MATCH_TAG_CONTENT_TYPE or QCBOR_TAGSPEC_MATCH_EITHER */
2522 /* Must check all the possible types for the tag content */
2523 for(size_t i = 0; i < sizeof(TagSpec.uAllowedContentTypes); i++) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002524 if(uDataType == TagSpec.uAllowedContentTypes[i]) {
2525 return QCBOR_SUCCESS;
2526 }
2527 }
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002528 /* Didn't match any of the tag content types */
2529 /* Check the tag for the either case */
2530 if(TagSpec.uTagRequirement == QCBOR_TAGSPEC_MATCH_EITHER) {
2531 if(uDataType == TagSpec.uTaggedType) {
2532 return QCBOR_SUCCESS;
2533 }
2534 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002535 }
2536
2537 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002538}
2539
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002540
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002541// Semi-private
2542// TODO: inline or collapse with QCBORDecode_GetTaggedStringInMapN?
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002543void QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
2544 int64_t nLabel,
2545 TagSpecification TagSpec,
2546 QCBORItem *pItem)
2547{
2548 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
2549 if(pMe->uLastError != QCBOR_SUCCESS) {
2550 return;
2551 }
2552
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002553 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem->uDataType);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002554}
2555
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002556// Semi-private
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002557void QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
2558 const char *szLabel,
2559 TagSpecification TagSpec,
2560 QCBORItem *pItem)
2561{
2562 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
2563 if(pMe->uLastError != QCBOR_SUCCESS) {
2564 return;
2565 }
2566
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002567 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem->uDataType);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002568}
2569
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002570// Semi-private
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002571void QCBORDecode_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
2572 int64_t nLabel,
2573 TagSpecification TagSpec,
2574 UsefulBufC *pString)
2575{
2576 QCBORItem Item;
2577 QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
2578 if(pMe->uLastError == QCBOR_SUCCESS) {
2579 *pString = Item.val.string;
2580 }
2581}
2582
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002583// Semi-private
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002584void QCBORDecode_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
2585 const char * szLabel,
2586 TagSpecification TagSpec,
2587 UsefulBufC *pString)
2588{
2589 QCBORItem Item;
2590 QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
2591 if(pMe->uLastError == QCBOR_SUCCESS) {
2592 *pString = Item.val.string;
2593 }
2594}
Laurence Lundblade1341c592020-04-11 14:19:05 -07002595
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002596/*
2597Public function, see header qcbor/qcbor_decode.h file
2598*/
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002599QCBORError QCBORDecode_GetItemsInMap(QCBORDecodeContext *pCtx, QCBORItem *pItemList)
2600{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002601 return MapSearch(pCtx, pItemList, NULL, NULL, NULL);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002602}
2603
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002604/*
2605Public function, see header qcbor/qcbor_decode.h file
2606*/
2607QCBORError QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pCtx,
2608 QCBORItem *pItemList,
2609 void *pCallbackCtx,
2610 QCBORItemCallback pfCB)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002611{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002612 return MapSearch(pCtx, pItemList, NULL, pCallbackCtx, pfCB);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002613}
2614
2615
Laurence Lundblade34691b92020-05-18 22:25:25 -07002616static void SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07002617{
Laurence Lundblade34691b92020-05-18 22:25:25 -07002618 if(pMe->uLastError != QCBOR_SUCCESS) {
2619 // Already in error state; do nothing.
2620 return;
2621 }
2622
2623 size_t uOffset;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002624 pMe->uLastError = (uint8_t)MapSearch(pMe, pSearch, &uOffset, NULL, NULL);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002625 if(pMe->uLastError != QCBOR_SUCCESS) {
2626 return;
2627 }
2628
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002629 /* Need to get the current pre-order nesting level and cursor to be
2630 at the first item in the map/array just entered.
2631
2632 Also need to current map nesting level and start cursor to
2633 be at the right place.
2634
2635 The UsefulInBuf offset could be anywhere, so no assumption is
2636 made about it.
2637
2638 No assumption is made about the pre-order nesting level either.
2639
2640 However the map mode nesting level is assumed to be one above
2641 the map level that is being entered.
2642 */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002643 /* Seek to the data item that is the map or array */
2644 UsefulInputBuf_Seek(&(pMe->InBuf), uOffset);
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002645 pMe->nesting.pCurrent = pMe->nesting.pCurrentBounded; // TODO: part of DecodeNesting
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002646
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002647 // TODO: check error?
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002648 QCBORDecode_EnterBoundedMode(pMe, pSearch->uDataType);
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002649
Laurence Lundblade34691b92020-05-18 22:25:25 -07002650 printdecode(pMe, "FinishEnter");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002651}
2652
2653
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002654/*
2655Public function, see header qcbor/qcbor_decode.h file
2656*/
Laurence Lundblade34691b92020-05-18 22:25:25 -07002657void QCBORDecode_EnterMapInMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002658{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002659 QCBORItem OneItemSeach[2];
2660 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
2661 OneItemSeach[0].label.int64 = nLabel;
2662 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
2663 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002664
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002665 /* The map to enter was found, now finish of entering it. */
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002666 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002667}
2668
2669
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002670/*
2671Public function, see header qcbor/qcbor_decode.h file
2672*/
Laurence Lundblade34691b92020-05-18 22:25:25 -07002673void QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002674{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002675 QCBORItem OneItemSeach[2];
2676 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2677 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
2678 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
2679 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002680
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002681 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002682}
2683
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002684/*
2685Public function, see header qcbor/qcbor_decode.h file
2686*/
Laurence Lundblade34691b92020-05-18 22:25:25 -07002687void QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07002688{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002689 QCBORItem OneItemSeach[2];
2690 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
2691 OneItemSeach[0].label.int64 = nLabel;
2692 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
2693 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002694
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002695 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002696}
2697
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002698/*
2699Public function, see header qcbor/qcbor_decode.h file
2700*/
Laurence Lundblade34691b92020-05-18 22:25:25 -07002701void QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
2702{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002703 QCBORItem OneItemSeach[2];
2704 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2705 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
2706 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
2707 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002708
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002709 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002710}
2711
2712
2713
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002714/* Next item must be map or this generates an error */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002715void QCBORDecode_EnterBoundedMode(QCBORDecodeContext *pMe, uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002716{
Laurence Lundblade34691b92020-05-18 22:25:25 -07002717 if(pMe->uLastError != QCBOR_SUCCESS) {
2718 // Already in error state; do nothing.
2719 return;
2720 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002721
2722 /* Get the data item that is the map that is being searched */
Laurence Lundblade34691b92020-05-18 22:25:25 -07002723 QCBORItem Item;
Laurence Lundblade986017c2020-05-23 19:25:02 -07002724 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002725 if(pMe->uLastError != QCBOR_SUCCESS) {
2726 return;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002727 }
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002728 if(Item.uDataType != uType) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07002729 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
2730 return;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002731 }
2732
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002733 DecodeNesting_EnterBoundedMode(&(pMe->nesting), UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002734
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002735 // TODO: restrict input to less than this or some other invalidation strategy.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002736 pMe->uMapEndOffsetCache = 0xffffffff; // Invalidate the cached map end.
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002737
Laurence Lundblade34691b92020-05-18 22:25:25 -07002738 printdecode(pMe, "EnterMapModeDone");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002739}
2740
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002741static QCBORError
2742ExitExit(QCBORDecodeContext *pMe, uint32_t uEndOffset)
2743{
2744 // TODO: is this necessary? Pretty sure it is not
2745 //pMe->nesting.pCurrentBounded->bBoundedMode = false;
2746
2747 QCBORError uErr;
2748 /* Exiting a bounded mode level. Bounded mode could be
2749 either an array, map or wrapped bstr.
2750
2751 The following have to be set when exiting a bounded mode level
2752 - The byte offset of the useful input buffer set to the item after the map, array or bstr just consumed.
2753 - The length of the useful input buf has to be adjusted if exiting bstr wrapped CBOR
2754 - The pre-order traversal nesting level, which could be just one level up, or all the way to the top.
2755 - The count of items in the pre-order nesting level if it is a definite length map or array.
2756 - The bounded nesting level, which could be one bounded level up, or all the way to the top
2757
2758 That means that the pre-order traversal must be set up
2759 to the position just after the array, map or wrapped
2760 bstr that was consumed.
2761
2762
2763*/
2764 /* First work is to set up the pre-order traversal
2765 so that it is positioned just after the array, map
2766 or wrapped bstr that was just consumed. The
2767 useful input buf cursor, nesting level and item
2768 count needs to be adjusted. The exit of the array
2769 map or wrapped bstr might be the last in the
2770 above nesting map or array and so on. Ascender()
2771 does lots of work to unwind all the way to the top
2772 through maps and arrays of definite or indefinte
2773 lengths. */
2774 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
2775
2776 pMe->nesting.pCurrent = pMe->nesting.pCurrentBounded - 1; // TODO error check
2777
2778 uErr = Ascender(pMe);
2779 if(uErr != QCBOR_SUCCESS) {
2780 goto Done;
2781 }
2782
2783/*
2784 It also means that the next highest bounded mode
2785 must be put into effect. That, or the top-level sequence
2786 is reached (which is the primordial bounded bstr in a sense. */
2787 /* Also ascend to the next higest bounded mode level if
2788 there is one. */
2789 while(pMe->nesting.pCurrentBounded != &(pMe->nesting.pMapsAndArrays[0])) {
2790 pMe->nesting.pCurrentBounded--;
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07002791 if(DecodeNesting_IsCurrentBounded(&(pMe->nesting))) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002792 break;
2793 }
2794 }
2795
2796 pMe->uMapEndOffsetCache = 0xffffffff; // Invalidate the cached map end.
2797
2798Done:
2799 printdecode(pMe, "exit exit");
2800 return uErr;
2801}
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002802
2803// Semi-private function
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002804void QCBORDecode_ExitBoundedMode(QCBORDecodeContext *pMe, uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002805{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002806 if(pMe->uLastError != QCBOR_SUCCESS) {
2807 // Already in error state; do nothing.
2808 return;
2809 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002810
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002811 printdecode(pMe, "start exit");
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002812
2813 QCBORError uErr = QCBOR_SUCCESS;
2814
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002815 if(!DecodeNesting_CheckBoundedType(&(pMe->nesting), uType)){
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002816 uErr = QCBOR_ERR_CLOSE_MISMATCH;
2817 goto Done;
2818 }
2819
2820 /* Have to set the offset to the end of the map/array
2821 that is being exited. If there is no cached value,
2822 from previous map search, then do a dummy search. */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002823 if(pMe->uMapEndOffsetCache == 0xffffffff) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002824 QCBORItem Dummy;
2825 Dummy.uLabelType = QCBOR_TYPE_NONE;
2826 uErr = MapSearch(pMe, &Dummy, NULL, NULL, NULL);
2827 if(uErr != QCBOR_SUCCESS) {
2828 goto Done;
2829 }
2830 }
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002831
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002832 uErr = ExitExit(pMe, pMe->uMapEndOffsetCache);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002833
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002834Done:
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002835 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002836}
2837
2838
Laurence Lundblade1341c592020-04-11 14:19:05 -07002839void QCBORDecode_RewindMap(QCBORDecodeContext *pMe)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002840{
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002841 // TODO: check for map mode; test this
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002842 //pMe->nesting.pCurrent->uCount = pMe->nesting.pCurrent->u.ma.uCountTotal;
2843 UsefulInputBuf_Seek(&(pMe->InBuf), pMe->nesting.pCurrent->u.ma.uStartOffset);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002844}
2845
2846
Laurence Lundblade1341c592020-04-11 14:19:05 -07002847
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002848static QCBORError InternalEnterWrappedBstr(QCBORDecodeContext *pMe, const QCBORItem *pItem, uint8_t uTagRequirement, UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002849{
2850 if(pMe->uLastError != QCBOR_SUCCESS) {
2851 // Already in error state; do nothing.
2852 return pMe->uLastError;
2853 }
2854
2855 QCBORError uError = QCBOR_SUCCESS;
2856
2857 if(pItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
2858 uError = QCBOR_ERR_UNEXPECTED_TYPE;
2859 goto Done;;
2860 }
2861
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002862 // TODO: check for the other wrapped CBOR tag
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002863 const TagSpecification TagSpec = {uTagRequirement, QBCOR_TYPE_WRAPPED_CBOR, {QCBOR_TYPE_BYTE_STRING, 0,0,0,0,0}};
2864
2865 uError = CheckTagRequirement(TagSpec, pItem->uDataType);
2866 if(uError != QCBOR_SUCCESS) {
2867 goto Done;
2868 }
2869
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07002870 if(DecodeNesting_IsDefiniteLength(&(pMe->nesting))) {
2871 /* Reverse the decrement done by GetNext() for the bstr as
2872 so the increment in ExitExit()->Ascender() will work right. */
2873 pMe->nesting.pCurrent->u.ma.uCountCursor++;
2874 }
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002875
2876 if(pBstr) {
2877 *pBstr = pItem->val.string;
2878 }
2879
2880 const size_t uPreviousLength = UsefulInputBuf_GetLength(&(pMe->InBuf));
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002881
2882 // Need to move UIB input cursor to the right place
2883
2884 // Really this is a subtraction and an assignment; not much code
2885 // There is a range check in the seek.
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002886 // The bstr was just consumed so the cursor is at the next item after it
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002887
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002888 const size_t uEndOfBstr = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002889
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002890
2891 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOfBstr - pItem->val.string.len);
2892
2893 UsefulInputBuf_SetBufferLen(&(pMe->InBuf), uEndOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002894
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002895 uError = DecodeNesting_DescendWrappedBstr(&(pMe->nesting),
2896 uPreviousLength,
2897 uEndOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002898Done:
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002899 printdecode(pMe, "Entered Bstr");
2900
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002901 return uError;
2902
2903}
2904
2905
2906void QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe, uint8_t uTagRequirement, UsefulBufC *pBstr)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002907{
2908 if(pMe->uLastError != QCBOR_SUCCESS) {
2909 // Already in error state; do nothing.
2910 return;
2911 }
2912
2913 /* Get the data item that is the map that is being searched */
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002914 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002915 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
2916 if(pMe->uLastError != QCBOR_SUCCESS) {
2917 return;
2918 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002919
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002920 pMe->uLastError = (uint8_t)InternalEnterWrappedBstr(pMe, &Item, uTagRequirement, pBstr);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002921}
2922
2923
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002924void QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe, uint8_t uTagRequirement, int64_t nLabel, UsefulBufC *pBstr)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002925{
2926 QCBORItem Item;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002927 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002928
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002929 pMe->uLastError = (uint8_t)InternalEnterWrappedBstr(pMe, &Item, uTagRequirement, pBstr);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002930}
2931
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002932
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002933void QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe, uint8_t uTagRequirement, const char *szLabel, UsefulBufC *pBstr)
2934{
2935 QCBORItem Item;
2936 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
2937
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002938 pMe->uLastError = (uint8_t)InternalEnterWrappedBstr(pMe, &Item, uTagRequirement, pBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002939}
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002940
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002941
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002942void QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002943{
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002944 // TODO: test for right mode?
2945
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002946 /* Reset the length of the Useful\InputBuf to what it was before
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002947 the bstr wrapped CBOR was entered.
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002948 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002949 UsefulInputBuf_SetBufferLen(&(pMe->InBuf),
2950 DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002951
2952
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002953 QCBORError uErr = ExitExit(pMe, DecodeNesting_GetEndOfBstr(&(pMe->nesting)));
2954 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002955}
2956
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002957
Laurence Lundbladee6430642020-03-14 21:15:44 -07002958
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002959
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002960
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002961
Laurence Lundblade11a064e2020-05-07 13:13:42 -07002962
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002963
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002964static QCBORError InterpretBool(const QCBORItem *pItem, bool *pBool)
2965{
2966 switch(pItem->uDataType) {
2967 case QCBOR_TYPE_TRUE:
2968 *pBool = true;
2969 return QCBOR_SUCCESS;
2970 break;
2971
2972 case QCBOR_TYPE_FALSE:
2973 *pBool = false;
2974 return QCBOR_SUCCESS;
2975 break;
2976
2977 default:
2978 return QCBOR_ERR_UNEXPECTED_TYPE;
2979 break;
2980 }
2981}
Laurence Lundbladee6430642020-03-14 21:15:44 -07002982
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002983/*
2984Public function, see header qcbor/qcbor_decode.h file
2985*/
Laurence Lundbladec4537442020-04-14 18:53:22 -07002986void QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002987{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002988 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002989 // Already in error state, do nothing
Laurence Lundbladee6430642020-03-14 21:15:44 -07002990 return;
2991 }
2992
Laurence Lundbladec4537442020-04-14 18:53:22 -07002993 QCBORError nError;
2994 QCBORItem Item;
2995
2996 nError = QCBORDecode_GetNext(pMe, &Item);
2997 if(nError != QCBOR_SUCCESS) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002998 pMe->uLastError = (uint8_t)nError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002999 return;
3000 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003001 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003002}
3003
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003004/*
3005Public function, see header qcbor/qcbor_decode.h file
3006*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003007void QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe, int64_t nLabel, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003008{
3009 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003010 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003011
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003012 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003013}
3014
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003015/*
3016Public function, see header qcbor/qcbor_decode.h file
3017*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003018void QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, bool *pValue)
3019{
3020 QCBORItem Item;
3021 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3022
3023 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
3024}
3025
3026
3027
3028void QCBORDecode_GetTaggedStringInternal(QCBORDecodeContext *pMe, TagSpecification TagSpec, UsefulBufC *pBstr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003029{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07003030 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003031 // Already in error state, do nothing
3032 return;
3033 }
3034
3035 QCBORError nError;
3036 QCBORItem Item;
3037
3038 nError = QCBORDecode_GetNext(pMe, &Item);
3039 if(nError != QCBOR_SUCCESS) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003040 pMe->uLastError = (uint8_t)nError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003041 return;
3042 }
3043
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003044 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, Item.uDataType);
3045
3046 if(pMe->uLastError == QCBOR_SUCCESS) {
3047 *pBstr = Item.val.string;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003048 }
3049}
3050
Laurence Lundbladec4537442020-04-14 18:53:22 -07003051
3052
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003053
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003054static QCBORError ConvertBigNum(uint8_t uTagRequirement, const QCBORItem *pItem, UsefulBufC *pValue, bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003055{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003056 *pbIsNegative = false;
3057
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003058 bool bMustBeTagged = true; // TODO: fix this --- they have to tell us if they are expecting positive or negative
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003059
3060 switch(pItem->uDataType) {
3061 case QCBOR_TYPE_BYTE_STRING:
3062 // TODO: check that there is no tag here?
3063 if(bMustBeTagged) {
3064 return QCBOR_ERR_UNEXPECTED_TYPE;
3065 } else {
3066 *pValue = pItem->val.string;
3067 return QCBOR_SUCCESS;
3068 }
3069 break;
3070
3071 case QCBOR_TYPE_POSBIGNUM:
3072 *pValue = pItem->val.string;
3073 return QCBOR_SUCCESS;
3074 break;
3075
3076 case QCBOR_TYPE_NEGBIGNUM:
3077 *pbIsNegative = true;
3078 *pValue = pItem->val.string;
3079 return QCBOR_SUCCESS;
3080 break;
3081
3082 default:
3083 return QCBOR_ERR_UNEXPECTED_TYPE;
3084 break;
3085 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07003086}
3087
3088
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003089/*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003090 @param[in] bMustBeTagged If \c true, then the data item must be tagged as either
3091 a positive or negative bignum. If \c false, then it only must be a byte string and bIsNegative
3092 will always be false on the asumption that it is positive, but it can be interpretted as
3093 negative if the the sign is know from other context.
3094 @param[out] pValue The bytes that make up the big num
3095 @param[out] pbIsNegative \c true if tagged as a negative big num. \c false otherwise.
3096
3097 if bMustBeTagged is false, then this will succeed if the data item is a plain byte string,
3098 a positive big num or a negative big num.
3099
3100 */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003101void QCBORDecode_GetBignum(QCBORDecodeContext *pMe, uint8_t uTagRequirement, UsefulBufC *pValue, bool *pbIsNegative)
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003102{
3103 if(pMe->uLastError != QCBOR_SUCCESS) {
3104 // Already in error state, do nothing
3105 return;
3106 }
3107
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003108 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003109 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
3110 if(uError != QCBOR_SUCCESS) {
3111 pMe->uLastError = (uint8_t)uError;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003112 return;
3113 }
3114
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003115 pMe->uLastError = (uint8_t)ConvertBigNum(uTagRequirement, &Item, pValue, pbIsNegative);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003116}
3117
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003118/*
3119Public function, see header qcbor/qcbor_decode.h file
3120*/
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003121void QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, UsefulBufC *pValue, bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003122{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003123 QCBORItem Item;
3124 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003125
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003126 pMe->uLastError = (uint8_t)ConvertBigNum(uTagRequirement, &Item, pValue, pbIsNegative);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003127}
3128
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003129/*
3130Public function, see header qcbor/qcbor_decode.h file
3131*/
3132void QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint8_t uTagRequirement, UsefulBufC *pValue, bool *pbIsNegative)
3133{
3134 QCBORItem Item;
3135 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3136
3137 pMe->uLastError = (uint8_t)ConvertBigNum(uTagRequirement, &Item, pValue, pbIsNegative);
3138}
3139
3140
3141
3142// Semi private
3143QCBORError FarfMIME(uint8_t uTagRequirement, const QCBORItem *pItem, UsefulBufC *pMessage, bool *pbIsNot7Bit)
3144{
3145 const TagSpecification TagSpecText = {uTagRequirement, QCBOR_TYPE_MIME, {QCBOR_TYPE_TEXT_STRING, 0,0,0,0,0}};
3146 const TagSpecification TagSpecBinary = {uTagRequirement, QCBOR_TYPE_BINARY_MIME, {QCBOR_TYPE_BYTE_STRING, 0,0,0,0,0}};
3147
3148 QCBORError uReturn;
3149
3150 if(CheckTagRequirement(TagSpecText, pItem->uDataType)) {
3151 *pMessage = pItem->val.string;
3152 if(pbIsNot7Bit != NULL) {
3153 *pbIsNot7Bit = false;
3154 }
3155 uReturn = QCBOR_SUCCESS;
3156 } else if(CheckTagRequirement(TagSpecBinary, pItem->uDataType)) {
3157 *pMessage = pItem->val.string;
3158 if(pbIsNot7Bit != NULL) {
3159 *pbIsNot7Bit = true;
3160 }
3161 uReturn = QCBOR_SUCCESS;
3162
3163 } else {
3164 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
3165 }
3166
3167 return uReturn;
3168}
3169
3170
3171
3172
3173
Laurence Lundbladec4537442020-04-14 18:53:22 -07003174
3175
3176
Laurence Lundbladee6430642020-03-14 21:15:44 -07003177
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003178typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003179
3180
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003181// The main exponentiator that works on only positive numbers
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003182static QCBORError Exponentitate10(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003183{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003184 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003185
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003186 if(uResult != 0) {
3187 /* This loop will run a maximum of 19 times because
3188 * UINT64_MAX < 10 ^^ 19. More than that will cause
3189 * exit with the overflow error
3190 */
3191 for(; nExponent > 0; nExponent--) {
3192 if(uResult > UINT64_MAX / 10) {
3193 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Error overflow
3194 }
3195 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003196 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07003197
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003198 for(; nExponent < 0; nExponent++) {
3199 uResult = uResult / 10;
3200 if(uResult == 0) {
3201 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Underflow error
3202 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07003203 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07003204 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003205 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07003206
3207 *puResult = uResult;
3208
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003209 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003210}
3211
3212
Laurence Lundbladee6430642020-03-14 21:15:44 -07003213/* Convert a decimal fraction to an int64_t without using
3214 floating point or math libraries. Most decimal fractions
3215 will not fit in an int64_t and this will error out with
3216 under or overflow
3217 */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003218static QCBORError Exponentitate2(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003219{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003220 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003221
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003222 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003223
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003224 /* This loop will run a maximum of 64 times because
Laurence Lundbladee6430642020-03-14 21:15:44 -07003225 * INT64_MAX < 2^31. More than that will cause
3226 * exist with the overflow error
3227 */
3228 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003229 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003230 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Error overflow
Laurence Lundbladee6430642020-03-14 21:15:44 -07003231 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003232 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003233 nExponent--;
3234 }
3235
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003236 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003237 if(uResult == 0) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003238 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Underflow error
3239 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003240 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003241 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003242 }
3243
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003244 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003245
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003246 return QCBOR_SUCCESS;
3247}
3248
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003249/*
3250 Compute value with signed mantissa and signed result. Works with exponent of 2 or 10 based on exponentiator.
3251 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003252static inline QCBORError ExponentiateNN(int64_t nMantissa, int64_t nExponent, int64_t *pnResult, fExponentiator pfExp)
3253{
3254 uint64_t uResult;
3255
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003256 // Take the absolute value of the mantissa and convert to unsigned.
3257 // TODO: this should be possible in one intruction
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003258 uint64_t uMantissa = nMantissa > 0 ? (uint64_t)nMantissa : (uint64_t)-nMantissa;
3259
3260 // Do the exponentiation of the positive mantissa
3261 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
3262 if(uReturn) {
3263 return uReturn;
3264 }
3265
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003266
Laurence Lundblade983500d2020-05-14 11:49:34 -07003267 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
3268 of INT64_MIN. This assumes two's compliment representation where
3269 INT64_MIN is one increment farther from 0 than INT64_MAX.
3270 Trying to write -INT64_MIN doesn't work to get this because the
3271 compiler tries to work with an int64_t which can't represent
3272 -INT64_MIN.
3273 */
3274 uint64_t uMax = nMantissa > 0 ? INT64_MAX : (uint64_t)INT64_MAX+1;
3275
3276 // Error out if too large
3277 if(uResult > uMax) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003278 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3279 }
3280
3281 // Casts are safe because of checks above
3282 *pnResult = nMantissa > 0 ? (int64_t)uResult : -(int64_t)uResult;
3283
3284 return QCBOR_SUCCESS;
3285}
3286
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003287/*
3288 Compute value with signed mantissa and unsigned result. Works with exponent of 2 or 10 based on exponentiator.
3289 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003290static inline QCBORError ExponentitateNU(int64_t nMantissa, int64_t nExponent, uint64_t *puResult, fExponentiator pfExp)
3291{
3292 if(nMantissa < 0) {
3293 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3294 }
3295
3296 // Cast to unsigned is OK because of check for negative
3297 // Cast to unsigned is OK because UINT64_MAX > INT64_MAX
3298 // Exponentiation is straight forward
3299 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
3300}
3301
3302
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003303#include <math.h>
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003304
3305
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003306static QCBORError ConvertBigNumToUnsigned(const UsefulBufC BigNum, uint64_t uMax, uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003307{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003308 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003309
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003310 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003311 const uint8_t *pByte = BigNum.ptr;
3312 size_t uLen = BigNum.len;
3313 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07003314 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003315 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003316 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07003317 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003318 }
3319
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003320 *pResult = uResult;
3321 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003322}
3323
Laurence Lundblade887add82020-05-17 05:50:34 -07003324static inline QCBORError ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum, uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003325{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003326 return ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003327}
3328
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003329static inline QCBORError ConvertPositiveBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003330{
3331 uint64_t uResult;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003332 QCBORError uError = ConvertBigNumToUnsigned(BigNum, INT64_MAX, &uResult);
3333 if(uError) {
3334 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003335 }
3336 /* Cast is safe because ConvertBigNum is told to limit to INT64_MAX */
3337 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003338 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003339}
3340
3341
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003342static inline QCBORError ConvertNegativeBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003343{
3344 uint64_t uResult;
Laurence Lundbladeda095972020-06-06 18:35:33 -07003345 /* negaative int furthest from zero is INT64_MIN
3346 which is expressed as -INT64_MAX-1. The value of
3347 a negative bignum is -n-1, one further from zero
3348 than the positive bignum */
3349
3350 /* say INT64_MIN is -2; then INT64_MAX is 1.
3351 Then -n-1 <= INT64_MIN.
3352 Then -n -1 <= -INT64_MAX - 1
3353 THen n <= INT64_MAX. */
3354 QCBORError uError = ConvertBigNumToUnsigned(BigNum, INT64_MAX, &uResult);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003355 if(uError) {
3356 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003357 }
3358 /* Cast is safe because ConvertBigNum is told to limit to INT64_MAX */
Laurence Lundblade887add82020-05-17 05:50:34 -07003359 // TODO: this code is incorrect. See RFC 7049
Laurence Lundbladeda095972020-06-06 18:35:33 -07003360 uResult++; // this is the -1 in -n-1
Laurence Lundbladee6430642020-03-14 21:15:44 -07003361 *pResult = -(int64_t)uResult;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003362 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003363}
3364
Laurence Lundbladef6c86662020-05-12 02:08:00 -07003365#include "fenv.h"
Laurence Lundbladec4537442020-04-14 18:53:22 -07003366
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003367
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003368/*
3369Convert a integers and floats to an int64_t.
3370
3371\param[in] uOptions Bit mask list of conversion options.
3372
3373\retval QCBOR_ERR_CONVERSION_NOT_REQUESTED Conversion, possible, but not requested in uOptions.
3374
3375\retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
3376
3377\retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large or too small.
3378
3379*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003380static QCBORError ConvertInt64(const QCBORItem *pItem, uint32_t uOptions, int64_t *pnValue)
3381{
3382 switch(pItem->uDataType) {
3383 // TODO: float when ifdefs are set
3384 case QCBOR_TYPE_DOUBLE:
3385 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3386 // TODO: what about under/overflow here?
3387 // Invokes the floating-point HW and/or compiler-added libraries
3388 feclearexcept(FE_ALL_EXCEPT);
3389 *pnValue = llround(pItem->val.dfnum);
3390 if(fetestexcept(FE_INVALID)) {
3391 // TODO: better error code
3392 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3393 }
3394 } else {
3395 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3396 }
3397 break;
3398
3399 case QCBOR_TYPE_INT64:
3400 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
3401 *pnValue = pItem->val.int64;
3402 } else {
3403 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3404 }
3405 break;
3406
3407 case QCBOR_TYPE_UINT64:
3408 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
3409 if(pItem->val.uint64 < INT64_MAX) {
3410 *pnValue = pItem->val.int64;
3411 } else {
3412 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3413 }
3414 } else {
3415 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3416 }
3417 break;
3418
3419 default:
3420 return QCBOR_ERR_UNEXPECTED_TYPE;
3421 }
3422 return QCBOR_SUCCESS;
3423}
3424
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003425
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003426void QCBORDecode_GetInt64ConvertInternal(QCBORDecodeContext *pMe,
3427 uint32_t uOptions,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003428 int64_t *pnValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003429 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003430{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07003431 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003432 return;
3433 }
3434
Laurence Lundbladee6430642020-03-14 21:15:44 -07003435 QCBORItem Item;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003436 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
3437 if(uError) {
3438 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003439 return;
3440 }
3441
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003442 if(pItem) {
3443 *pItem = Item;
3444 }
3445
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003446 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003447}
3448
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003449
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003450void QCBORDecode_GetInt64ConvertInternalInMapN(QCBORDecodeContext *pMe,
3451 int64_t nLabel,
3452 uint32_t uOptions,
3453 int64_t *pnValue,
3454 QCBORItem *pItem)
3455{
3456 QCBORItem Item;
3457 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
3458
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003459 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003460}
3461
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003462
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003463void QCBORDecode_GetInt64ConvertInternalInMapSZ(QCBORDecodeContext *pMe,
3464 const char * szLabel,
3465 uint32_t uOptions,
3466 int64_t *pnValue,
3467 QCBORItem *pItem)
3468{
3469 if(pMe->uLastError != QCBOR_SUCCESS) {
3470 return;
3471 }
3472
3473 QCBORItem Item;
3474 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3475
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003476 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003477}
3478
3479
3480
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003481/*
3482 Convert a large variety of integer types to an int64_t.
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003483
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003484 \param[in] uOptions Bit mask list of conversion options.
3485
3486 \retval QCBOR_ERR_CONVERSION_NOT_REQUESTED Conversion, possible, but not requested in uOptions.
3487
3488 \retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
3489
3490 \retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large or too small.
3491
3492 */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003493static QCBORError Int64ConvertAll(const QCBORItem *pItem, uint32_t uOptions, int64_t *pnValue)
3494{
3495 QCBORError uErr;
3496
3497 switch(pItem->uDataType) {
3498
3499 case QCBOR_TYPE_POSBIGNUM:
3500 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3501 return ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003502 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003503 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003504 }
3505 break;
3506
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003507 case QCBOR_TYPE_NEGBIGNUM:
3508 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3509 return ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003510 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003511 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003512 }
3513 break;
3514
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003515#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
3516 case QCBOR_TYPE_DECIMAL_FRACTION:
3517 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3518 return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
3519 pItem->val.expAndMantissa.nExponent,
3520 pnValue,
3521 &Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003522 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003523 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3524 }
3525 break;
3526
3527 case QCBOR_TYPE_BIGFLOAT:
3528 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3529 return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
3530 pItem->val.expAndMantissa.nExponent,
3531 pnValue,
3532 Exponentitate2);
3533 } else {
3534 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3535 }
3536 break;
3537
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003538 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
3539 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3540 int64_t nMantissa;
3541 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3542 if(uErr) {
3543 return uErr;
3544 }
3545 return ExponentiateNN(nMantissa,
3546 pItem->val.expAndMantissa.nExponent,
3547 pnValue,
3548 Exponentitate10);
3549 } else {
3550 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3551 }
3552 break;
3553
3554 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
3555 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3556 int64_t nMantissa;
3557 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3558 if(uErr) {
3559 return uErr;
3560 }
3561 return ExponentiateNN(nMantissa,
3562 pItem->val.expAndMantissa.nExponent,
3563 pnValue,
3564 Exponentitate10);
3565 } else {
3566 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3567 }
3568 break;
3569
3570 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
3571 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3572 int64_t nMantissa;
3573 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3574 if(uErr) {
3575 return uErr;
3576 }
3577 return ExponentiateNN(nMantissa,
3578 pItem->val.expAndMantissa.nExponent,
3579 pnValue,
3580 Exponentitate2);
3581 } else {
3582 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3583 }
3584 break;
3585
3586 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
3587 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3588 int64_t nMantissa;
3589 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3590 if(uErr) {
3591 return uErr;
3592 }
3593 return ExponentiateNN(nMantissa,
3594 pItem->val.expAndMantissa.nExponent,
3595 pnValue,
3596 Exponentitate2);
3597 } else {
3598 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003599 }
3600 break;
3601
Laurence Lundbladec4537442020-04-14 18:53:22 -07003602 default:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003603 return QCBOR_ERR_UNEXPECTED_TYPE;
3604#endif
Laurence Lundbladec4537442020-04-14 18:53:22 -07003605 }
3606}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003607
3608
Laurence Lundbladec4537442020-04-14 18:53:22 -07003609/*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003610 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003611 */
3612void QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003613{
3614 QCBORItem Item;
3615
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003616 QCBORDecode_GetInt64ConvertInternal(pMe, uOptions, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003617
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003618 if(pMe->uLastError == QCBOR_SUCCESS) {
3619 // The above conversion succeeded
3620 return;
3621 }
3622
Laurence Lundbladef6c86662020-05-12 02:08:00 -07003623 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003624 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07003625 return;
3626 }
3627
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003628 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003629}
3630
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003631
3632/*
3633Public function, see header qcbor/qcbor_decode.h file
3634*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003635void QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, int64_t *pnValue)
3636{
3637 QCBORItem Item;
3638
3639 QCBORDecode_GetInt64ConvertInternalInMapN(pMe, nLabel, uOptions, pnValue, &Item);
3640
3641 if(pMe->uLastError == QCBOR_SUCCESS) {
3642 // The above conversion succeeded
3643 return;
3644 }
3645
3646 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3647 // The above conversion failed in a way that code below can't correct
3648 return;
3649 }
3650
3651 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
3652}
3653
3654
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003655/*
3656Public function, see header qcbor/qcbor_decode.h file
3657*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003658void QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, int64_t *pnValue)
3659{
3660 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003661 QCBORDecode_GetInt64ConvertInternalInMapSZ(pMe, szLabel, uOptions, pnValue, &Item);
3662
3663 if(pMe->uLastError == QCBOR_SUCCESS) {
3664 // The above conversion succeeded
3665 return;
3666 }
3667
3668 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3669 // The above conversion failed in a way that code below can't correct
3670 return;
3671 }
3672
3673 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
3674}
3675
3676
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003677static QCBORError ConvertUint64(const QCBORItem *pItem, uint32_t uOptions, uint64_t *puValue)
3678{
3679 switch(pItem->uDataType) {
3680 // TODO: type flaot
3681 case QCBOR_TYPE_DOUBLE:
3682 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3683 feclearexcept(FE_ALL_EXCEPT);
3684 double dRounded = round(pItem->val.dfnum);
3685 // TODO: over/underflow
3686 if(fetestexcept(FE_INVALID)) {
3687 // TODO: better error code
3688 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3689 } else if(isnan(dRounded)) {
3690 // TODO: better error code
3691 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3692 } else if(dRounded >= 0) {
3693 *puValue = (uint64_t)dRounded;
3694 } else {
3695 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3696 }
3697 } else {
3698 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3699 }
3700 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003701
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003702 case QCBOR_TYPE_INT64:
3703 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
3704 if(pItem->val.int64 >= 0) {
3705 *puValue = (uint64_t)pItem->val.int64;
3706 } else {
3707 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3708 }
3709 } else {
3710 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3711 }
3712 break;
3713
3714 case QCBOR_TYPE_UINT64:
3715 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
3716 *puValue = pItem->val.uint64;
3717 } else {
3718 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3719 }
3720 break;
3721
3722 default:
3723 return QCBOR_ERR_UNEXPECTED_TYPE;
3724 }
3725 return QCBOR_SUCCESS;
3726}
Laurence Lundbladec4537442020-04-14 18:53:22 -07003727
3728
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003729void QCBORDecode_GetUInt64ConvertInternal(QCBORDecodeContext *pMe,
3730 uint32_t uOptions,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003731 uint64_t *puValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003732 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003733{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003734 if(pMe->uLastError != QCBOR_SUCCESS) {
3735 return;
3736 }
3737
Laurence Lundbladec4537442020-04-14 18:53:22 -07003738 QCBORItem Item;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003739
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003740 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
3741 if(uError) {
3742 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003743 return;
3744 }
3745
Laurence Lundbladea826c502020-05-10 21:07:00 -07003746 if(pItem) {
3747 *pItem = Item;
3748 }
3749
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003750 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003751}
3752
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003753
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003754void QCBORDecode_GetInt8ConvertInternal(QCBORDecodeContext *pMe, uint32_t uOptions, int8_t *pnValue, QCBORItem *pItem)
3755{
3756 int64_t uValue;
3757 QCBORDecode_GetInt64ConvertInternal(pMe, uOptions, &uValue, pItem);
3758 if(pMe->uLastError != QCBOR_SUCCESS) {
3759 return;
3760 }
3761
3762 if(QCBOR_Int64ToInt8(uValue, pnValue)) {
3763 pMe->uLastError = QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3764 }
3765}
3766
3767void QCBORDecode_GetInt8ConvertInternalInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, int8_t *pnValue, QCBORItem *pItem)
3768{
3769 int64_t uValue;
3770 QCBORDecode_GetInt64ConvertInternalInMapN(pMe, nLabel, uOptions, &uValue, pItem);
3771 if(pMe->uLastError != QCBOR_SUCCESS) {
3772 return;
3773 }
3774
3775 if(QCBOR_Int64ToInt8(uValue, pnValue)) {
3776 pMe->uLastError = QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3777 }
3778}
3779
3780void QCBORDecode_GetInt8ConvertInternalInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, int8_t *pnValue, QCBORItem *pItem)
3781{
3782 int64_t uValue;
3783 QCBORDecode_GetInt64ConvertInternalInMapSZ(pMe, szLabel, uOptions, &uValue, pItem);
3784 if(pMe->uLastError != QCBOR_SUCCESS) {
3785 return;
3786 }
3787
3788 if(QCBOR_Int64ToInt8(uValue, pnValue)) {
3789 pMe->uLastError = QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3790 }
3791}
3792
3793
3794
3795
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003796void QCBORDecode_GetUint64ConvertInternalInMapN(QCBORDecodeContext *pMe,
3797 int64_t nLabel,
3798 uint32_t uOptions,
3799 uint64_t *puValue,
3800 QCBORItem *pItem)
3801{
3802 QCBORItem Item;
3803 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
3804
3805 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
3806}
3807
3808
3809void QCBORDecode_GetUint64ConvertInternalInMapSZ(QCBORDecodeContext *pMe,
3810 const char * szLabel,
3811 uint32_t uOptions,
3812 uint64_t *puValue,
3813 QCBORItem *pItem)
3814{
3815 if(pMe->uLastError != QCBOR_SUCCESS) {
3816 return;
3817 }
3818
3819 QCBORItem Item;
3820 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3821
3822 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
3823}
3824
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003825/*
3826 Public function, see header qcbor/qcbor_decode.h file
3827*/
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003828static QCBORError Uint64ConvertAll(const QCBORItem *pItem, uint32_t uOptions, uint64_t *puValue)
3829{
3830 QCBORError uErr;
3831
3832 switch(pItem->uDataType) {
3833
3834 case QCBOR_TYPE_POSBIGNUM:
3835 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3836 return ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
3837 } else {
3838 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3839 }
3840 break;
3841
3842 case QCBOR_TYPE_NEGBIGNUM:
3843 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3844 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3845 } else {
3846 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3847 }
3848 break;
3849
3850#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
3851
3852 case QCBOR_TYPE_DECIMAL_FRACTION:
3853 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3854 return ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
3855 pItem->val.expAndMantissa.nExponent,
3856 puValue,
3857 Exponentitate10);
3858 } else {
3859 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3860 }
3861 break;
3862
3863 case QCBOR_TYPE_BIGFLOAT:
3864 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3865 return ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
3866 pItem->val.expAndMantissa.nExponent,
3867 puValue,
3868 Exponentitate2);
3869 } else {
3870 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3871 }
3872 break;
3873
3874 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
3875 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3876 // TODO: Would be better to convert to unsigned
3877 int64_t nMantissa;
3878 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3879 if(uErr != QCBOR_SUCCESS) {
3880 return uErr;
3881 }
3882 return ExponentitateNU(nMantissa,
3883 pItem->val.expAndMantissa.nExponent,
3884 puValue,
3885 Exponentitate10);
3886 } else {
3887 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3888 }
3889 break;
3890
3891 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
3892 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3893 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3894 } else {
3895 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3896 }
3897 break;
3898
3899 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
3900 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3901 // TODO: Would be better to convert to unsigned
3902 int64_t nMantissa;
3903 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3904 if(uErr != QCBOR_SUCCESS) {
3905 return uErr;
3906 }
3907 return ExponentitateNU(nMantissa,
3908 pItem->val.expAndMantissa.nExponent,
3909 puValue,
3910 Exponentitate2);
3911 } else {
3912 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3913 }
3914 break;
3915
3916 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
3917 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3918 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3919 } else {
3920 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3921 }
3922 break;
3923#endif
3924 default:
3925 return QCBOR_ERR_UNEXPECTED_TYPE;
3926 }
3927}
3928
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003929/*
3930 Public function, see header qcbor/qcbor_decode.h file
3931*/
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003932void QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003933{
3934 QCBORItem Item;
3935
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003936 QCBORDecode_GetUInt64ConvertInternal(pMe, uOptions, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003937
Laurence Lundbladef6c86662020-05-12 02:08:00 -07003938 if(pMe->uLastError == QCBOR_SUCCESS) {
3939 // The above conversion succeeded
3940 return;
3941 }
3942
3943 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3944 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07003945 return;
3946 }
3947
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003948 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003949}
3950
Laurence Lundbladec4537442020-04-14 18:53:22 -07003951
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003952/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003953 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003954*/
3955void QCBORDecode_GetUint64ConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, uint64_t *puValue)
3956{
3957 QCBORItem Item;
3958
3959 QCBORDecode_GetUint64ConvertInternalInMapN(pMe, nLabel, uOptions, puValue, &Item);
3960
3961 if(pMe->uLastError == QCBOR_SUCCESS) {
3962 // The above conversion succeeded
3963 return;
3964 }
3965
3966 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3967 // The above conversion failed in a way that code below can't correct
3968 return;
3969 }
3970
3971 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
3972}
3973
3974
3975/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003976 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003977*/
3978void QCBORDecode_GetUint64ConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, uint64_t *puValue)
3979{
3980 QCBORItem Item;
3981 QCBORDecode_GetUint64ConvertInternalInMapSZ(pMe, szLabel, uOptions, puValue, &Item);
3982
3983 if(pMe->uLastError == QCBOR_SUCCESS) {
3984 // The above conversion succeeded
3985 return;
3986 }
3987
3988 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3989 // The above conversion failed in a way that code below can't correct
3990 return;
3991 }
3992
3993 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
3994}
3995
3996
3997static QCBORError ConvertDouble(const QCBORItem *pItem, uint32_t uOptions, double *pdValue)
3998{
3999 switch(pItem->uDataType) {
4000 // TODO: float when ifdefs are set
4001 case QCBOR_TYPE_DOUBLE:
4002 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
4003 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
4004 *pdValue = pItem->val.dfnum;
4005 } else {
4006 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4007 }
4008 }
4009 break;
4010
4011 case QCBOR_TYPE_INT64:
4012 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
4013 // TODO: how does this work?
4014 *pdValue = (double)pItem->val.int64;
4015
4016 } else {
4017 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4018 }
4019 break;
4020
4021 case QCBOR_TYPE_UINT64:
4022 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
4023 *pdValue = (double)pItem->val.uint64;
4024 } else {
4025 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4026 }
4027 break;
4028
4029 default:
4030 return QCBOR_ERR_UNEXPECTED_TYPE;
4031 }
4032
4033 return QCBOR_SUCCESS;
4034}
4035
4036
4037
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004038void QCBORDecode_GetDoubleConvertInternal(QCBORDecodeContext *pMe,
4039 uint32_t uOptions,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004040 double *pdValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004041 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004042{
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004043 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07004044 return;
4045 }
4046
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004047 QCBORItem Item;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004048
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004049 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004050 if(uError) {
4051 pMe->uLastError = (uint8_t)uError;
4052 return;
4053 }
4054
4055 if(pItem) {
4056 *pItem = Item;
4057 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07004058
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004059 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004060}
Laurence Lundbladec4537442020-04-14 18:53:22 -07004061
Laurence Lundbladec4537442020-04-14 18:53:22 -07004062
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004063void QCBORDecode_GetDoubleConvertInternalInMapN(QCBORDecodeContext *pMe,
4064 int64_t nLabel,
4065 uint32_t uOptions,
4066 double *pdValue,
4067 QCBORItem *pItem)
4068{
4069 QCBORItem Item;
4070 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
4071
4072 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
4073}
4074
4075void QCBORDecode_GetDoubleConvertInternalInMapSZ(QCBORDecodeContext *pMe,
4076 const char * szLabel,
4077 uint32_t uOptions,
4078 double *pdValue,
4079 QCBORItem *pItem)
4080{
4081 if(pMe->uLastError != QCBOR_SUCCESS) {
4082 return;
4083 }
4084
4085 QCBORItem Item;
4086 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4087
4088 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
4089}
4090
4091
4092
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07004093static double ConvertBigNumToDouble(const UsefulBufC BigNum)
4094{
4095 double dResult;
4096
4097 dResult = 0.0;
4098 const uint8_t *pByte = BigNum.ptr;
4099 size_t uLen = BigNum.len;
4100 /* This will overflow and become the float value INFINITY if the number
4101 is too large to fit. No error will be logged.
4102 TODO: should an error be logged? */
4103 while(uLen--) {
4104 dResult = (dResult * 256.0) + (double)*pByte++;
4105 }
4106
4107 return dResult;
4108}
4109
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004110static QCBORError DoubleConvertAll(const QCBORItem *pItem, uint32_t uOptions, double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004111{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004112 /*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004113 https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
4114
4115 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004116 switch(pItem->uDataType) {
4117 // TODO: type float
4118 case QCBOR_TYPE_DECIMAL_FRACTION:
4119 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
4120 // TODO: rounding and overflow errors
4121 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
4122 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
4123 } else {
4124 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4125 }
4126 break;
4127
4128 case QCBOR_TYPE_BIGFLOAT:
4129 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
4130 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
4131 exp2((double)pItem->val.expAndMantissa.nExponent);
4132 } else {
4133 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4134 }
4135 break;
4136
4137 case QCBOR_TYPE_POSBIGNUM:
4138 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
4139 *pdValue = ConvertBigNumToDouble(pItem->val.bigNum);
4140 } else {
4141 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4142 }
4143 break;
4144
4145 case QCBOR_TYPE_NEGBIGNUM:
4146 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07004147 *pdValue = -1-ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004148 } else {
4149 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4150 }
4151 break;
4152
4153 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
4154 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
4155 double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
4156 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
4157 } else {
4158 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4159 }
4160 break;
4161
4162 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
4163 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
4164 double dMantissa = -ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
4165 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
4166 } else {
4167 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4168 }
4169 break;
4170
4171 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
4172 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
4173 double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
4174 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
4175 } else {
4176 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4177 }
4178 break;
4179
4180 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
4181 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07004182 double dMantissa = -1-ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004183 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
4184 } else {
4185 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4186 }
4187 break;
4188
4189 default:
4190 return QCBOR_ERR_UNEXPECTED_TYPE;
4191 }
4192
4193 return QCBOR_SUCCESS;
4194}
4195
4196
4197/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004198 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004199*/
4200void QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, double *pdValue)
4201{
4202
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004203 QCBORItem Item;
4204
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004205 QCBORDecode_GetDoubleConvertInternal(pMe, uOptions, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004206
4207 if(pMe->uLastError == QCBOR_SUCCESS) {
4208 // The above conversion succeeded
4209 return;
4210 }
4211
4212 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
4213 // The above conversion failed in a way that code below can't correct
4214 return;
4215 }
4216
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004217 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004218}
4219
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004220
4221/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004222 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004223*/
4224void QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, double *pdValue)
4225{
4226 QCBORItem Item;
4227
4228 QCBORDecode_GetDoubleConvertInternalInMapN(pMe, nLabel, uOptions, pdValue, &Item);
4229
4230 if(pMe->uLastError == QCBOR_SUCCESS) {
4231 // The above conversion succeeded
4232 return;
4233 }
4234
4235 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
4236 // The above conversion failed in a way that code below can't correct
4237 return;
4238 }
4239
4240 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
4241}
4242
4243
4244/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004245 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004246*/
4247void QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, double *pdValue)
4248{
4249 QCBORItem Item;
4250 QCBORDecode_GetDoubleConvertInternalInMapSZ(pMe, szLabel, uOptions, pdValue, &Item);
4251
4252 if(pMe->uLastError == QCBOR_SUCCESS) {
4253 // The above conversion succeeded
4254 return;
4255 }
4256
4257 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
4258 // The above conversion failed in a way that code below can't correct
4259 return;
4260 }
4261
4262 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
4263}
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004264
4265
4266void FarfDecimalFraction(QCBORDecodeContext *pMe,
4267 uint8_t uTagRequirement,
4268 QCBORItem *pItem,
4269 int64_t *pnMantissa,
4270 int64_t *pnExponent)
4271{
4272 QCBORError uErr;
4273
4274 if(pItem->uDataType == QCBOR_TYPE_ARRAY) {
4275 if(uTagRequirement == QCBOR_TAGSPEC_MATCH_TAG_CONTENT_TYPE) {
4276 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4277 return;
4278 }
4279 uErr = QCBORDecode_MantissaAndExponent(pMe, pItem);
4280 if(uErr != QCBOR_SUCCESS) {
4281 pMe->uLastError = (uint8_t)uErr;
4282 return;
4283 }
4284 }
4285
4286 if(uTagRequirement == QCBOR_TAGSPEC_MATCH_TAG_CONTENT_TYPE) {
4287 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4288 return;
4289 }
4290
4291 switch (pItem->uDataType) {
4292
4293 case QCBOR_TYPE_DECIMAL_FRACTION:
4294 *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
4295 *pnExponent = pItem->val.expAndMantissa.nExponent;
4296 break;
4297
4298 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
4299 *pnExponent = pItem->val.expAndMantissa.nExponent;
4300
4301 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
4302 if(uErr != QCBOR_SUCCESS) {
4303 pMe->uLastError = (uint8_t)uErr;
4304 }
4305 break;
4306
4307 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
4308 *pnExponent = pItem->val.expAndMantissa.nExponent;
4309
4310 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
4311 if(uErr != QCBOR_SUCCESS) {
4312 pMe->uLastError = (uint8_t)uErr;
4313 }
4314 break;
4315
4316 default:
4317 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4318 }
4319}
4320
4321void QCBORDecode_GetDecimalFractionN(QCBORDecodeContext *pMe,
4322 uint8_t uTagRequirement,
4323 int64_t nLabel,
4324 int64_t *pnMantissa,
4325 int64_t *pnExponent)
4326{
4327 QCBORItem Item;
4328
4329 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
4330 FarfDecimalFraction(pMe, uTagRequirement, &Item, pnMantissa, pnExponent);
4331}
4332
4333
4334
4335void QCBORDecode_GetDecimalFractionSZ(QCBORDecodeContext *pMe,
4336 uint8_t uTagRequirement,
4337 const char *szLabel,
4338 int64_t *pnMantissa,
4339 int64_t *pnExponent)
4340{
4341 QCBORItem Item;
4342
4343 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4344
4345 FarfDecimalFraction(pMe, uTagRequirement, &Item, pnMantissa, pnExponent);
4346}
4347
4348
4349UsefulBufC ConvertIntToBigNum(uint64_t uInt, UsefulBuf Buffer)
4350{
4351 while(uInt & 0xff0000000000UL) {
4352 uInt = uInt << 8;
4353 };
4354
4355 UsefulOutBuf UOB;
4356
4357 UsefulOutBuf_Init(&UOB, Buffer);
4358
4359 while(uInt) {
4360 UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff0000000000UL) >> 56));
4361 uInt = uInt << 8;
4362 }
4363
4364 return UsefulOutBuf_OutUBuf(&UOB);
4365}
4366
4367
4368void QCBORDecode_GetDecimalFractionBigN(QCBORDecodeContext *pMe,
4369 uint8_t uTagRequirement,
4370 int64_t nLabel,
4371 UsefulBuf pBufferForMantissa,
4372 UsefulBufC *pMantissa,
4373 bool *pbIsNegative,
4374 int64_t *pnExponent)
4375{
4376 QCBORItem Item;
4377 QCBORError uErr;
4378
4379 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
4380
4381 if(Item.uDataType == QCBOR_TYPE_ARRAY) {
4382 uErr = QCBORDecode_MantissaAndExponent(pMe, &Item);
4383 if(uErr != QCBOR_SUCCESS) {
4384 pMe->uLastError = (uint8_t)uErr;
4385 return;
4386 }
4387 }
4388
4389 uint64_t uMantissa;
4390
4391 switch (Item.uDataType) {
4392
4393 case QCBOR_TYPE_DECIMAL_FRACTION:
4394 if(Item.val.expAndMantissa.Mantissa.nInt >= 0) {
4395 uMantissa = (uint64_t)Item.val.expAndMantissa.Mantissa.nInt;
4396 *pbIsNegative = false;
4397 } else {
4398 uMantissa = (uint64_t)-Item.val.expAndMantissa.Mantissa.nInt;
4399 *pbIsNegative = true;
4400 }
4401 *pMantissa = ConvertIntToBigNum(uMantissa, pBufferForMantissa);
4402 *pnExponent = Item.val.expAndMantissa.nExponent;
4403 break;
4404
4405 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
4406 *pnExponent = Item.val.expAndMantissa.nExponent;
4407 *pMantissa = Item.val.expAndMantissa.Mantissa.bigNum;
4408 *pbIsNegative = false;
4409 break;
4410
4411 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
4412 *pnExponent = Item.val.expAndMantissa.nExponent;
4413 *pMantissa = Item.val.expAndMantissa.Mantissa.bigNum;
4414 *pbIsNegative = true;
4415 break;
4416
4417 default:
4418 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4419 }
4420}