blob: 3913e7e645ba7b7e00121c90b4d7bd7fcd061792 [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
116// TODO: test Map as array better?
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
126DecodeNesting_GetLevel(const QCBORDecodeNesting *pNesting)
127{
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
134
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700135inline static bool DecodeNesting_InBoundedMode(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700136{
137 return pNesting->pCurrent->uType & QCBOR_NEST_TYPE_IS_BOUND;
138}
139
140/*inline static bool IsArray(const QCBORDecodeNesting *pNesting)
141{
142 const unsigned uIndex = DecodeNesting_GetLevel(pNesting);
143
144 return (0x01ULL << ((uIndex * 3) + 1)) & pNesting->uTypeBitMap;
145}
146
147inline static bool IsBstr(const QCBORDecodeNesting *pNesting)
148{
149 const unsigned uIndex = DecodeNesting_GetLevel(pNesting);
150
151 return (0x01ULL << ((uIndex * 3) + 2)) & pNesting->uTypeBitMap;
152}*/
153
154
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700155inline static bool
156DecodeNesting_IsAtTop(const QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700157{
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700158 if(pNesting->pCurrent == &(pNesting->pMapsAndArrays[0])) {
159 return true;
160 } else {
161 return false;
162 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700163}
164
Laurence Lundblade937ea812020-05-08 11:38:23 -0700165// Determine if at the end of a map or array while in map mode
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700166inline static bool
167DecodeNesting_AtEnd(const QCBORDecodeNesting *pNesting)
168{
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700169 if(pNesting->pCurrentMap && DecodeNesting_InBoundedMode(pNesting)) {
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700170 if(pNesting->pCurrentMap->uCount == 0) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700171 // In map mode and consumed all items, so it is the end
172 return true;
173 } else {
174 // In map mode, all items not consumed, so it is NOT the end
175 return false;
176 }
177 } else {
Laurence Lundblade937ea812020-05-08 11:38:23 -0700178 // Not in map mode. The end is determined in other ways.
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700179 return false;
180 }
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700181}
182
183
Laurence Lundbladeee851742020-01-08 08:37:05 -0800184inline static int
185DecodeNesting_IsIndefiniteLength(const QCBORDecodeNesting *pNesting)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700186{
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700187 return pNesting->pCurrent->uCount == UINT16_MAX;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700188 //return pNesting->pCurrent->uType & QCBOR_NEST_TYPE_IS_INDEFINITE;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700189}
190
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800191
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700192inline static uint8_t
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700193DecodeNesting_GetBoundedModeLevel(QCBORDecodeNesting *pNesting)
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700194{
195 // Check in DecodeNesting_Descend and never having
196 // QCBOR_MAX_ARRAY_NESTING > 255 gaurantees cast is safe
197 return (uint8_t)(pNesting->pCurrentMap - &(pNesting->pMapsAndArrays[0]));
198}
199
Laurence Lundbladeee851742020-01-08 08:37:05 -0800200inline static int
201DecodeNesting_TypeIsMap(const QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700202{
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700203 if(DecodeNesting_IsAtTop(pNesting)) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700204 return 0;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700205 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800206
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700207 return CBOR_MAJOR_TYPE_MAP == pNesting->pCurrent->uMajorType;
208}
209
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700210
211// return 1 if closed out an array or map
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700212inline static void
213DecodeNesting_DecrementX(QCBORDecodeNesting *pNesting)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700214{
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700215 pNesting->pCurrent->uCount--;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700216}
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700217
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700218inline static bool
219DecodeNesting_IsEndOfDefiniteLengthMapOrArray(QCBORDecodeNesting *pNesting)
220{
221 if(pNesting->pCurrent->uCount == 0) {
222 return true;
223 } else {
224 return false;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700225 }
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800226}
227
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700228inline static void
229DecodeNesting_Ascend(QCBORDecodeNesting *pNesting)
230{
231 pNesting->pCurrent--;
232}
233
234
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700235
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700236
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700237inline static void
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700238DecodeNesting_EnterBoundedMode(QCBORDecodeNesting *pNesting, size_t uOffset)
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700239{
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700240 /* Have descended into this is called. The job here is just to mark it in bounded mode */
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700241 pNesting->pCurrentMap = pNesting->pCurrent;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700242 pNesting->pCurrentMap->uType |= QCBOR_NEST_TYPE_IS_BOUND;
243 // Cast to uint32_t is safe because QCBOR restricts encoded input to < UINT32_MAX
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700244 pNesting->pCurrentMap->uOffset = (uint32_t)uOffset;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700245}
246
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700247
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700248
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700249
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700250inline static QCBORError
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700251DecodeNesting_Descend(QCBORDecodeNesting *pNesting, uint8_t uQCBORType, uint64_t uCount, uint32_t uEndOffset)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700252{
253 QCBORError nReturn = QCBOR_SUCCESS;
254
255 if(uCount == 0) {
256 // Nothing to do for empty definite lenth arrays. They are just are
257 // effectively the same as an item that is not a map or array
258 goto Done;
259 // Empty indefinite length maps and arrays are handled elsewhere
260 }
261
262 // Error out if arrays is too long to handle
263 if(uCount != UINT16_MAX && uCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
264 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
265 goto Done;
266 }
267
268 // Error out if nesting is too deep
269 if(pNesting->pCurrent >= &(pNesting->pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING])) {
270 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
271 goto Done;
272 }
273
274 // The actual descend
275 pNesting->pCurrent++;
276
277 // Fill in the new level fully
278 pNesting->pCurrent->uMajorType = uQCBORType;
279 pNesting->pCurrent->uCount = (uint16_t)uCount;
280 pNesting->pCurrent->uSaveCount = (uint16_t)uCount;
281 pNesting->pCurrent->uEndOffset = uEndOffset;
282 pNesting->pCurrent->uMapMode = 0;
283
284Done:
285 return nReturn;;
286}
287
288
289
Laurence Lundbladeee851742020-01-08 08:37:05 -0800290inline static void
291DecodeNesting_Init(QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700292{
293 pNesting->pCurrent = &(pNesting->pMapsAndArrays[0]);
294}
295
296
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700297static void DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting, QCBORDecodeNesting *pSave)
298{
299 *pSave = *pNesting;
300 pNesting->pCurrent = pNesting->pCurrentMap;
301
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700302 if(!DecodeNesting_IsIndefiniteLength(pNesting)) {
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700303 pNesting->pCurrent->uCount = pNesting->pCurrent->uSaveCount;
304 }
305}
306
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700307static inline void DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting, QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700308{
309 *pNesting = *pSave;
310}
311
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700312QCBORError DecodeNesting_EnterBstr(QCBORDecodeNesting *pNesting, uint32_t uEndOffset)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700313{
314 QCBORError uReturn ;
315
316 // Error out if nesting is too deep
317 if(pNesting->pCurrent >= &(pNesting->pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING])) {
318 uReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
319 goto Done;
320 }
321
322 // The actual descend
323 pNesting->pCurrent++;
324
325 // Record a few details for this nesting level
326 pNesting->pCurrent->uMajorType = 1; // TODO the right value for a bstr
327 pNesting->pCurrent->uCount = 0xffff;
328 pNesting->pCurrent->uSaveCount = 0xffff;
329 pNesting->pCurrent->uType = 0;
330
331 uReturn = QCBOR_SUCCESS;
332
333Done:
334 return uReturn;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700335}
336
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700337
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700338
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700339
Laurence Lundbladeee851742020-01-08 08:37:05 -0800340/*===========================================================================
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800341 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
342
343 The following four functions are pretty wrappers for invocation of
344 the string allocator supplied by the caller.
345
Laurence Lundbladeee851742020-01-08 08:37:05 -0800346 ===========================================================================*/
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800347
Laurence Lundbladeee851742020-01-08 08:37:05 -0800348static inline void
349StringAllocator_Free(const QCORInternalAllocator *pMe, void *pMem)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800350{
351 (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, 0);
352}
353
Laurence Lundbladeee851742020-01-08 08:37:05 -0800354// StringAllocator_Reallocate called with pMem NULL is
355// equal to StringAllocator_Allocate()
356static inline UsefulBuf
357StringAllocator_Reallocate(const QCORInternalAllocator *pMe,
358 void *pMem,
359 size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800360{
361 return (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, uSize);
362}
363
Laurence Lundbladeee851742020-01-08 08:37:05 -0800364static inline UsefulBuf
365StringAllocator_Allocate(const QCORInternalAllocator *pMe, size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800366{
367 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
368}
369
Laurence Lundbladeee851742020-01-08 08:37:05 -0800370static inline void
371StringAllocator_Destruct(const QCORInternalAllocator *pMe)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800372{
373 if(pMe->pfAllocator) {
374 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
375 }
376}
377
378
379
Laurence Lundbladeee851742020-01-08 08:37:05 -0800380/*===========================================================================
381 QCBORDecode -- The main implementation of CBOR decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700382
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800383 See qcbor/qcbor_decode.h for definition of the object
384 used here: QCBORDecodeContext
Laurence Lundbladeee851742020-01-08 08:37:05 -0800385 ===========================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700386/*
387 Public function, see header file
388 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800389void QCBORDecode_Init(QCBORDecodeContext *me,
390 UsefulBufC EncodedCBOR,
391 QCBORDecodeMode nDecodeMode)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700392{
393 memset(me, 0, sizeof(QCBORDecodeContext));
394 UsefulInputBuf_Init(&(me->InBuf), EncodedCBOR);
Laurence Lundbladeee851742020-01-08 08:37:05 -0800395 // Don't bother with error check on decode mode. If a bad value is
396 // passed it will just act as if the default normal mode of 0 was set.
Laurence Lundbladee6bcef12020-04-01 10:56:27 -0700397 me->uDecodeMode = (uint8_t)nDecodeMode;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700398 DecodeNesting_Init(&(me->nesting));
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700399 for(int i = 0; i < QCBOR_NUM_MAPPED_TAGS; i++) {
400 me->auMappedTags[i] = 0xffff;
401 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700402}
403
404
405/*
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700406 Public function, see header file
407 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800408void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
409 QCBORStringAllocate pfAllocateFunction,
410 void *pAllocateContext,
411 bool bAllStrings)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700412{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800413 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
414 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
415 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700416}
417
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800418
419/*
420 Public function, see header file
421 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800422void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *me,
423 const QCBORTagListIn *pTagList)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700424{
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700425 // This does nothing now. It is retained for backwards compatibility
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700426}
427
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700428
429/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800430 This decodes the fundamental part of a CBOR data item, the type and
431 number
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800432
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700433 This is the Counterpart to InsertEncodedTypeAndNumber().
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800434
Laurence Lundbladeee851742020-01-08 08:37:05 -0800435 This does the network->host byte order conversion. The conversion
436 here also results in the conversion for floats in addition to that
437 for lengths, tags and integer values.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800438
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700439 This returns:
440 pnMajorType -- the major type for the item
Laurence Lundbladeee851742020-01-08 08:37:05 -0800441
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800442 puArgument -- the "number" which is used a the value for integers,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800443 tags and floats and length for strings and arrays
444
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800445 pnAdditionalInfo -- Pass this along to know what kind of float or
Laurence Lundbladeee851742020-01-08 08:37:05 -0800446 if length is indefinite
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800447
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800448 The int type is preferred to uint8_t for some variables as this
449 avoids integer promotions, can reduce code size and makes
450 static analyzers happier.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700451 */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800452inline static QCBORError DecodeTypeAndNumber(UsefulInputBuf *pUInBuf,
453 int *pnMajorType,
454 uint64_t *puArgument,
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800455 int *pnAdditionalInfo)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700456{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700457 QCBORError nReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800458
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700459 // Get the initial byte that every CBOR data item has
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800460 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800461
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700462 // Break down the initial byte
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800463 const int nTmpMajorType = nInitialByte >> 5;
464 const int nAdditionalInfo = nInitialByte & 0x1f;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800465
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800466 // Where the number or argument accumulates
467 uint64_t uArgument;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800468
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800469 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700470 // Need to get 1,2,4 or 8 additional argument bytes. Map
471 // LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800472 static const uint8_t aIterate[] = {1,2,4,8};
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800473
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800474 // Loop getting all the bytes in the argument
475 uArgument = 0;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800476 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800477 // This shift and add gives the endian conversion
478 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
479 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800480 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800481 // The reserved and thus-far unused additional info values
482 nReturn = QCBOR_ERR_UNSUPPORTED;
483 goto Done;
484 } else {
485 // Less than 24, additional info is argument or 31, an indefinite length
486 // No more bytes to get
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800487 uArgument = (uint64_t)nAdditionalInfo;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700488 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800489
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700490 if(UsefulInputBuf_GetError(pUInBuf)) {
491 nReturn = QCBOR_ERR_HIT_END;
492 goto Done;
493 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800494
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700495 // All successful if we got here.
496 nReturn = QCBOR_SUCCESS;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800497 *pnMajorType = nTmpMajorType;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800498 *puArgument = uArgument;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800499 *pnAdditionalInfo = nAdditionalInfo;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800500
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700501Done:
502 return nReturn;
503}
504
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800505
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700506/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800507 CBOR doesn't explicitly specify two's compliment for integers but all
508 CPUs use it these days and the test vectors in the RFC are so. All
509 integers in the CBOR structure are positive and the major type
510 indicates positive or negative. CBOR can express positive integers
511 up to 2^x - 1 where x is the number of bits and negative integers
512 down to 2^x. Note that negative numbers can be one more away from
513 zero than positive. Stdint, as far as I can tell, uses two's
514 compliment to represent negative integers.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800515
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700516 See http://www.unix.org/whitepapers/64bit.html for reasons int isn't
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800517 used carefully here, and in particular why it isn't used in the interface.
518 Also see
519 https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers
520
521 Int is used for values that need less than 16-bits and would be subject
522 to integer promotion and complaining by static analyzers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700523 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800524inline static QCBORError
525DecodeInteger(int nMajorType, uint64_t uNumber, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700526{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700527 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800528
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700529 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
530 if (uNumber <= INT64_MAX) {
531 pDecodedItem->val.int64 = (int64_t)uNumber;
532 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800533
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700534 } else {
535 pDecodedItem->val.uint64 = uNumber;
536 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800537
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700538 }
539 } else {
540 if(uNumber <= INT64_MAX) {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800541 // CBOR's representation of negative numbers lines up with the
542 // two-compliment representation. A negative integer has one
543 // more in range than a positive integer. INT64_MIN is
544 // equal to (-INT64_MAX) - 1.
545 pDecodedItem->val.int64 = (-(int64_t)uNumber) - 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700546 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800547
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700548 } else {
549 // C can't represent a negative integer in this range
Laurence Lundblade21d1d812019-09-28 22:47:49 -1000550 // so it is an error.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700551 nReturn = QCBOR_ERR_INT_OVERFLOW;
552 }
553 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800554
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700555 return nReturn;
556}
557
558// Make sure #define value line up as DecodeSimple counts on this.
559#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
560#error QCBOR_TYPE_FALSE macro value wrong
561#endif
562
563#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
564#error QCBOR_TYPE_TRUE macro value wrong
565#endif
566
567#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
568#error QCBOR_TYPE_NULL macro value wrong
569#endif
570
571#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
572#error QCBOR_TYPE_UNDEF macro value wrong
573#endif
574
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700575#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
576#error QCBOR_TYPE_BREAK macro value wrong
577#endif
578
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700579#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
580#error QCBOR_TYPE_DOUBLE macro value wrong
581#endif
582
583#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
584#error QCBOR_TYPE_FLOAT macro value wrong
585#endif
586
587/*
588 Decode true, false, floats, break...
589 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800590inline static QCBORError
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800591DecodeSimple(int nAdditionalInfo, uint64_t uNumber, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700592{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700593 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800594
Laurence Lundbladeee851742020-01-08 08:37:05 -0800595 // uAdditionalInfo is 5 bits from the initial byte compile time checks
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800596 // above make sure uAdditionalInfo values line up with uDataType values.
597 // DecodeTypeAndNumber never returns a major type > 1f so cast is safe
598 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800599
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800600 switch(nAdditionalInfo) {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800601 // No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they are
602 // caught before this is called.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800603
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700604 case HALF_PREC_FLOAT:
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700605 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uNumber);
606 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700607 break;
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700608 case SINGLE_PREC_FLOAT:
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700609 pDecodedItem->val.dfnum = (double)UsefulBufUtil_CopyUint32ToFloat((uint32_t)uNumber);
610 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700611 break;
612 case DOUBLE_PREC_FLOAT:
613 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uNumber);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700614 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700615 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800616
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700617 case CBOR_SIMPLEV_FALSE: // 20
618 case CBOR_SIMPLEV_TRUE: // 21
619 case CBOR_SIMPLEV_NULL: // 22
620 case CBOR_SIMPLEV_UNDEF: // 23
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700621 case CBOR_SIMPLE_BREAK: // 31
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700622 break; // nothing to do
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800623
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700624 case CBOR_SIMPLEV_ONEBYTE: // 24
625 if(uNumber <= CBOR_SIMPLE_BREAK) {
626 // This takes out f8 00 ... f8 1f which should be encoded as e0 … f7
Laurence Lundblade077475f2019-04-26 09:06:33 -0700627 nReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700628 goto Done;
629 }
Laurence Lundblade5e390822019-01-06 12:35:01 -0800630 /* FALLTHROUGH */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700631 // fall through intentionally
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800632
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700633 default: // 0-19
634 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
Laurence Lundbladeee851742020-01-08 08:37:05 -0800635 /*
636 DecodeTypeAndNumber will make uNumber equal to
637 uAdditionalInfo when uAdditionalInfo is < 24 This cast is
638 safe because the 2, 4 and 8 byte lengths of uNumber are in
639 the double/float cases above
640 */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700641 pDecodedItem->val.uSimple = (uint8_t)uNumber;
642 break;
643 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800644
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700645Done:
646 return nReturn;
647}
648
649
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700650/*
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530651 Decode text and byte strings. Call the string allocator if asked to.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700652 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800653inline static QCBORError DecodeBytes(const QCORInternalAllocator *pAllocator,
654 int nMajorType,
655 uint64_t uStrLen,
656 UsefulInputBuf *pUInBuf,
657 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700658{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700659 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800660
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800661 // CBOR lengths can be 64 bits, but size_t is not 64 bits on all CPUs.
662 // This check makes the casts to size_t below safe.
663
664 // 4 bytes less than the largest sizeof() so this can be tested by
665 // putting a SIZE_MAX length in the CBOR test input (no one will
666 // care the limit on strings is 4 bytes shorter).
667 if(uStrLen > SIZE_MAX-4) {
668 nReturn = QCBOR_ERR_STRING_TOO_LONG;
669 goto Done;
670 }
671
672 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, (size_t)uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530673 if(UsefulBuf_IsNULLC(Bytes)) {
674 // Failed to get the bytes for this string item
675 nReturn = QCBOR_ERR_HIT_END;
676 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700677 }
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530678
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800679 if(pAllocator) {
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530680 // We are asked to use string allocator to make a copy
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800681 UsefulBuf NewMem = StringAllocator_Allocate(pAllocator, (size_t)uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530682 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade30816f22018-11-10 13:40:22 +0700683 nReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530684 goto Done;
685 }
686 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800687 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530688 } else {
689 // Normal case with no string allocator
690 pDecodedItem->val.string = Bytes;
691 }
Laurence Lundbladeee851742020-01-08 08:37:05 -0800692 const bool bIsBstr = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING);
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800693 // Cast because ternary operator causes promotion to integer
694 pDecodedItem->uDataType = (uint8_t)(bIsBstr ? QCBOR_TYPE_BYTE_STRING
695 : QCBOR_TYPE_TEXT_STRING);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800696
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530697Done:
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700698 return nReturn;
699}
700
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700701
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800702
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700703
704
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700705
706
Laurence Lundbladeee851742020-01-08 08:37:05 -0800707// Make sure the constants align as this is assumed by
708// the GetAnItem() implementation
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700709#if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
710#error QCBOR_TYPE_ARRAY value not lined up with major type
711#endif
712#if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
713#error QCBOR_TYPE_MAP value not lined up with major type
714#endif
715
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700716/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800717 This gets a single data item and decodes it including preceding
718 optional tagging. This does not deal with arrays and maps and nesting
719 except to decode the data item introducing them. Arrays and maps are
720 handled at the next level up in GetNext().
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800721
Laurence Lundbladeee851742020-01-08 08:37:05 -0800722 Errors detected here include: an array that is too long to decode,
723 hit end of buffer unexpectedly, a few forms of invalid encoded CBOR
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700724 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800725static QCBORError GetNext_Item(UsefulInputBuf *pUInBuf,
726 QCBORItem *pDecodedItem,
727 const QCORInternalAllocator *pAllocator)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700728{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700729 QCBORError nReturn;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800730
Laurence Lundbladeee851742020-01-08 08:37:05 -0800731 /*
732 Get the major type and the number. Number could be length of more
733 bytes or the value depending on the major type nAdditionalInfo is
734 an encoding of the length of the uNumber and is needed to decode
735 floats and doubles
736 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800737 int nMajorType;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700738 uint64_t uNumber;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800739 int nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800740
Laurence Lundblade4b09f632019-10-09 14:34:59 -0700741 memset(pDecodedItem, 0, sizeof(QCBORItem));
742
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800743 nReturn = DecodeTypeAndNumber(pUInBuf, &nMajorType, &uNumber, &nAdditionalInfo);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800744
Laurence Lundbladeee851742020-01-08 08:37:05 -0800745 // Error out here if we got into trouble on the type and number. The
746 // code after this will not work if the type and number is not good.
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700747 if(nReturn) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700748 goto Done;
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700749 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800750
Laurence Lundbladeee851742020-01-08 08:37:05 -0800751 // At this point the major type and the value are valid. We've got
752 // the type and the number that starts every CBOR data item.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800753 switch (nMajorType) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700754 case CBOR_MAJOR_TYPE_POSITIVE_INT: // Major type 0
755 case CBOR_MAJOR_TYPE_NEGATIVE_INT: // Major type 1
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800756 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700757 nReturn = QCBOR_ERR_BAD_INT;
758 } else {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800759 nReturn = DecodeInteger(nMajorType, uNumber, pDecodedItem);
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700760 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700761 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800762
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700763 case CBOR_MAJOR_TYPE_BYTE_STRING: // Major type 2
764 case CBOR_MAJOR_TYPE_TEXT_STRING: // Major type 3
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800765 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
766 const bool bIsBstr = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING);
767 pDecodedItem->uDataType = (uint8_t)(bIsBstr ? QCBOR_TYPE_BYTE_STRING
768 : QCBOR_TYPE_TEXT_STRING);
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530769 pDecodedItem->val.string = (UsefulBufC){NULL, SIZE_MAX};
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700770 } else {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800771 nReturn = DecodeBytes(pAllocator, nMajorType, uNumber, pUInBuf, pDecodedItem);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700772 }
773 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800774
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700775 case CBOR_MAJOR_TYPE_ARRAY: // Major type 4
776 case CBOR_MAJOR_TYPE_MAP: // Major type 5
777 // Record the number of items in the array or map
778 if(uNumber > QCBOR_MAX_ITEMS_IN_ARRAY) {
779 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
780 goto Done;
781 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800782 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530783 pDecodedItem->val.uCount = UINT16_MAX; // Indicate indefinite length
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700784 } else {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800785 // type conversion OK because of check above
786 pDecodedItem->val.uCount = (uint16_t)uNumber;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700787 }
Laurence Lundbladeee851742020-01-08 08:37:05 -0800788 // C preproc #if above makes sure constants for major types align
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800789 // DecodeTypeAndNumber never returns a major type > 7 so cast is safe
790 pDecodedItem->uDataType = (uint8_t)nMajorType;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700791 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800792
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700793 case CBOR_MAJOR_TYPE_OPTIONAL: // Major type 6, optional prepended tags
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800794 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700795 nReturn = QCBOR_ERR_BAD_INT;
796 } else {
797 pDecodedItem->val.uTagV = uNumber;
798 pDecodedItem->uDataType = QCBOR_TYPE_OPTTAG;
799 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700800 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800801
Laurence Lundbladeee851742020-01-08 08:37:05 -0800802 case CBOR_MAJOR_TYPE_SIMPLE:
803 // Major type 7, float, double, true, false, null...
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800804 nReturn = DecodeSimple(nAdditionalInfo, uNumber, pDecodedItem);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700805 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800806
Laurence Lundbladeee851742020-01-08 08:37:05 -0800807 default:
808 // Never happens because DecodeTypeAndNumber() should never return > 7
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700809 nReturn = QCBOR_ERR_UNSUPPORTED;
810 break;
811 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800812
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700813Done:
814 return nReturn;
815}
816
817
818
819/*
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800820 This layer deals with indefinite length strings. It pulls all the
Laurence Lundbladeee851742020-01-08 08:37:05 -0800821 individual chunk items together into one QCBORItem using the string
822 allocator.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800823
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530824 Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700825 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800826static inline QCBORError
827GetNext_FullItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700828{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700829 // Stack usage; int/ptr 2 UsefulBuf 2 QCBORItem -- 96
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700830
831 // Get pointer to string allocator. First use is to pass it to
832 // GetNext_Item() when option is set to allocate for *every* string.
833 // Second use here is to allocate space to coallese indefinite
834 // length string items into one.
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800835 const QCORInternalAllocator *pAllocator = me->StringAllocator.pfAllocator ?
836 &(me->StringAllocator) :
837 NULL;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800838
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700839 QCBORError nReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800840 nReturn = GetNext_Item(&(me->InBuf),
841 pDecodedItem,
842 me->bStringAllocateAll ? pAllocator: NULL);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700843 if(nReturn) {
844 goto Done;
845 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800846
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700847 // To reduce code size by removing support for indefinite length strings, the
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530848 // code in this function from here down can be eliminated. Run tests, except
849 // indefinite length string tests, to be sure all is OK if this is removed.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800850
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800851 // Only do indefinite length processing on strings
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700852 const uint8_t uStringType = pDecodedItem->uDataType;
853 if(uStringType!= QCBOR_TYPE_BYTE_STRING && uStringType != QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700854 goto Done; // no need to do any work here on non-string types
855 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800856
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800857 // Is this a string with an indefinite length?
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530858 if(pDecodedItem->val.string.len != SIZE_MAX) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800859 goto Done; // length is not indefinite, so no work to do here
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700860 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800861
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530862 // Can't do indefinite length strings without a string allocator
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800863 if(pAllocator == NULL) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700864 nReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
865 goto Done;
866 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800867
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700868 // Loop getting chunk of indefinite string
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700869 UsefulBufC FullString = NULLUsefulBufC;
870
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700871 for(;;) {
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700872 // Get item for next chunk
873 QCBORItem StringChunkItem;
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700874 // NULL string allocator passed here. Do not need to allocate
875 // chunks even if bStringAllocateAll is set.
Laurence Lundbladefae26bf2019-02-18 11:15:43 -0800876 nReturn = GetNext_Item(&(me->InBuf), &StringChunkItem, NULL);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700877 if(nReturn) {
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700878 break; // Error getting the next chunk
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700879 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800880
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530881 // See if it is a marker at end of indefinite length string
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700882 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800883 // String is complete
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700884 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +0530885 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700886 break;
887 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800888
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700889 // Match data type of chunk to type at beginning.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530890 // Also catches error of other non-string types that don't belong.
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700891 // Also catches indefinite length strings inside indefinite length strings
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800892 if(StringChunkItem.uDataType != uStringType ||
893 StringChunkItem.val.string.len == SIZE_MAX) {
Laurence Lundblade30816f22018-11-10 13:40:22 +0700894 nReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700895 break;
896 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800897
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530898 // Alloc new buffer or expand previously allocated buffer so it can fit
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800899 // The first time throurgh FullString.ptr is NULL and this is
900 // equivalent to StringAllocator_Allocate()
901 UsefulBuf NewMem = StringAllocator_Reallocate(pAllocator,
902 UNCONST_POINTER(FullString.ptr),
903 FullString.len + StringChunkItem.val.string.len);
904
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700905 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530906 // Allocation of memory for the string failed
Laurence Lundblade30816f22018-11-10 13:40:22 +0700907 nReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700908 break;
909 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800910
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700911 // Copy new string chunk at the end of string so far.
912 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700913 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800914
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800915 if(nReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
916 // Getting the item failed, clean up the allocated memory
917 StringAllocator_Free(pAllocator, UNCONST_POINTER(FullString.ptr));
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700918 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800919
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700920Done:
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700921 return nReturn;
922}
923
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700924
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700925uint64_t ConvertTag(QCBORDecodeContext *me, uint16_t uTagVal) {
926 if(uTagVal < 0xfff0) {
927 return uTagVal;
928 } else {
929 // TODO constant and error check
930 int x = uTagVal - 0xfff0;
931 return me->auMappedTags[x];
932 }
933}
934
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700935/*
Laurence Lundblade59289e52019-12-30 13:44:37 -0800936 Gets all optional tag data items preceding a data item that is not an
937 optional tag and records them as bits in the tag map.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700938 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800939static QCBORError
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700940GetNext_TaggedItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700941{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700942 // Stack usage: int/ptr: 3 -- 24
Laurence Lundblade30816f22018-11-10 13:40:22 +0700943 QCBORError nReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700944
945 uint16_t auTags[QCBOR_MAX_TAGS_PER_ITEM] = {0xffff, 0xffff, 0xffff, 0xffff};
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700946
Laurence Lundblade59289e52019-12-30 13:44:37 -0800947 // Loop fetching items until the item fetched is not a tag
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700948 for(;;) {
949 nReturn = GetNext_FullItem(me, pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700950 if(nReturn) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700951 goto Done; // Error out of the loop
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700952 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800953
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700954 if(pDecodedItem->uDataType != QCBOR_TYPE_OPTTAG) {
955 // Successful exit from loop; maybe got some tags, maybe not
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700956 memcpy(pDecodedItem->uTags, auTags, sizeof(auTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700957 break;
958 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800959
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700960 // Is there room for the tag in the tags list?
961 size_t uTagIndex;
962 for(uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) {
963 if(auTags[uTagIndex] == 0xffff) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700964 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700965 }
966 }
967 if(uTagIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
968 return 99; // TODO error code
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700969 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800970
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700971 // Is the tag > 16 bits?
972 if(pDecodedItem->val.uTagV > 0xffff) {
973 size_t uTagMapIndex;
974 // Is there room in the tag map?
975 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
976 if(me->auMappedTags[uTagMapIndex] == 0xffff) {
977 break;
978 }
979 if(me->auMappedTags[uTagMapIndex] == pDecodedItem->val.uTagV) {
980 break;
981 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700982 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700983 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
984 // No room for the tag
985 return 97; // TODO error code
986 }
987
988 // Cover the case where tag is new and were it is already in the map
989 me->auMappedTags[uTagMapIndex] = pDecodedItem->val.uTagV;
990 auTags[uTagIndex] = (uint16_t)(uTagMapIndex + 0xfff0); // TODO proper constant and cast
991
992 } else {
993 auTags[uTagIndex] = (uint16_t)pDecodedItem->val.uTagV;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700994 }
995 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800996
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700997Done:
998 return nReturn;
999}
1000
1001
1002/*
Laurence Lundbladeee851742020-01-08 08:37:05 -08001003 This layer takes care of map entries. It combines the label and data
1004 items into one QCBORItem.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001005 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001006static inline QCBORError
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001007GetNext_MapEntry(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001008{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001009 // Stack use: int/ptr 1, QCBORItem -- 56
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001010 QCBORError nReturn = GetNext_TaggedItem(me, pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001011 if(nReturn)
1012 goto Done;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001013
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001014 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001015 // Break can't be a map entry
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001016 goto Done;
1017 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001018
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001019 if(me->uDecodeMode != QCBOR_DECODE_MODE_MAP_AS_ARRAY) {
1020 // In a map and caller wants maps decoded, not treated as arrays
1021
1022 if(DecodeNesting_TypeIsMap(&(me->nesting))) {
1023 // If in a map and the right decoding mode, get the label
1024
Laurence Lundbladeee851742020-01-08 08:37:05 -08001025 // Save label in pDecodedItem and get the next which will
1026 // be the real data
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001027 QCBORItem LabelItem = *pDecodedItem;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001028 nReturn = GetNext_TaggedItem(me, pDecodedItem);
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001029 if(nReturn)
1030 goto Done;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001031
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301032 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001033
1034 if(LabelItem.uDataType == QCBOR_TYPE_TEXT_STRING) {
1035 // strings are always good labels
1036 pDecodedItem->label.string = LabelItem.val.string;
1037 pDecodedItem->uLabelType = QCBOR_TYPE_TEXT_STRING;
1038 } else if (QCBOR_DECODE_MODE_MAP_STRINGS_ONLY == me->uDecodeMode) {
Laurence Lundbladeee851742020-01-08 08:37:05 -08001039 // It's not a string and we only want strings
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001040 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
1041 goto Done;
1042 } else if(LabelItem.uDataType == QCBOR_TYPE_INT64) {
1043 pDecodedItem->label.int64 = LabelItem.val.int64;
1044 pDecodedItem->uLabelType = QCBOR_TYPE_INT64;
1045 } else if(LabelItem.uDataType == QCBOR_TYPE_UINT64) {
1046 pDecodedItem->label.uint64 = LabelItem.val.uint64;
1047 pDecodedItem->uLabelType = QCBOR_TYPE_UINT64;
1048 } else if(LabelItem.uDataType == QCBOR_TYPE_BYTE_STRING) {
1049 pDecodedItem->label.string = LabelItem.val.string;
1050 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
1051 pDecodedItem->uLabelType = QCBOR_TYPE_BYTE_STRING;
1052 } else {
1053 // label is not an int or a string. It is an arrray
1054 // or a float or such and this implementation doesn't handle that.
1055 // Also, tags on labels are ignored.
1056 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
1057 goto Done;
1058 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001059 }
1060 } else {
1061 if(pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001062 if(pDecodedItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
1063 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
1064 goto Done;
1065 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001066 // Decoding a map as an array
1067 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001068 // Cast is safe because of check against QCBOR_MAX_ITEMS_IN_ARRAY/2
1069 // Cast is needed because of integer promotion
1070 pDecodedItem->val.uCount = (uint16_t)(pDecodedItem->val.uCount * 2);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001071 }
1072 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001073
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001074Done:
1075 return nReturn;
1076}
1077
1078
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001079static QCBORError
1080NextIsBreak(UsefulInputBuf *pUIB, bool *pbNextIsBreak)
1081{
1082 *pbNextIsBreak = false;
1083 if(UsefulInputBuf_BytesUnconsumed(pUIB) != 0) {
1084 // TODO: use the Peek method?
1085 QCBORItem Peek;
1086 size_t uPeek = UsefulInputBuf_Tell(pUIB);
1087 QCBORError uReturn = GetNext_Item(pUIB, &Peek, NULL);
1088 if(uReturn != QCBOR_SUCCESS) {
1089 return uReturn;
1090 }
1091 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
1092 // It is not a break, rewind so it can be processed normally.
1093 UsefulInputBuf_Seek(pUIB, uPeek);
1094 } else {
1095 *pbNextIsBreak = true;
1096 }
1097 }
1098
1099 return QCBOR_SUCCESS;
1100}
1101
1102
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001103/*
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001104 An item was just consumed, now figure out if it was the
1105 end of an array or map that can be closed out. That
1106 may in turn close out another map or array.
1107 */
1108static QCBORError Ascender(QCBORDecodeContext *pMe)
1109{
1110 QCBORError uReturn;
1111
1112 /* This loops ascending nesting levels as long as there is ascending to do */
1113 while(1) {
1114 if(!DecodeNesting_IsAtTop(&(pMe->nesting)) && !DecodeNesting_IsIndefiniteLength(&(pMe->nesting))) {
1115 /* 1st Case: in a definite length array (not a CBOR sequence). Simply
1116 decrement the item count. If it doesn't go to zero, then all is done.
1117 If it does go to zero, the bottom of the loop ascends one nesting level
1118 and the loop continues.
1119 */
1120 DecodeNesting_DecrementX(&(pMe->nesting));
1121 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
1122 /* Didn't close out map or array; all work here is done */
1123 break;
1124 }
1125
1126 } else {
1127 /* 2nd, 3rd, 4th and 5th cases where a check for a following CBOR break must be checked for */
1128 bool bIsBreak = false;
1129 uReturn = NextIsBreak(&(pMe->InBuf), &bIsBreak);
1130 if(uReturn != QCBOR_SUCCESS) {
1131 goto Done;
1132 }
1133
1134 if(bIsBreak) {
1135 if(DecodeNesting_IsAtTop(&(pMe->nesting))) {
1136 /* 2nd case where a break occurs at the top level and thus
1137 in a CBOR sequence. Always an error because break is
1138 not inside an indefinite length map or array. */
1139 uReturn = QCBOR_ERR_BAD_BREAK;
1140 goto Done;
1141 } else {
1142 /* 3rd case, the normal end of an indefinite length map
1143 or array. The bottom of the loop ascends one nesting
1144 level and the loop continues. */
1145 }
1146 } else {
1147 /* 4th case where an indefinite length array is not closed out
1148 and 5th case which is just an item in a CBOR sequence. In either
1149 there is no close out so all work here is done.
1150 */
1151 break;
1152 }
1153 }
1154
1155 /* All items in the level have been consumed. */
1156
1157 /* But ascent in bounded mode is only by explicit call to QCBORDecode_ExitBoundedMode() */
1158 if(DecodeNesting_InBoundedMode(&(pMe->nesting))) {
1159 /* Set the count to zero for indefinite length arrays to indicate cursor is at end of bounded map / array */
1160 pMe->nesting.pCurrent->uCount = 0;
1161 break;
1162 }
1163
1164 /* Finally, actually ascend one level. */
1165 DecodeNesting_Ascend(&(pMe->nesting));
1166 }
1167
1168 uReturn = QCBOR_SUCCESS;
1169
1170Done:
1171 return uReturn;
1172}
1173
1174
1175/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001176 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001177 TODO: correct this comment
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001178 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001179static QCBORError
1180QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001181{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001182 QCBORError uReturn;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001183 /* === First figure out if at the end of traversal === */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001184
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001185 /* Case 1. Out of bytes to consume.
1186
1187 This is either the end of the top-level CBOR that was give
1188 to QCBORDecode_Init() or the end of a tag 24 bstr wrapped CBOR.
1189 It is detected by all bytes being consumed from the UsefulInputBuf.
1190
1191 To go back out of the tag 24 bstr wrapped item, the caller must
1192 explicitly call Exit() which will reset the UsefulInputBuf
1193 to the next highest bstr wrapped or the top level.
1194
1195 This is always the end condition that QCBORDecode_Finish()
1196 considers complete.
1197
1198 TODO: can the DecodeNesting_IsAtTop be removed? QCBORDecode_Finish()
1199 will perform this check.
1200
1201 */
Laurence Lundblade937ea812020-05-08 11:38:23 -07001202 /* For a pre-order traversal a non-error end occurs when there
1203 are no more bytes to consume and the nesting level is at the top.
1204 If it's not at the top, then the CBOR is not well formed. This error
1205 is caught elsewhere.
1206
1207 This handles the end of CBOR sequences as well as non-sequences. */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001208 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf)) == 0 && DecodeNesting_IsAtTop(&(me->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001209 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001210 goto Done;
1211 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07001212
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001213
1214 /* Case 2. End of map or array in bounded mode
1215
1216 The caller is attempting traveral of a bounded map or array and
1217 has got to the end of it.
1218
1219 The caller must explicitly exit the bounded mode map or array
1220 to get past this condition.
1221
1222 To complete a decode of the full input CBOR, the caller must
1223 exit all maps and arrays in bounded mode and this is never
1224 the successful end of decoding.
1225
1226 */
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001227 /* It is also an end of the input when in map mode and the cursor
Laurence Lundblade937ea812020-05-08 11:38:23 -07001228 is at the end of the map */
1229
1230
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001231 // This is to handle bounded mode
Laurence Lundblade937ea812020-05-08 11:38:23 -07001232 if(DecodeNesting_AtEnd(&(me->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001233 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07001234 goto Done;
1235 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001236
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001237 /* === Not at the end; get another item === */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001238 uReturn = GetNext_MapEntry(me, pDecodedItem);
1239 if(uReturn) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001240 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001241 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301242
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001243 // Breaks ending arrays/maps are always processed at the end of this function.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301244 // They should never show up here.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301245 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001246 uReturn = QCBOR_ERR_BAD_BREAK;
Laurence Lundblade6de37062018-10-15 12:22:42 +05301247 goto Done;
Laurence Lundblade5b8c5852018-10-14 21:11:42 +05301248 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001249
Laurence Lundblade6de37062018-10-15 12:22:42 +05301250 // Record the nesting level for this data item before processing any of
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301251 // decrementing and descending.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301252 pDecodedItem->uNestingLevel = DecodeNesting_GetLevel(&(me->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001253
Laurence Lundblade6de37062018-10-15 12:22:42 +05301254 // Process the item just received for descent or decrement, and
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001255 // ascend if decrements are enough to close out a definite length array/map
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001256 if(IsMapOrArray(pDecodedItem->uDataType) && pDecodedItem->val.uCount != 0) {
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001257 // If the new item is array or map, the nesting level descends
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001258 uReturn = DecodeNesting_Descend(&(me->nesting), pDecodedItem->uDataType, pDecodedItem->val.uCount, 0L);
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001259 // Maps and arrays do count in as items in the map/array that encloses
1260 // them so a decrement needs to be done for them too, but that is done
1261 // only when all the items in them have been processed, not when they
Laurence Lundblade9916b1b2019-09-07 22:33:25 -07001262 // are opened with the exception of an empty map or array.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001263 if(uReturn != QCBOR_SUCCESS) {
1264 goto Done;
1265 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001266 }
1267
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001268 if(!IsMapOrArray(pDecodedItem->uDataType) ||
1269 pDecodedItem->val.uCount == 0 || pDecodedItem->val.uCount == UINT16_MAX) {
1270 /* The following cases are handled here:
1271 - A non-aggregate like an integer or string
1272 - An empty definite length map or array
1273 - An indefinite length map or array that might be empty or might not.
1274 */
1275
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001276
1277
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001278 /* === Figure out if item got closed out maps or arrays === */
1279
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001280 /*
1281 This needs to decrement, check for end and ascend
1282 the tree until an an ascend is not possible or the bounded
1283 limit is reached or the end of the encoded CBOR input
1284 is reached. For
1285 definite length maps and arrays the end is by count. For
1286 indefinite it is by a break.
1287
1288 Also state needs to be set that can tell the code at the
1289 beginning of this function that the end was reached.
1290
1291 This is complicated...
1292
1293
1294 This will handle an indefinite length array
1295 inside a definte length array inside an indefinite
1296 length array...
1297
1298 */
1299
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001300 // Decrement the count of items in the enclosing map/array
1301 // If the count in the enclosing map/array goes to zero, that
Laurence Lundblade6de37062018-10-15 12:22:42 +05301302 // triggers a decrement in the map/array above that and
1303 // an ascend in nesting level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001304 /* If the just consumed item is at the end of a map or
1305 array ascend in the nesting tracking. That may
1306 in turn may be the end of the above nesting level
1307 and so on up to the end of the whole encoded CBOR.
1308
1309 Each level could be a definite or indefinte length
1310 map or array. These are handled very differently.
1311
1312 */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001313 uReturn = Ascender(me);
1314 if(uReturn) {
1315 goto Done;
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001316 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05301317 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001318
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001319
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001320
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001321 /* === Tell the caller the nest level of the next item === */
1322
Laurence Lundblade6de37062018-10-15 12:22:42 +05301323 // Tell the caller what level is next. This tells them what maps/arrays
1324 // were closed out and makes it possible for them to reconstruct
1325 // the tree with just the information returned by GetNext
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07001326 // TODO: pull this into DecodeNesting_GetLevel
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001327 if(DecodeNesting_InBoundedMode(&(me->nesting)) && me->nesting.pCurrent->uCount == 0) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001328 // At end of a map / array in map mode, so next nest is 0 to
1329 // indicate this end.
1330 pDecodedItem->uNextNestLevel = 0;
1331 } else {
1332 pDecodedItem->uNextNestLevel = DecodeNesting_GetLevel(&(me->nesting));
1333 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001334
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001335Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001336 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundbladee9482dd2019-10-11 12:58:46 -07001337 // Make sure uDataType and uLabelType are QCBOR_TYPE_NONE
1338 memset(pDecodedItem, 0, sizeof(QCBORItem));
1339 }
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001340 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001341}
1342
1343
Laurence Lundblade59289e52019-12-30 13:44:37 -08001344/*
1345 Mostly just assign the right data type for the date string.
1346 */
1347inline static QCBORError DecodeDateString(QCBORItem *pDecodedItem)
1348{
1349 // Stack Use: UsefulBuf 1 16
1350 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1351 return QCBOR_ERR_BAD_OPT_TAG;
1352 }
1353
1354 const UsefulBufC Temp = pDecodedItem->val.string;
1355 pDecodedItem->val.dateString = Temp;
1356 pDecodedItem->uDataType = QCBOR_TYPE_DATE_STRING;
1357 return QCBOR_SUCCESS;
1358}
1359
1360
1361/*
Laurence Lundbladeee851742020-01-08 08:37:05 -08001362 The epoch formatted date. Turns lots of different forms of encoding
1363 date into uniform one
Laurence Lundblade59289e52019-12-30 13:44:37 -08001364 */
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001365static QCBORError DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08001366{
1367 // Stack usage: 1
1368 QCBORError nReturn = QCBOR_SUCCESS;
1369
1370 pDecodedItem->val.epochDate.fSecondsFraction = 0;
1371
1372 switch (pDecodedItem->uDataType) {
1373
1374 case QCBOR_TYPE_INT64:
1375 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
1376 break;
1377
1378 case QCBOR_TYPE_UINT64:
1379 if(pDecodedItem->val.uint64 > INT64_MAX) {
1380 nReturn = QCBOR_ERR_DATE_OVERFLOW;
1381 goto Done;
1382 }
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001383 pDecodedItem->val.epochDate.nSeconds = (int64_t)pDecodedItem->val.uint64;
Laurence Lundblade59289e52019-12-30 13:44:37 -08001384 break;
1385
1386 case QCBOR_TYPE_DOUBLE:
1387 {
1388 // This comparison needs to be done as a float before
1389 // conversion to an int64_t to be able to detect doubles
1390 // that are too large to fit into an int64_t. A double
1391 // has 52 bits of preceision. An int64_t has 63. Casting
1392 // INT64_MAX to a double actually causes a round up which
1393 // is bad and wrong for the comparison because it will
1394 // allow conversion of doubles that can't fit into a
1395 // uint64_t. To remedy this INT64_MAX - 0x7ff is used as
1396 // the cutoff point as if that rounds up in conversion to
1397 // double it will still be less than INT64_MAX. 0x7ff is
1398 // picked because it has 11 bits set.
1399 //
1400 // INT64_MAX seconds is on the order of 10 billion years,
1401 // and the earth is less than 5 billion years old, so for
1402 // most uses this conversion error won't occur even though
1403 // doubles can go much larger.
1404 //
1405 // Without the 0x7ff there is a ~30 minute range of time
1406 // values 10 billion years in the past and in the future
1407 // where this this code would go wrong.
1408 const double d = pDecodedItem->val.dfnum;
1409 if(d > (double)(INT64_MAX - 0x7ff)) {
1410 nReturn = QCBOR_ERR_DATE_OVERFLOW;
1411 goto Done;
1412 }
1413 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
1414 pDecodedItem->val.epochDate.fSecondsFraction = d - (double)pDecodedItem->val.epochDate.nSeconds;
1415 }
1416 break;
1417
1418 default:
1419 nReturn = QCBOR_ERR_BAD_OPT_TAG;
1420 goto Done;
1421 }
1422 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
1423
1424Done:
1425 return nReturn;
1426}
1427
1428
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001429/*
1430 Mostly just assign the right data type for the bignum.
1431 */
1432inline static QCBORError DecodeBigNum(QCBORItem *pDecodedItem)
1433{
1434 // Stack Use: UsefulBuf 1 -- 16
1435 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1436 return QCBOR_ERR_BAD_OPT_TAG;
1437 }
1438 const UsefulBufC Temp = pDecodedItem->val.string;
1439 pDecodedItem->val.bigNum = Temp;
1440 const bool bIsPosBigNum = (bool)(pDecodedItem->uTags[0] == CBOR_TAG_POS_BIGNUM);
1441 pDecodedItem->uDataType = (uint8_t)(bIsPosBigNum ? QCBOR_TYPE_POSBIGNUM
1442 : QCBOR_TYPE_NEGBIGNUM);
1443 return QCBOR_SUCCESS;
1444}
1445
1446
Laurence Lundblade59289e52019-12-30 13:44:37 -08001447#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
1448/*
1449 Decode decimal fractions and big floats.
1450
1451 When called pDecodedItem must be the array that is tagged as a big
1452 float or decimal fraction, the array that has the two members, the
1453 exponent and mantissa.
1454
1455 This will fetch and decode the exponent and mantissa and put the
1456 result back into pDecodedItem.
1457 */
1458inline static QCBORError
1459QCBORDecode_MantissaAndExponent(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
1460{
1461 QCBORError nReturn;
1462
1463 // --- Make sure it is an array; track nesting level of members ---
1464 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
1465 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1466 goto Done;
1467 }
1468
1469 // A check for pDecodedItem->val.uCount == 2 would work for
Laurence Lundbladeee851742020-01-08 08:37:05 -08001470 // definite length arrays, but not for indefnite. Instead remember
1471 // the nesting level the two integers must be at, which is one
1472 // deeper than that of the array.
Laurence Lundblade59289e52019-12-30 13:44:37 -08001473 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
1474
1475 // --- Is it a decimal fraction or a bigfloat? ---
1476 const bool bIsTaggedDecimalFraction = QCBORDecode_IsTagged(me, pDecodedItem, CBOR_TAG_DECIMAL_FRACTION);
1477 pDecodedItem->uDataType = bIsTaggedDecimalFraction ? QCBOR_TYPE_DECIMAL_FRACTION : QCBOR_TYPE_BIGFLOAT;
1478
1479 // --- Get the exponent ---
1480 QCBORItem exponentItem;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001481 nReturn = QCBORDecode_GetNextMapOrArray(me, &exponentItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001482 if(nReturn != QCBOR_SUCCESS) {
1483 goto Done;
1484 }
1485 if(exponentItem.uNestingLevel != nNestLevel) {
1486 // Array is empty or a map/array encountered when expecting an int
1487 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1488 goto Done;
1489 }
1490 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
1491 // Data arriving as an unsigned int < INT64_MAX has been converted
1492 // to QCBOR_TYPE_INT64 and thus handled here. This is also means
1493 // that the only data arriving here of type QCBOR_TYPE_UINT64 data
1494 // will be too large for this to handle and thus an error that will
1495 // get handled in the next else.
1496 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
1497 } else {
1498 // Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX
1499 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1500 goto Done;
1501 }
1502
1503 // --- Get the mantissa ---
1504 QCBORItem mantissaItem;
1505 nReturn = QCBORDecode_GetNextWithTags(me, &mantissaItem, NULL);
1506 if(nReturn != QCBOR_SUCCESS) {
1507 goto Done;
1508 }
1509 if(mantissaItem.uNestingLevel != nNestLevel) {
1510 // Mantissa missing or map/array encountered when expecting number
1511 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1512 goto Done;
1513 }
1514 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
1515 // Data arriving as an unsigned int < INT64_MAX has been converted
1516 // to QCBOR_TYPE_INT64 and thus handled here. This is also means
1517 // that the only data arriving here of type QCBOR_TYPE_UINT64 data
1518 // will be too large for this to handle and thus an error that
1519 // will get handled in an else below.
1520 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
1521 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM || mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
1522 // Got a good big num mantissa
1523 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
1524 // Depends on numbering of QCBOR_TYPE_XXX
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001525 pDecodedItem->uDataType = (uint8_t)(pDecodedItem->uDataType +
1526 mantissaItem.uDataType - QCBOR_TYPE_POSBIGNUM +
1527 1);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001528 } else {
1529 // Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX
1530 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1531 goto Done;
1532 }
1533
1534 // --- Check that array only has the two numbers ---
1535 if(mantissaItem.uNextNestLevel == nNestLevel) {
1536 // Extra items in the decimal fraction / big num
1537 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1538 goto Done;
1539 }
1540
1541Done:
1542
1543 return nReturn;
1544}
1545#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
1546
1547
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001548
1549/*
1550 */
1551inline static QCBORError DecodeURI(QCBORItem *pDecodedItem)
1552{
1553 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1554 return QCBOR_ERR_BAD_OPT_TAG;
1555 }
1556 pDecodedItem->uDataType = QCBOR_TYPE_URI;
1557 return QCBOR_SUCCESS;
1558}
1559
1560
1561inline static QCBORError DecodeB64URL(QCBORItem *pDecodedItem)
1562{
1563 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1564 return QCBOR_ERR_BAD_OPT_TAG;
1565 }
1566 pDecodedItem->uDataType = QCBOR_TYPE_BASE64URL;
1567 return QCBOR_SUCCESS;
1568}
1569
1570
1571inline static QCBORError DecodeB64(QCBORItem *pDecodedItem)
1572{
1573 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1574 return QCBOR_ERR_BAD_OPT_TAG;
1575 }
1576 pDecodedItem->uDataType = QCBOR_TYPE_BASE64;
1577 return QCBOR_SUCCESS;
1578}
1579
1580
1581inline static QCBORError DecodeRegex(QCBORItem *pDecodedItem)
1582{
1583 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1584 return QCBOR_ERR_BAD_OPT_TAG;
1585 }
1586 pDecodedItem->uDataType = QCBOR_TYPE_REGEX;
1587 return QCBOR_SUCCESS;
1588}
1589
1590
1591inline static QCBORError DecodeMIME(QCBORItem *pDecodedItem)
1592{
1593 if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) {
1594 pDecodedItem->uDataType = QCBOR_TYPE_MIME;
1595 } else if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1596 pDecodedItem->uDataType = QCBOR_TYPE_BINARY_MIME;
1597 } else {
1598 return QCBOR_ERR_BAD_OPT_TAG;
1599 }
1600 return QCBOR_SUCCESS;
1601}
1602
1603
1604/*
1605 */
1606inline static QCBORError DecodeUUID(QCBORItem *pDecodedItem)
1607{
1608 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1609 return QCBOR_ERR_BAD_OPT_TAG;
1610 }
1611 pDecodedItem->uDataType = QCBOR_TYPE_UUID;
1612 return QCBOR_SUCCESS;
1613}
1614
1615
Laurence Lundblade59289e52019-12-30 13:44:37 -08001616/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001617 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08001618 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001619QCBORError
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001620QCBORDecode_GetNext(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08001621{
1622 QCBORError nReturn;
1623
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001624 nReturn = QCBORDecode_GetNextMapOrArray(me, pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001625 if(nReturn != QCBOR_SUCCESS) {
1626 goto Done;
1627 }
1628
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001629 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM; i++) {
1630 switch(pDecodedItem->uTags[i] ) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08001631
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001632 case CBOR_TAG_DATE_STRING:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001633 nReturn = DecodeDateString(pDecodedItem);
1634 break;
1635
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001636 case CBOR_TAG_DATE_EPOCH:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001637 nReturn = DecodeDateEpoch(pDecodedItem);
1638 break;
1639
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001640 case CBOR_TAG_POS_BIGNUM:
1641 case CBOR_TAG_NEG_BIGNUM:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001642 nReturn = DecodeBigNum(pDecodedItem);
1643 break;
1644
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001645 #ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
1646 case CBOR_TAG_DECIMAL_FRACTION:
1647 case CBOR_TAG_BIGFLOAT:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001648 // For aggregate tagged types, what goes into pTags is only collected
1649 // from the surrounding data item, not the contents, so pTags is not
1650 // passed on here.
1651
1652 nReturn = QCBORDecode_MantissaAndExponent(me, pDecodedItem);
1653 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001654 #endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08001655
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001656 case CBOR_TAG_URI:
1657 nReturn = DecodeURI(pDecodedItem);
1658 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001659
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001660 case CBOR_TAG_B64URL:
1661 nReturn = DecodeB64URL(pDecodedItem);
1662 break;
1663
1664 case CBOR_TAG_B64:
1665 nReturn = DecodeB64(pDecodedItem);
1666 break;
1667
1668 case CBOR_TAG_MIME:
1669 case CBOR_TAG_BINARY_MIME:
1670 nReturn = DecodeMIME(pDecodedItem);
1671 break;
1672
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001673 case CBOR_TAG_REGEX:
1674 nReturn = DecodeRegex(pDecodedItem);
1675 break;
1676
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001677 case CBOR_TAG_BIN_UUID:
1678 nReturn = DecodeUUID(pDecodedItem);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001679 break;
1680
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001681 case 0xffff:
1682 // The end of the tag list or no tags
1683 // Successful exit from the loop.
1684 goto Done;
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001685
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001686 default:
1687 // A tag that is not understood
1688 // A successful exit from the loop
1689 goto Done;
1690
1691 }
1692 if(nReturn != QCBOR_SUCCESS) {
1693 goto Done;
1694 }
Laurence Lundblade59289e52019-12-30 13:44:37 -08001695 }
1696
1697Done:
1698 if(nReturn != QCBOR_SUCCESS) {
1699 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
1700 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
1701 }
1702 return nReturn;
1703}
1704
1705
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001706QCBORError QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
1707{
1708 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
1709
1710 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
1711
1712 UsefulInputBuf_Seek(&(pMe->InBuf), uOffset);
1713
1714 return uErr;
1715}
1716
1717
Laurence Lundblade59289e52019-12-30 13:44:37 -08001718/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001719 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08001720 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001721QCBORError
1722QCBORDecode_GetNextWithTags(QCBORDecodeContext *me,
1723 QCBORItem *pDecodedItem,
1724 QCBORTagListOut *pTags)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001725{
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001726 QCBORError nReturn;
1727
1728 nReturn = QCBORDecode_GetNext(me, pDecodedItem);
1729 if(nReturn != QCBOR_SUCCESS) {
1730 return nReturn;
1731 }
1732
1733 if(pTags != NULL) {
1734 pTags->uNumUsed = 0;
1735 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM; i++) {
1736 if(pDecodedItem->uTags[i] == 0xffff) {
1737 break;
1738 }
1739 if(pTags->uNumUsed >= pTags->uNumAllocated) {
1740 return QCBOR_ERR_TOO_MANY_TAGS;
1741 }
1742 pTags->puTags[pTags->uNumUsed] = ConvertTag(me, pDecodedItem->uTags[i]);
1743 pTags->uNumUsed++;
1744 }
1745 }
1746
1747 return QCBOR_SUCCESS;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001748}
1749
1750
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001751/*
Laurence Lundblade6de37062018-10-15 12:22:42 +05301752 Decoding items is done in 5 layered functions, one calling the
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301753 next one down. If a layer has no work to do for a particular item
1754 it returns quickly.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001755
Laurence Lundblade59289e52019-12-30 13:44:37 -08001756 - QCBORDecode_GetNext, GetNextWithTags -- The top layer processes
1757 tagged data items, turning them into the local C representation.
1758 For the most simple it is just associating a QCBOR_TYPE with the data. For
1759 the complex ones that an aggregate of data items, there is some further
1760 decoding and a little bit of recursion.
1761
1762 - QCBORDecode_GetNextMapOrArray - This manages the beginnings and
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301763 ends of maps and arrays. It tracks descending into and ascending
Laurence Lundblade6de37062018-10-15 12:22:42 +05301764 out of maps/arrays. It processes all breaks that terminate
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001765 indefinite length maps and arrays.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001766
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301767 - GetNext_MapEntry -- This handles the combining of two
1768 items, the label and the data, that make up a map entry.
1769 It only does work on maps. It combines the label and data
1770 items into one labeled item.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001771
Laurence Lundblade59289e52019-12-30 13:44:37 -08001772 - GetNext_TaggedItem -- This decodes type 6 tagging. It turns the
1773 tags into bit flags associated with the data item. No actual decoding
1774 of the contents of the tagged item is performed here.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001775
Laurence Lundblade59289e52019-12-30 13:44:37 -08001776 - GetNext_FullItem -- This assembles the sub-items that make up
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301777 an indefinte length string into one string item. It uses the
Laurence Lundblade6de37062018-10-15 12:22:42 +05301778 string allocater to create contiguous space for the item. It
1779 processes all breaks that are part of indefinite length strings.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001780
Laurence Lundblade59289e52019-12-30 13:44:37 -08001781 - GetNext_Item -- This decodes the atomic data items in CBOR. Each
1782 atomic data item has a "major type", an integer "argument" and optionally
1783 some content. For text and byte strings, the content is the bytes
1784 that make up the string. These are the smallest data items that are
1785 considered to be well-formed. The content may also be other data items in
1786 the case of aggregate types. They are not handled in this layer.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001787
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001788 Roughly this takes 300 bytes of stack for vars. Need to
1789 evaluate this more carefully and correctly.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001790
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301791 */
1792
1793
1794/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001795 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001796 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001797int QCBORDecode_IsTagged(QCBORDecodeContext *me,
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001798 const QCBORItem *pItem,
1799 uint64_t uTag)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001800{
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001801 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM; i++ ) {
1802 if(pItem->uTags[i] == 0xffff) {
1803 break;
1804 }
1805 if(ConvertTag(me, pItem->uTags[i]) == uTag) {
1806 return 1;
1807 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001808 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001809
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001810 return 0;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001811}
1812
1813
1814/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001815 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001816 */
Laurence Lundblade30816f22018-11-10 13:40:22 +07001817QCBORError QCBORDecode_Finish(QCBORDecodeContext *me)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001818{
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001819 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001820
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001821 // Error out if all the maps/arrays are not closed out
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001822 if(!DecodeNesting_IsAtTop(&(me->nesting))) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001823 nReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
1824 goto Done;
1825 }
1826
1827 // Error out if not all the bytes are consumed
1828 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) {
1829 nReturn = QCBOR_ERR_EXTRA_BYTES;
1830 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001831
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001832Done:
Laurence Lundblade6de37062018-10-15 12:22:42 +05301833 // Call the destructor for the string allocator if there is one.
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001834 // Always called, even if there are errors; always have to clean up
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001835 StringAllocator_Destruct(&(me->StringAllocator));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001836
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001837 return nReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001838}
1839
1840
1841
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001842/*
1843
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001844Decoder errors handled in this file
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001845
Laurence Lundbladeee851742020-01-08 08:37:05 -08001846 - Hit end of input before it was expected while decoding type and
1847 number QCBOR_ERR_HIT_END
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001848
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001849 - negative integer that is too large for C QCBOR_ERR_INT_OVERFLOW
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001850
Laurence Lundbladeee851742020-01-08 08:37:05 -08001851 - Hit end of input while decoding a text or byte string
1852 QCBOR_ERR_HIT_END
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001853
Laurence Lundbladeee851742020-01-08 08:37:05 -08001854 - Encountered conflicting tags -- e.g., an item is tagged both a date
1855 string and an epoch date QCBOR_ERR_UNSUPPORTED
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001856
Laurence Lundbladeee851742020-01-08 08:37:05 -08001857 - Encontered an array or mapp that has too many items
1858 QCBOR_ERR_ARRAY_TOO_LONG
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001859
Laurence Lundbladeee851742020-01-08 08:37:05 -08001860 - Encountered array/map nesting that is too deep
1861 QCBOR_ERR_ARRAY_NESTING_TOO_DEEP
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001862
Laurence Lundbladeee851742020-01-08 08:37:05 -08001863 - An epoch date > INT64_MAX or < INT64_MIN was encountered
1864 QCBOR_ERR_DATE_OVERFLOW
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001865
Laurence Lundbladeee851742020-01-08 08:37:05 -08001866 - The type of a map label is not a string or int
1867 QCBOR_ERR_MAP_LABEL_TYPE
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001868
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001869 - Hit end with arrays or maps still open -- QCBOR_ERR_EXTRA_BYTES
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001870
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001871 */
1872
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001873
1874
Laurence Lundbladef6531662018-12-04 10:42:22 +09001875
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001876/* ===========================================================================
1877 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001878
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001879 This implements a simple sting allocator for indefinite length
1880 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
1881 implements the function type QCBORStringAllocate and allows easy
1882 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09001883
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001884 This particular allocator is built-in for convenience. The caller
1885 can implement their own. All of this following code will get
1886 dead-stripped if QCBORDecode_SetMemPool() is not called.
1887
1888 This is a very primitive memory allocator. It does not track
1889 individual allocations, only a high-water mark. A free or
1890 reallocation must be of the last chunk allocated.
1891
1892 The size of the pool and offset to free memory are packed into the
1893 first 8 bytes of the memory pool so we don't have to keep them in
1894 the decode context. Since the address of the pool may not be
1895 aligned, they have to be packed and unpacked as if they were
1896 serialized data of the wire or such.
1897
1898 The sizes packed in are uint32_t to be the same on all CPU types
1899 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08001900 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001901
1902
Laurence Lundbladeee851742020-01-08 08:37:05 -08001903static inline int
1904MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001905{
1906 // Use of UsefulInputBuf is overkill, but it is convenient.
1907 UsefulInputBuf UIB;
1908
Laurence Lundbladeee851742020-01-08 08:37:05 -08001909 // Just assume the size here. It was checked during SetUp so
1910 // the assumption is safe.
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001911 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem, QCBOR_DECODE_MIN_MEM_POOL_SIZE});
1912 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
1913 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
1914 return UsefulInputBuf_GetError(&UIB);
1915}
1916
1917
Laurence Lundbladeee851742020-01-08 08:37:05 -08001918static inline int
1919MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001920{
1921 // Use of UsefulOutBuf is overkill, but convenient. The
1922 // length check performed here is useful.
1923 UsefulOutBuf UOB;
1924
1925 UsefulOutBuf_Init(&UOB, Pool);
1926 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
1927 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
1928 return UsefulOutBuf_GetError(&UOB);
1929}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001930
1931
1932/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001933 Internal function for an allocation, reallocation free and destuct.
1934
1935 Having only one function rather than one each per mode saves space in
1936 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001937
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001938 Code Reviewers: THIS FUNCTION DOES POINTER MATH
1939 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001940static UsefulBuf
1941MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001942{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001943 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001944
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001945 uint32_t uPoolSize;
1946 uint32_t uFreeOffset;
1947
1948 if(uNewSize > UINT32_MAX) {
1949 // This allocator is only good up to 4GB. This check should
1950 // optimize out if sizeof(size_t) == sizeof(uint32_t)
1951 goto Done;
1952 }
1953 const uint32_t uNewSize32 = (uint32_t)uNewSize;
1954
1955 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
1956 goto Done;
1957 }
1958
1959 if(uNewSize) {
1960 if(pMem) {
1961 // REALLOCATION MODE
1962 // Calculate pointer to the end of the memory pool. It is
1963 // assumed that pPool + uPoolSize won't wrap around by
1964 // assuming the caller won't pass a pool buffer in that is
1965 // not in legitimate memory space.
1966 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
1967
1968 // Check that the pointer for reallocation is in the range of the
1969 // pool. This also makes sure that pointer math further down
1970 // doesn't wrap under or over.
1971 if(pMem >= pPool && pMem < pPoolEnd) {
1972 // Offset to start of chunk for reallocation. This won't
1973 // wrap under because of check that pMem >= pPool. Cast
1974 // is safe because the pool is always less than UINT32_MAX
1975 // because of check in QCBORDecode_SetMemPool().
1976 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
1977
1978 // Check to see if the allocation will fit. uPoolSize -
1979 // uMemOffset will not wrap under because of check that
1980 // pMem is in the range of the uPoolSize by check above.
1981 if(uNewSize <= uPoolSize - uMemOffset) {
1982 ReturnValue.ptr = pMem;
1983 ReturnValue.len = uNewSize;
1984
1985 // Addition won't wrap around over because uNewSize was
1986 // checked to be sure it is less than the pool size.
1987 uFreeOffset = uMemOffset + uNewSize32;
1988 }
1989 }
1990 } else {
1991 // ALLOCATION MODE
1992 // uPoolSize - uFreeOffset will not underflow because this
1993 // pool implementation makes sure uFreeOffset is always
1994 // smaller than uPoolSize through this check here and
1995 // reallocation case.
1996 if(uNewSize <= uPoolSize - uFreeOffset) {
1997 ReturnValue.len = uNewSize;
1998 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001999 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002000 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002001 }
2002 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002003 if(pMem) {
2004 // FREE MODE
2005 // Cast is safe because of limit on pool size in
2006 // QCBORDecode_SetMemPool()
2007 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
2008 } else {
2009 // DESTRUCT MODE
2010 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002011 }
2012 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002013
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002014 UsefulBuf Pool = {pPool, uPoolSize};
2015 MemPool_Pack(Pool, uFreeOffset);
2016
2017Done:
2018 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002019}
2020
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002021
Laurence Lundbladef6531662018-12-04 10:42:22 +09002022/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08002023 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09002024 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08002025QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
2026 UsefulBuf Pool,
2027 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002028{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002029 // The pool size and free mem offset are packed into the beginning
2030 // of the pool memory. This compile time check make sure the
2031 // constant in the header is correct. This check should optimize
2032 // down to nothing.
2033 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundblade30816f22018-11-10 13:40:22 +07002034 return QCBOR_ERR_BUFFER_TOO_SMALL;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002035 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002036
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002037 // The pool size and free offset packed in to the beginning of pool
2038 // memory are only 32-bits. This check will optimize out on 32-bit
2039 // machines.
2040 if(Pool.len > UINT32_MAX) {
2041 return QCBOR_ERR_BUFFER_TOO_LARGE;
2042 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002043
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002044 // This checks that the pool buffer given is big enough.
2045 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
2046 return QCBOR_ERR_BUFFER_TOO_SMALL;
2047 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002048
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002049 pMe->StringAllocator.pfAllocator = MemPool_Function;
2050 pMe->StringAllocator.pAllocateCxt = Pool.ptr;
2051 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002052
Laurence Lundblade30816f22018-11-10 13:40:22 +07002053 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002054}
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002055
Laurence Lundblade1341c592020-04-11 14:19:05 -07002056#include <stdio.h>
2057void printdecode(QCBORDecodeContext *pMe, const char *szName)
2058{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002059 printf("---%s--%d--%d--\nLevel Count Type Offset SaveCount MapMode\n",
2060 szName,
2061 (uint32_t)pMe->InBuf.cursor,
2062 (uint32_t)pMe->InBuf.UB.len);
Laurence Lundblade64b607e2020-05-13 13:05:57 -07002063 for(int i = 0; i < QCBOR_MAX_ARRAY_NESTING; i++) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002064 if(&(pMe->nesting.pMapsAndArrays[i]) > pMe->nesting.pCurrent) {
2065 break;
2066 }
Laurence Lundblade64b607e2020-05-13 13:05:57 -07002067 printf("%2s %2d %5d %s %6u %2d %d\n",
2068 pMe->nesting.pCurrentMap == &(pMe->nesting.pMapsAndArrays[i]) ? "->": " ",
Laurence Lundblade1341c592020-04-11 14:19:05 -07002069 i,
2070 pMe->nesting.pMapsAndArrays[i].uCount,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002071 pMe->nesting.pMapsAndArrays[i].uMajorType == QCBOR_TYPE_MAP ? " map" :
2072 (pMe->nesting.pMapsAndArrays[i].uMajorType == QCBOR_TYPE_ARRAY ? "array" :
2073 (pMe->nesting.pMapsAndArrays[i].uMajorType == QCBOR_TYPE_NONE ? " none" : "?????")),
Laurence Lundblade1341c592020-04-11 14:19:05 -07002074 pMe->nesting.pMapsAndArrays[i].uOffset,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002075 pMe->nesting.pMapsAndArrays[i].uSaveCount,
2076 pMe->nesting.pMapsAndArrays[i].uMapMode
Laurence Lundblade1341c592020-04-11 14:19:05 -07002077 );
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002078
Laurence Lundblade1341c592020-04-11 14:19:05 -07002079 }
Laurence Lundblade64b607e2020-05-13 13:05:57 -07002080 printf("\n");
Laurence Lundblade1341c592020-04-11 14:19:05 -07002081}
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002082
2083
2084/*
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002085 *
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002086 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002087static inline QCBORError
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002088ConsumeItem(QCBORDecodeContext *pMe,
2089 const QCBORItem *pItemToConsume,
2090 uint_fast8_t *puNextNestLevel)
2091{
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002092 QCBORError uReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002093 QCBORItem Item;
2094
2095 printdecode(pMe, "ConsumeItem");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002096
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002097 if(IsMapOrArray(pItemToConsume->uDataType)) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002098 /* There is only real work to do for maps and arrays */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002099
Laurence Lundblade1341c592020-04-11 14:19:05 -07002100 /* This works for definite and indefinite length
2101 * maps and arrays by using the nesting level
2102 */
2103 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002104 uReturn = QCBORDecode_GetNext(pMe, &Item);
2105 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002106 goto Done;
2107 }
2108 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002109
Laurence Lundblade1341c592020-04-11 14:19:05 -07002110 if(puNextNestLevel != NULL) {
2111 *puNextNestLevel = Item.uNextNestLevel;
2112 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002113 uReturn = QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002114
Laurence Lundblade1341c592020-04-11 14:19:05 -07002115 } else {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002116 /* item_to_consume is not a map or array */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002117 if(puNextNestLevel != NULL) {
2118 /* Just pass the nesting level through */
2119 *puNextNestLevel = pItemToConsume->uNextNestLevel;
2120 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002121 uReturn = QCBOR_SUCCESS;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002122 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002123
2124Done:
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002125 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002126}
2127
2128
Laurence Lundblade1341c592020-04-11 14:19:05 -07002129/* Return true if the labels in Item1 and Item2 are the same.
2130 Works only for integer and string labels. Returns false
2131 for any other type. */
2132static inline bool
2133MatchLabel(QCBORItem Item1, QCBORItem Item2)
2134{
2135 if(Item1.uLabelType == QCBOR_TYPE_INT64) {
2136 if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
2137 return true;
2138 }
2139 } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002140 if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002141 return true;
2142 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002143 } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002144 if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
2145 return true;
2146 }
2147 } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
2148 if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
2149 return true;
2150 }
2151 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002152
Laurence Lundblade1341c592020-04-11 14:19:05 -07002153 /* Other label types are never matched */
2154 return false;
2155}
2156
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002157static inline bool
2158MatchType(QCBORItem Item1, QCBORItem Item2)
2159{
2160 if(Item1.uDataType == Item2.uDataType) {
2161 return true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002162 } else if(Item1.uDataType == QCBOR_TYPE_ANY) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002163 return true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002164 } else if(Item2.uDataType == QCBOR_TYPE_ANY) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002165 return true;
2166 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002167 return false;
2168}
2169
2170
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002171/**
2172 \brief Search a map for a set of items
2173
2174 @param[in] pMe The decode context to search.
2175 @param[in,out] pItemArray The items to search for and the items found.
2176 @param[in] pCBContext Context for the not-found item call back
2177 @param[in] pfCallback Function to call on items not matched in pItemArray
2178
2179 @retval QCBOR_ERR_NOT_ENTERED Trying to search without having entered a map
2180
2181 @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.
2182
2183 @retval QCBOR_ERR_UNEXPECTED_TYPE The label was matched, but not the type.
2184
2185 @retval Also errors returned by QCBORDecode_GetNext().
2186
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002187 On input pItemArray contains a list of labels and data types
2188 of items to be found.
2189
2190 On output the fully retrieved items are filled in with
2191 values and such. The label was matched, so it never changes.
2192
2193 If an item was not found, its data type is set to none.
2194
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002195 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002196static QCBORError
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002197MapSearch(QCBORDecodeContext *pMe,
2198 QCBORItem *pItemArray,
2199 size_t *puOffset,
2200 size_t *puEndOffset,
2201 void *pCBContext,
2202 QCBORItemCallback pfCallback)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002203{
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002204 QCBORError uReturn;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002205
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002206 QCBORDecodeNesting SaveNesting;
2207 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002208
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002209 // Reposition to search from the start of the map / array
2210 UsefulInputBuf_Seek(&(pMe->InBuf), pMe->nesting.pCurrentMap->uOffset);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002211
2212 /* Loop over all the items in the map. They could be
2213 * deeply nested and this should handle both definite
2214 * and indefinite length maps and arrays, so this
2215 * adds some complexity. */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002216 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Laurence Lundblade1341c592020-04-11 14:19:05 -07002217
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002218 uint_fast8_t uNextNestLevel;
2219
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002220 uint64_t uFoundItemBitMap = 0;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002221
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002222 /* Iterate over items in the map / array */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002223 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002224 /* Remember offset of the item because sometimes it has to be returned */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002225 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002226
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002227 /* Get the item */
2228 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002229 uReturn = QCBORDecode_GetNext(pMe, &Item);
2230 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002231 /* Got non-well-formed CBOR */
2232 goto Done;
2233 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002234
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002235 /* See if item has one of the labels that are of interest */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002236 int nIndex;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002237 QCBORItem *pIterator;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002238 for(pIterator = pItemArray, nIndex = 0; pIterator->uLabelType != 0; pIterator++, nIndex++) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002239 if(MatchLabel(Item, *pIterator)) {
2240 // A label match has been found
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002241 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
2242 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002243 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002244 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002245 /* Also try to match its type */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002246 if(!MatchType(Item, *pIterator)) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002247 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002248 goto Done;
2249 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002250
2251 /* Successful match. Return the item. */
2252 *pIterator = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002253 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002254 if(puOffset) {
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002255 *puOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002256 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002257 } else {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002258 /* Call the callback on unmatched labels */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002259 /* It is tempting to do duplicate detection here, but that would
2260 require dynamic memory allocation because the number of labels
2261 that might be encountered is unbounded.
2262 */
2263 if(pfCallback) {
2264 uReturn = (*pfCallback)(pCBContext, &Item);
2265 if(uReturn != QCBOR_SUCCESS) {
2266 goto Done;
2267 }
2268 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002269 }
2270 }
2271
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002272 /* Consume the item whether matched or not. This
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002273 does the work of traversing maps and array and
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002274 everything in them. In this loop only the
2275 items at the current nesting level are examined
2276 to match the labels. */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002277 uReturn = ConsumeItem(pMe, &Item, &uNextNestLevel);
2278 if(uReturn) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002279 goto Done;
2280 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002281
2282 } while (uNextNestLevel >= uMapNestLevel);
2283
2284
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002285 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002286
2287 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
2288 // Cast OK because encoded CBOR is limited to UINT32_MAX
2289 pMe->uMapEndOffset = (uint32_t)uEndOffset;
2290 // TODO: is zero *puOffset OK?
2291 if(puEndOffset) {
2292 *puEndOffset = uEndOffset;
2293 }
2294
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002295 /* For all items not found, set the data type to QCBOR_TYPE_NONE */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002296 int i;
2297 QCBORItem *pIterator;
2298 for(pIterator = pItemArray, i = 0; pIterator->uLabelType != 0; pIterator++, i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002299 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002300 pIterator->uDataType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002301 }
2302 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002303
2304Done:
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002305 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002306
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002307 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002308}
2309
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002310
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002311/*
2312Public function, see header qcbor/qcbor_decode.h file
2313*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002314void QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
2315 int64_t nLabel,
2316 uint8_t uQcborType,
2317 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002318{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002319 if(pMe->uLastError != QCBOR_SUCCESS) {
2320 return;
2321 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002322
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002323 QCBORItem OneItemSeach[2];
2324 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
2325 OneItemSeach[0].label.int64 = nLabel;
2326 OneItemSeach[0].uDataType = uQcborType;
2327 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07002328
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002329 QCBORError nReturn = MapSearch(pMe, OneItemSeach, NULL, NULL, NULL, NULL);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002330 if(nReturn) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002331 pMe->uLastError = (uint8_t)nReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002332 }
2333
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002334 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
2335 pMe->uLastError = QCBOR_ERR_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002336 }
2337
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002338 *pItem = OneItemSeach[0];
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002339}
2340
2341
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002342/*
2343Public function, see header qcbor/qcbor_decode.h file
2344*/
Laurence Lundbladeda095972020-06-06 18:35:33 -07002345void QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
2346 const char *szLabel,
2347 uint8_t uQcborType,
2348 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002349{
Laurence Lundbladeda095972020-06-06 18:35:33 -07002350 if(pMe->uLastError != QCBOR_SUCCESS) {
2351 return;
2352 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002353
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002354 QCBORItem OneItemSeach[2];
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002355 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2356 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
2357 OneItemSeach[0].uDataType = uQcborType;
2358 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07002359
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002360 QCBORError nReturn = MapSearch(pMe, OneItemSeach, NULL, NULL, NULL, NULL);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002361 if(nReturn) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07002362 pMe->uLastError = (uint8_t)nReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002363 }
2364
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002365 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07002366 pMe->uLastError = QCBOR_ERR_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002367 }
2368
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002369 *pItem = OneItemSeach[0];
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002370}
2371
2372
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002373/**
2374 @param[in] TagSpec Specification for matching tags.
2375 @param[in] uDataType A QCBOR data type
2376
2377 @retval QCBOR_SUCCESS \c uDataType is allowed by @c TagSpec
2378 @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec
2379
2380 The data type must be one of the QCBOR_TYPEs, not the IETF CBOR Registered tag value.
2381 */
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002382static QCBORError CheckTagRequirement(const TagSpecification TagSpec, uint8_t uDataType)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002383{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002384 if(TagSpec.uTagRequirement == QCBOR_TAGSPEC_MATCH_TAG) {
2385 /* Must match the tag */
2386 if(uDataType == TagSpec.uTaggedType) {
2387 return QCBOR_SUCCESS;
2388 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002389 } else {
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002390 /* QCBOR_TAGSPEC_MATCH_TAG_CONTENT_TYPE or QCBOR_TAGSPEC_MATCH_EITHER */
2391 /* Must check all the possible types for the tag content */
2392 for(size_t i = 0; i < sizeof(TagSpec.uAllowedContentTypes); i++) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002393 if(uDataType == TagSpec.uAllowedContentTypes[i]) {
2394 return QCBOR_SUCCESS;
2395 }
2396 }
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002397 /* Didn't match any of the tag content types */
2398 /* Check the tag for the either case */
2399 if(TagSpec.uTagRequirement == QCBOR_TAGSPEC_MATCH_EITHER) {
2400 if(uDataType == TagSpec.uTaggedType) {
2401 return QCBOR_SUCCESS;
2402 }
2403 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002404 }
2405
2406 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002407}
2408
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002409
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002410// Semi-private
2411// TODO: inline or collapse with QCBORDecode_GetTaggedStringInMapN?
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002412void QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
2413 int64_t nLabel,
2414 TagSpecification TagSpec,
2415 QCBORItem *pItem)
2416{
2417 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
2418 if(pMe->uLastError != QCBOR_SUCCESS) {
2419 return;
2420 }
2421
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002422 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem->uDataType);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002423}
2424
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002425// Semi-private
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002426void QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
2427 const char *szLabel,
2428 TagSpecification TagSpec,
2429 QCBORItem *pItem)
2430{
2431 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
2432 if(pMe->uLastError != QCBOR_SUCCESS) {
2433 return;
2434 }
2435
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002436 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem->uDataType);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002437}
2438
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002439// Semi-private
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002440void QCBORDecode_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
2441 int64_t nLabel,
2442 TagSpecification TagSpec,
2443 UsefulBufC *pString)
2444{
2445 QCBORItem Item;
2446 QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
2447 if(pMe->uLastError == QCBOR_SUCCESS) {
2448 *pString = Item.val.string;
2449 }
2450}
2451
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002452// Semi-private
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002453void QCBORDecode_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
2454 const char * szLabel,
2455 TagSpecification TagSpec,
2456 UsefulBufC *pString)
2457{
2458 QCBORItem Item;
2459 QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
2460 if(pMe->uLastError == QCBOR_SUCCESS) {
2461 *pString = Item.val.string;
2462 }
2463}
Laurence Lundblade1341c592020-04-11 14:19:05 -07002464
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002465/*
2466Public function, see header qcbor/qcbor_decode.h file
2467*/
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002468QCBORError QCBORDecode_GetItemsInMap(QCBORDecodeContext *pCtx, QCBORItem *pItemList)
2469{
2470 return MapSearch(pCtx, pItemList, NULL, NULL, NULL, NULL);
2471}
2472
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002473/*
2474Public function, see header qcbor/qcbor_decode.h file
2475*/
2476QCBORError QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pCtx,
2477 QCBORItem *pItemList,
2478 void *pCallbackCtx,
2479 QCBORItemCallback pfCB)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002480{
2481 return MapSearch(pCtx, pItemList, NULL, NULL, pCallbackCtx, pfCB);
2482}
2483
2484
Laurence Lundblade34691b92020-05-18 22:25:25 -07002485static void SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07002486{
Laurence Lundblade34691b92020-05-18 22:25:25 -07002487 if(pMe->uLastError != QCBOR_SUCCESS) {
2488 // Already in error state; do nothing.
2489 return;
2490 }
2491
2492 size_t uOffset;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002493 pMe->uLastError = (uint8_t)MapSearch(pMe, pSearch, &uOffset, NULL, NULL, NULL);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002494 if(pMe->uLastError != QCBOR_SUCCESS) {
2495 return;
2496 }
2497
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002498 /* Need to get the current pre-order nesting level and cursor to be
2499 at the first item in the map/array just entered.
2500
2501 Also need to current map nesting level and start cursor to
2502 be at the right place.
2503
2504 The UsefulInBuf offset could be anywhere, so no assumption is
2505 made about it.
2506
2507 No assumption is made about the pre-order nesting level either.
2508
2509 However the map mode nesting level is assumed to be one above
2510 the map level that is being entered.
2511 */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002512 /* Seek to the data item that is the map or array */
2513 UsefulInputBuf_Seek(&(pMe->InBuf), uOffset);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002514 pMe->nesting.pCurrent = pMe->nesting.pCurrentMap; // TODO: part of DecodeNesting
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002515
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002516 // TODO: check error?
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002517 QCBORDecode_EnterBoundedMode(pMe, pSearch->uDataType);
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002518
Laurence Lundblade34691b92020-05-18 22:25:25 -07002519 printdecode(pMe, "FinishEnter");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002520}
2521
2522
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002523/*
2524Public function, see header qcbor/qcbor_decode.h file
2525*/
Laurence Lundblade34691b92020-05-18 22:25:25 -07002526void QCBORDecode_EnterMapInMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002527{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002528 QCBORItem OneItemSeach[2];
2529 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
2530 OneItemSeach[0].label.int64 = nLabel;
2531 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
2532 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002533
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002534 /* The map to enter was found, now finish of entering it. */
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002535 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002536}
2537
2538
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002539/*
2540Public function, see header qcbor/qcbor_decode.h file
2541*/
Laurence Lundblade34691b92020-05-18 22:25:25 -07002542void QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002543{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002544 QCBORItem OneItemSeach[2];
2545 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2546 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
2547 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
2548 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002549
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002550 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002551}
2552
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002553/*
2554Public function, see header qcbor/qcbor_decode.h file
2555*/
Laurence Lundblade34691b92020-05-18 22:25:25 -07002556void QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07002557{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002558 QCBORItem OneItemSeach[2];
2559 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
2560 OneItemSeach[0].label.int64 = nLabel;
2561 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
2562 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002563
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002564 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002565}
2566
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002567/*
2568Public function, see header qcbor/qcbor_decode.h file
2569*/
Laurence Lundblade34691b92020-05-18 22:25:25 -07002570void QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
2571{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002572 QCBORItem OneItemSeach[2];
2573 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2574 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
2575 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
2576 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002577
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002578 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002579}
2580
2581
2582
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002583/* Next item must be map or this generates an error */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002584void QCBORDecode_EnterBoundedMode(QCBORDecodeContext *pMe, uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002585{
Laurence Lundblade34691b92020-05-18 22:25:25 -07002586 if(pMe->uLastError != QCBOR_SUCCESS) {
2587 // Already in error state; do nothing.
2588 return;
2589 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002590
2591 /* Get the data item that is the map that is being searched */
Laurence Lundblade34691b92020-05-18 22:25:25 -07002592 QCBORItem Item;
Laurence Lundblade986017c2020-05-23 19:25:02 -07002593 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002594 if(pMe->uLastError != QCBOR_SUCCESS) {
2595 return;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002596 }
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002597 if(Item.uDataType != uType) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07002598 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
2599 return;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002600 }
2601
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002602 DecodeNesting_EnterBoundedMode(&(pMe->nesting), UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002603
Laurence Lundblade34691b92020-05-18 22:25:25 -07002604 printdecode(pMe, "EnterMapModeDone");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002605}
2606
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002607void QCBORDecode_ExitBoundedMode(QCBORDecodeContext *pMe, uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002608{
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002609 QCBORError uErr;
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002610 size_t uEndOffset;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002611
2612 (void)uType; // TODO: error check
2613
2614/*
2615 if(pMe->uMapEndOffset) {
2616 uEndOffset = pMe->uMapEndOffset;
2617 // It is only valid once.
2618 pMe->uMapEndOffset = 0;
2619 } else { */
2620 // Find offset of the end the bounded array / map
2621 QCBORItem Dummy;
2622
2623 Dummy.uLabelType = QCBOR_TYPE_NONE;
2624
2625 QCBORError nReturn = MapSearch(pMe, &Dummy, NULL, &uEndOffset, NULL, NULL);
2626
2627 (void)nReturn; // TODO:
2628// }
2629
2630 printdecode(pMe, "start exit");
2631
2632 /* Before acending mark this level as no longer in bound mode. */
2633 pMe->nesting.pCurrentMap->uType &= ~QCBOR_NEST_TYPE_IS_BOUND;
2634
2635
2636 /* Set the pre-order traversal state to just after
2637 the map or array that was exited. */
2638 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
2639
2640 // Always go up one level
2641 // Need error check to know level is bounded mode and not at top level
2642 pMe->nesting.pCurrent = pMe->nesting.pCurrentMap - 1; // TODO error check
2643
2644 uErr = Ascender(pMe);
2645
2646 /* Also ascend to the next higest bounded mode level if
2647 there is one. */
2648 while(1) {
2649 pMe->nesting.pCurrentMap--;
2650 if(DecodeNesting_InBoundedMode(&(pMe->nesting))) {
2651 break;
2652 }
2653 if(pMe->nesting.pCurrentMap == &(pMe->nesting.pMapsAndArrays[0])) {
2654 pMe->nesting.pCurrentMap = NULL;
2655 break;
2656 }
2657 }
2658
2659 printdecode(pMe, "end exit");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002660}
2661
2662
Laurence Lundblade1341c592020-04-11 14:19:05 -07002663void QCBORDecode_RewindMap(QCBORDecodeContext *pMe)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002664{
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002665 // TODO: check for map mode; test this
Laurence Lundblade1341c592020-04-11 14:19:05 -07002666 pMe->nesting.pCurrent->uCount = pMe->nesting.pCurrent->uSaveCount;
2667 UsefulInputBuf_Seek(&(pMe->InBuf), pMe->nesting.pCurrent->uOffset);
2668}
2669
2670
Laurence Lundblade1341c592020-04-11 14:19:05 -07002671
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002672void QCBORDecode_EnterBstr(QCBORDecodeContext *pMe)
2673{
2674 if(pMe->uLastError != QCBOR_SUCCESS) {
2675 // Already in error state; do nothing.
2676 return;
2677 }
2678
2679 /* Get the data item that is the map that is being searched */
2680 QCBORItem Item;
2681 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
2682 if(pMe->uLastError != QCBOR_SUCCESS) {
2683 return;
2684 }
2685 if(Item.uDataType != QCBOR_TYPE_BYTE_STRING) {
2686 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
2687 return;
2688 }
2689
2690 // TODO: check for tag 24
2691
2692 // Need to move UIB input cursor to the right place
2693
2694 // Really this is a subtraction and an assignment; not much code
2695 // There is a range check in the seek.
2696 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
2697
2698 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset - Item.val.string.len);
2699
2700 UsefulInputBuf_SetBufferLen(&(pMe->InBuf), uEndOffset);
2701
2702 // TODO: comment on cast
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002703 pMe->uLastError = (uint8_t)DecodeNesting_Descend(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING, UINT16_MAX, (uint32_t)uEndOffset);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002704}
2705
2706
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002707void QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe, uint8_t uTagRequirement, UsefulBufC *pBstr)
2708{
2709 QCBORItem Item;
2710 QCBORDecode_GetNext(pMe, &Item);
2711 // Need to set UIB cursor to start of bstr and UIB length to end of bstr
2712
2713 // TODO: combine with above
2714
2715}
2716
2717//void QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pCtx, int64_t uLabel, UsefulBufC *pBstr);
2718
2719//void QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pCtx, const char *szLabel, UsefulBufC *pBstr);
2720
2721void QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pCtx)
2722{
2723 // Need to set the cursor to end of the bstr and length to the next length
2724 // above in the nesting tree (or the top level length).
2725
2726}
2727
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002728
Laurence Lundbladee6430642020-03-14 21:15:44 -07002729
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002730
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002731
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002732
Laurence Lundblade11a064e2020-05-07 13:13:42 -07002733
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002734
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002735static QCBORError InterpretBool(const QCBORItem *pItem, bool *pBool)
2736{
2737 switch(pItem->uDataType) {
2738 case QCBOR_TYPE_TRUE:
2739 *pBool = true;
2740 return QCBOR_SUCCESS;
2741 break;
2742
2743 case QCBOR_TYPE_FALSE:
2744 *pBool = false;
2745 return QCBOR_SUCCESS;
2746 break;
2747
2748 default:
2749 return QCBOR_ERR_UNEXPECTED_TYPE;
2750 break;
2751 }
2752}
Laurence Lundbladee6430642020-03-14 21:15:44 -07002753
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002754/*
2755Public function, see header qcbor/qcbor_decode.h file
2756*/
Laurence Lundbladec4537442020-04-14 18:53:22 -07002757void QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002758{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002759 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002760 // Already in error state, do nothing
Laurence Lundbladee6430642020-03-14 21:15:44 -07002761 return;
2762 }
2763
Laurence Lundbladec4537442020-04-14 18:53:22 -07002764 QCBORError nError;
2765 QCBORItem Item;
2766
2767 nError = QCBORDecode_GetNext(pMe, &Item);
2768 if(nError != QCBOR_SUCCESS) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002769 pMe->uLastError = (uint8_t)nError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002770 return;
2771 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002772 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002773}
2774
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002775/*
2776Public function, see header qcbor/qcbor_decode.h file
2777*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002778void QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe, int64_t nLabel, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002779{
2780 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002781 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002782
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002783 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002784}
2785
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002786/*
2787Public function, see header qcbor/qcbor_decode.h file
2788*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002789void QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, bool *pValue)
2790{
2791 QCBORItem Item;
2792 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
2793
2794 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
2795}
2796
2797
2798
2799void QCBORDecode_GetTaggedStringInternal(QCBORDecodeContext *pMe, TagSpecification TagSpec, UsefulBufC *pBstr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002800{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002801 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002802 // Already in error state, do nothing
2803 return;
2804 }
2805
2806 QCBORError nError;
2807 QCBORItem Item;
2808
2809 nError = QCBORDecode_GetNext(pMe, &Item);
2810 if(nError != QCBOR_SUCCESS) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002811 pMe->uLastError = (uint8_t)nError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002812 return;
2813 }
2814
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002815 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, Item.uDataType);
2816
2817 if(pMe->uLastError == QCBOR_SUCCESS) {
2818 *pBstr = Item.val.string;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002819 }
2820}
2821
Laurence Lundbladec4537442020-04-14 18:53:22 -07002822
2823
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002824
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002825static QCBORError ConvertBigNum(uint8_t uTagRequirement, const QCBORItem *pItem, UsefulBufC *pValue, bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002826{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002827 *pbIsNegative = false;
2828
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002829 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 -07002830
2831 switch(pItem->uDataType) {
2832 case QCBOR_TYPE_BYTE_STRING:
2833 // TODO: check that there is no tag here?
2834 if(bMustBeTagged) {
2835 return QCBOR_ERR_UNEXPECTED_TYPE;
2836 } else {
2837 *pValue = pItem->val.string;
2838 return QCBOR_SUCCESS;
2839 }
2840 break;
2841
2842 case QCBOR_TYPE_POSBIGNUM:
2843 *pValue = pItem->val.string;
2844 return QCBOR_SUCCESS;
2845 break;
2846
2847 case QCBOR_TYPE_NEGBIGNUM:
2848 *pbIsNegative = true;
2849 *pValue = pItem->val.string;
2850 return QCBOR_SUCCESS;
2851 break;
2852
2853 default:
2854 return QCBOR_ERR_UNEXPECTED_TYPE;
2855 break;
2856 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002857}
2858
2859
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002860/*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002861 @param[in] bMustBeTagged If \c true, then the data item must be tagged as either
2862 a positive or negative bignum. If \c false, then it only must be a byte string and bIsNegative
2863 will always be false on the asumption that it is positive, but it can be interpretted as
2864 negative if the the sign is know from other context.
2865 @param[out] pValue The bytes that make up the big num
2866 @param[out] pbIsNegative \c true if tagged as a negative big num. \c false otherwise.
2867
2868 if bMustBeTagged is false, then this will succeed if the data item is a plain byte string,
2869 a positive big num or a negative big num.
2870
2871 */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002872void QCBORDecode_GetBignum(QCBORDecodeContext *pMe, uint8_t uTagRequirement, UsefulBufC *pValue, bool *pbIsNegative)
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002873{
2874 if(pMe->uLastError != QCBOR_SUCCESS) {
2875 // Already in error state, do nothing
2876 return;
2877 }
2878
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002879 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002880 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
2881 if(uError != QCBOR_SUCCESS) {
2882 pMe->uLastError = (uint8_t)uError;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002883 return;
2884 }
2885
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002886 pMe->uLastError = (uint8_t)ConvertBigNum(uTagRequirement, &Item, pValue, pbIsNegative);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002887}
2888
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002889/*
2890Public function, see header qcbor/qcbor_decode.h file
2891*/
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002892void QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, UsefulBufC *pValue, bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002893{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002894 QCBORItem Item;
2895 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002896
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002897 pMe->uLastError = (uint8_t)ConvertBigNum(uTagRequirement, &Item, pValue, pbIsNegative);
Laurence Lundbladec4537442020-04-14 18:53:22 -07002898}
2899
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002900/*
2901Public function, see header qcbor/qcbor_decode.h file
2902*/
2903void QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint8_t uTagRequirement, UsefulBufC *pValue, bool *pbIsNegative)
2904{
2905 QCBORItem Item;
2906 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
2907
2908 pMe->uLastError = (uint8_t)ConvertBigNum(uTagRequirement, &Item, pValue, pbIsNegative);
2909}
2910
2911
2912
2913// Semi private
2914QCBORError FarfMIME(uint8_t uTagRequirement, const QCBORItem *pItem, UsefulBufC *pMessage, bool *pbIsNot7Bit)
2915{
2916 const TagSpecification TagSpecText = {uTagRequirement, QCBOR_TYPE_MIME, {QCBOR_TYPE_TEXT_STRING, 0,0,0,0,0}};
2917 const TagSpecification TagSpecBinary = {uTagRequirement, QCBOR_TYPE_BINARY_MIME, {QCBOR_TYPE_BYTE_STRING, 0,0,0,0,0}};
2918
2919 QCBORError uReturn;
2920
2921 if(CheckTagRequirement(TagSpecText, pItem->uDataType)) {
2922 *pMessage = pItem->val.string;
2923 if(pbIsNot7Bit != NULL) {
2924 *pbIsNot7Bit = false;
2925 }
2926 uReturn = QCBOR_SUCCESS;
2927 } else if(CheckTagRequirement(TagSpecBinary, pItem->uDataType)) {
2928 *pMessage = pItem->val.string;
2929 if(pbIsNot7Bit != NULL) {
2930 *pbIsNot7Bit = true;
2931 }
2932 uReturn = QCBOR_SUCCESS;
2933
2934 } else {
2935 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
2936 }
2937
2938 return uReturn;
2939}
2940
2941
2942
2943
2944
Laurence Lundbladec4537442020-04-14 18:53:22 -07002945
2946
2947
Laurence Lundbladee6430642020-03-14 21:15:44 -07002948
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002949typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002950
2951
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002952// The main exponentiator that works on only positive numbers
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002953static QCBORError Exponentitate10(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002954{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002955 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002956
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002957 if(uResult != 0) {
2958 /* This loop will run a maximum of 19 times because
2959 * UINT64_MAX < 10 ^^ 19. More than that will cause
2960 * exit with the overflow error
2961 */
2962 for(; nExponent > 0; nExponent--) {
2963 if(uResult > UINT64_MAX / 10) {
2964 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Error overflow
2965 }
2966 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002967 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002968
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002969 for(; nExponent < 0; nExponent++) {
2970 uResult = uResult / 10;
2971 if(uResult == 0) {
2972 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Underflow error
2973 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002974 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002975 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002976 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07002977
2978 *puResult = uResult;
2979
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002980 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002981}
2982
2983
Laurence Lundbladee6430642020-03-14 21:15:44 -07002984/* Convert a decimal fraction to an int64_t without using
2985 floating point or math libraries. Most decimal fractions
2986 will not fit in an int64_t and this will error out with
2987 under or overflow
2988 */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002989static QCBORError Exponentitate2(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002990{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002991 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002992
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002993 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002994
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002995 /* This loop will run a maximum of 64 times because
Laurence Lundbladee6430642020-03-14 21:15:44 -07002996 * INT64_MAX < 2^31. More than that will cause
2997 * exist with the overflow error
2998 */
2999 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003000 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003001 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Error overflow
Laurence Lundbladee6430642020-03-14 21:15:44 -07003002 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003003 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003004 nExponent--;
3005 }
3006
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003007 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003008 if(uResult == 0) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003009 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Underflow error
3010 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003011 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003012 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003013 }
3014
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003015 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003016
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003017 return QCBOR_SUCCESS;
3018}
3019
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003020/*
3021 Compute value with signed mantissa and signed result. Works with exponent of 2 or 10 based on exponentiator.
3022 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003023static inline QCBORError ExponentiateNN(int64_t nMantissa, int64_t nExponent, int64_t *pnResult, fExponentiator pfExp)
3024{
3025 uint64_t uResult;
3026
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003027 // Take the absolute value of the mantissa and convert to unsigned.
3028 // TODO: this should be possible in one intruction
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003029 uint64_t uMantissa = nMantissa > 0 ? (uint64_t)nMantissa : (uint64_t)-nMantissa;
3030
3031 // Do the exponentiation of the positive mantissa
3032 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
3033 if(uReturn) {
3034 return uReturn;
3035 }
3036
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003037
Laurence Lundblade983500d2020-05-14 11:49:34 -07003038 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
3039 of INT64_MIN. This assumes two's compliment representation where
3040 INT64_MIN is one increment farther from 0 than INT64_MAX.
3041 Trying to write -INT64_MIN doesn't work to get this because the
3042 compiler tries to work with an int64_t which can't represent
3043 -INT64_MIN.
3044 */
3045 uint64_t uMax = nMantissa > 0 ? INT64_MAX : (uint64_t)INT64_MAX+1;
3046
3047 // Error out if too large
3048 if(uResult > uMax) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003049 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3050 }
3051
3052 // Casts are safe because of checks above
3053 *pnResult = nMantissa > 0 ? (int64_t)uResult : -(int64_t)uResult;
3054
3055 return QCBOR_SUCCESS;
3056}
3057
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003058/*
3059 Compute value with signed mantissa and unsigned result. Works with exponent of 2 or 10 based on exponentiator.
3060 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003061static inline QCBORError ExponentitateNU(int64_t nMantissa, int64_t nExponent, uint64_t *puResult, fExponentiator pfExp)
3062{
3063 if(nMantissa < 0) {
3064 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3065 }
3066
3067 // Cast to unsigned is OK because of check for negative
3068 // Cast to unsigned is OK because UINT64_MAX > INT64_MAX
3069 // Exponentiation is straight forward
3070 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
3071}
3072
3073
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003074#include <math.h>
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003075
3076
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003077static QCBORError ConvertBigNumToUnsigned(const UsefulBufC BigNum, uint64_t uMax, uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003078{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003079 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003080
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003081 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003082 const uint8_t *pByte = BigNum.ptr;
3083 size_t uLen = BigNum.len;
3084 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07003085 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003086 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003087 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07003088 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003089 }
3090
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003091 *pResult = uResult;
3092 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003093}
3094
Laurence Lundblade887add82020-05-17 05:50:34 -07003095static inline QCBORError ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum, uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003096{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003097 return ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003098}
3099
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003100static inline QCBORError ConvertPositiveBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003101{
3102 uint64_t uResult;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003103 QCBORError uError = ConvertBigNumToUnsigned(BigNum, INT64_MAX, &uResult);
3104 if(uError) {
3105 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003106 }
3107 /* Cast is safe because ConvertBigNum is told to limit to INT64_MAX */
3108 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003109 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003110}
3111
3112
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003113static inline QCBORError ConvertNegativeBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003114{
3115 uint64_t uResult;
Laurence Lundbladeda095972020-06-06 18:35:33 -07003116 /* negaative int furthest from zero is INT64_MIN
3117 which is expressed as -INT64_MAX-1. The value of
3118 a negative bignum is -n-1, one further from zero
3119 than the positive bignum */
3120
3121 /* say INT64_MIN is -2; then INT64_MAX is 1.
3122 Then -n-1 <= INT64_MIN.
3123 Then -n -1 <= -INT64_MAX - 1
3124 THen n <= INT64_MAX. */
3125 QCBORError uError = ConvertBigNumToUnsigned(BigNum, INT64_MAX, &uResult);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003126 if(uError) {
3127 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003128 }
3129 /* Cast is safe because ConvertBigNum is told to limit to INT64_MAX */
Laurence Lundblade887add82020-05-17 05:50:34 -07003130 // TODO: this code is incorrect. See RFC 7049
Laurence Lundbladeda095972020-06-06 18:35:33 -07003131 uResult++; // this is the -1 in -n-1
Laurence Lundbladee6430642020-03-14 21:15:44 -07003132 *pResult = -(int64_t)uResult;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003133 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003134}
3135
Laurence Lundbladef6c86662020-05-12 02:08:00 -07003136#include "fenv.h"
Laurence Lundbladec4537442020-04-14 18:53:22 -07003137
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003138
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003139/*
3140Convert a integers and floats to an int64_t.
3141
3142\param[in] uOptions Bit mask list of conversion options.
3143
3144\retval QCBOR_ERR_CONVERSION_NOT_REQUESTED Conversion, possible, but not requested in uOptions.
3145
3146\retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
3147
3148\retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large or too small.
3149
3150*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003151static QCBORError ConvertInt64(const QCBORItem *pItem, uint32_t uOptions, int64_t *pnValue)
3152{
3153 switch(pItem->uDataType) {
3154 // TODO: float when ifdefs are set
3155 case QCBOR_TYPE_DOUBLE:
3156 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3157 // TODO: what about under/overflow here?
3158 // Invokes the floating-point HW and/or compiler-added libraries
3159 feclearexcept(FE_ALL_EXCEPT);
3160 *pnValue = llround(pItem->val.dfnum);
3161 if(fetestexcept(FE_INVALID)) {
3162 // TODO: better error code
3163 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3164 }
3165 } else {
3166 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3167 }
3168 break;
3169
3170 case QCBOR_TYPE_INT64:
3171 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
3172 *pnValue = pItem->val.int64;
3173 } else {
3174 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3175 }
3176 break;
3177
3178 case QCBOR_TYPE_UINT64:
3179 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
3180 if(pItem->val.uint64 < INT64_MAX) {
3181 *pnValue = pItem->val.int64;
3182 } else {
3183 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3184 }
3185 } else {
3186 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3187 }
3188 break;
3189
3190 default:
3191 return QCBOR_ERR_UNEXPECTED_TYPE;
3192 }
3193 return QCBOR_SUCCESS;
3194}
3195
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003196
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003197void QCBORDecode_GetInt64ConvertInternal(QCBORDecodeContext *pMe,
3198 uint32_t uOptions,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003199 int64_t *pnValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003200 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003201{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07003202 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003203 return;
3204 }
3205
Laurence Lundbladee6430642020-03-14 21:15:44 -07003206 QCBORItem Item;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003207 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
3208 if(uError) {
3209 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003210 return;
3211 }
3212
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003213 if(pItem) {
3214 *pItem = Item;
3215 }
3216
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003217 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003218}
3219
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003220
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003221void QCBORDecode_GetInt64ConvertInternalInMapN(QCBORDecodeContext *pMe,
3222 int64_t nLabel,
3223 uint32_t uOptions,
3224 int64_t *pnValue,
3225 QCBORItem *pItem)
3226{
3227 QCBORItem Item;
3228 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
3229
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003230 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003231}
3232
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003233
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003234void QCBORDecode_GetInt64ConvertInternalInMapSZ(QCBORDecodeContext *pMe,
3235 const char * szLabel,
3236 uint32_t uOptions,
3237 int64_t *pnValue,
3238 QCBORItem *pItem)
3239{
3240 if(pMe->uLastError != QCBOR_SUCCESS) {
3241 return;
3242 }
3243
3244 QCBORItem Item;
3245 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3246
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003247 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003248}
3249
3250
3251
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003252/*
3253 Convert a large variety of integer types to an int64_t.
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003254
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003255 \param[in] uOptions Bit mask list of conversion options.
3256
3257 \retval QCBOR_ERR_CONVERSION_NOT_REQUESTED Conversion, possible, but not requested in uOptions.
3258
3259 \retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
3260
3261 \retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large or too small.
3262
3263 */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003264static QCBORError Int64ConvertAll(const QCBORItem *pItem, uint32_t uOptions, int64_t *pnValue)
3265{
3266 QCBORError uErr;
3267
3268 switch(pItem->uDataType) {
3269
3270 case QCBOR_TYPE_POSBIGNUM:
3271 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3272 return ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003273 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003274 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003275 }
3276 break;
3277
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003278 case QCBOR_TYPE_NEGBIGNUM:
3279 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3280 return ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003281 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003282 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003283 }
3284 break;
3285
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003286#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
3287 case QCBOR_TYPE_DECIMAL_FRACTION:
3288 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3289 return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
3290 pItem->val.expAndMantissa.nExponent,
3291 pnValue,
3292 &Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003293 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003294 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3295 }
3296 break;
3297
3298 case QCBOR_TYPE_BIGFLOAT:
3299 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3300 return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
3301 pItem->val.expAndMantissa.nExponent,
3302 pnValue,
3303 Exponentitate2);
3304 } else {
3305 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3306 }
3307 break;
3308
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003309 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
3310 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3311 int64_t nMantissa;
3312 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3313 if(uErr) {
3314 return uErr;
3315 }
3316 return ExponentiateNN(nMantissa,
3317 pItem->val.expAndMantissa.nExponent,
3318 pnValue,
3319 Exponentitate10);
3320 } else {
3321 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3322 }
3323 break;
3324
3325 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
3326 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3327 int64_t nMantissa;
3328 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3329 if(uErr) {
3330 return uErr;
3331 }
3332 return ExponentiateNN(nMantissa,
3333 pItem->val.expAndMantissa.nExponent,
3334 pnValue,
3335 Exponentitate10);
3336 } else {
3337 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3338 }
3339 break;
3340
3341 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
3342 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3343 int64_t nMantissa;
3344 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3345 if(uErr) {
3346 return uErr;
3347 }
3348 return ExponentiateNN(nMantissa,
3349 pItem->val.expAndMantissa.nExponent,
3350 pnValue,
3351 Exponentitate2);
3352 } else {
3353 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3354 }
3355 break;
3356
3357 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
3358 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3359 int64_t nMantissa;
3360 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3361 if(uErr) {
3362 return uErr;
3363 }
3364 return ExponentiateNN(nMantissa,
3365 pItem->val.expAndMantissa.nExponent,
3366 pnValue,
3367 Exponentitate2);
3368 } else {
3369 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003370 }
3371 break;
3372
Laurence Lundbladec4537442020-04-14 18:53:22 -07003373 default:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003374 return QCBOR_ERR_UNEXPECTED_TYPE;
3375#endif
Laurence Lundbladec4537442020-04-14 18:53:22 -07003376 }
3377}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003378
3379
Laurence Lundbladec4537442020-04-14 18:53:22 -07003380/*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003381 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003382 */
3383void QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003384{
3385 QCBORItem Item;
3386
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003387 QCBORDecode_GetInt64ConvertInternal(pMe, uOptions, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003388
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003389 if(pMe->uLastError == QCBOR_SUCCESS) {
3390 // The above conversion succeeded
3391 return;
3392 }
3393
Laurence Lundbladef6c86662020-05-12 02:08:00 -07003394 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003395 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07003396 return;
3397 }
3398
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003399 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003400}
3401
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003402
3403/*
3404Public function, see header qcbor/qcbor_decode.h file
3405*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003406void QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, int64_t *pnValue)
3407{
3408 QCBORItem Item;
3409
3410 QCBORDecode_GetInt64ConvertInternalInMapN(pMe, nLabel, uOptions, pnValue, &Item);
3411
3412 if(pMe->uLastError == QCBOR_SUCCESS) {
3413 // The above conversion succeeded
3414 return;
3415 }
3416
3417 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3418 // The above conversion failed in a way that code below can't correct
3419 return;
3420 }
3421
3422 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
3423}
3424
3425
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003426/*
3427Public function, see header qcbor/qcbor_decode.h file
3428*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003429void QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, int64_t *pnValue)
3430{
3431 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003432 QCBORDecode_GetInt64ConvertInternalInMapSZ(pMe, szLabel, uOptions, pnValue, &Item);
3433
3434 if(pMe->uLastError == QCBOR_SUCCESS) {
3435 // The above conversion succeeded
3436 return;
3437 }
3438
3439 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3440 // The above conversion failed in a way that code below can't correct
3441 return;
3442 }
3443
3444 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
3445}
3446
3447
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003448static QCBORError ConvertUint64(const QCBORItem *pItem, uint32_t uOptions, uint64_t *puValue)
3449{
3450 switch(pItem->uDataType) {
3451 // TODO: type flaot
3452 case QCBOR_TYPE_DOUBLE:
3453 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3454 feclearexcept(FE_ALL_EXCEPT);
3455 double dRounded = round(pItem->val.dfnum);
3456 // TODO: over/underflow
3457 if(fetestexcept(FE_INVALID)) {
3458 // TODO: better error code
3459 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3460 } else if(isnan(dRounded)) {
3461 // TODO: better error code
3462 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3463 } else if(dRounded >= 0) {
3464 *puValue = (uint64_t)dRounded;
3465 } else {
3466 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3467 }
3468 } else {
3469 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3470 }
3471 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003472
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003473 case QCBOR_TYPE_INT64:
3474 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
3475 if(pItem->val.int64 >= 0) {
3476 *puValue = (uint64_t)pItem->val.int64;
3477 } else {
3478 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3479 }
3480 } else {
3481 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3482 }
3483 break;
3484
3485 case QCBOR_TYPE_UINT64:
3486 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
3487 *puValue = pItem->val.uint64;
3488 } else {
3489 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3490 }
3491 break;
3492
3493 default:
3494 return QCBOR_ERR_UNEXPECTED_TYPE;
3495 }
3496 return QCBOR_SUCCESS;
3497}
Laurence Lundbladec4537442020-04-14 18:53:22 -07003498
3499
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003500void QCBORDecode_GetUInt64ConvertInternal(QCBORDecodeContext *pMe,
3501 uint32_t uOptions,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003502 uint64_t *puValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003503 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003504{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003505 if(pMe->uLastError != QCBOR_SUCCESS) {
3506 return;
3507 }
3508
Laurence Lundbladec4537442020-04-14 18:53:22 -07003509 QCBORItem Item;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003510
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003511 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
3512 if(uError) {
3513 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003514 return;
3515 }
3516
Laurence Lundbladea826c502020-05-10 21:07:00 -07003517 if(pItem) {
3518 *pItem = Item;
3519 }
3520
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003521 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003522}
3523
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003524
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003525void QCBORDecode_GetInt8ConvertInternal(QCBORDecodeContext *pMe, uint32_t uOptions, int8_t *pnValue, QCBORItem *pItem)
3526{
3527 int64_t uValue;
3528 QCBORDecode_GetInt64ConvertInternal(pMe, uOptions, &uValue, pItem);
3529 if(pMe->uLastError != QCBOR_SUCCESS) {
3530 return;
3531 }
3532
3533 if(QCBOR_Int64ToInt8(uValue, pnValue)) {
3534 pMe->uLastError = QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3535 }
3536}
3537
3538void QCBORDecode_GetInt8ConvertInternalInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, int8_t *pnValue, QCBORItem *pItem)
3539{
3540 int64_t uValue;
3541 QCBORDecode_GetInt64ConvertInternalInMapN(pMe, nLabel, uOptions, &uValue, pItem);
3542 if(pMe->uLastError != QCBOR_SUCCESS) {
3543 return;
3544 }
3545
3546 if(QCBOR_Int64ToInt8(uValue, pnValue)) {
3547 pMe->uLastError = QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3548 }
3549}
3550
3551void QCBORDecode_GetInt8ConvertInternalInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, int8_t *pnValue, QCBORItem *pItem)
3552{
3553 int64_t uValue;
3554 QCBORDecode_GetInt64ConvertInternalInMapSZ(pMe, szLabel, uOptions, &uValue, pItem);
3555 if(pMe->uLastError != QCBOR_SUCCESS) {
3556 return;
3557 }
3558
3559 if(QCBOR_Int64ToInt8(uValue, pnValue)) {
3560 pMe->uLastError = QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3561 }
3562}
3563
3564
3565
3566
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003567void QCBORDecode_GetUint64ConvertInternalInMapN(QCBORDecodeContext *pMe,
3568 int64_t nLabel,
3569 uint32_t uOptions,
3570 uint64_t *puValue,
3571 QCBORItem *pItem)
3572{
3573 QCBORItem Item;
3574 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
3575
3576 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
3577}
3578
3579
3580void QCBORDecode_GetUint64ConvertInternalInMapSZ(QCBORDecodeContext *pMe,
3581 const char * szLabel,
3582 uint32_t uOptions,
3583 uint64_t *puValue,
3584 QCBORItem *pItem)
3585{
3586 if(pMe->uLastError != QCBOR_SUCCESS) {
3587 return;
3588 }
3589
3590 QCBORItem Item;
3591 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3592
3593 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
3594}
3595
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003596/*
3597 Public function, see header qcbor/qcbor_decode.h file
3598*/
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003599static QCBORError Uint64ConvertAll(const QCBORItem *pItem, uint32_t uOptions, uint64_t *puValue)
3600{
3601 QCBORError uErr;
3602
3603 switch(pItem->uDataType) {
3604
3605 case QCBOR_TYPE_POSBIGNUM:
3606 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3607 return ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
3608 } else {
3609 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3610 }
3611 break;
3612
3613 case QCBOR_TYPE_NEGBIGNUM:
3614 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3615 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3616 } else {
3617 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3618 }
3619 break;
3620
3621#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
3622
3623 case QCBOR_TYPE_DECIMAL_FRACTION:
3624 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3625 return ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
3626 pItem->val.expAndMantissa.nExponent,
3627 puValue,
3628 Exponentitate10);
3629 } else {
3630 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3631 }
3632 break;
3633
3634 case QCBOR_TYPE_BIGFLOAT:
3635 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3636 return ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
3637 pItem->val.expAndMantissa.nExponent,
3638 puValue,
3639 Exponentitate2);
3640 } else {
3641 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3642 }
3643 break;
3644
3645 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
3646 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3647 // TODO: Would be better to convert to unsigned
3648 int64_t nMantissa;
3649 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3650 if(uErr != QCBOR_SUCCESS) {
3651 return uErr;
3652 }
3653 return ExponentitateNU(nMantissa,
3654 pItem->val.expAndMantissa.nExponent,
3655 puValue,
3656 Exponentitate10);
3657 } else {
3658 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3659 }
3660 break;
3661
3662 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
3663 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3664 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3665 } else {
3666 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3667 }
3668 break;
3669
3670 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
3671 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3672 // TODO: Would be better to convert to unsigned
3673 int64_t nMantissa;
3674 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3675 if(uErr != QCBOR_SUCCESS) {
3676 return uErr;
3677 }
3678 return ExponentitateNU(nMantissa,
3679 pItem->val.expAndMantissa.nExponent,
3680 puValue,
3681 Exponentitate2);
3682 } else {
3683 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3684 }
3685 break;
3686
3687 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
3688 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3689 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3690 } else {
3691 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3692 }
3693 break;
3694#endif
3695 default:
3696 return QCBOR_ERR_UNEXPECTED_TYPE;
3697 }
3698}
3699
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003700/*
3701 Public function, see header qcbor/qcbor_decode.h file
3702*/
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003703void QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003704{
3705 QCBORItem Item;
3706
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003707 QCBORDecode_GetUInt64ConvertInternal(pMe, uOptions, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003708
Laurence Lundbladef6c86662020-05-12 02:08:00 -07003709 if(pMe->uLastError == QCBOR_SUCCESS) {
3710 // The above conversion succeeded
3711 return;
3712 }
3713
3714 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3715 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07003716 return;
3717 }
3718
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003719 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003720}
3721
Laurence Lundbladec4537442020-04-14 18:53:22 -07003722
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003723/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003724 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003725*/
3726void QCBORDecode_GetUint64ConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, uint64_t *puValue)
3727{
3728 QCBORItem Item;
3729
3730 QCBORDecode_GetUint64ConvertInternalInMapN(pMe, nLabel, uOptions, puValue, &Item);
3731
3732 if(pMe->uLastError == QCBOR_SUCCESS) {
3733 // The above conversion succeeded
3734 return;
3735 }
3736
3737 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3738 // The above conversion failed in a way that code below can't correct
3739 return;
3740 }
3741
3742 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
3743}
3744
3745
3746/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003747 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003748*/
3749void QCBORDecode_GetUint64ConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, uint64_t *puValue)
3750{
3751 QCBORItem Item;
3752 QCBORDecode_GetUint64ConvertInternalInMapSZ(pMe, szLabel, uOptions, puValue, &Item);
3753
3754 if(pMe->uLastError == QCBOR_SUCCESS) {
3755 // The above conversion succeeded
3756 return;
3757 }
3758
3759 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3760 // The above conversion failed in a way that code below can't correct
3761 return;
3762 }
3763
3764 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
3765}
3766
3767
3768static QCBORError ConvertDouble(const QCBORItem *pItem, uint32_t uOptions, double *pdValue)
3769{
3770 switch(pItem->uDataType) {
3771 // TODO: float when ifdefs are set
3772 case QCBOR_TYPE_DOUBLE:
3773 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3774 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3775 *pdValue = pItem->val.dfnum;
3776 } else {
3777 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3778 }
3779 }
3780 break;
3781
3782 case QCBOR_TYPE_INT64:
3783 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
3784 // TODO: how does this work?
3785 *pdValue = (double)pItem->val.int64;
3786
3787 } else {
3788 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3789 }
3790 break;
3791
3792 case QCBOR_TYPE_UINT64:
3793 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
3794 *pdValue = (double)pItem->val.uint64;
3795 } else {
3796 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3797 }
3798 break;
3799
3800 default:
3801 return QCBOR_ERR_UNEXPECTED_TYPE;
3802 }
3803
3804 return QCBOR_SUCCESS;
3805}
3806
3807
3808
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003809void QCBORDecode_GetDoubleConvertInternal(QCBORDecodeContext *pMe,
3810 uint32_t uOptions,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003811 double *pdValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003812 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003813{
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003814 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003815 return;
3816 }
3817
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003818 QCBORItem Item;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003819
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003820 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003821 if(uError) {
3822 pMe->uLastError = (uint8_t)uError;
3823 return;
3824 }
3825
3826 if(pItem) {
3827 *pItem = Item;
3828 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07003829
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003830 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003831}
Laurence Lundbladec4537442020-04-14 18:53:22 -07003832
Laurence Lundbladec4537442020-04-14 18:53:22 -07003833
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003834void QCBORDecode_GetDoubleConvertInternalInMapN(QCBORDecodeContext *pMe,
3835 int64_t nLabel,
3836 uint32_t uOptions,
3837 double *pdValue,
3838 QCBORItem *pItem)
3839{
3840 QCBORItem Item;
3841 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
3842
3843 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
3844}
3845
3846void QCBORDecode_GetDoubleConvertInternalInMapSZ(QCBORDecodeContext *pMe,
3847 const char * szLabel,
3848 uint32_t uOptions,
3849 double *pdValue,
3850 QCBORItem *pItem)
3851{
3852 if(pMe->uLastError != QCBOR_SUCCESS) {
3853 return;
3854 }
3855
3856 QCBORItem Item;
3857 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3858
3859 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
3860}
3861
3862
3863
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003864static double ConvertBigNumToDouble(const UsefulBufC BigNum)
3865{
3866 double dResult;
3867
3868 dResult = 0.0;
3869 const uint8_t *pByte = BigNum.ptr;
3870 size_t uLen = BigNum.len;
3871 /* This will overflow and become the float value INFINITY if the number
3872 is too large to fit. No error will be logged.
3873 TODO: should an error be logged? */
3874 while(uLen--) {
3875 dResult = (dResult * 256.0) + (double)*pByte++;
3876 }
3877
3878 return dResult;
3879}
3880
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003881static QCBORError DoubleConvertAll(const QCBORItem *pItem, uint32_t uOptions, double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003882{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003883 /*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003884 https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
3885
3886 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003887 switch(pItem->uDataType) {
3888 // TODO: type float
3889 case QCBOR_TYPE_DECIMAL_FRACTION:
3890 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3891 // TODO: rounding and overflow errors
3892 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
3893 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
3894 } else {
3895 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3896 }
3897 break;
3898
3899 case QCBOR_TYPE_BIGFLOAT:
3900 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
3901 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
3902 exp2((double)pItem->val.expAndMantissa.nExponent);
3903 } else {
3904 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3905 }
3906 break;
3907
3908 case QCBOR_TYPE_POSBIGNUM:
3909 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3910 *pdValue = ConvertBigNumToDouble(pItem->val.bigNum);
3911 } else {
3912 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3913 }
3914 break;
3915
3916 case QCBOR_TYPE_NEGBIGNUM:
3917 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07003918 *pdValue = -1-ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003919 } else {
3920 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3921 }
3922 break;
3923
3924 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
3925 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3926 double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
3927 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
3928 } else {
3929 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3930 }
3931 break;
3932
3933 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
3934 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3935 double dMantissa = -ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
3936 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
3937 } else {
3938 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3939 }
3940 break;
3941
3942 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
3943 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3944 double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
3945 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
3946 } else {
3947 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3948 }
3949 break;
3950
3951 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
3952 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07003953 double dMantissa = -1-ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003954 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
3955 } else {
3956 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3957 }
3958 break;
3959
3960 default:
3961 return QCBOR_ERR_UNEXPECTED_TYPE;
3962 }
3963
3964 return QCBOR_SUCCESS;
3965}
3966
3967
3968/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003969 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003970*/
3971void QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, double *pdValue)
3972{
3973
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003974 QCBORItem Item;
3975
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003976 QCBORDecode_GetDoubleConvertInternal(pMe, uOptions, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003977
3978 if(pMe->uLastError == QCBOR_SUCCESS) {
3979 // The above conversion succeeded
3980 return;
3981 }
3982
3983 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3984 // The above conversion failed in a way that code below can't correct
3985 return;
3986 }
3987
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003988 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003989}
3990
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003991
3992/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003993 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003994*/
3995void QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, double *pdValue)
3996{
3997 QCBORItem Item;
3998
3999 QCBORDecode_GetDoubleConvertInternalInMapN(pMe, nLabel, uOptions, pdValue, &Item);
4000
4001 if(pMe->uLastError == QCBOR_SUCCESS) {
4002 // The above conversion succeeded
4003 return;
4004 }
4005
4006 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
4007 // The above conversion failed in a way that code below can't correct
4008 return;
4009 }
4010
4011 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
4012}
4013
4014
4015/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004016 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004017*/
4018void QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, double *pdValue)
4019{
4020 QCBORItem Item;
4021 QCBORDecode_GetDoubleConvertInternalInMapSZ(pMe, szLabel, uOptions, pdValue, &Item);
4022
4023 if(pMe->uLastError == QCBOR_SUCCESS) {
4024 // The above conversion succeeded
4025 return;
4026 }
4027
4028 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
4029 // The above conversion failed in a way that code below can't correct
4030 return;
4031 }
4032
4033 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
4034}
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004035
4036
4037void FarfDecimalFraction(QCBORDecodeContext *pMe,
4038 uint8_t uTagRequirement,
4039 QCBORItem *pItem,
4040 int64_t *pnMantissa,
4041 int64_t *pnExponent)
4042{
4043 QCBORError uErr;
4044
4045 if(pItem->uDataType == QCBOR_TYPE_ARRAY) {
4046 if(uTagRequirement == QCBOR_TAGSPEC_MATCH_TAG_CONTENT_TYPE) {
4047 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4048 return;
4049 }
4050 uErr = QCBORDecode_MantissaAndExponent(pMe, pItem);
4051 if(uErr != QCBOR_SUCCESS) {
4052 pMe->uLastError = (uint8_t)uErr;
4053 return;
4054 }
4055 }
4056
4057 if(uTagRequirement == QCBOR_TAGSPEC_MATCH_TAG_CONTENT_TYPE) {
4058 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4059 return;
4060 }
4061
4062 switch (pItem->uDataType) {
4063
4064 case QCBOR_TYPE_DECIMAL_FRACTION:
4065 *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
4066 *pnExponent = pItem->val.expAndMantissa.nExponent;
4067 break;
4068
4069 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
4070 *pnExponent = pItem->val.expAndMantissa.nExponent;
4071
4072 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
4073 if(uErr != QCBOR_SUCCESS) {
4074 pMe->uLastError = (uint8_t)uErr;
4075 }
4076 break;
4077
4078 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
4079 *pnExponent = pItem->val.expAndMantissa.nExponent;
4080
4081 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
4082 if(uErr != QCBOR_SUCCESS) {
4083 pMe->uLastError = (uint8_t)uErr;
4084 }
4085 break;
4086
4087 default:
4088 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4089 }
4090}
4091
4092void QCBORDecode_GetDecimalFractionN(QCBORDecodeContext *pMe,
4093 uint8_t uTagRequirement,
4094 int64_t nLabel,
4095 int64_t *pnMantissa,
4096 int64_t *pnExponent)
4097{
4098 QCBORItem Item;
4099
4100 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
4101 FarfDecimalFraction(pMe, uTagRequirement, &Item, pnMantissa, pnExponent);
4102}
4103
4104
4105
4106void QCBORDecode_GetDecimalFractionSZ(QCBORDecodeContext *pMe,
4107 uint8_t uTagRequirement,
4108 const char *szLabel,
4109 int64_t *pnMantissa,
4110 int64_t *pnExponent)
4111{
4112 QCBORItem Item;
4113
4114 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4115
4116 FarfDecimalFraction(pMe, uTagRequirement, &Item, pnMantissa, pnExponent);
4117}
4118
4119
4120UsefulBufC ConvertIntToBigNum(uint64_t uInt, UsefulBuf Buffer)
4121{
4122 while(uInt & 0xff0000000000UL) {
4123 uInt = uInt << 8;
4124 };
4125
4126 UsefulOutBuf UOB;
4127
4128 UsefulOutBuf_Init(&UOB, Buffer);
4129
4130 while(uInt) {
4131 UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff0000000000UL) >> 56));
4132 uInt = uInt << 8;
4133 }
4134
4135 return UsefulOutBuf_OutUBuf(&UOB);
4136}
4137
4138
4139void QCBORDecode_GetDecimalFractionBigN(QCBORDecodeContext *pMe,
4140 uint8_t uTagRequirement,
4141 int64_t nLabel,
4142 UsefulBuf pBufferForMantissa,
4143 UsefulBufC *pMantissa,
4144 bool *pbIsNegative,
4145 int64_t *pnExponent)
4146{
4147 QCBORItem Item;
4148 QCBORError uErr;
4149
4150 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
4151
4152 if(Item.uDataType == QCBOR_TYPE_ARRAY) {
4153 uErr = QCBORDecode_MantissaAndExponent(pMe, &Item);
4154 if(uErr != QCBOR_SUCCESS) {
4155 pMe->uLastError = (uint8_t)uErr;
4156 return;
4157 }
4158 }
4159
4160 uint64_t uMantissa;
4161
4162 switch (Item.uDataType) {
4163
4164 case QCBOR_TYPE_DECIMAL_FRACTION:
4165 if(Item.val.expAndMantissa.Mantissa.nInt >= 0) {
4166 uMantissa = (uint64_t)Item.val.expAndMantissa.Mantissa.nInt;
4167 *pbIsNegative = false;
4168 } else {
4169 uMantissa = (uint64_t)-Item.val.expAndMantissa.Mantissa.nInt;
4170 *pbIsNegative = true;
4171 }
4172 *pMantissa = ConvertIntToBigNum(uMantissa, pBufferForMantissa);
4173 *pnExponent = Item.val.expAndMantissa.nExponent;
4174 break;
4175
4176 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
4177 *pnExponent = Item.val.expAndMantissa.nExponent;
4178 *pMantissa = Item.val.expAndMantissa.Mantissa.bigNum;
4179 *pbIsNegative = false;
4180 break;
4181
4182 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
4183 *pnExponent = Item.val.expAndMantissa.nExponent;
4184 *pMantissa = Item.val.expAndMantissa.Mantissa.bigNum;
4185 *pbIsNegative = true;
4186 break;
4187
4188 default:
4189 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4190 }
4191}