blob: 2637f3d6ff5e99c500be94ce826eaf10dc9e7e47 [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
184inline static bool DecodeNesting_InBoundedMode(const QCBORDecodeNesting *pNesting)
185{
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 }
218 if(!DecodeNesting_InBoundedMode(pNesting)) { // TODO: pCurrent vs pCurrentBounded
219 /* 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 Lundblade0a042a92020-06-12 14:09:50 -0700268
269// return 1 if closed out an array or map
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700270inline static void
271DecodeNesting_DecrementX(QCBORDecodeNesting *pNesting)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700272{
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700273 /* Only call on array / map; TODO: add check?*/
274 pNesting->pCurrent->u.ma.uCountCursor--;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700275}
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700276
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700277
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800278
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700279inline static void
280DecodeNesting_Ascend(QCBORDecodeNesting *pNesting)
281{
282 pNesting->pCurrent--;
283}
284
285
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700286
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700287
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700288inline static void
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700289DecodeNesting_EnterBoundedMode(QCBORDecodeNesting *pNesting, size_t uOffset)
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700290{
Laurence Lundblade0750fc42020-06-20 21:02:34 -0700291 /* Have descended into this before this is called. The job here is just to mark it in bounded mode */
292 pNesting->pCurrentBounded = pNesting->pCurrent;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700293 DecodeNesting_SetBoundedMode(pNesting, uOffset);
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700294}
295
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700296
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700297
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700298
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700299inline static QCBORError
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700300DecodeNesting_DescendMapOrArray(QCBORDecodeNesting *pNesting,
301 uint8_t uQCBORType,
302 uint64_t uCount)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700303{
304 QCBORError nReturn = QCBOR_SUCCESS;
305
306 if(uCount == 0) {
307 // Nothing to do for empty definite lenth arrays. They are just are
308 // effectively the same as an item that is not a map or array
309 goto Done;
310 // Empty indefinite length maps and arrays are handled elsewhere
311 }
312
313 // Error out if arrays is too long to handle
314 if(uCount != UINT16_MAX && uCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
315 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
316 goto Done;
317 }
318
319 // Error out if nesting is too deep
320 if(pNesting->pCurrent >= &(pNesting->pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING])) {
321 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
322 goto Done;
323 }
324
325 // The actual descend
326 pNesting->pCurrent++;
327
328 // Fill in the new level fully
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700329 pNesting->pCurrent->uLevelType = uQCBORType;
330 pNesting->pCurrent->u.ma.uCountCursor = (uint16_t)uCount;
331 pNesting->pCurrent->u.ma.uCountTotal = (uint16_t)uCount;
332
333 DecodeNesting_ClearBoundedMode(pNesting);
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700334
335Done:
336 return nReturn;;
337}
338
339
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700340inline static QCBORError
341DecodeNesting_DescendWrappedBstr(QCBORDecodeNesting *pNesting,
342 size_t uEndOffset,
343 size_t uEndOfBstr)
344{
345 QCBORError nReturn = QCBOR_SUCCESS;
346
347 // Error out if nesting is too deep
348 if(pNesting->pCurrent >= &(pNesting->pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING])) {
349 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
350 goto Done;
351 }
352
353 // The actual descend
354 pNesting->pCurrent++;
355
356 // Fill in the new level fully
357 pNesting->pCurrent->uLevelType = QCBOR_TYPE_BYTE_STRING;
358 pNesting->pCurrent->u.bs.uPreviousEndOffset = (uint32_t)uEndOffset;
359 pNesting->pCurrent->u.bs.uEndOfBstr = (uint32_t)uEndOfBstr;
360
361 pNesting->pCurrentBounded = pNesting->pCurrent;
362
363Done:
364 return nReturn;;
365}
366
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700367
Laurence Lundbladeee851742020-01-08 08:37:05 -0800368inline static void
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700369DecodeNesting_Init(QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700370{
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700371 pNesting->pMapsAndArrays[0].uLevelType = QCBOR_TYPE_BYTE_STRING;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700372 pNesting->pCurrent = &(pNesting->pMapsAndArrays[0]);
373}
374
375
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700376static void DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting, QCBORDecodeNesting *pSave)
377{
378 *pSave = *pNesting;
Laurence Lundblade0750fc42020-06-20 21:02:34 -0700379 pNesting->pCurrent = pNesting->pCurrentBounded;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700380
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700381 if(!DecodeNesting_IsIndefiniteLength(pNesting)) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700382 pNesting->pCurrent->u.ma.uCountCursor = pNesting->pCurrent->u.ma.uCountTotal;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700383 }
384}
385
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700386static inline void DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting, QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700387{
388 *pNesting = *pSave;
389}
390
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700391
392static inline uint32_t DecodeNesting_GetEndOfBstr(QCBORDecodeNesting *pMe)
393{
394 return pMe->pCurrentBounded->u.bs.uEndOfBstr;
395}
396
397
398static inline uint32_t DecodeNesting_GetPreviousBoundedEnd(QCBORDecodeNesting *pMe)
399{
400 return pMe->pCurrentBounded->u.bs.uPreviousEndOffset;
401}
402
403
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700404QCBORError DecodeNesting_EnterBstr(QCBORDecodeNesting *pNesting, uint32_t uEndOffset)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700405{
406 QCBORError uReturn ;
407
408 // Error out if nesting is too deep
409 if(pNesting->pCurrent >= &(pNesting->pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING])) {
410 uReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
411 goto Done;
412 }
413
414 // The actual descend
415 pNesting->pCurrent++;
416
417 // Record a few details for this nesting level
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700418 pNesting->pCurrent->uLevelType = QCBOR_TYPE_BYTE_STRING; // TODO the right value for a bstr
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700419
420 uReturn = QCBOR_SUCCESS;
421
422Done:
423 return uReturn;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700424}
425
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700426
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700427
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700428
Laurence Lundbladeee851742020-01-08 08:37:05 -0800429/*===========================================================================
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800430 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
431
432 The following four functions are pretty wrappers for invocation of
433 the string allocator supplied by the caller.
434
Laurence Lundbladeee851742020-01-08 08:37:05 -0800435 ===========================================================================*/
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800436
Laurence Lundbladeee851742020-01-08 08:37:05 -0800437static inline void
438StringAllocator_Free(const QCORInternalAllocator *pMe, void *pMem)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800439{
440 (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, 0);
441}
442
Laurence Lundbladeee851742020-01-08 08:37:05 -0800443// StringAllocator_Reallocate called with pMem NULL is
444// equal to StringAllocator_Allocate()
445static inline UsefulBuf
446StringAllocator_Reallocate(const QCORInternalAllocator *pMe,
447 void *pMem,
448 size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800449{
450 return (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, uSize);
451}
452
Laurence Lundbladeee851742020-01-08 08:37:05 -0800453static inline UsefulBuf
454StringAllocator_Allocate(const QCORInternalAllocator *pMe, size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800455{
456 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
457}
458
Laurence Lundbladeee851742020-01-08 08:37:05 -0800459static inline void
460StringAllocator_Destruct(const QCORInternalAllocator *pMe)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800461{
462 if(pMe->pfAllocator) {
463 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
464 }
465}
466
467
468
Laurence Lundbladeee851742020-01-08 08:37:05 -0800469/*===========================================================================
470 QCBORDecode -- The main implementation of CBOR decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700471
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800472 See qcbor/qcbor_decode.h for definition of the object
473 used here: QCBORDecodeContext
Laurence Lundbladeee851742020-01-08 08:37:05 -0800474 ===========================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700475/*
476 Public function, see header file
477 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800478void QCBORDecode_Init(QCBORDecodeContext *me,
479 UsefulBufC EncodedCBOR,
480 QCBORDecodeMode nDecodeMode)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700481{
482 memset(me, 0, sizeof(QCBORDecodeContext));
483 UsefulInputBuf_Init(&(me->InBuf), EncodedCBOR);
Laurence Lundbladeee851742020-01-08 08:37:05 -0800484 // Don't bother with error check on decode mode. If a bad value is
485 // passed it will just act as if the default normal mode of 0 was set.
Laurence Lundbladee6bcef12020-04-01 10:56:27 -0700486 me->uDecodeMode = (uint8_t)nDecodeMode;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700487 DecodeNesting_Init(&(me->nesting));
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700488 for(int i = 0; i < QCBOR_NUM_MAPPED_TAGS; i++) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -0700489 me->auMappedTags[i] = CBOR_TAG_INVALID16;
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700490 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700491}
492
493
494/*
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700495 Public function, see header file
496 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800497void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
498 QCBORStringAllocate pfAllocateFunction,
499 void *pAllocateContext,
500 bool bAllStrings)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700501{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800502 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
503 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
504 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700505}
506
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800507
508/*
509 Public function, see header file
510 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800511void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *me,
512 const QCBORTagListIn *pTagList)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700513{
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700514 // This does nothing now. It is retained for backwards compatibility
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700515}
516
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700517
518/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800519 This decodes the fundamental part of a CBOR data item, the type and
520 number
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800521
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700522 This is the Counterpart to InsertEncodedTypeAndNumber().
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800523
Laurence Lundbladeee851742020-01-08 08:37:05 -0800524 This does the network->host byte order conversion. The conversion
525 here also results in the conversion for floats in addition to that
526 for lengths, tags and integer values.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800527
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700528 This returns:
529 pnMajorType -- the major type for the item
Laurence Lundbladeee851742020-01-08 08:37:05 -0800530
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800531 puArgument -- the "number" which is used a the value for integers,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800532 tags and floats and length for strings and arrays
533
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800534 pnAdditionalInfo -- Pass this along to know what kind of float or
Laurence Lundbladeee851742020-01-08 08:37:05 -0800535 if length is indefinite
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800536
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800537 The int type is preferred to uint8_t for some variables as this
538 avoids integer promotions, can reduce code size and makes
539 static analyzers happier.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700540 */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800541inline static QCBORError DecodeTypeAndNumber(UsefulInputBuf *pUInBuf,
542 int *pnMajorType,
543 uint64_t *puArgument,
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800544 int *pnAdditionalInfo)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700545{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700546 QCBORError nReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800547
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700548 // Get the initial byte that every CBOR data item has
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800549 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800550
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700551 // Break down the initial byte
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800552 const int nTmpMajorType = nInitialByte >> 5;
553 const int nAdditionalInfo = nInitialByte & 0x1f;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800554
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800555 // Where the number or argument accumulates
556 uint64_t uArgument;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800557
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800558 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700559 // Need to get 1,2,4 or 8 additional argument bytes. Map
560 // LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800561 static const uint8_t aIterate[] = {1,2,4,8};
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800562
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800563 // Loop getting all the bytes in the argument
564 uArgument = 0;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800565 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800566 // This shift and add gives the endian conversion
567 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
568 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800569 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800570 // The reserved and thus-far unused additional info values
571 nReturn = QCBOR_ERR_UNSUPPORTED;
572 goto Done;
573 } else {
574 // Less than 24, additional info is argument or 31, an indefinite length
575 // No more bytes to get
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800576 uArgument = (uint64_t)nAdditionalInfo;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700577 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800578
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700579 if(UsefulInputBuf_GetError(pUInBuf)) {
580 nReturn = QCBOR_ERR_HIT_END;
581 goto Done;
582 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800583
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700584 // All successful if we got here.
585 nReturn = QCBOR_SUCCESS;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800586 *pnMajorType = nTmpMajorType;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800587 *puArgument = uArgument;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800588 *pnAdditionalInfo = nAdditionalInfo;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800589
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700590Done:
591 return nReturn;
592}
593
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800594
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700595/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800596 CBOR doesn't explicitly specify two's compliment for integers but all
597 CPUs use it these days and the test vectors in the RFC are so. All
598 integers in the CBOR structure are positive and the major type
599 indicates positive or negative. CBOR can express positive integers
600 up to 2^x - 1 where x is the number of bits and negative integers
601 down to 2^x. Note that negative numbers can be one more away from
602 zero than positive. Stdint, as far as I can tell, uses two's
603 compliment to represent negative integers.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800604
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700605 See http://www.unix.org/whitepapers/64bit.html for reasons int isn't
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800606 used carefully here, and in particular why it isn't used in the interface.
607 Also see
608 https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers
609
610 Int is used for values that need less than 16-bits and would be subject
611 to integer promotion and complaining by static analyzers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700612 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800613inline static QCBORError
614DecodeInteger(int nMajorType, uint64_t uNumber, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700615{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700616 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800617
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700618 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
619 if (uNumber <= INT64_MAX) {
620 pDecodedItem->val.int64 = (int64_t)uNumber;
621 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800622
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700623 } else {
624 pDecodedItem->val.uint64 = uNumber;
625 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800626
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700627 }
628 } else {
629 if(uNumber <= INT64_MAX) {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800630 // CBOR's representation of negative numbers lines up with the
631 // two-compliment representation. A negative integer has one
632 // more in range than a positive integer. INT64_MIN is
633 // equal to (-INT64_MAX) - 1.
634 pDecodedItem->val.int64 = (-(int64_t)uNumber) - 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700635 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800636
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700637 } else {
638 // C can't represent a negative integer in this range
Laurence Lundblade21d1d812019-09-28 22:47:49 -1000639 // so it is an error.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700640 nReturn = QCBOR_ERR_INT_OVERFLOW;
641 }
642 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800643
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700644 return nReturn;
645}
646
647// Make sure #define value line up as DecodeSimple counts on this.
648#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
649#error QCBOR_TYPE_FALSE macro value wrong
650#endif
651
652#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
653#error QCBOR_TYPE_TRUE macro value wrong
654#endif
655
656#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
657#error QCBOR_TYPE_NULL macro value wrong
658#endif
659
660#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
661#error QCBOR_TYPE_UNDEF macro value wrong
662#endif
663
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700664#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
665#error QCBOR_TYPE_BREAK macro value wrong
666#endif
667
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700668#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
669#error QCBOR_TYPE_DOUBLE macro value wrong
670#endif
671
672#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
673#error QCBOR_TYPE_FLOAT macro value wrong
674#endif
675
676/*
677 Decode true, false, floats, break...
678 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800679inline static QCBORError
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800680DecodeSimple(int nAdditionalInfo, uint64_t uNumber, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700681{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700682 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800683
Laurence Lundbladeee851742020-01-08 08:37:05 -0800684 // uAdditionalInfo is 5 bits from the initial byte compile time checks
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800685 // above make sure uAdditionalInfo values line up with uDataType values.
686 // DecodeTypeAndNumber never returns a major type > 1f so cast is safe
687 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800688
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800689 switch(nAdditionalInfo) {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800690 // No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they are
691 // caught before this is called.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800692
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700693 case HALF_PREC_FLOAT:
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700694 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uNumber);
695 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700696 break;
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700697 case SINGLE_PREC_FLOAT:
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700698 pDecodedItem->val.dfnum = (double)UsefulBufUtil_CopyUint32ToFloat((uint32_t)uNumber);
699 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700700 break;
701 case DOUBLE_PREC_FLOAT:
702 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uNumber);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700703 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700704 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800705
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700706 case CBOR_SIMPLEV_FALSE: // 20
707 case CBOR_SIMPLEV_TRUE: // 21
708 case CBOR_SIMPLEV_NULL: // 22
709 case CBOR_SIMPLEV_UNDEF: // 23
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700710 case CBOR_SIMPLE_BREAK: // 31
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700711 break; // nothing to do
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800712
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700713 case CBOR_SIMPLEV_ONEBYTE: // 24
714 if(uNumber <= CBOR_SIMPLE_BREAK) {
715 // This takes out f8 00 ... f8 1f which should be encoded as e0 … f7
Laurence Lundblade077475f2019-04-26 09:06:33 -0700716 nReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700717 goto Done;
718 }
Laurence Lundblade5e390822019-01-06 12:35:01 -0800719 /* FALLTHROUGH */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700720 // fall through intentionally
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800721
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700722 default: // 0-19
723 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
Laurence Lundbladeee851742020-01-08 08:37:05 -0800724 /*
725 DecodeTypeAndNumber will make uNumber equal to
726 uAdditionalInfo when uAdditionalInfo is < 24 This cast is
727 safe because the 2, 4 and 8 byte lengths of uNumber are in
728 the double/float cases above
729 */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700730 pDecodedItem->val.uSimple = (uint8_t)uNumber;
731 break;
732 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800733
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700734Done:
735 return nReturn;
736}
737
738
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700739/*
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530740 Decode text and byte strings. Call the string allocator if asked to.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700741 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800742inline static QCBORError DecodeBytes(const QCORInternalAllocator *pAllocator,
743 int nMajorType,
744 uint64_t uStrLen,
745 UsefulInputBuf *pUInBuf,
746 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700747{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700748 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800749
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800750 // CBOR lengths can be 64 bits, but size_t is not 64 bits on all CPUs.
751 // This check makes the casts to size_t below safe.
752
753 // 4 bytes less than the largest sizeof() so this can be tested by
754 // putting a SIZE_MAX length in the CBOR test input (no one will
755 // care the limit on strings is 4 bytes shorter).
756 if(uStrLen > SIZE_MAX-4) {
757 nReturn = QCBOR_ERR_STRING_TOO_LONG;
758 goto Done;
759 }
760
761 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, (size_t)uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530762 if(UsefulBuf_IsNULLC(Bytes)) {
763 // Failed to get the bytes for this string item
764 nReturn = QCBOR_ERR_HIT_END;
765 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700766 }
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530767
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800768 if(pAllocator) {
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530769 // We are asked to use string allocator to make a copy
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800770 UsefulBuf NewMem = StringAllocator_Allocate(pAllocator, (size_t)uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530771 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade30816f22018-11-10 13:40:22 +0700772 nReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530773 goto Done;
774 }
775 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800776 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530777 } else {
778 // Normal case with no string allocator
779 pDecodedItem->val.string = Bytes;
780 }
Laurence Lundbladeee851742020-01-08 08:37:05 -0800781 const bool bIsBstr = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING);
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800782 // Cast because ternary operator causes promotion to integer
783 pDecodedItem->uDataType = (uint8_t)(bIsBstr ? QCBOR_TYPE_BYTE_STRING
784 : QCBOR_TYPE_TEXT_STRING);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800785
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530786Done:
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700787 return nReturn;
788}
789
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700790
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800791
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700792
793
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700794
795
Laurence Lundbladeee851742020-01-08 08:37:05 -0800796// Make sure the constants align as this is assumed by
797// the GetAnItem() implementation
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700798#if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
799#error QCBOR_TYPE_ARRAY value not lined up with major type
800#endif
801#if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
802#error QCBOR_TYPE_MAP value not lined up with major type
803#endif
804
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700805/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800806 This gets a single data item and decodes it including preceding
807 optional tagging. This does not deal with arrays and maps and nesting
808 except to decode the data item introducing them. Arrays and maps are
809 handled at the next level up in GetNext().
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800810
Laurence Lundbladeee851742020-01-08 08:37:05 -0800811 Errors detected here include: an array that is too long to decode,
812 hit end of buffer unexpectedly, a few forms of invalid encoded CBOR
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700813 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800814static QCBORError GetNext_Item(UsefulInputBuf *pUInBuf,
815 QCBORItem *pDecodedItem,
816 const QCORInternalAllocator *pAllocator)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700817{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700818 QCBORError nReturn;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800819
Laurence Lundbladeee851742020-01-08 08:37:05 -0800820 /*
821 Get the major type and the number. Number could be length of more
822 bytes or the value depending on the major type nAdditionalInfo is
823 an encoding of the length of the uNumber and is needed to decode
824 floats and doubles
825 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800826 int nMajorType;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700827 uint64_t uNumber;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800828 int nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800829
Laurence Lundblade4b09f632019-10-09 14:34:59 -0700830 memset(pDecodedItem, 0, sizeof(QCBORItem));
831
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800832 nReturn = DecodeTypeAndNumber(pUInBuf, &nMajorType, &uNumber, &nAdditionalInfo);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800833
Laurence Lundbladeee851742020-01-08 08:37:05 -0800834 // Error out here if we got into trouble on the type and number. The
835 // code after this will not work if the type and number is not good.
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700836 if(nReturn) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700837 goto Done;
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700838 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800839
Laurence Lundbladeee851742020-01-08 08:37:05 -0800840 // At this point the major type and the value are valid. We've got
841 // the type and the number that starts every CBOR data item.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800842 switch (nMajorType) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700843 case CBOR_MAJOR_TYPE_POSITIVE_INT: // Major type 0
844 case CBOR_MAJOR_TYPE_NEGATIVE_INT: // Major type 1
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800845 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700846 nReturn = QCBOR_ERR_BAD_INT;
847 } else {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800848 nReturn = DecodeInteger(nMajorType, uNumber, pDecodedItem);
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700849 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700850 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800851
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700852 case CBOR_MAJOR_TYPE_BYTE_STRING: // Major type 2
853 case CBOR_MAJOR_TYPE_TEXT_STRING: // Major type 3
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800854 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
855 const bool bIsBstr = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING);
856 pDecodedItem->uDataType = (uint8_t)(bIsBstr ? QCBOR_TYPE_BYTE_STRING
857 : QCBOR_TYPE_TEXT_STRING);
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530858 pDecodedItem->val.string = (UsefulBufC){NULL, SIZE_MAX};
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700859 } else {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800860 nReturn = DecodeBytes(pAllocator, nMajorType, uNumber, pUInBuf, pDecodedItem);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700861 }
862 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800863
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700864 case CBOR_MAJOR_TYPE_ARRAY: // Major type 4
865 case CBOR_MAJOR_TYPE_MAP: // Major type 5
866 // Record the number of items in the array or map
867 if(uNumber > QCBOR_MAX_ITEMS_IN_ARRAY) {
868 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
869 goto Done;
870 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800871 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530872 pDecodedItem->val.uCount = UINT16_MAX; // Indicate indefinite length
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700873 } else {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800874 // type conversion OK because of check above
875 pDecodedItem->val.uCount = (uint16_t)uNumber;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700876 }
Laurence Lundbladeee851742020-01-08 08:37:05 -0800877 // C preproc #if above makes sure constants for major types align
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800878 // DecodeTypeAndNumber never returns a major type > 7 so cast is safe
879 pDecodedItem->uDataType = (uint8_t)nMajorType;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700880 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800881
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700882 case CBOR_MAJOR_TYPE_OPTIONAL: // Major type 6, optional prepended tags
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800883 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700884 nReturn = QCBOR_ERR_BAD_INT;
885 } else {
886 pDecodedItem->val.uTagV = uNumber;
887 pDecodedItem->uDataType = QCBOR_TYPE_OPTTAG;
888 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700889 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800890
Laurence Lundbladeee851742020-01-08 08:37:05 -0800891 case CBOR_MAJOR_TYPE_SIMPLE:
892 // Major type 7, float, double, true, false, null...
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800893 nReturn = DecodeSimple(nAdditionalInfo, uNumber, pDecodedItem);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700894 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800895
Laurence Lundbladeee851742020-01-08 08:37:05 -0800896 default:
897 // Never happens because DecodeTypeAndNumber() should never return > 7
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700898 nReturn = QCBOR_ERR_UNSUPPORTED;
899 break;
900 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800901
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700902Done:
903 return nReturn;
904}
905
906
907
908/*
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800909 This layer deals with indefinite length strings. It pulls all the
Laurence Lundbladeee851742020-01-08 08:37:05 -0800910 individual chunk items together into one QCBORItem using the string
911 allocator.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800912
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530913 Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700914 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800915static inline QCBORError
916GetNext_FullItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700917{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700918 // Stack usage; int/ptr 2 UsefulBuf 2 QCBORItem -- 96
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700919
920 // Get pointer to string allocator. First use is to pass it to
921 // GetNext_Item() when option is set to allocate for *every* string.
922 // Second use here is to allocate space to coallese indefinite
923 // length string items into one.
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800924 const QCORInternalAllocator *pAllocator = me->StringAllocator.pfAllocator ?
925 &(me->StringAllocator) :
926 NULL;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800927
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700928 QCBORError nReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800929 nReturn = GetNext_Item(&(me->InBuf),
930 pDecodedItem,
931 me->bStringAllocateAll ? pAllocator: NULL);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700932 if(nReturn) {
933 goto Done;
934 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800935
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700936 // To reduce code size by removing support for indefinite length strings, the
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530937 // code in this function from here down can be eliminated. Run tests, except
938 // indefinite length string tests, to be sure all is OK if this is removed.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800939
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800940 // Only do indefinite length processing on strings
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700941 const uint8_t uStringType = pDecodedItem->uDataType;
942 if(uStringType!= QCBOR_TYPE_BYTE_STRING && uStringType != QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700943 goto Done; // no need to do any work here on non-string types
944 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800945
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800946 // Is this a string with an indefinite length?
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530947 if(pDecodedItem->val.string.len != SIZE_MAX) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800948 goto Done; // length is not indefinite, so no work to do here
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700949 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800950
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530951 // Can't do indefinite length strings without a string allocator
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800952 if(pAllocator == NULL) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700953 nReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
954 goto Done;
955 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800956
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700957 // Loop getting chunk of indefinite string
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700958 UsefulBufC FullString = NULLUsefulBufC;
959
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700960 for(;;) {
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700961 // Get item for next chunk
962 QCBORItem StringChunkItem;
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700963 // NULL string allocator passed here. Do not need to allocate
964 // chunks even if bStringAllocateAll is set.
Laurence Lundbladefae26bf2019-02-18 11:15:43 -0800965 nReturn = GetNext_Item(&(me->InBuf), &StringChunkItem, NULL);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700966 if(nReturn) {
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700967 break; // Error getting the next chunk
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700968 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800969
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530970 // See if it is a marker at end of indefinite length string
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700971 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800972 // String is complete
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700973 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +0530974 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700975 break;
976 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800977
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700978 // Match data type of chunk to type at beginning.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530979 // Also catches error of other non-string types that don't belong.
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700980 // Also catches indefinite length strings inside indefinite length strings
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800981 if(StringChunkItem.uDataType != uStringType ||
982 StringChunkItem.val.string.len == SIZE_MAX) {
Laurence Lundblade30816f22018-11-10 13:40:22 +0700983 nReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700984 break;
985 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800986
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530987 // Alloc new buffer or expand previously allocated buffer so it can fit
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800988 // The first time throurgh FullString.ptr is NULL and this is
989 // equivalent to StringAllocator_Allocate()
990 UsefulBuf NewMem = StringAllocator_Reallocate(pAllocator,
991 UNCONST_POINTER(FullString.ptr),
992 FullString.len + StringChunkItem.val.string.len);
993
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700994 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530995 // Allocation of memory for the string failed
Laurence Lundblade30816f22018-11-10 13:40:22 +0700996 nReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700997 break;
998 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800999
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001000 // Copy new string chunk at the end of string so far.
1001 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001002 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001003
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001004 if(nReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
1005 // Getting the item failed, clean up the allocated memory
1006 StringAllocator_Free(pAllocator, UNCONST_POINTER(FullString.ptr));
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001007 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001008
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001009Done:
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001010 return nReturn;
1011}
1012
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001013
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001014uint64_t ConvertTag(QCBORDecodeContext *me, uint16_t uTagVal) {
1015 if(uTagVal < 0xfff0) {
1016 return uTagVal;
1017 } else {
1018 // TODO constant and error check
1019 int x = uTagVal - 0xfff0;
1020 return me->auMappedTags[x];
1021 }
1022}
1023
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001024/*
Laurence Lundblade59289e52019-12-30 13:44:37 -08001025 Gets all optional tag data items preceding a data item that is not an
1026 optional tag and records them as bits in the tag map.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001027 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001028static QCBORError
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001029GetNext_TaggedItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001030{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001031 // Stack usage: int/ptr: 3 -- 24
Laurence Lundblade30816f22018-11-10 13:40:22 +07001032 QCBORError nReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001033
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001034 uint16_t auTags[QCBOR_MAX_TAGS_PER_ITEM] = {CBOR_TAG_INVALID16,
1035 CBOR_TAG_INVALID16,
1036 CBOR_TAG_INVALID16,
1037 CBOR_TAG_INVALID16};
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001038
Laurence Lundblade59289e52019-12-30 13:44:37 -08001039 // Loop fetching items until the item fetched is not a tag
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001040 for(;;) {
1041 nReturn = GetNext_FullItem(me, pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001042 if(nReturn) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001043 goto Done; // Error out of the loop
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001044 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001045
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001046 if(pDecodedItem->uDataType != QCBOR_TYPE_OPTTAG) {
1047 // Successful exit from loop; maybe got some tags, maybe not
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001048 memcpy(pDecodedItem->uTags, auTags, sizeof(auTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001049 break;
1050 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001051
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001052 // Is there room for the tag in the tags list?
1053 size_t uTagIndex;
1054 for(uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001055 if(auTags[uTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001056 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001057 }
1058 }
1059 if(uTagIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001060 return QCBOR_ERR_TOO_MANY_TAGS;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001061 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001062
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001063 // Is the tag > 16 bits?
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001064 if(pDecodedItem->val.uTagV > CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001065 size_t uTagMapIndex;
1066 // Is there room in the tag map?
1067 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001068 if(me->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001069 break;
1070 }
1071 if(me->auMappedTags[uTagMapIndex] == pDecodedItem->val.uTagV) {
1072 break;
1073 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001074 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001075 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
1076 // No room for the tag
1077 return 97; // TODO error code
1078 }
1079
1080 // Cover the case where tag is new and were it is already in the map
1081 me->auMappedTags[uTagMapIndex] = pDecodedItem->val.uTagV;
1082 auTags[uTagIndex] = (uint16_t)(uTagMapIndex + 0xfff0); // TODO proper constant and cast
1083
1084 } else {
1085 auTags[uTagIndex] = (uint16_t)pDecodedItem->val.uTagV;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001086 }
1087 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001088
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001089Done:
1090 return nReturn;
1091}
1092
1093
1094/*
Laurence Lundbladeee851742020-01-08 08:37:05 -08001095 This layer takes care of map entries. It combines the label and data
1096 items into one QCBORItem.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001097 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001098static inline QCBORError
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001099GetNext_MapEntry(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001100{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001101 // Stack use: int/ptr 1, QCBORItem -- 56
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001102 QCBORError nReturn = GetNext_TaggedItem(me, pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001103 if(nReturn)
1104 goto Done;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001105
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001106 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001107 // Break can't be a map entry
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001108 goto Done;
1109 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001110
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001111 if(me->uDecodeMode != QCBOR_DECODE_MODE_MAP_AS_ARRAY) {
1112 // In a map and caller wants maps decoded, not treated as arrays
1113
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001114 if(DecodeNesting_IsCurrentTypeMap(&(me->nesting))) {
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001115 // If in a map and the right decoding mode, get the label
1116
Laurence Lundbladeee851742020-01-08 08:37:05 -08001117 // Save label in pDecodedItem and get the next which will
1118 // be the real data
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001119 QCBORItem LabelItem = *pDecodedItem;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001120 nReturn = GetNext_TaggedItem(me, pDecodedItem);
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001121 if(nReturn)
1122 goto Done;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001123
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301124 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001125
1126 if(LabelItem.uDataType == QCBOR_TYPE_TEXT_STRING) {
1127 // strings are always good labels
1128 pDecodedItem->label.string = LabelItem.val.string;
1129 pDecodedItem->uLabelType = QCBOR_TYPE_TEXT_STRING;
1130 } else if (QCBOR_DECODE_MODE_MAP_STRINGS_ONLY == me->uDecodeMode) {
Laurence Lundbladeee851742020-01-08 08:37:05 -08001131 // It's not a string and we only want strings
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001132 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
1133 goto Done;
1134 } else if(LabelItem.uDataType == QCBOR_TYPE_INT64) {
1135 pDecodedItem->label.int64 = LabelItem.val.int64;
1136 pDecodedItem->uLabelType = QCBOR_TYPE_INT64;
1137 } else if(LabelItem.uDataType == QCBOR_TYPE_UINT64) {
1138 pDecodedItem->label.uint64 = LabelItem.val.uint64;
1139 pDecodedItem->uLabelType = QCBOR_TYPE_UINT64;
1140 } else if(LabelItem.uDataType == QCBOR_TYPE_BYTE_STRING) {
1141 pDecodedItem->label.string = LabelItem.val.string;
1142 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
1143 pDecodedItem->uLabelType = QCBOR_TYPE_BYTE_STRING;
1144 } else {
1145 // label is not an int or a string. It is an arrray
1146 // or a float or such and this implementation doesn't handle that.
1147 // Also, tags on labels are ignored.
1148 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
1149 goto Done;
1150 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001151 }
1152 } else {
1153 if(pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001154 if(pDecodedItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
1155 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
1156 goto Done;
1157 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001158 // Decoding a map as an array
1159 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001160 // Cast is safe because of check against QCBOR_MAX_ITEMS_IN_ARRAY/2
1161 // Cast is needed because of integer promotion
1162 pDecodedItem->val.uCount = (uint16_t)(pDecodedItem->val.uCount * 2);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001163 }
1164 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001165
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001166Done:
1167 return nReturn;
1168}
1169
1170
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001171static QCBORError
1172NextIsBreak(UsefulInputBuf *pUIB, bool *pbNextIsBreak)
1173{
1174 *pbNextIsBreak = false;
1175 if(UsefulInputBuf_BytesUnconsumed(pUIB) != 0) {
1176 // TODO: use the Peek method?
1177 QCBORItem Peek;
1178 size_t uPeek = UsefulInputBuf_Tell(pUIB);
1179 QCBORError uReturn = GetNext_Item(pUIB, &Peek, NULL);
1180 if(uReturn != QCBOR_SUCCESS) {
1181 return uReturn;
1182 }
1183 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
1184 // It is not a break, rewind so it can be processed normally.
1185 UsefulInputBuf_Seek(pUIB, uPeek);
1186 } else {
1187 *pbNextIsBreak = true;
1188 }
1189 }
1190
1191 return QCBOR_SUCCESS;
1192}
1193
1194
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001195/*
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001196 An item was just consumed, now figure out if it was the
1197 end of an array or map that can be closed out. That
1198 may in turn close out another map or array.
1199 */
1200static QCBORError Ascender(QCBORDecodeContext *pMe)
1201{
1202 QCBORError uReturn;
1203
1204 /* This loops ascending nesting levels as long as there is ascending to do */
1205 while(1) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001206 if(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting)) && !DecodeNesting_IsIndefiniteLength(&(pMe->nesting))) {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001207 /* 1st Case: in a definite length array (not a CBOR sequence). Simply
1208 decrement the item count. If it doesn't go to zero, then all is done.
1209 If it does go to zero, the bottom of the loop ascends one nesting level
1210 and the loop continues.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001211
1212 // TODO: check this.
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001213 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001214 if(DecodeNesting_IsDefiniteLength(&(pMe->nesting))) {
1215 DecodeNesting_DecrementX(&(pMe->nesting));
1216 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
1217 /* Didn't close out map or array; all work here is done */
1218 break;
1219 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001220 }
1221
1222 } else {
1223 /* 2nd, 3rd, 4th and 5th cases where a check for a following CBOR break must be checked for */
1224 bool bIsBreak = false;
1225 uReturn = NextIsBreak(&(pMe->InBuf), &bIsBreak);
1226 if(uReturn != QCBOR_SUCCESS) {
1227 goto Done;
1228 }
1229
1230 if(bIsBreak) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001231 if(DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001232 /* 2nd case where a break occurs at the top level and thus
1233 in a CBOR sequence. Always an error because break is
1234 not inside an indefinite length map or array. */
1235 uReturn = QCBOR_ERR_BAD_BREAK;
1236 goto Done;
1237 } else {
1238 /* 3rd case, the normal end of an indefinite length map
1239 or array. The bottom of the loop ascends one nesting
1240 level and the loop continues. */
1241 }
1242 } else {
1243 /* 4th case where an indefinite length array is not closed out
1244 and 5th case which is just an item in a CBOR sequence. In either
1245 there is no close out so all work here is done.
1246 */
1247 break;
1248 }
1249 }
1250
1251 /* All items in the level have been consumed. */
1252
1253 /* But ascent in bounded mode is only by explicit call to QCBORDecode_ExitBoundedMode() */
1254 if(DecodeNesting_InBoundedMode(&(pMe->nesting))) {
1255 /* 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 -07001256 pMe->nesting.pCurrent->u.ma.uCountCursor = 0;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001257 break;
1258 }
1259
1260 /* Finally, actually ascend one level. */
1261 DecodeNesting_Ascend(&(pMe->nesting));
1262 }
1263
1264 uReturn = QCBOR_SUCCESS;
1265
1266Done:
1267 return uReturn;
1268}
1269
1270
1271/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001272 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001273 TODO: correct this comment
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001274 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001275static QCBORError
1276QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001277{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001278 QCBORError uReturn;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001279 /* === First figure out if at the end of traversal === */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001280
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001281 /* Case 1. Out of bytes to consume.
1282
1283 This is either the end of the top-level CBOR that was give
1284 to QCBORDecode_Init() or the end of a tag 24 bstr wrapped CBOR.
1285 It is detected by all bytes being consumed from the UsefulInputBuf.
1286
1287 To go back out of the tag 24 bstr wrapped item, the caller must
1288 explicitly call Exit() which will reset the UsefulInputBuf
1289 to the next highest bstr wrapped or the top level.
1290
1291 This is always the end condition that QCBORDecode_Finish()
1292 considers complete.
1293
1294 TODO: can the DecodeNesting_IsAtTop be removed? QCBORDecode_Finish()
1295 will perform this check.
1296
1297 */
Laurence Lundblade937ea812020-05-08 11:38:23 -07001298 /* For a pre-order traversal a non-error end occurs when there
1299 are no more bytes to consume and the nesting level is at the top.
1300 If it's not at the top, then the CBOR is not well formed. This error
1301 is caught elsewhere.
1302
1303 This handles the end of CBOR sequences as well as non-sequences. */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001304 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf)) == 0 && DecodeNesting_IsCurrentAtTop(&(me->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001305 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001306 goto Done;
1307 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07001308
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001309
1310 /* Case 2. End of map or array in bounded mode
1311
1312 The caller is attempting traveral of a bounded map or array and
1313 has got to the end of it.
1314
1315 The caller must explicitly exit the bounded mode map or array
1316 to get past this condition.
1317
1318 To complete a decode of the full input CBOR, the caller must
1319 exit all maps and arrays in bounded mode and this is never
1320 the successful end of decoding.
1321
1322 */
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001323 /* It is also an end of the input when in map mode and the cursor
Laurence Lundblade937ea812020-05-08 11:38:23 -07001324 is at the end of the map */
1325
1326
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001327 // This is to handle bounded mode
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001328 if(DecodeNesting_IsAtEndOfBoundedMapOrArray(&(me->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001329 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07001330 goto Done;
1331 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001332
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001333 /* === Not at the end; get another item === */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001334 uReturn = GetNext_MapEntry(me, pDecodedItem);
1335 if(uReturn) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001336 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001337 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301338
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001339 // Breaks ending arrays/maps are always processed at the end of this function.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301340 // They should never show up here.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301341 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001342 uReturn = QCBOR_ERR_BAD_BREAK;
Laurence Lundblade6de37062018-10-15 12:22:42 +05301343 goto Done;
Laurence Lundblade5b8c5852018-10-14 21:11:42 +05301344 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001345
Laurence Lundblade6de37062018-10-15 12:22:42 +05301346 // Record the nesting level for this data item before processing any of
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301347 // decrementing and descending.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001348 pDecodedItem->uNestingLevel = DecodeNesting_GetCurrentLevel(&(me->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001349
Laurence Lundblade6de37062018-10-15 12:22:42 +05301350 // Process the item just received for descent or decrement, and
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001351 // ascend if decrements are enough to close out a definite length array/map
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001352 if(IsMapOrArray(pDecodedItem->uDataType) && pDecodedItem->val.uCount != 0) {
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001353 // If the new item is array or map, the nesting level descends
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001354 uReturn = DecodeNesting_DescendMapOrArray(&(me->nesting), pDecodedItem->uDataType, pDecodedItem->val.uCount);
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001355 // Maps and arrays do count in as items in the map/array that encloses
1356 // them so a decrement needs to be done for them too, but that is done
1357 // only when all the items in them have been processed, not when they
Laurence Lundblade9916b1b2019-09-07 22:33:25 -07001358 // are opened with the exception of an empty map or array.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001359 if(uReturn != QCBOR_SUCCESS) {
1360 goto Done;
1361 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001362 }
1363
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001364 if(!IsMapOrArray(pDecodedItem->uDataType) ||
1365 pDecodedItem->val.uCount == 0 || pDecodedItem->val.uCount == UINT16_MAX) {
1366 /* The following cases are handled here:
1367 - A non-aggregate like an integer or string
1368 - An empty definite length map or array
1369 - An indefinite length map or array that might be empty or might not.
1370 */
1371
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001372
1373
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001374 /* === Figure out if item got closed out maps or arrays === */
1375
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001376 /*
1377 This needs to decrement, check for end and ascend
1378 the tree until an an ascend is not possible or the bounded
1379 limit is reached or the end of the encoded CBOR input
1380 is reached. For
1381 definite length maps and arrays the end is by count. For
1382 indefinite it is by a break.
1383
1384 Also state needs to be set that can tell the code at the
1385 beginning of this function that the end was reached.
1386
1387 This is complicated...
1388
1389
1390 This will handle an indefinite length array
1391 inside a definte length array inside an indefinite
1392 length array...
1393
1394 */
1395
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001396 // Decrement the count of items in the enclosing map/array
1397 // If the count in the enclosing map/array goes to zero, that
Laurence Lundblade6de37062018-10-15 12:22:42 +05301398 // triggers a decrement in the map/array above that and
1399 // an ascend in nesting level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001400 /* If the just consumed item is at the end of a map or
1401 array ascend in the nesting tracking. That may
1402 in turn may be the end of the above nesting level
1403 and so on up to the end of the whole encoded CBOR.
1404
1405 Each level could be a definite or indefinte length
1406 map or array. These are handled very differently.
1407
1408 */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001409 uReturn = Ascender(me);
1410 if(uReturn) {
1411 goto Done;
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001412 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05301413 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001414
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001415
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001416
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001417 /* === Tell the caller the nest level of the next item === */
1418
Laurence Lundblade6de37062018-10-15 12:22:42 +05301419 // Tell the caller what level is next. This tells them what maps/arrays
1420 // were closed out and makes it possible for them to reconstruct
1421 // the tree with just the information returned by GetNext
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07001422 // TODO: pull this into DecodeNesting_GetLevel
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001423 if(DecodeNesting_InBoundedMode(&(me->nesting)) && me->nesting.pCurrent->u.ma.uCountCursor == 0) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001424 // At end of a map / array in map mode, so next nest is 0 to
1425 // indicate this end.
1426 pDecodedItem->uNextNestLevel = 0;
1427 } else {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001428 pDecodedItem->uNextNestLevel = DecodeNesting_GetCurrentLevel(&(me->nesting));
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001429 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001430
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001431Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001432 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundbladee9482dd2019-10-11 12:58:46 -07001433 // Make sure uDataType and uLabelType are QCBOR_TYPE_NONE
1434 memset(pDecodedItem, 0, sizeof(QCBORItem));
1435 }
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001436 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001437}
1438
1439
Laurence Lundblade59289e52019-12-30 13:44:37 -08001440/*
1441 Mostly just assign the right data type for the date string.
1442 */
1443inline static QCBORError DecodeDateString(QCBORItem *pDecodedItem)
1444{
1445 // Stack Use: UsefulBuf 1 16
1446 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1447 return QCBOR_ERR_BAD_OPT_TAG;
1448 }
1449
1450 const UsefulBufC Temp = pDecodedItem->val.string;
1451 pDecodedItem->val.dateString = Temp;
1452 pDecodedItem->uDataType = QCBOR_TYPE_DATE_STRING;
1453 return QCBOR_SUCCESS;
1454}
1455
1456
1457/*
Laurence Lundbladeee851742020-01-08 08:37:05 -08001458 The epoch formatted date. Turns lots of different forms of encoding
1459 date into uniform one
Laurence Lundblade59289e52019-12-30 13:44:37 -08001460 */
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001461static QCBORError DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08001462{
1463 // Stack usage: 1
1464 QCBORError nReturn = QCBOR_SUCCESS;
1465
1466 pDecodedItem->val.epochDate.fSecondsFraction = 0;
1467
1468 switch (pDecodedItem->uDataType) {
1469
1470 case QCBOR_TYPE_INT64:
1471 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
1472 break;
1473
1474 case QCBOR_TYPE_UINT64:
1475 if(pDecodedItem->val.uint64 > INT64_MAX) {
1476 nReturn = QCBOR_ERR_DATE_OVERFLOW;
1477 goto Done;
1478 }
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001479 pDecodedItem->val.epochDate.nSeconds = (int64_t)pDecodedItem->val.uint64;
Laurence Lundblade59289e52019-12-30 13:44:37 -08001480 break;
1481
1482 case QCBOR_TYPE_DOUBLE:
1483 {
1484 // This comparison needs to be done as a float before
1485 // conversion to an int64_t to be able to detect doubles
1486 // that are too large to fit into an int64_t. A double
1487 // has 52 bits of preceision. An int64_t has 63. Casting
1488 // INT64_MAX to a double actually causes a round up which
1489 // is bad and wrong for the comparison because it will
1490 // allow conversion of doubles that can't fit into a
1491 // uint64_t. To remedy this INT64_MAX - 0x7ff is used as
1492 // the cutoff point as if that rounds up in conversion to
1493 // double it will still be less than INT64_MAX. 0x7ff is
1494 // picked because it has 11 bits set.
1495 //
1496 // INT64_MAX seconds is on the order of 10 billion years,
1497 // and the earth is less than 5 billion years old, so for
1498 // most uses this conversion error won't occur even though
1499 // doubles can go much larger.
1500 //
1501 // Without the 0x7ff there is a ~30 minute range of time
1502 // values 10 billion years in the past and in the future
1503 // where this this code would go wrong.
1504 const double d = pDecodedItem->val.dfnum;
1505 if(d > (double)(INT64_MAX - 0x7ff)) {
1506 nReturn = QCBOR_ERR_DATE_OVERFLOW;
1507 goto Done;
1508 }
1509 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
1510 pDecodedItem->val.epochDate.fSecondsFraction = d - (double)pDecodedItem->val.epochDate.nSeconds;
1511 }
1512 break;
1513
1514 default:
1515 nReturn = QCBOR_ERR_BAD_OPT_TAG;
1516 goto Done;
1517 }
1518 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
1519
1520Done:
1521 return nReturn;
1522}
1523
1524
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001525/*
1526 Mostly just assign the right data type for the bignum.
1527 */
1528inline static QCBORError DecodeBigNum(QCBORItem *pDecodedItem)
1529{
1530 // Stack Use: UsefulBuf 1 -- 16
1531 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1532 return QCBOR_ERR_BAD_OPT_TAG;
1533 }
1534 const UsefulBufC Temp = pDecodedItem->val.string;
1535 pDecodedItem->val.bigNum = Temp;
1536 const bool bIsPosBigNum = (bool)(pDecodedItem->uTags[0] == CBOR_TAG_POS_BIGNUM);
1537 pDecodedItem->uDataType = (uint8_t)(bIsPosBigNum ? QCBOR_TYPE_POSBIGNUM
1538 : QCBOR_TYPE_NEGBIGNUM);
1539 return QCBOR_SUCCESS;
1540}
1541
1542
Laurence Lundblade59289e52019-12-30 13:44:37 -08001543#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
1544/*
1545 Decode decimal fractions and big floats.
1546
1547 When called pDecodedItem must be the array that is tagged as a big
1548 float or decimal fraction, the array that has the two members, the
1549 exponent and mantissa.
1550
1551 This will fetch and decode the exponent and mantissa and put the
1552 result back into pDecodedItem.
1553 */
1554inline static QCBORError
1555QCBORDecode_MantissaAndExponent(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
1556{
1557 QCBORError nReturn;
1558
1559 // --- Make sure it is an array; track nesting level of members ---
1560 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
1561 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1562 goto Done;
1563 }
1564
1565 // A check for pDecodedItem->val.uCount == 2 would work for
Laurence Lundbladeee851742020-01-08 08:37:05 -08001566 // definite length arrays, but not for indefnite. Instead remember
1567 // the nesting level the two integers must be at, which is one
1568 // deeper than that of the array.
Laurence Lundblade59289e52019-12-30 13:44:37 -08001569 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
1570
1571 // --- Is it a decimal fraction or a bigfloat? ---
1572 const bool bIsTaggedDecimalFraction = QCBORDecode_IsTagged(me, pDecodedItem, CBOR_TAG_DECIMAL_FRACTION);
1573 pDecodedItem->uDataType = bIsTaggedDecimalFraction ? QCBOR_TYPE_DECIMAL_FRACTION : QCBOR_TYPE_BIGFLOAT;
1574
1575 // --- Get the exponent ---
1576 QCBORItem exponentItem;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001577 nReturn = QCBORDecode_GetNextMapOrArray(me, &exponentItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001578 if(nReturn != QCBOR_SUCCESS) {
1579 goto Done;
1580 }
1581 if(exponentItem.uNestingLevel != nNestLevel) {
1582 // Array is empty or a map/array encountered when expecting an int
1583 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1584 goto Done;
1585 }
1586 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
1587 // Data arriving as an unsigned int < INT64_MAX has been converted
1588 // to QCBOR_TYPE_INT64 and thus handled here. This is also means
1589 // that the only data arriving here of type QCBOR_TYPE_UINT64 data
1590 // will be too large for this to handle and thus an error that will
1591 // get handled in the next else.
1592 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
1593 } else {
1594 // Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX
1595 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1596 goto Done;
1597 }
1598
1599 // --- Get the mantissa ---
1600 QCBORItem mantissaItem;
1601 nReturn = QCBORDecode_GetNextWithTags(me, &mantissaItem, NULL);
1602 if(nReturn != QCBOR_SUCCESS) {
1603 goto Done;
1604 }
1605 if(mantissaItem.uNestingLevel != nNestLevel) {
1606 // Mantissa missing or map/array encountered when expecting number
1607 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1608 goto Done;
1609 }
1610 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
1611 // Data arriving as an unsigned int < INT64_MAX has been converted
1612 // to QCBOR_TYPE_INT64 and thus handled here. This is also means
1613 // that the only data arriving here of type QCBOR_TYPE_UINT64 data
1614 // will be too large for this to handle and thus an error that
1615 // will get handled in an else below.
1616 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
1617 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM || mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
1618 // Got a good big num mantissa
1619 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
1620 // Depends on numbering of QCBOR_TYPE_XXX
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001621 pDecodedItem->uDataType = (uint8_t)(pDecodedItem->uDataType +
1622 mantissaItem.uDataType - QCBOR_TYPE_POSBIGNUM +
1623 1);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001624 } else {
1625 // Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX
1626 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1627 goto Done;
1628 }
1629
1630 // --- Check that array only has the two numbers ---
1631 if(mantissaItem.uNextNestLevel == nNestLevel) {
1632 // Extra items in the decimal fraction / big num
1633 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1634 goto Done;
1635 }
1636
1637Done:
1638
1639 return nReturn;
1640}
1641#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
1642
1643
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001644
1645/*
1646 */
1647inline static QCBORError DecodeURI(QCBORItem *pDecodedItem)
1648{
1649 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1650 return QCBOR_ERR_BAD_OPT_TAG;
1651 }
1652 pDecodedItem->uDataType = QCBOR_TYPE_URI;
1653 return QCBOR_SUCCESS;
1654}
1655
1656
1657inline static QCBORError DecodeB64URL(QCBORItem *pDecodedItem)
1658{
1659 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1660 return QCBOR_ERR_BAD_OPT_TAG;
1661 }
1662 pDecodedItem->uDataType = QCBOR_TYPE_BASE64URL;
1663 return QCBOR_SUCCESS;
1664}
1665
1666
1667inline static QCBORError DecodeB64(QCBORItem *pDecodedItem)
1668{
1669 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1670 return QCBOR_ERR_BAD_OPT_TAG;
1671 }
1672 pDecodedItem->uDataType = QCBOR_TYPE_BASE64;
1673 return QCBOR_SUCCESS;
1674}
1675
1676
1677inline static QCBORError DecodeRegex(QCBORItem *pDecodedItem)
1678{
1679 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1680 return QCBOR_ERR_BAD_OPT_TAG;
1681 }
1682 pDecodedItem->uDataType = QCBOR_TYPE_REGEX;
1683 return QCBOR_SUCCESS;
1684}
1685
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07001686inline static QCBORError DecodeWrappedCBOR(QCBORItem *pDecodedItem)
1687{
1688 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1689 return QCBOR_ERR_BAD_OPT_TAG;
1690 }
1691 pDecodedItem->uDataType = QBCOR_TYPE_WRAPPED_CBOR;
1692 return QCBOR_SUCCESS;
1693}
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001694
1695inline static QCBORError DecodeMIME(QCBORItem *pDecodedItem)
1696{
1697 if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) {
1698 pDecodedItem->uDataType = QCBOR_TYPE_MIME;
1699 } else if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1700 pDecodedItem->uDataType = QCBOR_TYPE_BINARY_MIME;
1701 } else {
1702 return QCBOR_ERR_BAD_OPT_TAG;
1703 }
1704 return QCBOR_SUCCESS;
1705}
1706
1707
1708/*
1709 */
1710inline static QCBORError DecodeUUID(QCBORItem *pDecodedItem)
1711{
1712 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1713 return QCBOR_ERR_BAD_OPT_TAG;
1714 }
1715 pDecodedItem->uDataType = QCBOR_TYPE_UUID;
1716 return QCBOR_SUCCESS;
1717}
1718
1719
Laurence Lundblade59289e52019-12-30 13:44:37 -08001720/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001721 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08001722 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001723QCBORError
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001724QCBORDecode_GetNext(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08001725{
1726 QCBORError nReturn;
1727
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001728 nReturn = QCBORDecode_GetNextMapOrArray(me, pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001729 if(nReturn != QCBOR_SUCCESS) {
1730 goto Done;
1731 }
1732
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001733 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM; i++) {
1734 switch(pDecodedItem->uTags[i] ) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08001735
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001736 case CBOR_TAG_DATE_STRING:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001737 nReturn = DecodeDateString(pDecodedItem);
1738 break;
1739
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001740 case CBOR_TAG_DATE_EPOCH:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001741 nReturn = DecodeDateEpoch(pDecodedItem);
1742 break;
1743
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001744 case CBOR_TAG_POS_BIGNUM:
1745 case CBOR_TAG_NEG_BIGNUM:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001746 nReturn = DecodeBigNum(pDecodedItem);
1747 break;
1748
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001749 #ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
1750 case CBOR_TAG_DECIMAL_FRACTION:
1751 case CBOR_TAG_BIGFLOAT:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001752 // For aggregate tagged types, what goes into pTags is only collected
1753 // from the surrounding data item, not the contents, so pTags is not
1754 // passed on here.
1755
1756 nReturn = QCBORDecode_MantissaAndExponent(me, pDecodedItem);
1757 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001758 #endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08001759
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07001760 case CBOR_TAG_CBOR:
1761 nReturn = DecodeWrappedCBOR(pDecodedItem);
1762 break;
1763
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001764 case CBOR_TAG_URI:
1765 nReturn = DecodeURI(pDecodedItem);
1766 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001767
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001768 case CBOR_TAG_B64URL:
1769 nReturn = DecodeB64URL(pDecodedItem);
1770 break;
1771
1772 case CBOR_TAG_B64:
1773 nReturn = DecodeB64(pDecodedItem);
1774 break;
1775
1776 case CBOR_TAG_MIME:
1777 case CBOR_TAG_BINARY_MIME:
1778 nReturn = DecodeMIME(pDecodedItem);
1779 break;
1780
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001781 case CBOR_TAG_REGEX:
1782 nReturn = DecodeRegex(pDecodedItem);
1783 break;
1784
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001785 case CBOR_TAG_BIN_UUID:
1786 nReturn = DecodeUUID(pDecodedItem);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001787 break;
1788
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001789 case CBOR_TAG_INVALID16:
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001790 // The end of the tag list or no tags
1791 // Successful exit from the loop.
1792 goto Done;
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001793
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001794 default:
1795 // A tag that is not understood
1796 // A successful exit from the loop
1797 goto Done;
1798
1799 }
1800 if(nReturn != QCBOR_SUCCESS) {
1801 goto Done;
1802 }
Laurence Lundblade59289e52019-12-30 13:44:37 -08001803 }
1804
1805Done:
1806 if(nReturn != QCBOR_SUCCESS) {
1807 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
1808 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
1809 }
1810 return nReturn;
1811}
1812
1813
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001814QCBORError QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
1815{
1816 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
1817
1818 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
1819
1820 UsefulInputBuf_Seek(&(pMe->InBuf), uOffset);
1821
1822 return uErr;
1823}
1824
1825
Laurence Lundblade59289e52019-12-30 13:44:37 -08001826/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001827 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08001828 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001829QCBORError
1830QCBORDecode_GetNextWithTags(QCBORDecodeContext *me,
1831 QCBORItem *pDecodedItem,
1832 QCBORTagListOut *pTags)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001833{
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001834 QCBORError nReturn;
1835
1836 nReturn = QCBORDecode_GetNext(me, pDecodedItem);
1837 if(nReturn != QCBOR_SUCCESS) {
1838 return nReturn;
1839 }
1840
1841 if(pTags != NULL) {
1842 pTags->uNumUsed = 0;
1843 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM; i++) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001844 if(pDecodedItem->uTags[i] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001845 break;
1846 }
1847 if(pTags->uNumUsed >= pTags->uNumAllocated) {
1848 return QCBOR_ERR_TOO_MANY_TAGS;
1849 }
1850 pTags->puTags[pTags->uNumUsed] = ConvertTag(me, pDecodedItem->uTags[i]);
1851 pTags->uNumUsed++;
1852 }
1853 }
1854
1855 return QCBOR_SUCCESS;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001856}
1857
1858
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001859/*
Laurence Lundblade6de37062018-10-15 12:22:42 +05301860 Decoding items is done in 5 layered functions, one calling the
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301861 next one down. If a layer has no work to do for a particular item
1862 it returns quickly.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001863
Laurence Lundblade59289e52019-12-30 13:44:37 -08001864 - QCBORDecode_GetNext, GetNextWithTags -- The top layer processes
1865 tagged data items, turning them into the local C representation.
1866 For the most simple it is just associating a QCBOR_TYPE with the data. For
1867 the complex ones that an aggregate of data items, there is some further
1868 decoding and a little bit of recursion.
1869
1870 - QCBORDecode_GetNextMapOrArray - This manages the beginnings and
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301871 ends of maps and arrays. It tracks descending into and ascending
Laurence Lundblade6de37062018-10-15 12:22:42 +05301872 out of maps/arrays. It processes all breaks that terminate
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001873 indefinite length maps and arrays.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001874
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301875 - GetNext_MapEntry -- This handles the combining of two
1876 items, the label and the data, that make up a map entry.
1877 It only does work on maps. It combines the label and data
1878 items into one labeled item.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001879
Laurence Lundblade59289e52019-12-30 13:44:37 -08001880 - GetNext_TaggedItem -- This decodes type 6 tagging. It turns the
1881 tags into bit flags associated with the data item. No actual decoding
1882 of the contents of the tagged item is performed here.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001883
Laurence Lundblade59289e52019-12-30 13:44:37 -08001884 - GetNext_FullItem -- This assembles the sub-items that make up
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301885 an indefinte length string into one string item. It uses the
Laurence Lundblade6de37062018-10-15 12:22:42 +05301886 string allocater to create contiguous space for the item. It
1887 processes all breaks that are part of indefinite length strings.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001888
Laurence Lundblade59289e52019-12-30 13:44:37 -08001889 - GetNext_Item -- This decodes the atomic data items in CBOR. Each
1890 atomic data item has a "major type", an integer "argument" and optionally
1891 some content. For text and byte strings, the content is the bytes
1892 that make up the string. These are the smallest data items that are
1893 considered to be well-formed. The content may also be other data items in
1894 the case of aggregate types. They are not handled in this layer.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001895
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001896 Roughly this takes 300 bytes of stack for vars. Need to
1897 evaluate this more carefully and correctly.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001898
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301899 */
1900
1901
1902/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001903 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001904 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001905int QCBORDecode_IsTagged(QCBORDecodeContext *me,
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001906 const QCBORItem *pItem,
1907 uint64_t uTag)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001908{
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001909 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM; i++ ) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001910 if(pItem->uTags[i] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001911 break;
1912 }
1913 if(ConvertTag(me, pItem->uTags[i]) == uTag) {
1914 return 1;
1915 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001916 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001917
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001918 return 0;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001919}
1920
1921
1922/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001923 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001924 */
Laurence Lundblade30816f22018-11-10 13:40:22 +07001925QCBORError QCBORDecode_Finish(QCBORDecodeContext *me)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001926{
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001927 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001928
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001929 // Error out if all the maps/arrays are not closed out
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001930 if(!DecodeNesting_IsCurrentAtTop(&(me->nesting))) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001931 nReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
1932 goto Done;
1933 }
1934
1935 // Error out if not all the bytes are consumed
1936 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) {
1937 nReturn = QCBOR_ERR_EXTRA_BYTES;
1938 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001939
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001940Done:
Laurence Lundblade6de37062018-10-15 12:22:42 +05301941 // Call the destructor for the string allocator if there is one.
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001942 // Always called, even if there are errors; always have to clean up
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001943 StringAllocator_Destruct(&(me->StringAllocator));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001944
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001945 return nReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001946}
1947
1948
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001949/*
1950Public function, see header qcbor/qcbor_decode.h file
1951*/
Laurence Lundblade2b843b52020-06-16 20:51:03 -07001952uint64_t QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
1953 const QCBORItem *pItem,
1954 unsigned int uIndex)
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001955{
1956 if(uIndex > QCBOR_MAX_TAGS_PER_ITEM) {
1957 return CBOR_TAG_INVALID16;
1958 } else if(pItem->uTags[uIndex] <= QCBOR_LAST_UNMAPPED_TAG) {
1959 return pItem->uTags[uIndex];
1960 } else if(pItem->uTags[uIndex] < QCBOR_NUM_MAPPED_TAGS + QCBOR_LAST_UNMAPPED_TAG) {
1961 return pMe->auMappedTags[pItem->uTags[uIndex] - QCBOR_LAST_UNMAPPED_TAG];
1962 } else {
1963 return CBOR_TAG_INVALID16;
1964 }
1965}
1966
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001967
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001968/*
1969
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001970Decoder errors handled in this file
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001971
Laurence Lundbladeee851742020-01-08 08:37:05 -08001972 - Hit end of input before it was expected while decoding type and
1973 number QCBOR_ERR_HIT_END
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001974
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001975 - negative integer that is too large for C QCBOR_ERR_INT_OVERFLOW
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001976
Laurence Lundbladeee851742020-01-08 08:37:05 -08001977 - Hit end of input while decoding a text or byte string
1978 QCBOR_ERR_HIT_END
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001979
Laurence Lundbladeee851742020-01-08 08:37:05 -08001980 - Encountered conflicting tags -- e.g., an item is tagged both a date
1981 string and an epoch date QCBOR_ERR_UNSUPPORTED
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001982
Laurence Lundbladeee851742020-01-08 08:37:05 -08001983 - Encontered an array or mapp that has too many items
1984 QCBOR_ERR_ARRAY_TOO_LONG
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001985
Laurence Lundbladeee851742020-01-08 08:37:05 -08001986 - Encountered array/map nesting that is too deep
1987 QCBOR_ERR_ARRAY_NESTING_TOO_DEEP
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001988
Laurence Lundbladeee851742020-01-08 08:37:05 -08001989 - An epoch date > INT64_MAX or < INT64_MIN was encountered
1990 QCBOR_ERR_DATE_OVERFLOW
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001991
Laurence Lundbladeee851742020-01-08 08:37:05 -08001992 - The type of a map label is not a string or int
1993 QCBOR_ERR_MAP_LABEL_TYPE
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001994
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001995 - Hit end with arrays or maps still open -- QCBOR_ERR_EXTRA_BYTES
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001996
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001997 */
1998
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001999
2000
Laurence Lundbladef6531662018-12-04 10:42:22 +09002001
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002002/* ===========================================================================
2003 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002004
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002005 This implements a simple sting allocator for indefinite length
2006 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
2007 implements the function type QCBORStringAllocate and allows easy
2008 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09002009
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002010 This particular allocator is built-in for convenience. The caller
2011 can implement their own. All of this following code will get
2012 dead-stripped if QCBORDecode_SetMemPool() is not called.
2013
2014 This is a very primitive memory allocator. It does not track
2015 individual allocations, only a high-water mark. A free or
2016 reallocation must be of the last chunk allocated.
2017
2018 The size of the pool and offset to free memory are packed into the
2019 first 8 bytes of the memory pool so we don't have to keep them in
2020 the decode context. Since the address of the pool may not be
2021 aligned, they have to be packed and unpacked as if they were
2022 serialized data of the wire or such.
2023
2024 The sizes packed in are uint32_t to be the same on all CPU types
2025 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08002026 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002027
2028
Laurence Lundbladeee851742020-01-08 08:37:05 -08002029static inline int
2030MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002031{
2032 // Use of UsefulInputBuf is overkill, but it is convenient.
2033 UsefulInputBuf UIB;
2034
Laurence Lundbladeee851742020-01-08 08:37:05 -08002035 // Just assume the size here. It was checked during SetUp so
2036 // the assumption is safe.
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002037 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem, QCBOR_DECODE_MIN_MEM_POOL_SIZE});
2038 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
2039 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
2040 return UsefulInputBuf_GetError(&UIB);
2041}
2042
2043
Laurence Lundbladeee851742020-01-08 08:37:05 -08002044static inline int
2045MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002046{
2047 // Use of UsefulOutBuf is overkill, but convenient. The
2048 // length check performed here is useful.
2049 UsefulOutBuf UOB;
2050
2051 UsefulOutBuf_Init(&UOB, Pool);
2052 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
2053 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
2054 return UsefulOutBuf_GetError(&UOB);
2055}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002056
2057
2058/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002059 Internal function for an allocation, reallocation free and destuct.
2060
2061 Having only one function rather than one each per mode saves space in
2062 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002063
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002064 Code Reviewers: THIS FUNCTION DOES POINTER MATH
2065 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08002066static UsefulBuf
2067MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002068{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002069 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002070
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002071 uint32_t uPoolSize;
2072 uint32_t uFreeOffset;
2073
2074 if(uNewSize > UINT32_MAX) {
2075 // This allocator is only good up to 4GB. This check should
2076 // optimize out if sizeof(size_t) == sizeof(uint32_t)
2077 goto Done;
2078 }
2079 const uint32_t uNewSize32 = (uint32_t)uNewSize;
2080
2081 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
2082 goto Done;
2083 }
2084
2085 if(uNewSize) {
2086 if(pMem) {
2087 // REALLOCATION MODE
2088 // Calculate pointer to the end of the memory pool. It is
2089 // assumed that pPool + uPoolSize won't wrap around by
2090 // assuming the caller won't pass a pool buffer in that is
2091 // not in legitimate memory space.
2092 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
2093
2094 // Check that the pointer for reallocation is in the range of the
2095 // pool. This also makes sure that pointer math further down
2096 // doesn't wrap under or over.
2097 if(pMem >= pPool && pMem < pPoolEnd) {
2098 // Offset to start of chunk for reallocation. This won't
2099 // wrap under because of check that pMem >= pPool. Cast
2100 // is safe because the pool is always less than UINT32_MAX
2101 // because of check in QCBORDecode_SetMemPool().
2102 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
2103
2104 // Check to see if the allocation will fit. uPoolSize -
2105 // uMemOffset will not wrap under because of check that
2106 // pMem is in the range of the uPoolSize by check above.
2107 if(uNewSize <= uPoolSize - uMemOffset) {
2108 ReturnValue.ptr = pMem;
2109 ReturnValue.len = uNewSize;
2110
2111 // Addition won't wrap around over because uNewSize was
2112 // checked to be sure it is less than the pool size.
2113 uFreeOffset = uMemOffset + uNewSize32;
2114 }
2115 }
2116 } else {
2117 // ALLOCATION MODE
2118 // uPoolSize - uFreeOffset will not underflow because this
2119 // pool implementation makes sure uFreeOffset is always
2120 // smaller than uPoolSize through this check here and
2121 // reallocation case.
2122 if(uNewSize <= uPoolSize - uFreeOffset) {
2123 ReturnValue.len = uNewSize;
2124 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08002125 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002126 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002127 }
2128 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002129 if(pMem) {
2130 // FREE MODE
2131 // Cast is safe because of limit on pool size in
2132 // QCBORDecode_SetMemPool()
2133 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
2134 } else {
2135 // DESTRUCT MODE
2136 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002137 }
2138 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002139
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002140 UsefulBuf Pool = {pPool, uPoolSize};
2141 MemPool_Pack(Pool, uFreeOffset);
2142
2143Done:
2144 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002145}
2146
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002147
Laurence Lundbladef6531662018-12-04 10:42:22 +09002148/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08002149 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09002150 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08002151QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
2152 UsefulBuf Pool,
2153 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002154{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002155 // The pool size and free mem offset are packed into the beginning
2156 // of the pool memory. This compile time check make sure the
2157 // constant in the header is correct. This check should optimize
2158 // down to nothing.
2159 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundblade30816f22018-11-10 13:40:22 +07002160 return QCBOR_ERR_BUFFER_TOO_SMALL;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002161 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002162
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002163 // The pool size and free offset packed in to the beginning of pool
2164 // memory are only 32-bits. This check will optimize out on 32-bit
2165 // machines.
2166 if(Pool.len > UINT32_MAX) {
2167 return QCBOR_ERR_BUFFER_TOO_LARGE;
2168 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002169
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002170 // This checks that the pool buffer given is big enough.
2171 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
2172 return QCBOR_ERR_BUFFER_TOO_SMALL;
2173 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002174
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002175 pMe->StringAllocator.pfAllocator = MemPool_Function;
2176 pMe->StringAllocator.pAllocateCxt = Pool.ptr;
2177 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002178
Laurence Lundblade30816f22018-11-10 13:40:22 +07002179 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002180}
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002181
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002182
2183
Laurence Lundblade1341c592020-04-11 14:19:05 -07002184#include <stdio.h>
2185void printdecode(QCBORDecodeContext *pMe, const char *szName)
2186{
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002187 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 -07002188 szName,
2189 (uint32_t)pMe->InBuf.cursor,
2190 (uint32_t)pMe->InBuf.UB.len);
Laurence Lundblade64b607e2020-05-13 13:05:57 -07002191 for(int i = 0; i < QCBOR_MAX_ARRAY_NESTING; i++) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002192 if(&(pMe->nesting.pMapsAndArrays[i]) > pMe->nesting.pCurrent) {
2193 break;
2194 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002195
2196 // TODO: print different for BS and MA
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002197 printf("%2s %2d %5d %s %6u %5d %d %5d\n",
2198 pMe->nesting.pCurrentBounded == &(pMe->nesting.pMapsAndArrays[i]) ? "->": " ",
Laurence Lundblade1341c592020-04-11 14:19:05 -07002199 i,
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002200 pMe->nesting.pMapsAndArrays[i].u.ma.uCountCursor,
2201 pMe->nesting.pMapsAndArrays[i].uLevelType == QCBOR_TYPE_MAP ? "map " :
2202 (pMe->nesting.pMapsAndArrays[i].uLevelType == QCBOR_TYPE_ARRAY ? "array" :
2203 (pMe->nesting.pMapsAndArrays[i].uLevelType == QCBOR_TYPE_BYTE_STRING ? "bstr " :
2204 (pMe->nesting.pMapsAndArrays[i].uLevelType == QCBOR_TYPE_NONE ? "none " : "?????"))),
2205 pMe->nesting.pMapsAndArrays[i].u.ma.uStartOffset,
2206 pMe->nesting.pMapsAndArrays[i].u.ma.uCountTotal,
2207 0, // TODO: fix this
2208 pMe->nesting.pMapsAndArrays[i].u.bs.uPreviousEndOffset
Laurence Lundblade1341c592020-04-11 14:19:05 -07002209 );
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002210
Laurence Lundblade1341c592020-04-11 14:19:05 -07002211 }
Laurence Lundblade64b607e2020-05-13 13:05:57 -07002212 printf("\n");
Laurence Lundblade1341c592020-04-11 14:19:05 -07002213}
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002214
2215
2216/*
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002217 Consume an entire map or array (and do next to
2218 nothing for non-aggregate types).
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002219 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002220static inline QCBORError
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002221ConsumeItem(QCBORDecodeContext *pMe,
2222 const QCBORItem *pItemToConsume,
2223 uint_fast8_t *puNextNestLevel)
2224{
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002225 QCBORError uReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002226 QCBORItem Item;
2227
2228 printdecode(pMe, "ConsumeItem");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002229
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002230 if(IsMapOrArray(pItemToConsume->uDataType)) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002231 /* There is only real work to do for maps and arrays */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002232
Laurence Lundblade1341c592020-04-11 14:19:05 -07002233 /* This works for definite and indefinite length
2234 * maps and arrays by using the nesting level
2235 */
2236 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002237 uReturn = QCBORDecode_GetNext(pMe, &Item);
2238 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002239 goto Done;
2240 }
2241 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002242
Laurence Lundblade1341c592020-04-11 14:19:05 -07002243 if(puNextNestLevel != NULL) {
2244 *puNextNestLevel = Item.uNextNestLevel;
2245 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002246 uReturn = QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002247
Laurence Lundblade1341c592020-04-11 14:19:05 -07002248 } else {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002249 /* item_to_consume is not a map or array */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002250 if(puNextNestLevel != NULL) {
2251 /* Just pass the nesting level through */
2252 *puNextNestLevel = pItemToConsume->uNextNestLevel;
2253 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002254 uReturn = QCBOR_SUCCESS;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002255 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002256
2257Done:
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002258 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002259}
2260
2261
Laurence Lundblade1341c592020-04-11 14:19:05 -07002262/* Return true if the labels in Item1 and Item2 are the same.
2263 Works only for integer and string labels. Returns false
2264 for any other type. */
2265static inline bool
2266MatchLabel(QCBORItem Item1, QCBORItem Item2)
2267{
2268 if(Item1.uLabelType == QCBOR_TYPE_INT64) {
2269 if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
2270 return true;
2271 }
2272 } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002273 if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002274 return true;
2275 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002276 } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002277 if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
2278 return true;
2279 }
2280 } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
2281 if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
2282 return true;
2283 }
2284 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002285
Laurence Lundblade1341c592020-04-11 14:19:05 -07002286 /* Other label types are never matched */
2287 return false;
2288}
2289
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002290
2291/*
2292 Returns true if Item1 and Item2 are the same type
2293 or if either are of QCBOR_TYPE_ANY.
2294 */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002295static inline bool
2296MatchType(QCBORItem Item1, QCBORItem Item2)
2297{
2298 if(Item1.uDataType == Item2.uDataType) {
2299 return true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002300 } else if(Item1.uDataType == QCBOR_TYPE_ANY) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002301 return true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002302 } else if(Item2.uDataType == QCBOR_TYPE_ANY) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002303 return true;
2304 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002305 return false;
2306}
2307
2308
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002309/**
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002310 \brief Search a map for a set of items.
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002311
2312 @param[in] pMe The decode context to search.
2313 @param[in,out] pItemArray The items to search for and the items found.
2314 @param[in] pCBContext Context for the not-found item call back
2315 @param[in] pfCallback Function to call on items not matched in pItemArray
2316
2317 @retval QCBOR_ERR_NOT_ENTERED Trying to search without having entered a map
2318
2319 @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.
2320
2321 @retval QCBOR_ERR_UNEXPECTED_TYPE The label was matched, but not the type.
2322
2323 @retval Also errors returned by QCBORDecode_GetNext().
2324
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002325 On input pItemArray contains a list of labels and data types
2326 of items to be found.
2327
2328 On output the fully retrieved items are filled in with
2329 values and such. The label was matched, so it never changes.
2330
2331 If an item was not found, its data type is set to none.
2332
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002333 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002334static QCBORError
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002335MapSearch(QCBORDecodeContext *pMe,
2336 QCBORItem *pItemArray,
2337 size_t *puOffset,
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002338 void *pCBContext,
2339 QCBORItemCallback pfCallback)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002340{
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002341 QCBORError uReturn;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002342
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002343 QCBORDecodeNesting SaveNesting;
2344 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002345
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002346 /* Reposition to search from the start of the map / array */
2347 UsefulInputBuf_Seek(&(pMe->InBuf), pMe->nesting.pCurrentBounded->u.ma.uStartOffset);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002348
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002349 /*
2350 Loop over all the items in the map. They could be
2351 deeply nested and this should handle both definite
2352 and indefinite length maps and arrays, so this
2353 adds some complexity.
2354 */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002355 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Laurence Lundblade1341c592020-04-11 14:19:05 -07002356
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002357 uint_fast8_t uNextNestLevel;
2358
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002359 uint64_t uFoundItemBitMap = 0;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002360
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002361 /* Iterate over items in the map / array */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002362 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002363 /* Remember offset of the item because sometimes it has to be returned */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002364 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002365
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002366 /* Get the item */
2367 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002368 uReturn = QCBORDecode_GetNext(pMe, &Item);
2369 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002370 /* Got non-well-formed CBOR */
2371 goto Done;
2372 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002373
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002374 /* See if item has one of the labels that are of interest */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002375 int nIndex;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002376 QCBORItem *pIterator;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002377 for(pIterator = pItemArray, nIndex = 0; pIterator->uLabelType != 0; pIterator++, nIndex++) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002378 if(MatchLabel(Item, *pIterator)) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002379 /* A label match has been found */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002380 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
2381 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002382 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002383 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002384 /* Also try to match its type */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002385 if(!MatchType(Item, *pIterator)) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002386 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002387 goto Done;
2388 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002389
2390 /* Successful match. Return the item. */
2391 *pIterator = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002392 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002393 if(puOffset) {
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002394 *puOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002395 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002396 } else {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002397 /*
2398 Call the callback on unmatched labels.
2399 (It is tempting to do duplicate detection here, but that would
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002400 require dynamic memory allocation because the number of labels
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002401 that might be encountered is unbounded.)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002402 */
2403 if(pfCallback) {
2404 uReturn = (*pfCallback)(pCBContext, &Item);
2405 if(uReturn != QCBOR_SUCCESS) {
2406 goto Done;
2407 }
2408 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002409 }
2410 }
2411
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002412 /*
2413 Consume the item whether matched or not. This
2414 does the work of traversing maps and array and
2415 everything in them. In this loop only the
2416 items at the current nesting level are examined
2417 to match the labels.
2418 */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002419 uReturn = ConsumeItem(pMe, &Item, &uNextNestLevel);
2420 if(uReturn) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002421 goto Done;
2422 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002423
2424 } while (uNextNestLevel >= uMapNestLevel);
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002425
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002426 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002427
2428 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002429 /* Cast OK because encoded CBOR is limited to UINT32_MAX */
2430 pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002431
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002432 /* For all items not found, set the data type to QCBOR_TYPE_NONE */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002433 int i;
2434 QCBORItem *pIterator;
2435 for(pIterator = pItemArray, i = 0; pIterator->uLabelType != 0; pIterator++, i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002436 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002437 pIterator->uDataType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002438 }
2439 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002440
2441Done:
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002442 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002443
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002444 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002445}
2446
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002447
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002448/*
2449Public function, see header qcbor/qcbor_decode.h file
2450*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002451void QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
2452 int64_t nLabel,
2453 uint8_t uQcborType,
2454 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002455{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002456 if(pMe->uLastError != QCBOR_SUCCESS) {
2457 return;
2458 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002459
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002460 QCBORItem OneItemSeach[2];
2461 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
2462 OneItemSeach[0].label.int64 = nLabel;
2463 OneItemSeach[0].uDataType = uQcborType;
2464 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07002465
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002466 QCBORError nReturn = MapSearch(pMe, OneItemSeach, NULL, NULL, NULL);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002467 if(nReturn) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002468 pMe->uLastError = (uint8_t)nReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002469 }
2470
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002471 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
2472 pMe->uLastError = QCBOR_ERR_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002473 }
2474
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002475 *pItem = OneItemSeach[0];
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002476}
2477
2478
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002479/*
2480Public function, see header qcbor/qcbor_decode.h file
2481*/
Laurence Lundbladeda095972020-06-06 18:35:33 -07002482void QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
2483 const char *szLabel,
2484 uint8_t uQcborType,
2485 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002486{
Laurence Lundbladeda095972020-06-06 18:35:33 -07002487 if(pMe->uLastError != QCBOR_SUCCESS) {
2488 return;
2489 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002490
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002491 QCBORItem OneItemSeach[2];
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002492 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2493 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
2494 OneItemSeach[0].uDataType = uQcborType;
2495 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07002496
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002497 QCBORError nReturn = MapSearch(pMe, OneItemSeach, NULL, NULL, NULL);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002498 if(nReturn) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07002499 pMe->uLastError = (uint8_t)nReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002500 }
2501
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002502 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07002503 pMe->uLastError = QCBOR_ERR_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002504 }
2505
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002506 *pItem = OneItemSeach[0];
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002507}
2508
2509
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002510/**
2511 @param[in] TagSpec Specification for matching tags.
2512 @param[in] uDataType A QCBOR data type
2513
2514 @retval QCBOR_SUCCESS \c uDataType is allowed by @c TagSpec
2515 @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec
2516
2517 The data type must be one of the QCBOR_TYPEs, not the IETF CBOR Registered tag value.
2518 */
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002519static QCBORError CheckTagRequirement(const TagSpecification TagSpec, uint8_t uDataType)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002520{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002521 if(TagSpec.uTagRequirement == QCBOR_TAGSPEC_MATCH_TAG) {
2522 /* Must match the tag */
2523 if(uDataType == TagSpec.uTaggedType) {
2524 return QCBOR_SUCCESS;
2525 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002526 } else {
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002527 /* QCBOR_TAGSPEC_MATCH_TAG_CONTENT_TYPE or QCBOR_TAGSPEC_MATCH_EITHER */
2528 /* Must check all the possible types for the tag content */
2529 for(size_t i = 0; i < sizeof(TagSpec.uAllowedContentTypes); i++) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002530 if(uDataType == TagSpec.uAllowedContentTypes[i]) {
2531 return QCBOR_SUCCESS;
2532 }
2533 }
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002534 /* Didn't match any of the tag content types */
2535 /* Check the tag for the either case */
2536 if(TagSpec.uTagRequirement == QCBOR_TAGSPEC_MATCH_EITHER) {
2537 if(uDataType == TagSpec.uTaggedType) {
2538 return QCBOR_SUCCESS;
2539 }
2540 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002541 }
2542
2543 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002544}
2545
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002546
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002547// Semi-private
2548// TODO: inline or collapse with QCBORDecode_GetTaggedStringInMapN?
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002549void QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
2550 int64_t nLabel,
2551 TagSpecification TagSpec,
2552 QCBORItem *pItem)
2553{
2554 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
2555 if(pMe->uLastError != QCBOR_SUCCESS) {
2556 return;
2557 }
2558
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002559 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem->uDataType);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002560}
2561
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002562// Semi-private
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002563void QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
2564 const char *szLabel,
2565 TagSpecification TagSpec,
2566 QCBORItem *pItem)
2567{
2568 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
2569 if(pMe->uLastError != QCBOR_SUCCESS) {
2570 return;
2571 }
2572
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002573 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem->uDataType);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002574}
2575
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002576// Semi-private
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002577void QCBORDecode_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
2578 int64_t nLabel,
2579 TagSpecification TagSpec,
2580 UsefulBufC *pString)
2581{
2582 QCBORItem Item;
2583 QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
2584 if(pMe->uLastError == QCBOR_SUCCESS) {
2585 *pString = Item.val.string;
2586 }
2587}
2588
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002589// Semi-private
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002590void QCBORDecode_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
2591 const char * szLabel,
2592 TagSpecification TagSpec,
2593 UsefulBufC *pString)
2594{
2595 QCBORItem Item;
2596 QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
2597 if(pMe->uLastError == QCBOR_SUCCESS) {
2598 *pString = Item.val.string;
2599 }
2600}
Laurence Lundblade1341c592020-04-11 14:19:05 -07002601
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002602/*
2603Public function, see header qcbor/qcbor_decode.h file
2604*/
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002605QCBORError QCBORDecode_GetItemsInMap(QCBORDecodeContext *pCtx, QCBORItem *pItemList)
2606{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002607 return MapSearch(pCtx, pItemList, NULL, NULL, NULL);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002608}
2609
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002610/*
2611Public function, see header qcbor/qcbor_decode.h file
2612*/
2613QCBORError QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pCtx,
2614 QCBORItem *pItemList,
2615 void *pCallbackCtx,
2616 QCBORItemCallback pfCB)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002617{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002618 return MapSearch(pCtx, pItemList, NULL, pCallbackCtx, pfCB);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002619}
2620
2621
Laurence Lundblade34691b92020-05-18 22:25:25 -07002622static void SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07002623{
Laurence Lundblade34691b92020-05-18 22:25:25 -07002624 if(pMe->uLastError != QCBOR_SUCCESS) {
2625 // Already in error state; do nothing.
2626 return;
2627 }
2628
2629 size_t uOffset;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002630 pMe->uLastError = (uint8_t)MapSearch(pMe, pSearch, &uOffset, NULL, NULL);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002631 if(pMe->uLastError != QCBOR_SUCCESS) {
2632 return;
2633 }
2634
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002635 /* Need to get the current pre-order nesting level and cursor to be
2636 at the first item in the map/array just entered.
2637
2638 Also need to current map nesting level and start cursor to
2639 be at the right place.
2640
2641 The UsefulInBuf offset could be anywhere, so no assumption is
2642 made about it.
2643
2644 No assumption is made about the pre-order nesting level either.
2645
2646 However the map mode nesting level is assumed to be one above
2647 the map level that is being entered.
2648 */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002649 /* Seek to the data item that is the map or array */
2650 UsefulInputBuf_Seek(&(pMe->InBuf), uOffset);
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002651 pMe->nesting.pCurrent = pMe->nesting.pCurrentBounded; // TODO: part of DecodeNesting
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002652
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002653 // TODO: check error?
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002654 QCBORDecode_EnterBoundedMode(pMe, pSearch->uDataType);
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002655
Laurence Lundblade34691b92020-05-18 22:25:25 -07002656 printdecode(pMe, "FinishEnter");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002657}
2658
2659
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002660/*
2661Public function, see header qcbor/qcbor_decode.h file
2662*/
Laurence Lundblade34691b92020-05-18 22:25:25 -07002663void QCBORDecode_EnterMapInMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002664{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002665 QCBORItem OneItemSeach[2];
2666 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
2667 OneItemSeach[0].label.int64 = nLabel;
2668 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
2669 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002670
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002671 /* The map to enter was found, now finish of entering it. */
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002672 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002673}
2674
2675
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002676/*
2677Public function, see header qcbor/qcbor_decode.h file
2678*/
Laurence Lundblade34691b92020-05-18 22:25:25 -07002679void QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002680{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002681 QCBORItem OneItemSeach[2];
2682 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2683 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
2684 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
2685 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002686
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002687 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002688}
2689
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002690/*
2691Public function, see header qcbor/qcbor_decode.h file
2692*/
Laurence Lundblade34691b92020-05-18 22:25:25 -07002693void QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07002694{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002695 QCBORItem OneItemSeach[2];
2696 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
2697 OneItemSeach[0].label.int64 = nLabel;
2698 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
2699 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002700
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002701 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002702}
2703
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002704/*
2705Public function, see header qcbor/qcbor_decode.h file
2706*/
Laurence Lundblade34691b92020-05-18 22:25:25 -07002707void QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
2708{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002709 QCBORItem OneItemSeach[2];
2710 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2711 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
2712 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
2713 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002714
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002715 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002716}
2717
2718
2719
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002720/* Next item must be map or this generates an error */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002721void QCBORDecode_EnterBoundedMode(QCBORDecodeContext *pMe, uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002722{
Laurence Lundblade34691b92020-05-18 22:25:25 -07002723 if(pMe->uLastError != QCBOR_SUCCESS) {
2724 // Already in error state; do nothing.
2725 return;
2726 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002727
2728 /* Get the data item that is the map that is being searched */
Laurence Lundblade34691b92020-05-18 22:25:25 -07002729 QCBORItem Item;
Laurence Lundblade986017c2020-05-23 19:25:02 -07002730 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002731 if(pMe->uLastError != QCBOR_SUCCESS) {
2732 return;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002733 }
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002734 if(Item.uDataType != uType) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07002735 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
2736 return;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002737 }
2738
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002739 DecodeNesting_EnterBoundedMode(&(pMe->nesting), UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002740
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002741 // TODO: restrict input to less than this or some other invalidation strategy.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002742 pMe->uMapEndOffsetCache = 0xffffffff; // Invalidate the cached map end.
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002743
Laurence Lundblade34691b92020-05-18 22:25:25 -07002744 printdecode(pMe, "EnterMapModeDone");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002745}
2746
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002747static QCBORError
2748ExitExit(QCBORDecodeContext *pMe, uint32_t uEndOffset)
2749{
2750 // TODO: is this necessary? Pretty sure it is not
2751 //pMe->nesting.pCurrentBounded->bBoundedMode = false;
2752
2753 QCBORError uErr;
2754 /* Exiting a bounded mode level. Bounded mode could be
2755 either an array, map or wrapped bstr.
2756
2757 The following have to be set when exiting a bounded mode level
2758 - The byte offset of the useful input buffer set to the item after the map, array or bstr just consumed.
2759 - The length of the useful input buf has to be adjusted if exiting bstr wrapped CBOR
2760 - The pre-order traversal nesting level, which could be just one level up, or all the way to the top.
2761 - The count of items in the pre-order nesting level if it is a definite length map or array.
2762 - The bounded nesting level, which could be one bounded level up, or all the way to the top
2763
2764 That means that the pre-order traversal must be set up
2765 to the position just after the array, map or wrapped
2766 bstr that was consumed.
2767
2768
2769*/
2770 /* First work is to set up the pre-order traversal
2771 so that it is positioned just after the array, map
2772 or wrapped bstr that was just consumed. The
2773 useful input buf cursor, nesting level and item
2774 count needs to be adjusted. The exit of the array
2775 map or wrapped bstr might be the last in the
2776 above nesting map or array and so on. Ascender()
2777 does lots of work to unwind all the way to the top
2778 through maps and arrays of definite or indefinte
2779 lengths. */
2780 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
2781
2782 pMe->nesting.pCurrent = pMe->nesting.pCurrentBounded - 1; // TODO error check
2783
2784 uErr = Ascender(pMe);
2785 if(uErr != QCBOR_SUCCESS) {
2786 goto Done;
2787 }
2788
2789/*
2790 It also means that the next highest bounded mode
2791 must be put into effect. That, or the top-level sequence
2792 is reached (which is the primordial bounded bstr in a sense. */
2793 /* Also ascend to the next higest bounded mode level if
2794 there is one. */
2795 while(pMe->nesting.pCurrentBounded != &(pMe->nesting.pMapsAndArrays[0])) {
2796 pMe->nesting.pCurrentBounded--;
2797 if(DecodeNesting_InBoundedMode(&(pMe->nesting))) {
2798 break;
2799 }
2800 }
2801
2802 pMe->uMapEndOffsetCache = 0xffffffff; // Invalidate the cached map end.
2803
2804Done:
2805 printdecode(pMe, "exit exit");
2806 return uErr;
2807}
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002808
2809// Semi-private function
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002810void QCBORDecode_ExitBoundedMode(QCBORDecodeContext *pMe, uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002811{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002812 if(pMe->uLastError != QCBOR_SUCCESS) {
2813 // Already in error state; do nothing.
2814 return;
2815 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002816
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002817 printdecode(pMe, "start exit");
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002818
2819 QCBORError uErr = QCBOR_SUCCESS;
2820
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002821 if(!DecodeNesting_CheckBoundedType(&(pMe->nesting), uType)){
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002822 uErr = QCBOR_ERR_CLOSE_MISMATCH;
2823 goto Done;
2824 }
2825
2826 /* Have to set the offset to the end of the map/array
2827 that is being exited. If there is no cached value,
2828 from previous map search, then do a dummy search. */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002829 if(pMe->uMapEndOffsetCache == 0xffffffff) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002830 QCBORItem Dummy;
2831 Dummy.uLabelType = QCBOR_TYPE_NONE;
2832 uErr = MapSearch(pMe, &Dummy, NULL, NULL, NULL);
2833 if(uErr != QCBOR_SUCCESS) {
2834 goto Done;
2835 }
2836 }
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002837
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002838 uErr = ExitExit(pMe, pMe->uMapEndOffsetCache);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002839
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002840Done:
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002841 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002842}
2843
2844
Laurence Lundblade1341c592020-04-11 14:19:05 -07002845void QCBORDecode_RewindMap(QCBORDecodeContext *pMe)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002846{
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002847 // TODO: check for map mode; test this
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002848 //pMe->nesting.pCurrent->uCount = pMe->nesting.pCurrent->u.ma.uCountTotal;
2849 UsefulInputBuf_Seek(&(pMe->InBuf), pMe->nesting.pCurrent->u.ma.uStartOffset);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002850}
2851
2852
Laurence Lundblade1341c592020-04-11 14:19:05 -07002853
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002854static QCBORError InternalEnterWrappedBstr(QCBORDecodeContext *pMe, const QCBORItem *pItem, uint8_t uTagRequirement, UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002855{
2856 if(pMe->uLastError != QCBOR_SUCCESS) {
2857 // Already in error state; do nothing.
2858 return pMe->uLastError;
2859 }
2860
2861 QCBORError uError = QCBOR_SUCCESS;
2862
2863 if(pItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
2864 uError = QCBOR_ERR_UNEXPECTED_TYPE;
2865 goto Done;;
2866 }
2867
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002868 // TODO: check for the other wrapped CBOR tag
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002869 const TagSpecification TagSpec = {uTagRequirement, QBCOR_TYPE_WRAPPED_CBOR, {QCBOR_TYPE_BYTE_STRING, 0,0,0,0,0}};
2870
2871 uError = CheckTagRequirement(TagSpec, pItem->uDataType);
2872 if(uError != QCBOR_SUCCESS) {
2873 goto Done;
2874 }
2875
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002876 //if(pMe->nesting.pCurrent)
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002877 // TODO: will this work for indefinite lengths?
2878 pMe->nesting.pCurrent->u.ma.uCountCursor++; // Don't count the bstr yet
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002879
2880 if(pBstr) {
2881 *pBstr = pItem->val.string;
2882 }
2883
2884 const size_t uPreviousLength = UsefulInputBuf_GetLength(&(pMe->InBuf));
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002885
2886 // Need to move UIB input cursor to the right place
2887
2888 // Really this is a subtraction and an assignment; not much code
2889 // There is a range check in the seek.
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002890 // The bstr was just consumed so the cursor is at the next item after it
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002891
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002892 const size_t uEndOfBstr = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002893
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002894
2895 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOfBstr - pItem->val.string.len);
2896
2897 UsefulInputBuf_SetBufferLen(&(pMe->InBuf), uEndOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002898
2899 // TODO: comment on cast
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002900 uError = DecodeNesting_DescendWrappedBstr(&(pMe->nesting),
2901 uPreviousLength,
2902 uEndOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002903
2904Done:
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002905 printdecode(pMe, "Entered Bstr");
2906
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002907 return uError;
2908
2909}
2910
2911
2912void QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe, uint8_t uTagRequirement, UsefulBufC *pBstr)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002913{
2914 if(pMe->uLastError != QCBOR_SUCCESS) {
2915 // Already in error state; do nothing.
2916 return;
2917 }
2918
2919 /* Get the data item that is the map that is being searched */
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002920 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002921 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
2922 if(pMe->uLastError != QCBOR_SUCCESS) {
2923 return;
2924 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002925
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002926 pMe->uLastError = (uint8_t)InternalEnterWrappedBstr(pMe, &Item, uTagRequirement, pBstr);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002927}
2928
2929
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002930void QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe, uint8_t uTagRequirement, int64_t nLabel, UsefulBufC *pBstr)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002931{
2932 QCBORItem Item;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002933 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002934
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002935 pMe->uLastError = (uint8_t)InternalEnterWrappedBstr(pMe, &Item, uTagRequirement, pBstr);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002936}
2937
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002938
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002939void QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe, uint8_t uTagRequirement, const char *szLabel, UsefulBufC *pBstr)
2940{
2941 QCBORItem Item;
2942 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
2943
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002944 pMe->uLastError = (uint8_t)InternalEnterWrappedBstr(pMe, &Item, uTagRequirement, pBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002945}
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002946
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002947
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002948void QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002949{
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002950 // TODO: test for right mode?
2951
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002952 /* Reset the length of the Useful\InputBuf to what it was before
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002953 the bstr wrapped CBOR was entered.
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002954 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002955 UsefulInputBuf_SetBufferLen(&(pMe->InBuf),
2956 DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
Laurence Lundblade0750fc42020-06-20 21:02:34 -07002957
2958
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002959 QCBORError uErr = ExitExit(pMe, DecodeNesting_GetEndOfBstr(&(pMe->nesting)));
2960 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002961}
2962
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002963
Laurence Lundbladee6430642020-03-14 21:15:44 -07002964
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002965
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002966
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002967
Laurence Lundblade11a064e2020-05-07 13:13:42 -07002968
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002969
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002970static QCBORError InterpretBool(const QCBORItem *pItem, bool *pBool)
2971{
2972 switch(pItem->uDataType) {
2973 case QCBOR_TYPE_TRUE:
2974 *pBool = true;
2975 return QCBOR_SUCCESS;
2976 break;
2977
2978 case QCBOR_TYPE_FALSE:
2979 *pBool = false;
2980 return QCBOR_SUCCESS;
2981 break;
2982
2983 default:
2984 return QCBOR_ERR_UNEXPECTED_TYPE;
2985 break;
2986 }
2987}
Laurence Lundbladee6430642020-03-14 21:15:44 -07002988
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002989/*
2990Public function, see header qcbor/qcbor_decode.h file
2991*/
Laurence Lundbladec4537442020-04-14 18:53:22 -07002992void QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002993{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002994 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002995 // Already in error state, do nothing
Laurence Lundbladee6430642020-03-14 21:15:44 -07002996 return;
2997 }
2998
Laurence Lundbladec4537442020-04-14 18:53:22 -07002999 QCBORError nError;
3000 QCBORItem Item;
3001
3002 nError = QCBORDecode_GetNext(pMe, &Item);
3003 if(nError != QCBOR_SUCCESS) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003004 pMe->uLastError = (uint8_t)nError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003005 return;
3006 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003007 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003008}
3009
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003010/*
3011Public function, see header qcbor/qcbor_decode.h file
3012*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003013void QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe, int64_t nLabel, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003014{
3015 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003016 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003017
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003018 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003019}
3020
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003021/*
3022Public function, see header qcbor/qcbor_decode.h file
3023*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003024void QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, bool *pValue)
3025{
3026 QCBORItem Item;
3027 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3028
3029 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
3030}
3031
3032
3033
3034void QCBORDecode_GetTaggedStringInternal(QCBORDecodeContext *pMe, TagSpecification TagSpec, UsefulBufC *pBstr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003035{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07003036 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003037 // Already in error state, do nothing
3038 return;
3039 }
3040
3041 QCBORError nError;
3042 QCBORItem Item;
3043
3044 nError = QCBORDecode_GetNext(pMe, &Item);
3045 if(nError != QCBOR_SUCCESS) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003046 pMe->uLastError = (uint8_t)nError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003047 return;
3048 }
3049
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003050 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, Item.uDataType);
3051
3052 if(pMe->uLastError == QCBOR_SUCCESS) {
3053 *pBstr = Item.val.string;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003054 }
3055}
3056
Laurence Lundbladec4537442020-04-14 18:53:22 -07003057
3058
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003059
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003060static QCBORError ConvertBigNum(uint8_t uTagRequirement, const QCBORItem *pItem, UsefulBufC *pValue, bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003061{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003062 *pbIsNegative = false;
3063
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003064 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 -07003065
3066 switch(pItem->uDataType) {
3067 case QCBOR_TYPE_BYTE_STRING:
3068 // TODO: check that there is no tag here?
3069 if(bMustBeTagged) {
3070 return QCBOR_ERR_UNEXPECTED_TYPE;
3071 } else {
3072 *pValue = pItem->val.string;
3073 return QCBOR_SUCCESS;
3074 }
3075 break;
3076
3077 case QCBOR_TYPE_POSBIGNUM:
3078 *pValue = pItem->val.string;
3079 return QCBOR_SUCCESS;
3080 break;
3081
3082 case QCBOR_TYPE_NEGBIGNUM:
3083 *pbIsNegative = true;
3084 *pValue = pItem->val.string;
3085 return QCBOR_SUCCESS;
3086 break;
3087
3088 default:
3089 return QCBOR_ERR_UNEXPECTED_TYPE;
3090 break;
3091 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07003092}
3093
3094
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003095/*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003096 @param[in] bMustBeTagged If \c true, then the data item must be tagged as either
3097 a positive or negative bignum. If \c false, then it only must be a byte string and bIsNegative
3098 will always be false on the asumption that it is positive, but it can be interpretted as
3099 negative if the the sign is know from other context.
3100 @param[out] pValue The bytes that make up the big num
3101 @param[out] pbIsNegative \c true if tagged as a negative big num. \c false otherwise.
3102
3103 if bMustBeTagged is false, then this will succeed if the data item is a plain byte string,
3104 a positive big num or a negative big num.
3105
3106 */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003107void QCBORDecode_GetBignum(QCBORDecodeContext *pMe, uint8_t uTagRequirement, UsefulBufC *pValue, bool *pbIsNegative)
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003108{
3109 if(pMe->uLastError != QCBOR_SUCCESS) {
3110 // Already in error state, do nothing
3111 return;
3112 }
3113
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003114 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003115 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
3116 if(uError != QCBOR_SUCCESS) {
3117 pMe->uLastError = (uint8_t)uError;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003118 return;
3119 }
3120
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003121 pMe->uLastError = (uint8_t)ConvertBigNum(uTagRequirement, &Item, pValue, pbIsNegative);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003122}
3123
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003124/*
3125Public function, see header qcbor/qcbor_decode.h file
3126*/
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003127void QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, UsefulBufC *pValue, bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003128{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003129 QCBORItem Item;
3130 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003131
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003132 pMe->uLastError = (uint8_t)ConvertBigNum(uTagRequirement, &Item, pValue, pbIsNegative);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003133}
3134
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003135/*
3136Public function, see header qcbor/qcbor_decode.h file
3137*/
3138void QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint8_t uTagRequirement, UsefulBufC *pValue, bool *pbIsNegative)
3139{
3140 QCBORItem Item;
3141 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3142
3143 pMe->uLastError = (uint8_t)ConvertBigNum(uTagRequirement, &Item, pValue, pbIsNegative);
3144}
3145
3146
3147
3148// Semi private
3149QCBORError FarfMIME(uint8_t uTagRequirement, const QCBORItem *pItem, UsefulBufC *pMessage, bool *pbIsNot7Bit)
3150{
3151 const TagSpecification TagSpecText = {uTagRequirement, QCBOR_TYPE_MIME, {QCBOR_TYPE_TEXT_STRING, 0,0,0,0,0}};
3152 const TagSpecification TagSpecBinary = {uTagRequirement, QCBOR_TYPE_BINARY_MIME, {QCBOR_TYPE_BYTE_STRING, 0,0,0,0,0}};
3153
3154 QCBORError uReturn;
3155
3156 if(CheckTagRequirement(TagSpecText, pItem->uDataType)) {
3157 *pMessage = pItem->val.string;
3158 if(pbIsNot7Bit != NULL) {
3159 *pbIsNot7Bit = false;
3160 }
3161 uReturn = QCBOR_SUCCESS;
3162 } else if(CheckTagRequirement(TagSpecBinary, pItem->uDataType)) {
3163 *pMessage = pItem->val.string;
3164 if(pbIsNot7Bit != NULL) {
3165 *pbIsNot7Bit = true;
3166 }
3167 uReturn = QCBOR_SUCCESS;
3168
3169 } else {
3170 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
3171 }
3172
3173 return uReturn;
3174}
3175
3176
3177
3178
3179
Laurence Lundbladec4537442020-04-14 18:53:22 -07003180
3181
3182
Laurence Lundbladee6430642020-03-14 21:15:44 -07003183
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003184typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003185
3186
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003187// The main exponentiator that works on only positive numbers
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003188static QCBORError Exponentitate10(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003189{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003190 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003191
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003192 if(uResult != 0) {
3193 /* This loop will run a maximum of 19 times because
3194 * UINT64_MAX < 10 ^^ 19. More than that will cause
3195 * exit with the overflow error
3196 */
3197 for(; nExponent > 0; nExponent--) {
3198 if(uResult > UINT64_MAX / 10) {
3199 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Error overflow
3200 }
3201 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003202 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07003203
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003204 for(; nExponent < 0; nExponent++) {
3205 uResult = uResult / 10;
3206 if(uResult == 0) {
3207 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Underflow error
3208 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07003209 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07003210 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003211 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07003212
3213 *puResult = uResult;
3214
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003215 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003216}
3217
3218
Laurence Lundbladee6430642020-03-14 21:15:44 -07003219/* Convert a decimal fraction to an int64_t without using
3220 floating point or math libraries. Most decimal fractions
3221 will not fit in an int64_t and this will error out with
3222 under or overflow
3223 */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003224static QCBORError Exponentitate2(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003225{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003226 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003227
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003228 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003229
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003230 /* This loop will run a maximum of 64 times because
Laurence Lundbladee6430642020-03-14 21:15:44 -07003231 * INT64_MAX < 2^31. More than that will cause
3232 * exist with the overflow error
3233 */
3234 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003235 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003236 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Error overflow
Laurence Lundbladee6430642020-03-14 21:15:44 -07003237 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003238 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003239 nExponent--;
3240 }
3241
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003242 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003243 if(uResult == 0) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003244 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Underflow error
3245 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003246 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003247 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003248 }
3249
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003250 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003251
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003252 return QCBOR_SUCCESS;
3253}
3254
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003255/*
3256 Compute value with signed mantissa and signed result. Works with exponent of 2 or 10 based on exponentiator.
3257 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003258static inline QCBORError ExponentiateNN(int64_t nMantissa, int64_t nExponent, int64_t *pnResult, fExponentiator pfExp)
3259{
3260 uint64_t uResult;
3261
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003262 // Take the absolute value of the mantissa and convert to unsigned.
3263 // TODO: this should be possible in one intruction
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003264 uint64_t uMantissa = nMantissa > 0 ? (uint64_t)nMantissa : (uint64_t)-nMantissa;
3265
3266 // Do the exponentiation of the positive mantissa
3267 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
3268 if(uReturn) {
3269 return uReturn;
3270 }
3271
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003272
Laurence Lundblade983500d2020-05-14 11:49:34 -07003273 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
3274 of INT64_MIN. This assumes two's compliment representation where
3275 INT64_MIN is one increment farther from 0 than INT64_MAX.
3276 Trying to write -INT64_MIN doesn't work to get this because the
3277 compiler tries to work with an int64_t which can't represent
3278 -INT64_MIN.
3279 */
3280 uint64_t uMax = nMantissa > 0 ? INT64_MAX : (uint64_t)INT64_MAX+1;
3281
3282 // Error out if too large
3283 if(uResult > uMax) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003284 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3285 }
3286
3287 // Casts are safe because of checks above
3288 *pnResult = nMantissa > 0 ? (int64_t)uResult : -(int64_t)uResult;
3289
3290 return QCBOR_SUCCESS;
3291}
3292
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003293/*
3294 Compute value with signed mantissa and unsigned result. Works with exponent of 2 or 10 based on exponentiator.
3295 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003296static inline QCBORError ExponentitateNU(int64_t nMantissa, int64_t nExponent, uint64_t *puResult, fExponentiator pfExp)
3297{
3298 if(nMantissa < 0) {
3299 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3300 }
3301
3302 // Cast to unsigned is OK because of check for negative
3303 // Cast to unsigned is OK because UINT64_MAX > INT64_MAX
3304 // Exponentiation is straight forward
3305 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
3306}
3307
3308
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003309#include <math.h>
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003310
3311
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003312static QCBORError ConvertBigNumToUnsigned(const UsefulBufC BigNum, uint64_t uMax, uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003313{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003314 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003315
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003316 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003317 const uint8_t *pByte = BigNum.ptr;
3318 size_t uLen = BigNum.len;
3319 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07003320 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003321 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003322 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07003323 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003324 }
3325
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003326 *pResult = uResult;
3327 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003328}
3329
Laurence Lundblade887add82020-05-17 05:50:34 -07003330static inline QCBORError ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum, uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003331{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003332 return ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003333}
3334
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003335static inline QCBORError ConvertPositiveBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003336{
3337 uint64_t uResult;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003338 QCBORError uError = ConvertBigNumToUnsigned(BigNum, INT64_MAX, &uResult);
3339 if(uError) {
3340 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003341 }
3342 /* Cast is safe because ConvertBigNum is told to limit to INT64_MAX */
3343 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003344 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003345}
3346
3347
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003348static inline QCBORError ConvertNegativeBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003349{
3350 uint64_t uResult;
Laurence Lundbladeda095972020-06-06 18:35:33 -07003351 /* negaative int furthest from zero is INT64_MIN
3352 which is expressed as -INT64_MAX-1. The value of
3353 a negative bignum is -n-1, one further from zero
3354 than the positive bignum */
3355
3356 /* say INT64_MIN is -2; then INT64_MAX is 1.
3357 Then -n-1 <= INT64_MIN.
3358 Then -n -1 <= -INT64_MAX - 1
3359 THen n <= INT64_MAX. */
3360 QCBORError uError = ConvertBigNumToUnsigned(BigNum, INT64_MAX, &uResult);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003361 if(uError) {
3362 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003363 }
3364 /* Cast is safe because ConvertBigNum is told to limit to INT64_MAX */
Laurence Lundblade887add82020-05-17 05:50:34 -07003365 // TODO: this code is incorrect. See RFC 7049
Laurence Lundbladeda095972020-06-06 18:35:33 -07003366 uResult++; // this is the -1 in -n-1
Laurence Lundbladee6430642020-03-14 21:15:44 -07003367 *pResult = -(int64_t)uResult;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003368 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003369}
3370
Laurence Lundbladef6c86662020-05-12 02:08:00 -07003371#include "fenv.h"
Laurence Lundbladec4537442020-04-14 18:53:22 -07003372
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003373
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003374/*
3375Convert a integers and floats to an int64_t.
3376
3377\param[in] uOptions Bit mask list of conversion options.
3378
3379\retval QCBOR_ERR_CONVERSION_NOT_REQUESTED Conversion, possible, but not requested in uOptions.
3380
3381\retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
3382
3383\retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large or too small.
3384
3385*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003386static QCBORError ConvertInt64(const QCBORItem *pItem, uint32_t uOptions, int64_t *pnValue)
3387{
3388 switch(pItem->uDataType) {
3389 // TODO: float when ifdefs are set
3390 case QCBOR_TYPE_DOUBLE:
3391 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3392 // TODO: what about under/overflow here?
3393 // Invokes the floating-point HW and/or compiler-added libraries
3394 feclearexcept(FE_ALL_EXCEPT);
3395 *pnValue = llround(pItem->val.dfnum);
3396 if(fetestexcept(FE_INVALID)) {
3397 // TODO: better error code
3398 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3399 }
3400 } else {
3401 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3402 }
3403 break;
3404
3405 case QCBOR_TYPE_INT64:
3406 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
3407 *pnValue = pItem->val.int64;
3408 } else {
3409 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3410 }
3411 break;
3412
3413 case QCBOR_TYPE_UINT64:
3414 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
3415 if(pItem->val.uint64 < INT64_MAX) {
3416 *pnValue = pItem->val.int64;
3417 } else {
3418 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3419 }
3420 } else {
3421 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3422 }
3423 break;
3424
3425 default:
3426 return QCBOR_ERR_UNEXPECTED_TYPE;
3427 }
3428 return QCBOR_SUCCESS;
3429}
3430
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003431
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003432void QCBORDecode_GetInt64ConvertInternal(QCBORDecodeContext *pMe,
3433 uint32_t uOptions,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003434 int64_t *pnValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003435 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003436{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07003437 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003438 return;
3439 }
3440
Laurence Lundbladee6430642020-03-14 21:15:44 -07003441 QCBORItem Item;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003442 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
3443 if(uError) {
3444 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003445 return;
3446 }
3447
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003448 if(pItem) {
3449 *pItem = Item;
3450 }
3451
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003452 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003453}
3454
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003455
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003456void QCBORDecode_GetInt64ConvertInternalInMapN(QCBORDecodeContext *pMe,
3457 int64_t nLabel,
3458 uint32_t uOptions,
3459 int64_t *pnValue,
3460 QCBORItem *pItem)
3461{
3462 QCBORItem Item;
3463 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
3464
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003465 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003466}
3467
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003468
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003469void QCBORDecode_GetInt64ConvertInternalInMapSZ(QCBORDecodeContext *pMe,
3470 const char * szLabel,
3471 uint32_t uOptions,
3472 int64_t *pnValue,
3473 QCBORItem *pItem)
3474{
3475 if(pMe->uLastError != QCBOR_SUCCESS) {
3476 return;
3477 }
3478
3479 QCBORItem Item;
3480 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3481
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003482 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003483}
3484
3485
3486
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003487/*
3488 Convert a large variety of integer types to an int64_t.
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003489
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003490 \param[in] uOptions Bit mask list of conversion options.
3491
3492 \retval QCBOR_ERR_CONVERSION_NOT_REQUESTED Conversion, possible, but not requested in uOptions.
3493
3494 \retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
3495
3496 \retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large or too small.
3497
3498 */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003499static QCBORError Int64ConvertAll(const QCBORItem *pItem, uint32_t uOptions, int64_t *pnValue)
3500{
3501 QCBORError uErr;
3502
3503 switch(pItem->uDataType) {
3504
3505 case QCBOR_TYPE_POSBIGNUM:
3506 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3507 return ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003508 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003509 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003510 }
3511 break;
3512
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003513 case QCBOR_TYPE_NEGBIGNUM:
3514 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3515 return ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003516 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003517 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003518 }
3519 break;
3520
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003521#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
3522 case QCBOR_TYPE_DECIMAL_FRACTION:
3523 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3524 return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
3525 pItem->val.expAndMantissa.nExponent,
3526 pnValue,
3527 &Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003528 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003529 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3530 }
3531 break;
3532
3533 case QCBOR_TYPE_BIGFLOAT:
3534 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3535 return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
3536 pItem->val.expAndMantissa.nExponent,
3537 pnValue,
3538 Exponentitate2);
3539 } else {
3540 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3541 }
3542 break;
3543
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003544 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
3545 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3546 int64_t nMantissa;
3547 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3548 if(uErr) {
3549 return uErr;
3550 }
3551 return ExponentiateNN(nMantissa,
3552 pItem->val.expAndMantissa.nExponent,
3553 pnValue,
3554 Exponentitate10);
3555 } else {
3556 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3557 }
3558 break;
3559
3560 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
3561 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3562 int64_t nMantissa;
3563 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3564 if(uErr) {
3565 return uErr;
3566 }
3567 return ExponentiateNN(nMantissa,
3568 pItem->val.expAndMantissa.nExponent,
3569 pnValue,
3570 Exponentitate10);
3571 } else {
3572 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3573 }
3574 break;
3575
3576 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
3577 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3578 int64_t nMantissa;
3579 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3580 if(uErr) {
3581 return uErr;
3582 }
3583 return ExponentiateNN(nMantissa,
3584 pItem->val.expAndMantissa.nExponent,
3585 pnValue,
3586 Exponentitate2);
3587 } else {
3588 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3589 }
3590 break;
3591
3592 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
3593 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3594 int64_t nMantissa;
3595 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3596 if(uErr) {
3597 return uErr;
3598 }
3599 return ExponentiateNN(nMantissa,
3600 pItem->val.expAndMantissa.nExponent,
3601 pnValue,
3602 Exponentitate2);
3603 } else {
3604 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003605 }
3606 break;
3607
Laurence Lundbladec4537442020-04-14 18:53:22 -07003608 default:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003609 return QCBOR_ERR_UNEXPECTED_TYPE;
3610#endif
Laurence Lundbladec4537442020-04-14 18:53:22 -07003611 }
3612}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003613
3614
Laurence Lundbladec4537442020-04-14 18:53:22 -07003615/*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003616 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003617 */
3618void QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003619{
3620 QCBORItem Item;
3621
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003622 QCBORDecode_GetInt64ConvertInternal(pMe, uOptions, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003623
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003624 if(pMe->uLastError == QCBOR_SUCCESS) {
3625 // The above conversion succeeded
3626 return;
3627 }
3628
Laurence Lundbladef6c86662020-05-12 02:08:00 -07003629 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003630 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07003631 return;
3632 }
3633
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003634 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003635}
3636
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003637
3638/*
3639Public function, see header qcbor/qcbor_decode.h file
3640*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003641void QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, int64_t *pnValue)
3642{
3643 QCBORItem Item;
3644
3645 QCBORDecode_GetInt64ConvertInternalInMapN(pMe, nLabel, uOptions, pnValue, &Item);
3646
3647 if(pMe->uLastError == QCBOR_SUCCESS) {
3648 // The above conversion succeeded
3649 return;
3650 }
3651
3652 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3653 // The above conversion failed in a way that code below can't correct
3654 return;
3655 }
3656
3657 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
3658}
3659
3660
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003661/*
3662Public function, see header qcbor/qcbor_decode.h file
3663*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003664void QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, int64_t *pnValue)
3665{
3666 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003667 QCBORDecode_GetInt64ConvertInternalInMapSZ(pMe, szLabel, uOptions, pnValue, &Item);
3668
3669 if(pMe->uLastError == QCBOR_SUCCESS) {
3670 // The above conversion succeeded
3671 return;
3672 }
3673
3674 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3675 // The above conversion failed in a way that code below can't correct
3676 return;
3677 }
3678
3679 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
3680}
3681
3682
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003683static QCBORError ConvertUint64(const QCBORItem *pItem, uint32_t uOptions, uint64_t *puValue)
3684{
3685 switch(pItem->uDataType) {
3686 // TODO: type flaot
3687 case QCBOR_TYPE_DOUBLE:
3688 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3689 feclearexcept(FE_ALL_EXCEPT);
3690 double dRounded = round(pItem->val.dfnum);
3691 // TODO: over/underflow
3692 if(fetestexcept(FE_INVALID)) {
3693 // TODO: better error code
3694 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3695 } else if(isnan(dRounded)) {
3696 // TODO: better error code
3697 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3698 } else if(dRounded >= 0) {
3699 *puValue = (uint64_t)dRounded;
3700 } else {
3701 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3702 }
3703 } else {
3704 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3705 }
3706 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003707
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003708 case QCBOR_TYPE_INT64:
3709 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
3710 if(pItem->val.int64 >= 0) {
3711 *puValue = (uint64_t)pItem->val.int64;
3712 } else {
3713 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3714 }
3715 } else {
3716 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3717 }
3718 break;
3719
3720 case QCBOR_TYPE_UINT64:
3721 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
3722 *puValue = pItem->val.uint64;
3723 } else {
3724 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3725 }
3726 break;
3727
3728 default:
3729 return QCBOR_ERR_UNEXPECTED_TYPE;
3730 }
3731 return QCBOR_SUCCESS;
3732}
Laurence Lundbladec4537442020-04-14 18:53:22 -07003733
3734
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003735void QCBORDecode_GetUInt64ConvertInternal(QCBORDecodeContext *pMe,
3736 uint32_t uOptions,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003737 uint64_t *puValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003738 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003739{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003740 if(pMe->uLastError != QCBOR_SUCCESS) {
3741 return;
3742 }
3743
Laurence Lundbladec4537442020-04-14 18:53:22 -07003744 QCBORItem Item;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003745
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003746 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
3747 if(uError) {
3748 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003749 return;
3750 }
3751
Laurence Lundbladea826c502020-05-10 21:07:00 -07003752 if(pItem) {
3753 *pItem = Item;
3754 }
3755
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003756 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003757}
3758
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003759
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003760void QCBORDecode_GetInt8ConvertInternal(QCBORDecodeContext *pMe, uint32_t uOptions, int8_t *pnValue, QCBORItem *pItem)
3761{
3762 int64_t uValue;
3763 QCBORDecode_GetInt64ConvertInternal(pMe, uOptions, &uValue, pItem);
3764 if(pMe->uLastError != QCBOR_SUCCESS) {
3765 return;
3766 }
3767
3768 if(QCBOR_Int64ToInt8(uValue, pnValue)) {
3769 pMe->uLastError = QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3770 }
3771}
3772
3773void QCBORDecode_GetInt8ConvertInternalInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, int8_t *pnValue, QCBORItem *pItem)
3774{
3775 int64_t uValue;
3776 QCBORDecode_GetInt64ConvertInternalInMapN(pMe, nLabel, uOptions, &uValue, pItem);
3777 if(pMe->uLastError != QCBOR_SUCCESS) {
3778 return;
3779 }
3780
3781 if(QCBOR_Int64ToInt8(uValue, pnValue)) {
3782 pMe->uLastError = QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3783 }
3784}
3785
3786void QCBORDecode_GetInt8ConvertInternalInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, int8_t *pnValue, QCBORItem *pItem)
3787{
3788 int64_t uValue;
3789 QCBORDecode_GetInt64ConvertInternalInMapSZ(pMe, szLabel, uOptions, &uValue, pItem);
3790 if(pMe->uLastError != QCBOR_SUCCESS) {
3791 return;
3792 }
3793
3794 if(QCBOR_Int64ToInt8(uValue, pnValue)) {
3795 pMe->uLastError = QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3796 }
3797}
3798
3799
3800
3801
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003802void QCBORDecode_GetUint64ConvertInternalInMapN(QCBORDecodeContext *pMe,
3803 int64_t nLabel,
3804 uint32_t uOptions,
3805 uint64_t *puValue,
3806 QCBORItem *pItem)
3807{
3808 QCBORItem Item;
3809 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
3810
3811 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
3812}
3813
3814
3815void QCBORDecode_GetUint64ConvertInternalInMapSZ(QCBORDecodeContext *pMe,
3816 const char * szLabel,
3817 uint32_t uOptions,
3818 uint64_t *puValue,
3819 QCBORItem *pItem)
3820{
3821 if(pMe->uLastError != QCBOR_SUCCESS) {
3822 return;
3823 }
3824
3825 QCBORItem Item;
3826 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3827
3828 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
3829}
3830
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003831/*
3832 Public function, see header qcbor/qcbor_decode.h file
3833*/
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003834static QCBORError Uint64ConvertAll(const QCBORItem *pItem, uint32_t uOptions, uint64_t *puValue)
3835{
3836 QCBORError uErr;
3837
3838 switch(pItem->uDataType) {
3839
3840 case QCBOR_TYPE_POSBIGNUM:
3841 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3842 return ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
3843 } else {
3844 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3845 }
3846 break;
3847
3848 case QCBOR_TYPE_NEGBIGNUM:
3849 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3850 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3851 } else {
3852 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3853 }
3854 break;
3855
3856#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
3857
3858 case QCBOR_TYPE_DECIMAL_FRACTION:
3859 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3860 return ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
3861 pItem->val.expAndMantissa.nExponent,
3862 puValue,
3863 Exponentitate10);
3864 } else {
3865 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3866 }
3867 break;
3868
3869 case QCBOR_TYPE_BIGFLOAT:
3870 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3871 return ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
3872 pItem->val.expAndMantissa.nExponent,
3873 puValue,
3874 Exponentitate2);
3875 } else {
3876 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3877 }
3878 break;
3879
3880 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
3881 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3882 // TODO: Would be better to convert to unsigned
3883 int64_t nMantissa;
3884 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3885 if(uErr != QCBOR_SUCCESS) {
3886 return uErr;
3887 }
3888 return ExponentitateNU(nMantissa,
3889 pItem->val.expAndMantissa.nExponent,
3890 puValue,
3891 Exponentitate10);
3892 } else {
3893 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3894 }
3895 break;
3896
3897 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
3898 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3899 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3900 } else {
3901 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3902 }
3903 break;
3904
3905 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
3906 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3907 // TODO: Would be better to convert to unsigned
3908 int64_t nMantissa;
3909 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3910 if(uErr != QCBOR_SUCCESS) {
3911 return uErr;
3912 }
3913 return ExponentitateNU(nMantissa,
3914 pItem->val.expAndMantissa.nExponent,
3915 puValue,
3916 Exponentitate2);
3917 } else {
3918 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3919 }
3920 break;
3921
3922 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
3923 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3924 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3925 } else {
3926 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3927 }
3928 break;
3929#endif
3930 default:
3931 return QCBOR_ERR_UNEXPECTED_TYPE;
3932 }
3933}
3934
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003935/*
3936 Public function, see header qcbor/qcbor_decode.h file
3937*/
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003938void QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003939{
3940 QCBORItem Item;
3941
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003942 QCBORDecode_GetUInt64ConvertInternal(pMe, uOptions, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003943
Laurence Lundbladef6c86662020-05-12 02:08:00 -07003944 if(pMe->uLastError == QCBOR_SUCCESS) {
3945 // The above conversion succeeded
3946 return;
3947 }
3948
3949 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3950 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07003951 return;
3952 }
3953
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003954 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003955}
3956
Laurence Lundbladec4537442020-04-14 18:53:22 -07003957
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003958/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003959 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003960*/
3961void QCBORDecode_GetUint64ConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, uint64_t *puValue)
3962{
3963 QCBORItem Item;
3964
3965 QCBORDecode_GetUint64ConvertInternalInMapN(pMe, nLabel, uOptions, puValue, &Item);
3966
3967 if(pMe->uLastError == QCBOR_SUCCESS) {
3968 // The above conversion succeeded
3969 return;
3970 }
3971
3972 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3973 // The above conversion failed in a way that code below can't correct
3974 return;
3975 }
3976
3977 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
3978}
3979
3980
3981/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003982 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003983*/
3984void QCBORDecode_GetUint64ConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, uint64_t *puValue)
3985{
3986 QCBORItem Item;
3987 QCBORDecode_GetUint64ConvertInternalInMapSZ(pMe, szLabel, uOptions, puValue, &Item);
3988
3989 if(pMe->uLastError == QCBOR_SUCCESS) {
3990 // The above conversion succeeded
3991 return;
3992 }
3993
3994 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3995 // The above conversion failed in a way that code below can't correct
3996 return;
3997 }
3998
3999 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
4000}
4001
4002
4003static QCBORError ConvertDouble(const QCBORItem *pItem, uint32_t uOptions, double *pdValue)
4004{
4005 switch(pItem->uDataType) {
4006 // TODO: float when ifdefs are set
4007 case QCBOR_TYPE_DOUBLE:
4008 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
4009 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
4010 *pdValue = pItem->val.dfnum;
4011 } else {
4012 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4013 }
4014 }
4015 break;
4016
4017 case QCBOR_TYPE_INT64:
4018 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
4019 // TODO: how does this work?
4020 *pdValue = (double)pItem->val.int64;
4021
4022 } else {
4023 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4024 }
4025 break;
4026
4027 case QCBOR_TYPE_UINT64:
4028 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
4029 *pdValue = (double)pItem->val.uint64;
4030 } else {
4031 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4032 }
4033 break;
4034
4035 default:
4036 return QCBOR_ERR_UNEXPECTED_TYPE;
4037 }
4038
4039 return QCBOR_SUCCESS;
4040}
4041
4042
4043
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004044void QCBORDecode_GetDoubleConvertInternal(QCBORDecodeContext *pMe,
4045 uint32_t uOptions,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004046 double *pdValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004047 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004048{
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004049 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07004050 return;
4051 }
4052
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004053 QCBORItem Item;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004054
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004055 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004056 if(uError) {
4057 pMe->uLastError = (uint8_t)uError;
4058 return;
4059 }
4060
4061 if(pItem) {
4062 *pItem = Item;
4063 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07004064
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004065 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004066}
Laurence Lundbladec4537442020-04-14 18:53:22 -07004067
Laurence Lundbladec4537442020-04-14 18:53:22 -07004068
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004069void QCBORDecode_GetDoubleConvertInternalInMapN(QCBORDecodeContext *pMe,
4070 int64_t nLabel,
4071 uint32_t uOptions,
4072 double *pdValue,
4073 QCBORItem *pItem)
4074{
4075 QCBORItem Item;
4076 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
4077
4078 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
4079}
4080
4081void QCBORDecode_GetDoubleConvertInternalInMapSZ(QCBORDecodeContext *pMe,
4082 const char * szLabel,
4083 uint32_t uOptions,
4084 double *pdValue,
4085 QCBORItem *pItem)
4086{
4087 if(pMe->uLastError != QCBOR_SUCCESS) {
4088 return;
4089 }
4090
4091 QCBORItem Item;
4092 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4093
4094 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
4095}
4096
4097
4098
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07004099static double ConvertBigNumToDouble(const UsefulBufC BigNum)
4100{
4101 double dResult;
4102
4103 dResult = 0.0;
4104 const uint8_t *pByte = BigNum.ptr;
4105 size_t uLen = BigNum.len;
4106 /* This will overflow and become the float value INFINITY if the number
4107 is too large to fit. No error will be logged.
4108 TODO: should an error be logged? */
4109 while(uLen--) {
4110 dResult = (dResult * 256.0) + (double)*pByte++;
4111 }
4112
4113 return dResult;
4114}
4115
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004116static QCBORError DoubleConvertAll(const QCBORItem *pItem, uint32_t uOptions, double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004117{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004118 /*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004119 https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
4120
4121 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004122 switch(pItem->uDataType) {
4123 // TODO: type float
4124 case QCBOR_TYPE_DECIMAL_FRACTION:
4125 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
4126 // TODO: rounding and overflow errors
4127 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
4128 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
4129 } else {
4130 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4131 }
4132 break;
4133
4134 case QCBOR_TYPE_BIGFLOAT:
4135 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
4136 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
4137 exp2((double)pItem->val.expAndMantissa.nExponent);
4138 } else {
4139 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4140 }
4141 break;
4142
4143 case QCBOR_TYPE_POSBIGNUM:
4144 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
4145 *pdValue = ConvertBigNumToDouble(pItem->val.bigNum);
4146 } else {
4147 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4148 }
4149 break;
4150
4151 case QCBOR_TYPE_NEGBIGNUM:
4152 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07004153 *pdValue = -1-ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004154 } else {
4155 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4156 }
4157 break;
4158
4159 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
4160 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
4161 double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
4162 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
4163 } else {
4164 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4165 }
4166 break;
4167
4168 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
4169 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
4170 double dMantissa = -ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
4171 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
4172 } else {
4173 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4174 }
4175 break;
4176
4177 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
4178 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
4179 double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
4180 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
4181 } else {
4182 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4183 }
4184 break;
4185
4186 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
4187 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07004188 double dMantissa = -1-ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004189 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
4190 } else {
4191 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4192 }
4193 break;
4194
4195 default:
4196 return QCBOR_ERR_UNEXPECTED_TYPE;
4197 }
4198
4199 return QCBOR_SUCCESS;
4200}
4201
4202
4203/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004204 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004205*/
4206void QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, double *pdValue)
4207{
4208
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004209 QCBORItem Item;
4210
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004211 QCBORDecode_GetDoubleConvertInternal(pMe, uOptions, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004212
4213 if(pMe->uLastError == QCBOR_SUCCESS) {
4214 // The above conversion succeeded
4215 return;
4216 }
4217
4218 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
4219 // The above conversion failed in a way that code below can't correct
4220 return;
4221 }
4222
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004223 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004224}
4225
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004226
4227/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004228 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004229*/
4230void QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, double *pdValue)
4231{
4232 QCBORItem Item;
4233
4234 QCBORDecode_GetDoubleConvertInternalInMapN(pMe, nLabel, uOptions, pdValue, &Item);
4235
4236 if(pMe->uLastError == QCBOR_SUCCESS) {
4237 // The above conversion succeeded
4238 return;
4239 }
4240
4241 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
4242 // The above conversion failed in a way that code below can't correct
4243 return;
4244 }
4245
4246 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
4247}
4248
4249
4250/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004251 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004252*/
4253void QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, double *pdValue)
4254{
4255 QCBORItem Item;
4256 QCBORDecode_GetDoubleConvertInternalInMapSZ(pMe, szLabel, uOptions, pdValue, &Item);
4257
4258 if(pMe->uLastError == QCBOR_SUCCESS) {
4259 // The above conversion succeeded
4260 return;
4261 }
4262
4263 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
4264 // The above conversion failed in a way that code below can't correct
4265 return;
4266 }
4267
4268 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
4269}
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004270
4271
4272void FarfDecimalFraction(QCBORDecodeContext *pMe,
4273 uint8_t uTagRequirement,
4274 QCBORItem *pItem,
4275 int64_t *pnMantissa,
4276 int64_t *pnExponent)
4277{
4278 QCBORError uErr;
4279
4280 if(pItem->uDataType == QCBOR_TYPE_ARRAY) {
4281 if(uTagRequirement == QCBOR_TAGSPEC_MATCH_TAG_CONTENT_TYPE) {
4282 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4283 return;
4284 }
4285 uErr = QCBORDecode_MantissaAndExponent(pMe, pItem);
4286 if(uErr != QCBOR_SUCCESS) {
4287 pMe->uLastError = (uint8_t)uErr;
4288 return;
4289 }
4290 }
4291
4292 if(uTagRequirement == QCBOR_TAGSPEC_MATCH_TAG_CONTENT_TYPE) {
4293 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4294 return;
4295 }
4296
4297 switch (pItem->uDataType) {
4298
4299 case QCBOR_TYPE_DECIMAL_FRACTION:
4300 *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
4301 *pnExponent = pItem->val.expAndMantissa.nExponent;
4302 break;
4303
4304 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
4305 *pnExponent = pItem->val.expAndMantissa.nExponent;
4306
4307 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
4308 if(uErr != QCBOR_SUCCESS) {
4309 pMe->uLastError = (uint8_t)uErr;
4310 }
4311 break;
4312
4313 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
4314 *pnExponent = pItem->val.expAndMantissa.nExponent;
4315
4316 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
4317 if(uErr != QCBOR_SUCCESS) {
4318 pMe->uLastError = (uint8_t)uErr;
4319 }
4320 break;
4321
4322 default:
4323 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4324 }
4325}
4326
4327void QCBORDecode_GetDecimalFractionN(QCBORDecodeContext *pMe,
4328 uint8_t uTagRequirement,
4329 int64_t nLabel,
4330 int64_t *pnMantissa,
4331 int64_t *pnExponent)
4332{
4333 QCBORItem Item;
4334
4335 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
4336 FarfDecimalFraction(pMe, uTagRequirement, &Item, pnMantissa, pnExponent);
4337}
4338
4339
4340
4341void QCBORDecode_GetDecimalFractionSZ(QCBORDecodeContext *pMe,
4342 uint8_t uTagRequirement,
4343 const char *szLabel,
4344 int64_t *pnMantissa,
4345 int64_t *pnExponent)
4346{
4347 QCBORItem Item;
4348
4349 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4350
4351 FarfDecimalFraction(pMe, uTagRequirement, &Item, pnMantissa, pnExponent);
4352}
4353
4354
4355UsefulBufC ConvertIntToBigNum(uint64_t uInt, UsefulBuf Buffer)
4356{
4357 while(uInt & 0xff0000000000UL) {
4358 uInt = uInt << 8;
4359 };
4360
4361 UsefulOutBuf UOB;
4362
4363 UsefulOutBuf_Init(&UOB, Buffer);
4364
4365 while(uInt) {
4366 UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff0000000000UL) >> 56));
4367 uInt = uInt << 8;
4368 }
4369
4370 return UsefulOutBuf_OutUBuf(&UOB);
4371}
4372
4373
4374void QCBORDecode_GetDecimalFractionBigN(QCBORDecodeContext *pMe,
4375 uint8_t uTagRequirement,
4376 int64_t nLabel,
4377 UsefulBuf pBufferForMantissa,
4378 UsefulBufC *pMantissa,
4379 bool *pbIsNegative,
4380 int64_t *pnExponent)
4381{
4382 QCBORItem Item;
4383 QCBORError uErr;
4384
4385 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
4386
4387 if(Item.uDataType == QCBOR_TYPE_ARRAY) {
4388 uErr = QCBORDecode_MantissaAndExponent(pMe, &Item);
4389 if(uErr != QCBOR_SUCCESS) {
4390 pMe->uLastError = (uint8_t)uErr;
4391 return;
4392 }
4393 }
4394
4395 uint64_t uMantissa;
4396
4397 switch (Item.uDataType) {
4398
4399 case QCBOR_TYPE_DECIMAL_FRACTION:
4400 if(Item.val.expAndMantissa.Mantissa.nInt >= 0) {
4401 uMantissa = (uint64_t)Item.val.expAndMantissa.Mantissa.nInt;
4402 *pbIsNegative = false;
4403 } else {
4404 uMantissa = (uint64_t)-Item.val.expAndMantissa.Mantissa.nInt;
4405 *pbIsNegative = true;
4406 }
4407 *pMantissa = ConvertIntToBigNum(uMantissa, pBufferForMantissa);
4408 *pnExponent = Item.val.expAndMantissa.nExponent;
4409 break;
4410
4411 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
4412 *pnExponent = Item.val.expAndMantissa.nExponent;
4413 *pMantissa = Item.val.expAndMantissa.Mantissa.bigNum;
4414 *pbIsNegative = false;
4415 break;
4416
4417 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
4418 *pnExponent = Item.val.expAndMantissa.nExponent;
4419 *pMantissa = Item.val.expAndMantissa.Mantissa.bigNum;
4420 *pbIsNegative = true;
4421 break;
4422
4423 default:
4424 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4425 }
4426}