blob: f58c6c388d8da2dfd109edb9841aee337b773996 [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++) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -0700400 me->auMappedTags[i] = CBOR_TAG_INVALID16;
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700401 }
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
Laurence Lundbladec75e68b2020-06-15 20:34:46 -0700945 uint16_t auTags[QCBOR_MAX_TAGS_PER_ITEM] = {CBOR_TAG_INVALID16,
946 CBOR_TAG_INVALID16,
947 CBOR_TAG_INVALID16,
948 CBOR_TAG_INVALID16};
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700949
Laurence Lundblade59289e52019-12-30 13:44:37 -0800950 // Loop fetching items until the item fetched is not a tag
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700951 for(;;) {
952 nReturn = GetNext_FullItem(me, pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700953 if(nReturn) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700954 goto Done; // Error out of the loop
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700955 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800956
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700957 if(pDecodedItem->uDataType != QCBOR_TYPE_OPTTAG) {
958 // Successful exit from loop; maybe got some tags, maybe not
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700959 memcpy(pDecodedItem->uTags, auTags, sizeof(auTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700960 break;
961 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800962
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700963 // Is there room for the tag in the tags list?
964 size_t uTagIndex;
965 for(uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -0700966 if(auTags[uTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700967 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700968 }
969 }
970 if(uTagIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -0700971 return QCBOR_ERR_TOO_MANY_TAGS;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700972 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800973
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700974 // Is the tag > 16 bits?
Laurence Lundbladec75e68b2020-06-15 20:34:46 -0700975 if(pDecodedItem->val.uTagV > CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700976 size_t uTagMapIndex;
977 // Is there room in the tag map?
978 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -0700979 if(me->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700980 break;
981 }
982 if(me->auMappedTags[uTagMapIndex] == pDecodedItem->val.uTagV) {
983 break;
984 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700985 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700986 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
987 // No room for the tag
988 return 97; // TODO error code
989 }
990
991 // Cover the case where tag is new and were it is already in the map
992 me->auMappedTags[uTagMapIndex] = pDecodedItem->val.uTagV;
993 auTags[uTagIndex] = (uint16_t)(uTagMapIndex + 0xfff0); // TODO proper constant and cast
994
995 } else {
996 auTags[uTagIndex] = (uint16_t)pDecodedItem->val.uTagV;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700997 }
998 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800999
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001000Done:
1001 return nReturn;
1002}
1003
1004
1005/*
Laurence Lundbladeee851742020-01-08 08:37:05 -08001006 This layer takes care of map entries. It combines the label and data
1007 items into one QCBORItem.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001008 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001009static inline QCBORError
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001010GetNext_MapEntry(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001011{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001012 // Stack use: int/ptr 1, QCBORItem -- 56
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001013 QCBORError nReturn = GetNext_TaggedItem(me, pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001014 if(nReturn)
1015 goto Done;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001016
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001017 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001018 // Break can't be a map entry
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001019 goto Done;
1020 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001021
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001022 if(me->uDecodeMode != QCBOR_DECODE_MODE_MAP_AS_ARRAY) {
1023 // In a map and caller wants maps decoded, not treated as arrays
1024
1025 if(DecodeNesting_TypeIsMap(&(me->nesting))) {
1026 // If in a map and the right decoding mode, get the label
1027
Laurence Lundbladeee851742020-01-08 08:37:05 -08001028 // Save label in pDecodedItem and get the next which will
1029 // be the real data
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001030 QCBORItem LabelItem = *pDecodedItem;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001031 nReturn = GetNext_TaggedItem(me, pDecodedItem);
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001032 if(nReturn)
1033 goto Done;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001034
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301035 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001036
1037 if(LabelItem.uDataType == QCBOR_TYPE_TEXT_STRING) {
1038 // strings are always good labels
1039 pDecodedItem->label.string = LabelItem.val.string;
1040 pDecodedItem->uLabelType = QCBOR_TYPE_TEXT_STRING;
1041 } else if (QCBOR_DECODE_MODE_MAP_STRINGS_ONLY == me->uDecodeMode) {
Laurence Lundbladeee851742020-01-08 08:37:05 -08001042 // It's not a string and we only want strings
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001043 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
1044 goto Done;
1045 } else if(LabelItem.uDataType == QCBOR_TYPE_INT64) {
1046 pDecodedItem->label.int64 = LabelItem.val.int64;
1047 pDecodedItem->uLabelType = QCBOR_TYPE_INT64;
1048 } else if(LabelItem.uDataType == QCBOR_TYPE_UINT64) {
1049 pDecodedItem->label.uint64 = LabelItem.val.uint64;
1050 pDecodedItem->uLabelType = QCBOR_TYPE_UINT64;
1051 } else if(LabelItem.uDataType == QCBOR_TYPE_BYTE_STRING) {
1052 pDecodedItem->label.string = LabelItem.val.string;
1053 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
1054 pDecodedItem->uLabelType = QCBOR_TYPE_BYTE_STRING;
1055 } else {
1056 // label is not an int or a string. It is an arrray
1057 // or a float or such and this implementation doesn't handle that.
1058 // Also, tags on labels are ignored.
1059 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
1060 goto Done;
1061 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001062 }
1063 } else {
1064 if(pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001065 if(pDecodedItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
1066 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
1067 goto Done;
1068 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001069 // Decoding a map as an array
1070 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001071 // Cast is safe because of check against QCBOR_MAX_ITEMS_IN_ARRAY/2
1072 // Cast is needed because of integer promotion
1073 pDecodedItem->val.uCount = (uint16_t)(pDecodedItem->val.uCount * 2);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001074 }
1075 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001076
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001077Done:
1078 return nReturn;
1079}
1080
1081
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001082static QCBORError
1083NextIsBreak(UsefulInputBuf *pUIB, bool *pbNextIsBreak)
1084{
1085 *pbNextIsBreak = false;
1086 if(UsefulInputBuf_BytesUnconsumed(pUIB) != 0) {
1087 // TODO: use the Peek method?
1088 QCBORItem Peek;
1089 size_t uPeek = UsefulInputBuf_Tell(pUIB);
1090 QCBORError uReturn = GetNext_Item(pUIB, &Peek, NULL);
1091 if(uReturn != QCBOR_SUCCESS) {
1092 return uReturn;
1093 }
1094 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
1095 // It is not a break, rewind so it can be processed normally.
1096 UsefulInputBuf_Seek(pUIB, uPeek);
1097 } else {
1098 *pbNextIsBreak = true;
1099 }
1100 }
1101
1102 return QCBOR_SUCCESS;
1103}
1104
1105
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001106/*
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001107 An item was just consumed, now figure out if it was the
1108 end of an array or map that can be closed out. That
1109 may in turn close out another map or array.
1110 */
1111static QCBORError Ascender(QCBORDecodeContext *pMe)
1112{
1113 QCBORError uReturn;
1114
1115 /* This loops ascending nesting levels as long as there is ascending to do */
1116 while(1) {
1117 if(!DecodeNesting_IsAtTop(&(pMe->nesting)) && !DecodeNesting_IsIndefiniteLength(&(pMe->nesting))) {
1118 /* 1st Case: in a definite length array (not a CBOR sequence). Simply
1119 decrement the item count. If it doesn't go to zero, then all is done.
1120 If it does go to zero, the bottom of the loop ascends one nesting level
1121 and the loop continues.
1122 */
1123 DecodeNesting_DecrementX(&(pMe->nesting));
1124 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
1125 /* Didn't close out map or array; all work here is done */
1126 break;
1127 }
1128
1129 } else {
1130 /* 2nd, 3rd, 4th and 5th cases where a check for a following CBOR break must be checked for */
1131 bool bIsBreak = false;
1132 uReturn = NextIsBreak(&(pMe->InBuf), &bIsBreak);
1133 if(uReturn != QCBOR_SUCCESS) {
1134 goto Done;
1135 }
1136
1137 if(bIsBreak) {
1138 if(DecodeNesting_IsAtTop(&(pMe->nesting))) {
1139 /* 2nd case where a break occurs at the top level and thus
1140 in a CBOR sequence. Always an error because break is
1141 not inside an indefinite length map or array. */
1142 uReturn = QCBOR_ERR_BAD_BREAK;
1143 goto Done;
1144 } else {
1145 /* 3rd case, the normal end of an indefinite length map
1146 or array. The bottom of the loop ascends one nesting
1147 level and the loop continues. */
1148 }
1149 } else {
1150 /* 4th case where an indefinite length array is not closed out
1151 and 5th case which is just an item in a CBOR sequence. In either
1152 there is no close out so all work here is done.
1153 */
1154 break;
1155 }
1156 }
1157
1158 /* All items in the level have been consumed. */
1159
1160 /* But ascent in bounded mode is only by explicit call to QCBORDecode_ExitBoundedMode() */
1161 if(DecodeNesting_InBoundedMode(&(pMe->nesting))) {
1162 /* Set the count to zero for indefinite length arrays to indicate cursor is at end of bounded map / array */
1163 pMe->nesting.pCurrent->uCount = 0;
1164 break;
1165 }
1166
1167 /* Finally, actually ascend one level. */
1168 DecodeNesting_Ascend(&(pMe->nesting));
1169 }
1170
1171 uReturn = QCBOR_SUCCESS;
1172
1173Done:
1174 return uReturn;
1175}
1176
1177
1178/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001179 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001180 TODO: correct this comment
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001181 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001182static QCBORError
1183QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001184{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001185 QCBORError uReturn;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001186 /* === First figure out if at the end of traversal === */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001187
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001188 /* Case 1. Out of bytes to consume.
1189
1190 This is either the end of the top-level CBOR that was give
1191 to QCBORDecode_Init() or the end of a tag 24 bstr wrapped CBOR.
1192 It is detected by all bytes being consumed from the UsefulInputBuf.
1193
1194 To go back out of the tag 24 bstr wrapped item, the caller must
1195 explicitly call Exit() which will reset the UsefulInputBuf
1196 to the next highest bstr wrapped or the top level.
1197
1198 This is always the end condition that QCBORDecode_Finish()
1199 considers complete.
1200
1201 TODO: can the DecodeNesting_IsAtTop be removed? QCBORDecode_Finish()
1202 will perform this check.
1203
1204 */
Laurence Lundblade937ea812020-05-08 11:38:23 -07001205 /* For a pre-order traversal a non-error end occurs when there
1206 are no more bytes to consume and the nesting level is at the top.
1207 If it's not at the top, then the CBOR is not well formed. This error
1208 is caught elsewhere.
1209
1210 This handles the end of CBOR sequences as well as non-sequences. */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001211 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf)) == 0 && DecodeNesting_IsAtTop(&(me->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001212 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001213 goto Done;
1214 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07001215
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001216
1217 /* Case 2. End of map or array in bounded mode
1218
1219 The caller is attempting traveral of a bounded map or array and
1220 has got to the end of it.
1221
1222 The caller must explicitly exit the bounded mode map or array
1223 to get past this condition.
1224
1225 To complete a decode of the full input CBOR, the caller must
1226 exit all maps and arrays in bounded mode and this is never
1227 the successful end of decoding.
1228
1229 */
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001230 /* It is also an end of the input when in map mode and the cursor
Laurence Lundblade937ea812020-05-08 11:38:23 -07001231 is at the end of the map */
1232
1233
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001234 // This is to handle bounded mode
Laurence Lundblade937ea812020-05-08 11:38:23 -07001235 if(DecodeNesting_AtEnd(&(me->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001236 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07001237 goto Done;
1238 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001239
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001240 /* === Not at the end; get another item === */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001241 uReturn = GetNext_MapEntry(me, pDecodedItem);
1242 if(uReturn) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001243 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001244 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301245
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001246 // Breaks ending arrays/maps are always processed at the end of this function.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301247 // They should never show up here.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301248 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001249 uReturn = QCBOR_ERR_BAD_BREAK;
Laurence Lundblade6de37062018-10-15 12:22:42 +05301250 goto Done;
Laurence Lundblade5b8c5852018-10-14 21:11:42 +05301251 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001252
Laurence Lundblade6de37062018-10-15 12:22:42 +05301253 // Record the nesting level for this data item before processing any of
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301254 // decrementing and descending.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301255 pDecodedItem->uNestingLevel = DecodeNesting_GetLevel(&(me->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001256
Laurence Lundblade6de37062018-10-15 12:22:42 +05301257 // Process the item just received for descent or decrement, and
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001258 // ascend if decrements are enough to close out a definite length array/map
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001259 if(IsMapOrArray(pDecodedItem->uDataType) && pDecodedItem->val.uCount != 0) {
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001260 // If the new item is array or map, the nesting level descends
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001261 uReturn = DecodeNesting_Descend(&(me->nesting), pDecodedItem->uDataType, pDecodedItem->val.uCount, 0L);
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001262 // Maps and arrays do count in as items in the map/array that encloses
1263 // them so a decrement needs to be done for them too, but that is done
1264 // only when all the items in them have been processed, not when they
Laurence Lundblade9916b1b2019-09-07 22:33:25 -07001265 // are opened with the exception of an empty map or array.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001266 if(uReturn != QCBOR_SUCCESS) {
1267 goto Done;
1268 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001269 }
1270
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001271 if(!IsMapOrArray(pDecodedItem->uDataType) ||
1272 pDecodedItem->val.uCount == 0 || pDecodedItem->val.uCount == UINT16_MAX) {
1273 /* The following cases are handled here:
1274 - A non-aggregate like an integer or string
1275 - An empty definite length map or array
1276 - An indefinite length map or array that might be empty or might not.
1277 */
1278
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001279
1280
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001281 /* === Figure out if item got closed out maps or arrays === */
1282
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001283 /*
1284 This needs to decrement, check for end and ascend
1285 the tree until an an ascend is not possible or the bounded
1286 limit is reached or the end of the encoded CBOR input
1287 is reached. For
1288 definite length maps and arrays the end is by count. For
1289 indefinite it is by a break.
1290
1291 Also state needs to be set that can tell the code at the
1292 beginning of this function that the end was reached.
1293
1294 This is complicated...
1295
1296
1297 This will handle an indefinite length array
1298 inside a definte length array inside an indefinite
1299 length array...
1300
1301 */
1302
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001303 // Decrement the count of items in the enclosing map/array
1304 // If the count in the enclosing map/array goes to zero, that
Laurence Lundblade6de37062018-10-15 12:22:42 +05301305 // triggers a decrement in the map/array above that and
1306 // an ascend in nesting level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001307 /* If the just consumed item is at the end of a map or
1308 array ascend in the nesting tracking. That may
1309 in turn may be the end of the above nesting level
1310 and so on up to the end of the whole encoded CBOR.
1311
1312 Each level could be a definite or indefinte length
1313 map or array. These are handled very differently.
1314
1315 */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001316 uReturn = Ascender(me);
1317 if(uReturn) {
1318 goto Done;
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001319 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05301320 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001321
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001322
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001323
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001324 /* === Tell the caller the nest level of the next item === */
1325
Laurence Lundblade6de37062018-10-15 12:22:42 +05301326 // Tell the caller what level is next. This tells them what maps/arrays
1327 // were closed out and makes it possible for them to reconstruct
1328 // the tree with just the information returned by GetNext
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07001329 // TODO: pull this into DecodeNesting_GetLevel
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001330 if(DecodeNesting_InBoundedMode(&(me->nesting)) && me->nesting.pCurrent->uCount == 0) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001331 // At end of a map / array in map mode, so next nest is 0 to
1332 // indicate this end.
1333 pDecodedItem->uNextNestLevel = 0;
1334 } else {
1335 pDecodedItem->uNextNestLevel = DecodeNesting_GetLevel(&(me->nesting));
1336 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001337
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001338Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001339 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundbladee9482dd2019-10-11 12:58:46 -07001340 // Make sure uDataType and uLabelType are QCBOR_TYPE_NONE
1341 memset(pDecodedItem, 0, sizeof(QCBORItem));
1342 }
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001343 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001344}
1345
1346
Laurence Lundblade59289e52019-12-30 13:44:37 -08001347/*
1348 Mostly just assign the right data type for the date string.
1349 */
1350inline static QCBORError DecodeDateString(QCBORItem *pDecodedItem)
1351{
1352 // Stack Use: UsefulBuf 1 16
1353 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1354 return QCBOR_ERR_BAD_OPT_TAG;
1355 }
1356
1357 const UsefulBufC Temp = pDecodedItem->val.string;
1358 pDecodedItem->val.dateString = Temp;
1359 pDecodedItem->uDataType = QCBOR_TYPE_DATE_STRING;
1360 return QCBOR_SUCCESS;
1361}
1362
1363
1364/*
Laurence Lundbladeee851742020-01-08 08:37:05 -08001365 The epoch formatted date. Turns lots of different forms of encoding
1366 date into uniform one
Laurence Lundblade59289e52019-12-30 13:44:37 -08001367 */
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001368static QCBORError DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08001369{
1370 // Stack usage: 1
1371 QCBORError nReturn = QCBOR_SUCCESS;
1372
1373 pDecodedItem->val.epochDate.fSecondsFraction = 0;
1374
1375 switch (pDecodedItem->uDataType) {
1376
1377 case QCBOR_TYPE_INT64:
1378 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
1379 break;
1380
1381 case QCBOR_TYPE_UINT64:
1382 if(pDecodedItem->val.uint64 > INT64_MAX) {
1383 nReturn = QCBOR_ERR_DATE_OVERFLOW;
1384 goto Done;
1385 }
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001386 pDecodedItem->val.epochDate.nSeconds = (int64_t)pDecodedItem->val.uint64;
Laurence Lundblade59289e52019-12-30 13:44:37 -08001387 break;
1388
1389 case QCBOR_TYPE_DOUBLE:
1390 {
1391 // This comparison needs to be done as a float before
1392 // conversion to an int64_t to be able to detect doubles
1393 // that are too large to fit into an int64_t. A double
1394 // has 52 bits of preceision. An int64_t has 63. Casting
1395 // INT64_MAX to a double actually causes a round up which
1396 // is bad and wrong for the comparison because it will
1397 // allow conversion of doubles that can't fit into a
1398 // uint64_t. To remedy this INT64_MAX - 0x7ff is used as
1399 // the cutoff point as if that rounds up in conversion to
1400 // double it will still be less than INT64_MAX. 0x7ff is
1401 // picked because it has 11 bits set.
1402 //
1403 // INT64_MAX seconds is on the order of 10 billion years,
1404 // and the earth is less than 5 billion years old, so for
1405 // most uses this conversion error won't occur even though
1406 // doubles can go much larger.
1407 //
1408 // Without the 0x7ff there is a ~30 minute range of time
1409 // values 10 billion years in the past and in the future
1410 // where this this code would go wrong.
1411 const double d = pDecodedItem->val.dfnum;
1412 if(d > (double)(INT64_MAX - 0x7ff)) {
1413 nReturn = QCBOR_ERR_DATE_OVERFLOW;
1414 goto Done;
1415 }
1416 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
1417 pDecodedItem->val.epochDate.fSecondsFraction = d - (double)pDecodedItem->val.epochDate.nSeconds;
1418 }
1419 break;
1420
1421 default:
1422 nReturn = QCBOR_ERR_BAD_OPT_TAG;
1423 goto Done;
1424 }
1425 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
1426
1427Done:
1428 return nReturn;
1429}
1430
1431
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001432/*
1433 Mostly just assign the right data type for the bignum.
1434 */
1435inline static QCBORError DecodeBigNum(QCBORItem *pDecodedItem)
1436{
1437 // Stack Use: UsefulBuf 1 -- 16
1438 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1439 return QCBOR_ERR_BAD_OPT_TAG;
1440 }
1441 const UsefulBufC Temp = pDecodedItem->val.string;
1442 pDecodedItem->val.bigNum = Temp;
1443 const bool bIsPosBigNum = (bool)(pDecodedItem->uTags[0] == CBOR_TAG_POS_BIGNUM);
1444 pDecodedItem->uDataType = (uint8_t)(bIsPosBigNum ? QCBOR_TYPE_POSBIGNUM
1445 : QCBOR_TYPE_NEGBIGNUM);
1446 return QCBOR_SUCCESS;
1447}
1448
1449
Laurence Lundblade59289e52019-12-30 13:44:37 -08001450#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
1451/*
1452 Decode decimal fractions and big floats.
1453
1454 When called pDecodedItem must be the array that is tagged as a big
1455 float or decimal fraction, the array that has the two members, the
1456 exponent and mantissa.
1457
1458 This will fetch and decode the exponent and mantissa and put the
1459 result back into pDecodedItem.
1460 */
1461inline static QCBORError
1462QCBORDecode_MantissaAndExponent(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
1463{
1464 QCBORError nReturn;
1465
1466 // --- Make sure it is an array; track nesting level of members ---
1467 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
1468 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1469 goto Done;
1470 }
1471
1472 // A check for pDecodedItem->val.uCount == 2 would work for
Laurence Lundbladeee851742020-01-08 08:37:05 -08001473 // definite length arrays, but not for indefnite. Instead remember
1474 // the nesting level the two integers must be at, which is one
1475 // deeper than that of the array.
Laurence Lundblade59289e52019-12-30 13:44:37 -08001476 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
1477
1478 // --- Is it a decimal fraction or a bigfloat? ---
1479 const bool bIsTaggedDecimalFraction = QCBORDecode_IsTagged(me, pDecodedItem, CBOR_TAG_DECIMAL_FRACTION);
1480 pDecodedItem->uDataType = bIsTaggedDecimalFraction ? QCBOR_TYPE_DECIMAL_FRACTION : QCBOR_TYPE_BIGFLOAT;
1481
1482 // --- Get the exponent ---
1483 QCBORItem exponentItem;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001484 nReturn = QCBORDecode_GetNextMapOrArray(me, &exponentItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001485 if(nReturn != QCBOR_SUCCESS) {
1486 goto Done;
1487 }
1488 if(exponentItem.uNestingLevel != nNestLevel) {
1489 // Array is empty or a map/array encountered when expecting an int
1490 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1491 goto Done;
1492 }
1493 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
1494 // Data arriving as an unsigned int < INT64_MAX has been converted
1495 // to QCBOR_TYPE_INT64 and thus handled here. This is also means
1496 // that the only data arriving here of type QCBOR_TYPE_UINT64 data
1497 // will be too large for this to handle and thus an error that will
1498 // get handled in the next else.
1499 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
1500 } else {
1501 // Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX
1502 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1503 goto Done;
1504 }
1505
1506 // --- Get the mantissa ---
1507 QCBORItem mantissaItem;
1508 nReturn = QCBORDecode_GetNextWithTags(me, &mantissaItem, NULL);
1509 if(nReturn != QCBOR_SUCCESS) {
1510 goto Done;
1511 }
1512 if(mantissaItem.uNestingLevel != nNestLevel) {
1513 // Mantissa missing or map/array encountered when expecting number
1514 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1515 goto Done;
1516 }
1517 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
1518 // Data arriving as an unsigned int < INT64_MAX has been converted
1519 // to QCBOR_TYPE_INT64 and thus handled here. This is also means
1520 // that the only data arriving here of type QCBOR_TYPE_UINT64 data
1521 // will be too large for this to handle and thus an error that
1522 // will get handled in an else below.
1523 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
1524 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM || mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
1525 // Got a good big num mantissa
1526 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
1527 // Depends on numbering of QCBOR_TYPE_XXX
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001528 pDecodedItem->uDataType = (uint8_t)(pDecodedItem->uDataType +
1529 mantissaItem.uDataType - QCBOR_TYPE_POSBIGNUM +
1530 1);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001531 } else {
1532 // Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX
1533 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1534 goto Done;
1535 }
1536
1537 // --- Check that array only has the two numbers ---
1538 if(mantissaItem.uNextNestLevel == nNestLevel) {
1539 // Extra items in the decimal fraction / big num
1540 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1541 goto Done;
1542 }
1543
1544Done:
1545
1546 return nReturn;
1547}
1548#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
1549
1550
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001551
1552/*
1553 */
1554inline static QCBORError DecodeURI(QCBORItem *pDecodedItem)
1555{
1556 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1557 return QCBOR_ERR_BAD_OPT_TAG;
1558 }
1559 pDecodedItem->uDataType = QCBOR_TYPE_URI;
1560 return QCBOR_SUCCESS;
1561}
1562
1563
1564inline static QCBORError DecodeB64URL(QCBORItem *pDecodedItem)
1565{
1566 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1567 return QCBOR_ERR_BAD_OPT_TAG;
1568 }
1569 pDecodedItem->uDataType = QCBOR_TYPE_BASE64URL;
1570 return QCBOR_SUCCESS;
1571}
1572
1573
1574inline static QCBORError DecodeB64(QCBORItem *pDecodedItem)
1575{
1576 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1577 return QCBOR_ERR_BAD_OPT_TAG;
1578 }
1579 pDecodedItem->uDataType = QCBOR_TYPE_BASE64;
1580 return QCBOR_SUCCESS;
1581}
1582
1583
1584inline static QCBORError DecodeRegex(QCBORItem *pDecodedItem)
1585{
1586 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1587 return QCBOR_ERR_BAD_OPT_TAG;
1588 }
1589 pDecodedItem->uDataType = QCBOR_TYPE_REGEX;
1590 return QCBOR_SUCCESS;
1591}
1592
1593
1594inline static QCBORError DecodeMIME(QCBORItem *pDecodedItem)
1595{
1596 if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) {
1597 pDecodedItem->uDataType = QCBOR_TYPE_MIME;
1598 } else if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1599 pDecodedItem->uDataType = QCBOR_TYPE_BINARY_MIME;
1600 } else {
1601 return QCBOR_ERR_BAD_OPT_TAG;
1602 }
1603 return QCBOR_SUCCESS;
1604}
1605
1606
1607/*
1608 */
1609inline static QCBORError DecodeUUID(QCBORItem *pDecodedItem)
1610{
1611 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1612 return QCBOR_ERR_BAD_OPT_TAG;
1613 }
1614 pDecodedItem->uDataType = QCBOR_TYPE_UUID;
1615 return QCBOR_SUCCESS;
1616}
1617
1618
Laurence Lundblade59289e52019-12-30 13:44:37 -08001619/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001620 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08001621 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001622QCBORError
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001623QCBORDecode_GetNext(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08001624{
1625 QCBORError nReturn;
1626
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001627 nReturn = QCBORDecode_GetNextMapOrArray(me, pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001628 if(nReturn != QCBOR_SUCCESS) {
1629 goto Done;
1630 }
1631
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001632 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM; i++) {
1633 switch(pDecodedItem->uTags[i] ) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08001634
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001635 case CBOR_TAG_DATE_STRING:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001636 nReturn = DecodeDateString(pDecodedItem);
1637 break;
1638
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001639 case CBOR_TAG_DATE_EPOCH:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001640 nReturn = DecodeDateEpoch(pDecodedItem);
1641 break;
1642
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001643 case CBOR_TAG_POS_BIGNUM:
1644 case CBOR_TAG_NEG_BIGNUM:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001645 nReturn = DecodeBigNum(pDecodedItem);
1646 break;
1647
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001648 #ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
1649 case CBOR_TAG_DECIMAL_FRACTION:
1650 case CBOR_TAG_BIGFLOAT:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001651 // For aggregate tagged types, what goes into pTags is only collected
1652 // from the surrounding data item, not the contents, so pTags is not
1653 // passed on here.
1654
1655 nReturn = QCBORDecode_MantissaAndExponent(me, pDecodedItem);
1656 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001657 #endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08001658
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001659 case CBOR_TAG_URI:
1660 nReturn = DecodeURI(pDecodedItem);
1661 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001662
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001663 case CBOR_TAG_B64URL:
1664 nReturn = DecodeB64URL(pDecodedItem);
1665 break;
1666
1667 case CBOR_TAG_B64:
1668 nReturn = DecodeB64(pDecodedItem);
1669 break;
1670
1671 case CBOR_TAG_MIME:
1672 case CBOR_TAG_BINARY_MIME:
1673 nReturn = DecodeMIME(pDecodedItem);
1674 break;
1675
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001676 case CBOR_TAG_REGEX:
1677 nReturn = DecodeRegex(pDecodedItem);
1678 break;
1679
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001680 case CBOR_TAG_BIN_UUID:
1681 nReturn = DecodeUUID(pDecodedItem);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001682 break;
1683
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001684 case CBOR_TAG_INVALID16:
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001685 // The end of the tag list or no tags
1686 // Successful exit from the loop.
1687 goto Done;
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001688
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001689 default:
1690 // A tag that is not understood
1691 // A successful exit from the loop
1692 goto Done;
1693
1694 }
1695 if(nReturn != QCBOR_SUCCESS) {
1696 goto Done;
1697 }
Laurence Lundblade59289e52019-12-30 13:44:37 -08001698 }
1699
1700Done:
1701 if(nReturn != QCBOR_SUCCESS) {
1702 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
1703 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
1704 }
1705 return nReturn;
1706}
1707
1708
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001709QCBORError QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
1710{
1711 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
1712
1713 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
1714
1715 UsefulInputBuf_Seek(&(pMe->InBuf), uOffset);
1716
1717 return uErr;
1718}
1719
1720
Laurence Lundblade59289e52019-12-30 13:44:37 -08001721/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001722 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08001723 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001724QCBORError
1725QCBORDecode_GetNextWithTags(QCBORDecodeContext *me,
1726 QCBORItem *pDecodedItem,
1727 QCBORTagListOut *pTags)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001728{
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001729 QCBORError nReturn;
1730
1731 nReturn = QCBORDecode_GetNext(me, pDecodedItem);
1732 if(nReturn != QCBOR_SUCCESS) {
1733 return nReturn;
1734 }
1735
1736 if(pTags != NULL) {
1737 pTags->uNumUsed = 0;
1738 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM; i++) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001739 if(pDecodedItem->uTags[i] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001740 break;
1741 }
1742 if(pTags->uNumUsed >= pTags->uNumAllocated) {
1743 return QCBOR_ERR_TOO_MANY_TAGS;
1744 }
1745 pTags->puTags[pTags->uNumUsed] = ConvertTag(me, pDecodedItem->uTags[i]);
1746 pTags->uNumUsed++;
1747 }
1748 }
1749
1750 return QCBOR_SUCCESS;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001751}
1752
1753
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001754/*
Laurence Lundblade6de37062018-10-15 12:22:42 +05301755 Decoding items is done in 5 layered functions, one calling the
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301756 next one down. If a layer has no work to do for a particular item
1757 it returns quickly.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001758
Laurence Lundblade59289e52019-12-30 13:44:37 -08001759 - QCBORDecode_GetNext, GetNextWithTags -- The top layer processes
1760 tagged data items, turning them into the local C representation.
1761 For the most simple it is just associating a QCBOR_TYPE with the data. For
1762 the complex ones that an aggregate of data items, there is some further
1763 decoding and a little bit of recursion.
1764
1765 - QCBORDecode_GetNextMapOrArray - This manages the beginnings and
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301766 ends of maps and arrays. It tracks descending into and ascending
Laurence Lundblade6de37062018-10-15 12:22:42 +05301767 out of maps/arrays. It processes all breaks that terminate
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001768 indefinite length maps and arrays.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001769
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301770 - GetNext_MapEntry -- This handles the combining of two
1771 items, the label and the data, that make up a map entry.
1772 It only does work on maps. It combines the label and data
1773 items into one labeled item.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001774
Laurence Lundblade59289e52019-12-30 13:44:37 -08001775 - GetNext_TaggedItem -- This decodes type 6 tagging. It turns the
1776 tags into bit flags associated with the data item. No actual decoding
1777 of the contents of the tagged item is performed here.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001778
Laurence Lundblade59289e52019-12-30 13:44:37 -08001779 - GetNext_FullItem -- This assembles the sub-items that make up
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301780 an indefinte length string into one string item. It uses the
Laurence Lundblade6de37062018-10-15 12:22:42 +05301781 string allocater to create contiguous space for the item. It
1782 processes all breaks that are part of indefinite length strings.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001783
Laurence Lundblade59289e52019-12-30 13:44:37 -08001784 - GetNext_Item -- This decodes the atomic data items in CBOR. Each
1785 atomic data item has a "major type", an integer "argument" and optionally
1786 some content. For text and byte strings, the content is the bytes
1787 that make up the string. These are the smallest data items that are
1788 considered to be well-formed. The content may also be other data items in
1789 the case of aggregate types. They are not handled in this layer.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001790
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001791 Roughly this takes 300 bytes of stack for vars. Need to
1792 evaluate this more carefully and correctly.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001793
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301794 */
1795
1796
1797/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001798 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001799 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001800int QCBORDecode_IsTagged(QCBORDecodeContext *me,
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001801 const QCBORItem *pItem,
1802 uint64_t uTag)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001803{
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001804 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM; i++ ) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001805 if(pItem->uTags[i] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001806 break;
1807 }
1808 if(ConvertTag(me, pItem->uTags[i]) == uTag) {
1809 return 1;
1810 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001811 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001812
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001813 return 0;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001814}
1815
1816
1817/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001818 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001819 */
Laurence Lundblade30816f22018-11-10 13:40:22 +07001820QCBORError QCBORDecode_Finish(QCBORDecodeContext *me)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001821{
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001822 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001823
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001824 // Error out if all the maps/arrays are not closed out
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001825 if(!DecodeNesting_IsAtTop(&(me->nesting))) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001826 nReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
1827 goto Done;
1828 }
1829
1830 // Error out if not all the bytes are consumed
1831 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) {
1832 nReturn = QCBOR_ERR_EXTRA_BYTES;
1833 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001834
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001835Done:
Laurence Lundblade6de37062018-10-15 12:22:42 +05301836 // Call the destructor for the string allocator if there is one.
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001837 // Always called, even if there are errors; always have to clean up
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001838 StringAllocator_Destruct(&(me->StringAllocator));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001839
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001840 return nReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001841}
1842
1843
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001844/*
1845Public function, see header qcbor/qcbor_decode.h file
1846*/
1847uint64_t QCBORDecode_GetNthTag(QCBORDecodeContext *pMe, const QCBORItem *pItem, unsigned int uIndex)
1848{
1849 if(uIndex > QCBOR_MAX_TAGS_PER_ITEM) {
1850 return CBOR_TAG_INVALID16;
1851 } else if(pItem->uTags[uIndex] <= QCBOR_LAST_UNMAPPED_TAG) {
1852 return pItem->uTags[uIndex];
1853 } else if(pItem->uTags[uIndex] < QCBOR_NUM_MAPPED_TAGS + QCBOR_LAST_UNMAPPED_TAG) {
1854 return pMe->auMappedTags[pItem->uTags[uIndex] - QCBOR_LAST_UNMAPPED_TAG];
1855 } else {
1856 return CBOR_TAG_INVALID16;
1857 }
1858}
1859
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001860
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001861/*
1862
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001863Decoder errors handled in this file
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001864
Laurence Lundbladeee851742020-01-08 08:37:05 -08001865 - Hit end of input before it was expected while decoding type and
1866 number QCBOR_ERR_HIT_END
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001867
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001868 - negative integer that is too large for C QCBOR_ERR_INT_OVERFLOW
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001869
Laurence Lundbladeee851742020-01-08 08:37:05 -08001870 - Hit end of input while decoding a text or byte string
1871 QCBOR_ERR_HIT_END
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001872
Laurence Lundbladeee851742020-01-08 08:37:05 -08001873 - Encountered conflicting tags -- e.g., an item is tagged both a date
1874 string and an epoch date QCBOR_ERR_UNSUPPORTED
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001875
Laurence Lundbladeee851742020-01-08 08:37:05 -08001876 - Encontered an array or mapp that has too many items
1877 QCBOR_ERR_ARRAY_TOO_LONG
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001878
Laurence Lundbladeee851742020-01-08 08:37:05 -08001879 - Encountered array/map nesting that is too deep
1880 QCBOR_ERR_ARRAY_NESTING_TOO_DEEP
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001881
Laurence Lundbladeee851742020-01-08 08:37:05 -08001882 - An epoch date > INT64_MAX or < INT64_MIN was encountered
1883 QCBOR_ERR_DATE_OVERFLOW
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001884
Laurence Lundbladeee851742020-01-08 08:37:05 -08001885 - The type of a map label is not a string or int
1886 QCBOR_ERR_MAP_LABEL_TYPE
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001887
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001888 - Hit end with arrays or maps still open -- QCBOR_ERR_EXTRA_BYTES
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001889
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001890 */
1891
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001892
1893
Laurence Lundbladef6531662018-12-04 10:42:22 +09001894
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001895/* ===========================================================================
1896 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001897
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001898 This implements a simple sting allocator for indefinite length
1899 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
1900 implements the function type QCBORStringAllocate and allows easy
1901 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09001902
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001903 This particular allocator is built-in for convenience. The caller
1904 can implement their own. All of this following code will get
1905 dead-stripped if QCBORDecode_SetMemPool() is not called.
1906
1907 This is a very primitive memory allocator. It does not track
1908 individual allocations, only a high-water mark. A free or
1909 reallocation must be of the last chunk allocated.
1910
1911 The size of the pool and offset to free memory are packed into the
1912 first 8 bytes of the memory pool so we don't have to keep them in
1913 the decode context. Since the address of the pool may not be
1914 aligned, they have to be packed and unpacked as if they were
1915 serialized data of the wire or such.
1916
1917 The sizes packed in are uint32_t to be the same on all CPU types
1918 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08001919 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001920
1921
Laurence Lundbladeee851742020-01-08 08:37:05 -08001922static inline int
1923MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001924{
1925 // Use of UsefulInputBuf is overkill, but it is convenient.
1926 UsefulInputBuf UIB;
1927
Laurence Lundbladeee851742020-01-08 08:37:05 -08001928 // Just assume the size here. It was checked during SetUp so
1929 // the assumption is safe.
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001930 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem, QCBOR_DECODE_MIN_MEM_POOL_SIZE});
1931 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
1932 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
1933 return UsefulInputBuf_GetError(&UIB);
1934}
1935
1936
Laurence Lundbladeee851742020-01-08 08:37:05 -08001937static inline int
1938MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001939{
1940 // Use of UsefulOutBuf is overkill, but convenient. The
1941 // length check performed here is useful.
1942 UsefulOutBuf UOB;
1943
1944 UsefulOutBuf_Init(&UOB, Pool);
1945 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
1946 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
1947 return UsefulOutBuf_GetError(&UOB);
1948}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001949
1950
1951/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001952 Internal function for an allocation, reallocation free and destuct.
1953
1954 Having only one function rather than one each per mode saves space in
1955 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001956
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001957 Code Reviewers: THIS FUNCTION DOES POINTER MATH
1958 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001959static UsefulBuf
1960MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001961{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001962 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001963
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001964 uint32_t uPoolSize;
1965 uint32_t uFreeOffset;
1966
1967 if(uNewSize > UINT32_MAX) {
1968 // This allocator is only good up to 4GB. This check should
1969 // optimize out if sizeof(size_t) == sizeof(uint32_t)
1970 goto Done;
1971 }
1972 const uint32_t uNewSize32 = (uint32_t)uNewSize;
1973
1974 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
1975 goto Done;
1976 }
1977
1978 if(uNewSize) {
1979 if(pMem) {
1980 // REALLOCATION MODE
1981 // Calculate pointer to the end of the memory pool. It is
1982 // assumed that pPool + uPoolSize won't wrap around by
1983 // assuming the caller won't pass a pool buffer in that is
1984 // not in legitimate memory space.
1985 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
1986
1987 // Check that the pointer for reallocation is in the range of the
1988 // pool. This also makes sure that pointer math further down
1989 // doesn't wrap under or over.
1990 if(pMem >= pPool && pMem < pPoolEnd) {
1991 // Offset to start of chunk for reallocation. This won't
1992 // wrap under because of check that pMem >= pPool. Cast
1993 // is safe because the pool is always less than UINT32_MAX
1994 // because of check in QCBORDecode_SetMemPool().
1995 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
1996
1997 // Check to see if the allocation will fit. uPoolSize -
1998 // uMemOffset will not wrap under because of check that
1999 // pMem is in the range of the uPoolSize by check above.
2000 if(uNewSize <= uPoolSize - uMemOffset) {
2001 ReturnValue.ptr = pMem;
2002 ReturnValue.len = uNewSize;
2003
2004 // Addition won't wrap around over because uNewSize was
2005 // checked to be sure it is less than the pool size.
2006 uFreeOffset = uMemOffset + uNewSize32;
2007 }
2008 }
2009 } else {
2010 // ALLOCATION MODE
2011 // uPoolSize - uFreeOffset will not underflow because this
2012 // pool implementation makes sure uFreeOffset is always
2013 // smaller than uPoolSize through this check here and
2014 // reallocation case.
2015 if(uNewSize <= uPoolSize - uFreeOffset) {
2016 ReturnValue.len = uNewSize;
2017 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08002018 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002019 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002020 }
2021 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002022 if(pMem) {
2023 // FREE MODE
2024 // Cast is safe because of limit on pool size in
2025 // QCBORDecode_SetMemPool()
2026 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
2027 } else {
2028 // DESTRUCT MODE
2029 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002030 }
2031 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002032
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002033 UsefulBuf Pool = {pPool, uPoolSize};
2034 MemPool_Pack(Pool, uFreeOffset);
2035
2036Done:
2037 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002038}
2039
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002040
Laurence Lundbladef6531662018-12-04 10:42:22 +09002041/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08002042 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09002043 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08002044QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
2045 UsefulBuf Pool,
2046 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002047{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002048 // The pool size and free mem offset are packed into the beginning
2049 // of the pool memory. This compile time check make sure the
2050 // constant in the header is correct. This check should optimize
2051 // down to nothing.
2052 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundblade30816f22018-11-10 13:40:22 +07002053 return QCBOR_ERR_BUFFER_TOO_SMALL;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002054 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002055
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002056 // The pool size and free offset packed in to the beginning of pool
2057 // memory are only 32-bits. This check will optimize out on 32-bit
2058 // machines.
2059 if(Pool.len > UINT32_MAX) {
2060 return QCBOR_ERR_BUFFER_TOO_LARGE;
2061 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002062
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002063 // This checks that the pool buffer given is big enough.
2064 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
2065 return QCBOR_ERR_BUFFER_TOO_SMALL;
2066 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002067
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002068 pMe->StringAllocator.pfAllocator = MemPool_Function;
2069 pMe->StringAllocator.pAllocateCxt = Pool.ptr;
2070 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002071
Laurence Lundblade30816f22018-11-10 13:40:22 +07002072 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002073}
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002074
Laurence Lundblade1341c592020-04-11 14:19:05 -07002075#include <stdio.h>
2076void printdecode(QCBORDecodeContext *pMe, const char *szName)
2077{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002078 printf("---%s--%d--%d--\nLevel Count Type Offset SaveCount MapMode\n",
2079 szName,
2080 (uint32_t)pMe->InBuf.cursor,
2081 (uint32_t)pMe->InBuf.UB.len);
Laurence Lundblade64b607e2020-05-13 13:05:57 -07002082 for(int i = 0; i < QCBOR_MAX_ARRAY_NESTING; i++) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002083 if(&(pMe->nesting.pMapsAndArrays[i]) > pMe->nesting.pCurrent) {
2084 break;
2085 }
Laurence Lundblade64b607e2020-05-13 13:05:57 -07002086 printf("%2s %2d %5d %s %6u %2d %d\n",
2087 pMe->nesting.pCurrentMap == &(pMe->nesting.pMapsAndArrays[i]) ? "->": " ",
Laurence Lundblade1341c592020-04-11 14:19:05 -07002088 i,
2089 pMe->nesting.pMapsAndArrays[i].uCount,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002090 pMe->nesting.pMapsAndArrays[i].uMajorType == QCBOR_TYPE_MAP ? " map" :
2091 (pMe->nesting.pMapsAndArrays[i].uMajorType == QCBOR_TYPE_ARRAY ? "array" :
2092 (pMe->nesting.pMapsAndArrays[i].uMajorType == QCBOR_TYPE_NONE ? " none" : "?????")),
Laurence Lundblade1341c592020-04-11 14:19:05 -07002093 pMe->nesting.pMapsAndArrays[i].uOffset,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002094 pMe->nesting.pMapsAndArrays[i].uSaveCount,
2095 pMe->nesting.pMapsAndArrays[i].uMapMode
Laurence Lundblade1341c592020-04-11 14:19:05 -07002096 );
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002097
Laurence Lundblade1341c592020-04-11 14:19:05 -07002098 }
Laurence Lundblade64b607e2020-05-13 13:05:57 -07002099 printf("\n");
Laurence Lundblade1341c592020-04-11 14:19:05 -07002100}
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002101
2102
2103/*
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002104 *
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002105 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002106static inline QCBORError
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002107ConsumeItem(QCBORDecodeContext *pMe,
2108 const QCBORItem *pItemToConsume,
2109 uint_fast8_t *puNextNestLevel)
2110{
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002111 QCBORError uReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002112 QCBORItem Item;
2113
2114 printdecode(pMe, "ConsumeItem");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002115
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002116 if(IsMapOrArray(pItemToConsume->uDataType)) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002117 /* There is only real work to do for maps and arrays */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002118
Laurence Lundblade1341c592020-04-11 14:19:05 -07002119 /* This works for definite and indefinite length
2120 * maps and arrays by using the nesting level
2121 */
2122 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002123 uReturn = QCBORDecode_GetNext(pMe, &Item);
2124 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002125 goto Done;
2126 }
2127 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002128
Laurence Lundblade1341c592020-04-11 14:19:05 -07002129 if(puNextNestLevel != NULL) {
2130 *puNextNestLevel = Item.uNextNestLevel;
2131 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002132 uReturn = QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002133
Laurence Lundblade1341c592020-04-11 14:19:05 -07002134 } else {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002135 /* item_to_consume is not a map or array */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002136 if(puNextNestLevel != NULL) {
2137 /* Just pass the nesting level through */
2138 *puNextNestLevel = pItemToConsume->uNextNestLevel;
2139 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002140 uReturn = QCBOR_SUCCESS;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002141 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002142
2143Done:
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002144 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002145}
2146
2147
Laurence Lundblade1341c592020-04-11 14:19:05 -07002148/* Return true if the labels in Item1 and Item2 are the same.
2149 Works only for integer and string labels. Returns false
2150 for any other type. */
2151static inline bool
2152MatchLabel(QCBORItem Item1, QCBORItem Item2)
2153{
2154 if(Item1.uLabelType == QCBOR_TYPE_INT64) {
2155 if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
2156 return true;
2157 }
2158 } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002159 if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002160 return true;
2161 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002162 } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002163 if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
2164 return true;
2165 }
2166 } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
2167 if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
2168 return true;
2169 }
2170 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002171
Laurence Lundblade1341c592020-04-11 14:19:05 -07002172 /* Other label types are never matched */
2173 return false;
2174}
2175
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002176static inline bool
2177MatchType(QCBORItem Item1, QCBORItem Item2)
2178{
2179 if(Item1.uDataType == Item2.uDataType) {
2180 return true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002181 } else if(Item1.uDataType == QCBOR_TYPE_ANY) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002182 return true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002183 } else if(Item2.uDataType == QCBOR_TYPE_ANY) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002184 return true;
2185 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002186 return false;
2187}
2188
2189
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002190/**
2191 \brief Search a map for a set of items
2192
2193 @param[in] pMe The decode context to search.
2194 @param[in,out] pItemArray The items to search for and the items found.
2195 @param[in] pCBContext Context for the not-found item call back
2196 @param[in] pfCallback Function to call on items not matched in pItemArray
2197
2198 @retval QCBOR_ERR_NOT_ENTERED Trying to search without having entered a map
2199
2200 @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.
2201
2202 @retval QCBOR_ERR_UNEXPECTED_TYPE The label was matched, but not the type.
2203
2204 @retval Also errors returned by QCBORDecode_GetNext().
2205
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002206 On input pItemArray contains a list of labels and data types
2207 of items to be found.
2208
2209 On output the fully retrieved items are filled in with
2210 values and such. The label was matched, so it never changes.
2211
2212 If an item was not found, its data type is set to none.
2213
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002214 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002215static QCBORError
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002216MapSearch(QCBORDecodeContext *pMe,
2217 QCBORItem *pItemArray,
2218 size_t *puOffset,
2219 size_t *puEndOffset,
2220 void *pCBContext,
2221 QCBORItemCallback pfCallback)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002222{
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002223 QCBORError uReturn;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002224
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002225 QCBORDecodeNesting SaveNesting;
2226 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002227
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002228 // Reposition to search from the start of the map / array
2229 UsefulInputBuf_Seek(&(pMe->InBuf), pMe->nesting.pCurrentMap->uOffset);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002230
2231 /* Loop over all the items in the map. They could be
2232 * deeply nested and this should handle both definite
2233 * and indefinite length maps and arrays, so this
2234 * adds some complexity. */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002235 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Laurence Lundblade1341c592020-04-11 14:19:05 -07002236
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002237 uint_fast8_t uNextNestLevel;
2238
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002239 uint64_t uFoundItemBitMap = 0;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002240
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002241 /* Iterate over items in the map / array */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002242 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002243 /* Remember offset of the item because sometimes it has to be returned */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002244 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002245
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002246 /* Get the item */
2247 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002248 uReturn = QCBORDecode_GetNext(pMe, &Item);
2249 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002250 /* Got non-well-formed CBOR */
2251 goto Done;
2252 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002253
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002254 /* See if item has one of the labels that are of interest */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002255 int nIndex;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002256 QCBORItem *pIterator;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002257 for(pIterator = pItemArray, nIndex = 0; pIterator->uLabelType != 0; pIterator++, nIndex++) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002258 if(MatchLabel(Item, *pIterator)) {
2259 // A label match has been found
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002260 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
2261 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002262 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002263 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002264 /* Also try to match its type */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002265 if(!MatchType(Item, *pIterator)) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002266 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002267 goto Done;
2268 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002269
2270 /* Successful match. Return the item. */
2271 *pIterator = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002272 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002273 if(puOffset) {
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002274 *puOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002275 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002276 } else {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002277 /* Call the callback on unmatched labels */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002278 /* It is tempting to do duplicate detection here, but that would
2279 require dynamic memory allocation because the number of labels
2280 that might be encountered is unbounded.
2281 */
2282 if(pfCallback) {
2283 uReturn = (*pfCallback)(pCBContext, &Item);
2284 if(uReturn != QCBOR_SUCCESS) {
2285 goto Done;
2286 }
2287 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002288 }
2289 }
2290
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002291 /* Consume the item whether matched or not. This
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002292 does the work of traversing maps and array and
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002293 everything in them. In this loop only the
2294 items at the current nesting level are examined
2295 to match the labels. */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002296 uReturn = ConsumeItem(pMe, &Item, &uNextNestLevel);
2297 if(uReturn) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002298 goto Done;
2299 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002300
2301 } while (uNextNestLevel >= uMapNestLevel);
2302
2303
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002304 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002305
2306 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
2307 // Cast OK because encoded CBOR is limited to UINT32_MAX
2308 pMe->uMapEndOffset = (uint32_t)uEndOffset;
2309 // TODO: is zero *puOffset OK?
2310 if(puEndOffset) {
2311 *puEndOffset = uEndOffset;
2312 }
2313
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002314 /* For all items not found, set the data type to QCBOR_TYPE_NONE */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002315 int i;
2316 QCBORItem *pIterator;
2317 for(pIterator = pItemArray, i = 0; pIterator->uLabelType != 0; pIterator++, i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002318 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002319 pIterator->uDataType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002320 }
2321 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002322
2323Done:
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002324 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002325
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002326 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002327}
2328
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002329
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002330/*
2331Public function, see header qcbor/qcbor_decode.h file
2332*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002333void QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
2334 int64_t nLabel,
2335 uint8_t uQcborType,
2336 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002337{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002338 if(pMe->uLastError != QCBOR_SUCCESS) {
2339 return;
2340 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002341
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002342 QCBORItem OneItemSeach[2];
2343 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
2344 OneItemSeach[0].label.int64 = nLabel;
2345 OneItemSeach[0].uDataType = uQcborType;
2346 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07002347
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002348 QCBORError nReturn = MapSearch(pMe, OneItemSeach, NULL, NULL, NULL, NULL);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002349 if(nReturn) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002350 pMe->uLastError = (uint8_t)nReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002351 }
2352
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002353 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
2354 pMe->uLastError = QCBOR_ERR_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002355 }
2356
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002357 *pItem = OneItemSeach[0];
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002358}
2359
2360
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002361/*
2362Public function, see header qcbor/qcbor_decode.h file
2363*/
Laurence Lundbladeda095972020-06-06 18:35:33 -07002364void QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
2365 const char *szLabel,
2366 uint8_t uQcborType,
2367 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002368{
Laurence Lundbladeda095972020-06-06 18:35:33 -07002369 if(pMe->uLastError != QCBOR_SUCCESS) {
2370 return;
2371 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002372
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002373 QCBORItem OneItemSeach[2];
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002374 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2375 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
2376 OneItemSeach[0].uDataType = uQcborType;
2377 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07002378
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002379 QCBORError nReturn = MapSearch(pMe, OneItemSeach, NULL, NULL, NULL, NULL);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002380 if(nReturn) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07002381 pMe->uLastError = (uint8_t)nReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002382 }
2383
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002384 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07002385 pMe->uLastError = QCBOR_ERR_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002386 }
2387
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002388 *pItem = OneItemSeach[0];
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002389}
2390
2391
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002392/**
2393 @param[in] TagSpec Specification for matching tags.
2394 @param[in] uDataType A QCBOR data type
2395
2396 @retval QCBOR_SUCCESS \c uDataType is allowed by @c TagSpec
2397 @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec
2398
2399 The data type must be one of the QCBOR_TYPEs, not the IETF CBOR Registered tag value.
2400 */
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002401static QCBORError CheckTagRequirement(const TagSpecification TagSpec, uint8_t uDataType)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002402{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002403 if(TagSpec.uTagRequirement == QCBOR_TAGSPEC_MATCH_TAG) {
2404 /* Must match the tag */
2405 if(uDataType == TagSpec.uTaggedType) {
2406 return QCBOR_SUCCESS;
2407 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002408 } else {
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002409 /* QCBOR_TAGSPEC_MATCH_TAG_CONTENT_TYPE or QCBOR_TAGSPEC_MATCH_EITHER */
2410 /* Must check all the possible types for the tag content */
2411 for(size_t i = 0; i < sizeof(TagSpec.uAllowedContentTypes); i++) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002412 if(uDataType == TagSpec.uAllowedContentTypes[i]) {
2413 return QCBOR_SUCCESS;
2414 }
2415 }
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002416 /* Didn't match any of the tag content types */
2417 /* Check the tag for the either case */
2418 if(TagSpec.uTagRequirement == QCBOR_TAGSPEC_MATCH_EITHER) {
2419 if(uDataType == TagSpec.uTaggedType) {
2420 return QCBOR_SUCCESS;
2421 }
2422 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002423 }
2424
2425 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002426}
2427
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002428
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002429// Semi-private
2430// TODO: inline or collapse with QCBORDecode_GetTaggedStringInMapN?
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002431void QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
2432 int64_t nLabel,
2433 TagSpecification TagSpec,
2434 QCBORItem *pItem)
2435{
2436 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
2437 if(pMe->uLastError != QCBOR_SUCCESS) {
2438 return;
2439 }
2440
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002441 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem->uDataType);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002442}
2443
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002444// Semi-private
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002445void QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
2446 const char *szLabel,
2447 TagSpecification TagSpec,
2448 QCBORItem *pItem)
2449{
2450 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
2451 if(pMe->uLastError != QCBOR_SUCCESS) {
2452 return;
2453 }
2454
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002455 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem->uDataType);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002456}
2457
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002458// Semi-private
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002459void QCBORDecode_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
2460 int64_t nLabel,
2461 TagSpecification TagSpec,
2462 UsefulBufC *pString)
2463{
2464 QCBORItem Item;
2465 QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
2466 if(pMe->uLastError == QCBOR_SUCCESS) {
2467 *pString = Item.val.string;
2468 }
2469}
2470
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002471// Semi-private
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002472void QCBORDecode_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
2473 const char * szLabel,
2474 TagSpecification TagSpec,
2475 UsefulBufC *pString)
2476{
2477 QCBORItem Item;
2478 QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
2479 if(pMe->uLastError == QCBOR_SUCCESS) {
2480 *pString = Item.val.string;
2481 }
2482}
Laurence Lundblade1341c592020-04-11 14:19:05 -07002483
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002484/*
2485Public function, see header qcbor/qcbor_decode.h file
2486*/
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002487QCBORError QCBORDecode_GetItemsInMap(QCBORDecodeContext *pCtx, QCBORItem *pItemList)
2488{
2489 return MapSearch(pCtx, pItemList, NULL, NULL, NULL, NULL);
2490}
2491
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002492/*
2493Public function, see header qcbor/qcbor_decode.h file
2494*/
2495QCBORError QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pCtx,
2496 QCBORItem *pItemList,
2497 void *pCallbackCtx,
2498 QCBORItemCallback pfCB)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002499{
2500 return MapSearch(pCtx, pItemList, NULL, NULL, pCallbackCtx, pfCB);
2501}
2502
2503
Laurence Lundblade34691b92020-05-18 22:25:25 -07002504static void SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07002505{
Laurence Lundblade34691b92020-05-18 22:25:25 -07002506 if(pMe->uLastError != QCBOR_SUCCESS) {
2507 // Already in error state; do nothing.
2508 return;
2509 }
2510
2511 size_t uOffset;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002512 pMe->uLastError = (uint8_t)MapSearch(pMe, pSearch, &uOffset, NULL, NULL, NULL);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002513 if(pMe->uLastError != QCBOR_SUCCESS) {
2514 return;
2515 }
2516
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002517 /* Need to get the current pre-order nesting level and cursor to be
2518 at the first item in the map/array just entered.
2519
2520 Also need to current map nesting level and start cursor to
2521 be at the right place.
2522
2523 The UsefulInBuf offset could be anywhere, so no assumption is
2524 made about it.
2525
2526 No assumption is made about the pre-order nesting level either.
2527
2528 However the map mode nesting level is assumed to be one above
2529 the map level that is being entered.
2530 */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002531 /* Seek to the data item that is the map or array */
2532 UsefulInputBuf_Seek(&(pMe->InBuf), uOffset);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002533 pMe->nesting.pCurrent = pMe->nesting.pCurrentMap; // TODO: part of DecodeNesting
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002534
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002535 // TODO: check error?
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002536 QCBORDecode_EnterBoundedMode(pMe, pSearch->uDataType);
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002537
Laurence Lundblade34691b92020-05-18 22:25:25 -07002538 printdecode(pMe, "FinishEnter");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002539}
2540
2541
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002542/*
2543Public function, see header qcbor/qcbor_decode.h file
2544*/
Laurence Lundblade34691b92020-05-18 22:25:25 -07002545void QCBORDecode_EnterMapInMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002546{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002547 QCBORItem OneItemSeach[2];
2548 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
2549 OneItemSeach[0].label.int64 = nLabel;
2550 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
2551 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002552
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002553 /* The map to enter was found, now finish of entering it. */
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002554 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002555}
2556
2557
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002558/*
2559Public function, see header qcbor/qcbor_decode.h file
2560*/
Laurence Lundblade34691b92020-05-18 22:25:25 -07002561void QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002562{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002563 QCBORItem OneItemSeach[2];
2564 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2565 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
2566 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
2567 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002568
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002569 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002570}
2571
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002572/*
2573Public function, see header qcbor/qcbor_decode.h file
2574*/
Laurence Lundblade34691b92020-05-18 22:25:25 -07002575void QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07002576{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002577 QCBORItem OneItemSeach[2];
2578 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
2579 OneItemSeach[0].label.int64 = nLabel;
2580 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
2581 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002582
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002583 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002584}
2585
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002586/*
2587Public function, see header qcbor/qcbor_decode.h file
2588*/
Laurence Lundblade34691b92020-05-18 22:25:25 -07002589void QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
2590{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002591 QCBORItem OneItemSeach[2];
2592 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2593 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
2594 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
2595 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002596
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002597 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002598}
2599
2600
2601
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002602/* Next item must be map or this generates an error */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002603void QCBORDecode_EnterBoundedMode(QCBORDecodeContext *pMe, uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002604{
Laurence Lundblade34691b92020-05-18 22:25:25 -07002605 if(pMe->uLastError != QCBOR_SUCCESS) {
2606 // Already in error state; do nothing.
2607 return;
2608 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002609
2610 /* Get the data item that is the map that is being searched */
Laurence Lundblade34691b92020-05-18 22:25:25 -07002611 QCBORItem Item;
Laurence Lundblade986017c2020-05-23 19:25:02 -07002612 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002613 if(pMe->uLastError != QCBOR_SUCCESS) {
2614 return;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002615 }
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002616 if(Item.uDataType != uType) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07002617 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
2618 return;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002619 }
2620
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002621 DecodeNesting_EnterBoundedMode(&(pMe->nesting), UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002622
Laurence Lundblade34691b92020-05-18 22:25:25 -07002623 printdecode(pMe, "EnterMapModeDone");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002624}
2625
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002626void QCBORDecode_ExitBoundedMode(QCBORDecodeContext *pMe, uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002627{
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002628 QCBORError uErr;
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002629 size_t uEndOffset;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002630
2631 (void)uType; // TODO: error check
2632
2633/*
2634 if(pMe->uMapEndOffset) {
2635 uEndOffset = pMe->uMapEndOffset;
2636 // It is only valid once.
2637 pMe->uMapEndOffset = 0;
2638 } else { */
2639 // Find offset of the end the bounded array / map
2640 QCBORItem Dummy;
2641
2642 Dummy.uLabelType = QCBOR_TYPE_NONE;
2643
2644 QCBORError nReturn = MapSearch(pMe, &Dummy, NULL, &uEndOffset, NULL, NULL);
2645
2646 (void)nReturn; // TODO:
2647// }
2648
2649 printdecode(pMe, "start exit");
2650
2651 /* Before acending mark this level as no longer in bound mode. */
2652 pMe->nesting.pCurrentMap->uType &= ~QCBOR_NEST_TYPE_IS_BOUND;
2653
2654
2655 /* Set the pre-order traversal state to just after
2656 the map or array that was exited. */
2657 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
2658
2659 // Always go up one level
2660 // Need error check to know level is bounded mode and not at top level
2661 pMe->nesting.pCurrent = pMe->nesting.pCurrentMap - 1; // TODO error check
2662
2663 uErr = Ascender(pMe);
2664
2665 /* Also ascend to the next higest bounded mode level if
2666 there is one. */
2667 while(1) {
2668 pMe->nesting.pCurrentMap--;
2669 if(DecodeNesting_InBoundedMode(&(pMe->nesting))) {
2670 break;
2671 }
2672 if(pMe->nesting.pCurrentMap == &(pMe->nesting.pMapsAndArrays[0])) {
2673 pMe->nesting.pCurrentMap = NULL;
2674 break;
2675 }
2676 }
2677
2678 printdecode(pMe, "end exit");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002679}
2680
2681
Laurence Lundblade1341c592020-04-11 14:19:05 -07002682void QCBORDecode_RewindMap(QCBORDecodeContext *pMe)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002683{
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002684 // TODO: check for map mode; test this
Laurence Lundblade1341c592020-04-11 14:19:05 -07002685 pMe->nesting.pCurrent->uCount = pMe->nesting.pCurrent->uSaveCount;
2686 UsefulInputBuf_Seek(&(pMe->InBuf), pMe->nesting.pCurrent->uOffset);
2687}
2688
2689
Laurence Lundblade1341c592020-04-11 14:19:05 -07002690
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002691void QCBORDecode_EnterBstr(QCBORDecodeContext *pMe)
2692{
2693 if(pMe->uLastError != QCBOR_SUCCESS) {
2694 // Already in error state; do nothing.
2695 return;
2696 }
2697
2698 /* Get the data item that is the map that is being searched */
2699 QCBORItem Item;
2700 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
2701 if(pMe->uLastError != QCBOR_SUCCESS) {
2702 return;
2703 }
2704 if(Item.uDataType != QCBOR_TYPE_BYTE_STRING) {
2705 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
2706 return;
2707 }
2708
2709 // TODO: check for tag 24
2710
2711 // Need to move UIB input cursor to the right place
2712
2713 // Really this is a subtraction and an assignment; not much code
2714 // There is a range check in the seek.
2715 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
2716
2717 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset - Item.val.string.len);
2718
2719 UsefulInputBuf_SetBufferLen(&(pMe->InBuf), uEndOffset);
2720
2721 // TODO: comment on cast
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002722 pMe->uLastError = (uint8_t)DecodeNesting_Descend(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING, UINT16_MAX, (uint32_t)uEndOffset);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002723}
2724
2725
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002726void QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe, uint8_t uTagRequirement, UsefulBufC *pBstr)
2727{
2728 QCBORItem Item;
2729 QCBORDecode_GetNext(pMe, &Item);
2730 // Need to set UIB cursor to start of bstr and UIB length to end of bstr
2731
2732 // TODO: combine with above
2733
2734}
2735
2736//void QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pCtx, int64_t uLabel, UsefulBufC *pBstr);
2737
2738//void QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pCtx, const char *szLabel, UsefulBufC *pBstr);
2739
2740void QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pCtx)
2741{
2742 // Need to set the cursor to end of the bstr and length to the next length
2743 // above in the nesting tree (or the top level length).
2744
2745}
2746
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002747
Laurence Lundbladee6430642020-03-14 21:15:44 -07002748
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002749
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002750
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002751
Laurence Lundblade11a064e2020-05-07 13:13:42 -07002752
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002753
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002754static QCBORError InterpretBool(const QCBORItem *pItem, bool *pBool)
2755{
2756 switch(pItem->uDataType) {
2757 case QCBOR_TYPE_TRUE:
2758 *pBool = true;
2759 return QCBOR_SUCCESS;
2760 break;
2761
2762 case QCBOR_TYPE_FALSE:
2763 *pBool = false;
2764 return QCBOR_SUCCESS;
2765 break;
2766
2767 default:
2768 return QCBOR_ERR_UNEXPECTED_TYPE;
2769 break;
2770 }
2771}
Laurence Lundbladee6430642020-03-14 21:15:44 -07002772
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002773/*
2774Public function, see header qcbor/qcbor_decode.h file
2775*/
Laurence Lundbladec4537442020-04-14 18:53:22 -07002776void QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002777{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002778 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002779 // Already in error state, do nothing
Laurence Lundbladee6430642020-03-14 21:15:44 -07002780 return;
2781 }
2782
Laurence Lundbladec4537442020-04-14 18:53:22 -07002783 QCBORError nError;
2784 QCBORItem Item;
2785
2786 nError = QCBORDecode_GetNext(pMe, &Item);
2787 if(nError != QCBOR_SUCCESS) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002788 pMe->uLastError = (uint8_t)nError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002789 return;
2790 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002791 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002792}
2793
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002794/*
2795Public function, see header qcbor/qcbor_decode.h file
2796*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002797void QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe, int64_t nLabel, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002798{
2799 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002800 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002801
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002802 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002803}
2804
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002805/*
2806Public function, see header qcbor/qcbor_decode.h file
2807*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002808void QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, bool *pValue)
2809{
2810 QCBORItem Item;
2811 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
2812
2813 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
2814}
2815
2816
2817
2818void QCBORDecode_GetTaggedStringInternal(QCBORDecodeContext *pMe, TagSpecification TagSpec, UsefulBufC *pBstr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002819{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002820 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002821 // Already in error state, do nothing
2822 return;
2823 }
2824
2825 QCBORError nError;
2826 QCBORItem Item;
2827
2828 nError = QCBORDecode_GetNext(pMe, &Item);
2829 if(nError != QCBOR_SUCCESS) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002830 pMe->uLastError = (uint8_t)nError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002831 return;
2832 }
2833
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002834 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, Item.uDataType);
2835
2836 if(pMe->uLastError == QCBOR_SUCCESS) {
2837 *pBstr = Item.val.string;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002838 }
2839}
2840
Laurence Lundbladec4537442020-04-14 18:53:22 -07002841
2842
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002843
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002844static QCBORError ConvertBigNum(uint8_t uTagRequirement, const QCBORItem *pItem, UsefulBufC *pValue, bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002845{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002846 *pbIsNegative = false;
2847
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002848 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 -07002849
2850 switch(pItem->uDataType) {
2851 case QCBOR_TYPE_BYTE_STRING:
2852 // TODO: check that there is no tag here?
2853 if(bMustBeTagged) {
2854 return QCBOR_ERR_UNEXPECTED_TYPE;
2855 } else {
2856 *pValue = pItem->val.string;
2857 return QCBOR_SUCCESS;
2858 }
2859 break;
2860
2861 case QCBOR_TYPE_POSBIGNUM:
2862 *pValue = pItem->val.string;
2863 return QCBOR_SUCCESS;
2864 break;
2865
2866 case QCBOR_TYPE_NEGBIGNUM:
2867 *pbIsNegative = true;
2868 *pValue = pItem->val.string;
2869 return QCBOR_SUCCESS;
2870 break;
2871
2872 default:
2873 return QCBOR_ERR_UNEXPECTED_TYPE;
2874 break;
2875 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002876}
2877
2878
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002879/*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002880 @param[in] bMustBeTagged If \c true, then the data item must be tagged as either
2881 a positive or negative bignum. If \c false, then it only must be a byte string and bIsNegative
2882 will always be false on the asumption that it is positive, but it can be interpretted as
2883 negative if the the sign is know from other context.
2884 @param[out] pValue The bytes that make up the big num
2885 @param[out] pbIsNegative \c true if tagged as a negative big num. \c false otherwise.
2886
2887 if bMustBeTagged is false, then this will succeed if the data item is a plain byte string,
2888 a positive big num or a negative big num.
2889
2890 */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002891void QCBORDecode_GetBignum(QCBORDecodeContext *pMe, uint8_t uTagRequirement, UsefulBufC *pValue, bool *pbIsNegative)
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002892{
2893 if(pMe->uLastError != QCBOR_SUCCESS) {
2894 // Already in error state, do nothing
2895 return;
2896 }
2897
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002898 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002899 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
2900 if(uError != QCBOR_SUCCESS) {
2901 pMe->uLastError = (uint8_t)uError;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002902 return;
2903 }
2904
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002905 pMe->uLastError = (uint8_t)ConvertBigNum(uTagRequirement, &Item, pValue, pbIsNegative);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002906}
2907
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002908/*
2909Public function, see header qcbor/qcbor_decode.h file
2910*/
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002911void QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, UsefulBufC *pValue, bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002912{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002913 QCBORItem Item;
2914 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002915
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002916 pMe->uLastError = (uint8_t)ConvertBigNum(uTagRequirement, &Item, pValue, pbIsNegative);
Laurence Lundbladec4537442020-04-14 18:53:22 -07002917}
2918
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002919/*
2920Public function, see header qcbor/qcbor_decode.h file
2921*/
2922void QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint8_t uTagRequirement, UsefulBufC *pValue, bool *pbIsNegative)
2923{
2924 QCBORItem Item;
2925 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
2926
2927 pMe->uLastError = (uint8_t)ConvertBigNum(uTagRequirement, &Item, pValue, pbIsNegative);
2928}
2929
2930
2931
2932// Semi private
2933QCBORError FarfMIME(uint8_t uTagRequirement, const QCBORItem *pItem, UsefulBufC *pMessage, bool *pbIsNot7Bit)
2934{
2935 const TagSpecification TagSpecText = {uTagRequirement, QCBOR_TYPE_MIME, {QCBOR_TYPE_TEXT_STRING, 0,0,0,0,0}};
2936 const TagSpecification TagSpecBinary = {uTagRequirement, QCBOR_TYPE_BINARY_MIME, {QCBOR_TYPE_BYTE_STRING, 0,0,0,0,0}};
2937
2938 QCBORError uReturn;
2939
2940 if(CheckTagRequirement(TagSpecText, pItem->uDataType)) {
2941 *pMessage = pItem->val.string;
2942 if(pbIsNot7Bit != NULL) {
2943 *pbIsNot7Bit = false;
2944 }
2945 uReturn = QCBOR_SUCCESS;
2946 } else if(CheckTagRequirement(TagSpecBinary, pItem->uDataType)) {
2947 *pMessage = pItem->val.string;
2948 if(pbIsNot7Bit != NULL) {
2949 *pbIsNot7Bit = true;
2950 }
2951 uReturn = QCBOR_SUCCESS;
2952
2953 } else {
2954 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
2955 }
2956
2957 return uReturn;
2958}
2959
2960
2961
2962
2963
Laurence Lundbladec4537442020-04-14 18:53:22 -07002964
2965
2966
Laurence Lundbladee6430642020-03-14 21:15:44 -07002967
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002968typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002969
2970
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002971// The main exponentiator that works on only positive numbers
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002972static QCBORError Exponentitate10(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002973{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002974 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002975
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002976 if(uResult != 0) {
2977 /* This loop will run a maximum of 19 times because
2978 * UINT64_MAX < 10 ^^ 19. More than that will cause
2979 * exit with the overflow error
2980 */
2981 for(; nExponent > 0; nExponent--) {
2982 if(uResult > UINT64_MAX / 10) {
2983 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Error overflow
2984 }
2985 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002986 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002987
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002988 for(; nExponent < 0; nExponent++) {
2989 uResult = uResult / 10;
2990 if(uResult == 0) {
2991 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Underflow error
2992 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002993 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002994 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002995 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07002996
2997 *puResult = uResult;
2998
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002999 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003000}
3001
3002
Laurence Lundbladee6430642020-03-14 21:15:44 -07003003/* Convert a decimal fraction to an int64_t without using
3004 floating point or math libraries. Most decimal fractions
3005 will not fit in an int64_t and this will error out with
3006 under or overflow
3007 */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003008static QCBORError Exponentitate2(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003009{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003010 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003011
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003012 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003013
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003014 /* This loop will run a maximum of 64 times because
Laurence Lundbladee6430642020-03-14 21:15:44 -07003015 * INT64_MAX < 2^31. More than that will cause
3016 * exist with the overflow error
3017 */
3018 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003019 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003020 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Error overflow
Laurence Lundbladee6430642020-03-14 21:15:44 -07003021 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003022 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003023 nExponent--;
3024 }
3025
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003026 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003027 if(uResult == 0) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003028 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Underflow error
3029 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003030 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003031 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003032 }
3033
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003034 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003035
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003036 return QCBOR_SUCCESS;
3037}
3038
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003039/*
3040 Compute value with signed mantissa and signed result. Works with exponent of 2 or 10 based on exponentiator.
3041 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003042static inline QCBORError ExponentiateNN(int64_t nMantissa, int64_t nExponent, int64_t *pnResult, fExponentiator pfExp)
3043{
3044 uint64_t uResult;
3045
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003046 // Take the absolute value of the mantissa and convert to unsigned.
3047 // TODO: this should be possible in one intruction
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003048 uint64_t uMantissa = nMantissa > 0 ? (uint64_t)nMantissa : (uint64_t)-nMantissa;
3049
3050 // Do the exponentiation of the positive mantissa
3051 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
3052 if(uReturn) {
3053 return uReturn;
3054 }
3055
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003056
Laurence Lundblade983500d2020-05-14 11:49:34 -07003057 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
3058 of INT64_MIN. This assumes two's compliment representation where
3059 INT64_MIN is one increment farther from 0 than INT64_MAX.
3060 Trying to write -INT64_MIN doesn't work to get this because the
3061 compiler tries to work with an int64_t which can't represent
3062 -INT64_MIN.
3063 */
3064 uint64_t uMax = nMantissa > 0 ? INT64_MAX : (uint64_t)INT64_MAX+1;
3065
3066 // Error out if too large
3067 if(uResult > uMax) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003068 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3069 }
3070
3071 // Casts are safe because of checks above
3072 *pnResult = nMantissa > 0 ? (int64_t)uResult : -(int64_t)uResult;
3073
3074 return QCBOR_SUCCESS;
3075}
3076
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003077/*
3078 Compute value with signed mantissa and unsigned result. Works with exponent of 2 or 10 based on exponentiator.
3079 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003080static inline QCBORError ExponentitateNU(int64_t nMantissa, int64_t nExponent, uint64_t *puResult, fExponentiator pfExp)
3081{
3082 if(nMantissa < 0) {
3083 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3084 }
3085
3086 // Cast to unsigned is OK because of check for negative
3087 // Cast to unsigned is OK because UINT64_MAX > INT64_MAX
3088 // Exponentiation is straight forward
3089 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
3090}
3091
3092
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003093#include <math.h>
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003094
3095
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003096static QCBORError ConvertBigNumToUnsigned(const UsefulBufC BigNum, uint64_t uMax, uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003097{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003098 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003099
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003100 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003101 const uint8_t *pByte = BigNum.ptr;
3102 size_t uLen = BigNum.len;
3103 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07003104 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003105 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003106 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07003107 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003108 }
3109
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003110 *pResult = uResult;
3111 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003112}
3113
Laurence Lundblade887add82020-05-17 05:50:34 -07003114static inline QCBORError ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum, uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003115{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003116 return ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003117}
3118
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003119static inline QCBORError ConvertPositiveBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003120{
3121 uint64_t uResult;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003122 QCBORError uError = ConvertBigNumToUnsigned(BigNum, INT64_MAX, &uResult);
3123 if(uError) {
3124 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003125 }
3126 /* Cast is safe because ConvertBigNum is told to limit to INT64_MAX */
3127 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003128 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003129}
3130
3131
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003132static inline QCBORError ConvertNegativeBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003133{
3134 uint64_t uResult;
Laurence Lundbladeda095972020-06-06 18:35:33 -07003135 /* negaative int furthest from zero is INT64_MIN
3136 which is expressed as -INT64_MAX-1. The value of
3137 a negative bignum is -n-1, one further from zero
3138 than the positive bignum */
3139
3140 /* say INT64_MIN is -2; then INT64_MAX is 1.
3141 Then -n-1 <= INT64_MIN.
3142 Then -n -1 <= -INT64_MAX - 1
3143 THen n <= INT64_MAX. */
3144 QCBORError uError = ConvertBigNumToUnsigned(BigNum, INT64_MAX, &uResult);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003145 if(uError) {
3146 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003147 }
3148 /* Cast is safe because ConvertBigNum is told to limit to INT64_MAX */
Laurence Lundblade887add82020-05-17 05:50:34 -07003149 // TODO: this code is incorrect. See RFC 7049
Laurence Lundbladeda095972020-06-06 18:35:33 -07003150 uResult++; // this is the -1 in -n-1
Laurence Lundbladee6430642020-03-14 21:15:44 -07003151 *pResult = -(int64_t)uResult;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003152 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003153}
3154
Laurence Lundbladef6c86662020-05-12 02:08:00 -07003155#include "fenv.h"
Laurence Lundbladec4537442020-04-14 18:53:22 -07003156
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003157
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003158/*
3159Convert a integers and floats to an int64_t.
3160
3161\param[in] uOptions Bit mask list of conversion options.
3162
3163\retval QCBOR_ERR_CONVERSION_NOT_REQUESTED Conversion, possible, but not requested in uOptions.
3164
3165\retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
3166
3167\retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large or too small.
3168
3169*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003170static QCBORError ConvertInt64(const QCBORItem *pItem, uint32_t uOptions, int64_t *pnValue)
3171{
3172 switch(pItem->uDataType) {
3173 // TODO: float when ifdefs are set
3174 case QCBOR_TYPE_DOUBLE:
3175 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3176 // TODO: what about under/overflow here?
3177 // Invokes the floating-point HW and/or compiler-added libraries
3178 feclearexcept(FE_ALL_EXCEPT);
3179 *pnValue = llround(pItem->val.dfnum);
3180 if(fetestexcept(FE_INVALID)) {
3181 // TODO: better error code
3182 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3183 }
3184 } else {
3185 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3186 }
3187 break;
3188
3189 case QCBOR_TYPE_INT64:
3190 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
3191 *pnValue = pItem->val.int64;
3192 } else {
3193 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3194 }
3195 break;
3196
3197 case QCBOR_TYPE_UINT64:
3198 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
3199 if(pItem->val.uint64 < INT64_MAX) {
3200 *pnValue = pItem->val.int64;
3201 } else {
3202 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3203 }
3204 } else {
3205 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3206 }
3207 break;
3208
3209 default:
3210 return QCBOR_ERR_UNEXPECTED_TYPE;
3211 }
3212 return QCBOR_SUCCESS;
3213}
3214
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003215
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003216void QCBORDecode_GetInt64ConvertInternal(QCBORDecodeContext *pMe,
3217 uint32_t uOptions,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003218 int64_t *pnValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003219 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003220{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07003221 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003222 return;
3223 }
3224
Laurence Lundbladee6430642020-03-14 21:15:44 -07003225 QCBORItem Item;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003226 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
3227 if(uError) {
3228 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003229 return;
3230 }
3231
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003232 if(pItem) {
3233 *pItem = Item;
3234 }
3235
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003236 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003237}
3238
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003239
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003240void QCBORDecode_GetInt64ConvertInternalInMapN(QCBORDecodeContext *pMe,
3241 int64_t nLabel,
3242 uint32_t uOptions,
3243 int64_t *pnValue,
3244 QCBORItem *pItem)
3245{
3246 QCBORItem Item;
3247 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
3248
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003249 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003250}
3251
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003252
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003253void QCBORDecode_GetInt64ConvertInternalInMapSZ(QCBORDecodeContext *pMe,
3254 const char * szLabel,
3255 uint32_t uOptions,
3256 int64_t *pnValue,
3257 QCBORItem *pItem)
3258{
3259 if(pMe->uLastError != QCBOR_SUCCESS) {
3260 return;
3261 }
3262
3263 QCBORItem Item;
3264 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3265
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003266 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003267}
3268
3269
3270
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003271/*
3272 Convert a large variety of integer types to an int64_t.
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003273
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003274 \param[in] uOptions Bit mask list of conversion options.
3275
3276 \retval QCBOR_ERR_CONVERSION_NOT_REQUESTED Conversion, possible, but not requested in uOptions.
3277
3278 \retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
3279
3280 \retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large or too small.
3281
3282 */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003283static QCBORError Int64ConvertAll(const QCBORItem *pItem, uint32_t uOptions, int64_t *pnValue)
3284{
3285 QCBORError uErr;
3286
3287 switch(pItem->uDataType) {
3288
3289 case QCBOR_TYPE_POSBIGNUM:
3290 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3291 return ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003292 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003293 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003294 }
3295 break;
3296
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003297 case QCBOR_TYPE_NEGBIGNUM:
3298 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3299 return ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003300 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003301 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003302 }
3303 break;
3304
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003305#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
3306 case QCBOR_TYPE_DECIMAL_FRACTION:
3307 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3308 return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
3309 pItem->val.expAndMantissa.nExponent,
3310 pnValue,
3311 &Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003312 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003313 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3314 }
3315 break;
3316
3317 case QCBOR_TYPE_BIGFLOAT:
3318 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3319 return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
3320 pItem->val.expAndMantissa.nExponent,
3321 pnValue,
3322 Exponentitate2);
3323 } else {
3324 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3325 }
3326 break;
3327
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003328 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
3329 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3330 int64_t nMantissa;
3331 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3332 if(uErr) {
3333 return uErr;
3334 }
3335 return ExponentiateNN(nMantissa,
3336 pItem->val.expAndMantissa.nExponent,
3337 pnValue,
3338 Exponentitate10);
3339 } else {
3340 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3341 }
3342 break;
3343
3344 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
3345 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3346 int64_t nMantissa;
3347 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3348 if(uErr) {
3349 return uErr;
3350 }
3351 return ExponentiateNN(nMantissa,
3352 pItem->val.expAndMantissa.nExponent,
3353 pnValue,
3354 Exponentitate10);
3355 } else {
3356 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3357 }
3358 break;
3359
3360 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
3361 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3362 int64_t nMantissa;
3363 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3364 if(uErr) {
3365 return uErr;
3366 }
3367 return ExponentiateNN(nMantissa,
3368 pItem->val.expAndMantissa.nExponent,
3369 pnValue,
3370 Exponentitate2);
3371 } else {
3372 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3373 }
3374 break;
3375
3376 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
3377 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3378 int64_t nMantissa;
3379 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3380 if(uErr) {
3381 return uErr;
3382 }
3383 return ExponentiateNN(nMantissa,
3384 pItem->val.expAndMantissa.nExponent,
3385 pnValue,
3386 Exponentitate2);
3387 } else {
3388 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003389 }
3390 break;
3391
Laurence Lundbladec4537442020-04-14 18:53:22 -07003392 default:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003393 return QCBOR_ERR_UNEXPECTED_TYPE;
3394#endif
Laurence Lundbladec4537442020-04-14 18:53:22 -07003395 }
3396}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003397
3398
Laurence Lundbladec4537442020-04-14 18:53:22 -07003399/*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003400 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003401 */
3402void QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003403{
3404 QCBORItem Item;
3405
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003406 QCBORDecode_GetInt64ConvertInternal(pMe, uOptions, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003407
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003408 if(pMe->uLastError == QCBOR_SUCCESS) {
3409 // The above conversion succeeded
3410 return;
3411 }
3412
Laurence Lundbladef6c86662020-05-12 02:08:00 -07003413 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003414 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07003415 return;
3416 }
3417
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003418 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003419}
3420
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003421
3422/*
3423Public function, see header qcbor/qcbor_decode.h file
3424*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003425void QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, int64_t *pnValue)
3426{
3427 QCBORItem Item;
3428
3429 QCBORDecode_GetInt64ConvertInternalInMapN(pMe, nLabel, uOptions, pnValue, &Item);
3430
3431 if(pMe->uLastError == QCBOR_SUCCESS) {
3432 // The above conversion succeeded
3433 return;
3434 }
3435
3436 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3437 // The above conversion failed in a way that code below can't correct
3438 return;
3439 }
3440
3441 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
3442}
3443
3444
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003445/*
3446Public function, see header qcbor/qcbor_decode.h file
3447*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003448void QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, int64_t *pnValue)
3449{
3450 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003451 QCBORDecode_GetInt64ConvertInternalInMapSZ(pMe, szLabel, uOptions, pnValue, &Item);
3452
3453 if(pMe->uLastError == QCBOR_SUCCESS) {
3454 // The above conversion succeeded
3455 return;
3456 }
3457
3458 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3459 // The above conversion failed in a way that code below can't correct
3460 return;
3461 }
3462
3463 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
3464}
3465
3466
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003467static QCBORError ConvertUint64(const QCBORItem *pItem, uint32_t uOptions, uint64_t *puValue)
3468{
3469 switch(pItem->uDataType) {
3470 // TODO: type flaot
3471 case QCBOR_TYPE_DOUBLE:
3472 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3473 feclearexcept(FE_ALL_EXCEPT);
3474 double dRounded = round(pItem->val.dfnum);
3475 // TODO: over/underflow
3476 if(fetestexcept(FE_INVALID)) {
3477 // TODO: better error code
3478 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3479 } else if(isnan(dRounded)) {
3480 // TODO: better error code
3481 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3482 } else if(dRounded >= 0) {
3483 *puValue = (uint64_t)dRounded;
3484 } else {
3485 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3486 }
3487 } else {
3488 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3489 }
3490 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003491
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003492 case QCBOR_TYPE_INT64:
3493 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
3494 if(pItem->val.int64 >= 0) {
3495 *puValue = (uint64_t)pItem->val.int64;
3496 } else {
3497 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3498 }
3499 } else {
3500 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3501 }
3502 break;
3503
3504 case QCBOR_TYPE_UINT64:
3505 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
3506 *puValue = pItem->val.uint64;
3507 } else {
3508 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3509 }
3510 break;
3511
3512 default:
3513 return QCBOR_ERR_UNEXPECTED_TYPE;
3514 }
3515 return QCBOR_SUCCESS;
3516}
Laurence Lundbladec4537442020-04-14 18:53:22 -07003517
3518
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003519void QCBORDecode_GetUInt64ConvertInternal(QCBORDecodeContext *pMe,
3520 uint32_t uOptions,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003521 uint64_t *puValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003522 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003523{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003524 if(pMe->uLastError != QCBOR_SUCCESS) {
3525 return;
3526 }
3527
Laurence Lundbladec4537442020-04-14 18:53:22 -07003528 QCBORItem Item;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003529
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003530 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
3531 if(uError) {
3532 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003533 return;
3534 }
3535
Laurence Lundbladea826c502020-05-10 21:07:00 -07003536 if(pItem) {
3537 *pItem = Item;
3538 }
3539
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003540 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003541}
3542
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003543
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003544void QCBORDecode_GetInt8ConvertInternal(QCBORDecodeContext *pMe, uint32_t uOptions, int8_t *pnValue, QCBORItem *pItem)
3545{
3546 int64_t uValue;
3547 QCBORDecode_GetInt64ConvertInternal(pMe, uOptions, &uValue, pItem);
3548 if(pMe->uLastError != QCBOR_SUCCESS) {
3549 return;
3550 }
3551
3552 if(QCBOR_Int64ToInt8(uValue, pnValue)) {
3553 pMe->uLastError = QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3554 }
3555}
3556
3557void QCBORDecode_GetInt8ConvertInternalInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, int8_t *pnValue, QCBORItem *pItem)
3558{
3559 int64_t uValue;
3560 QCBORDecode_GetInt64ConvertInternalInMapN(pMe, nLabel, uOptions, &uValue, pItem);
3561 if(pMe->uLastError != QCBOR_SUCCESS) {
3562 return;
3563 }
3564
3565 if(QCBOR_Int64ToInt8(uValue, pnValue)) {
3566 pMe->uLastError = QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3567 }
3568}
3569
3570void QCBORDecode_GetInt8ConvertInternalInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, int8_t *pnValue, QCBORItem *pItem)
3571{
3572 int64_t uValue;
3573 QCBORDecode_GetInt64ConvertInternalInMapSZ(pMe, szLabel, uOptions, &uValue, pItem);
3574 if(pMe->uLastError != QCBOR_SUCCESS) {
3575 return;
3576 }
3577
3578 if(QCBOR_Int64ToInt8(uValue, pnValue)) {
3579 pMe->uLastError = QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3580 }
3581}
3582
3583
3584
3585
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003586void QCBORDecode_GetUint64ConvertInternalInMapN(QCBORDecodeContext *pMe,
3587 int64_t nLabel,
3588 uint32_t uOptions,
3589 uint64_t *puValue,
3590 QCBORItem *pItem)
3591{
3592 QCBORItem Item;
3593 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
3594
3595 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
3596}
3597
3598
3599void QCBORDecode_GetUint64ConvertInternalInMapSZ(QCBORDecodeContext *pMe,
3600 const char * szLabel,
3601 uint32_t uOptions,
3602 uint64_t *puValue,
3603 QCBORItem *pItem)
3604{
3605 if(pMe->uLastError != QCBOR_SUCCESS) {
3606 return;
3607 }
3608
3609 QCBORItem Item;
3610 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3611
3612 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
3613}
3614
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003615/*
3616 Public function, see header qcbor/qcbor_decode.h file
3617*/
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003618static QCBORError Uint64ConvertAll(const QCBORItem *pItem, uint32_t uOptions, uint64_t *puValue)
3619{
3620 QCBORError uErr;
3621
3622 switch(pItem->uDataType) {
3623
3624 case QCBOR_TYPE_POSBIGNUM:
3625 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3626 return ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
3627 } else {
3628 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3629 }
3630 break;
3631
3632 case QCBOR_TYPE_NEGBIGNUM:
3633 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3634 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3635 } else {
3636 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3637 }
3638 break;
3639
3640#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
3641
3642 case QCBOR_TYPE_DECIMAL_FRACTION:
3643 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3644 return ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
3645 pItem->val.expAndMantissa.nExponent,
3646 puValue,
3647 Exponentitate10);
3648 } else {
3649 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3650 }
3651 break;
3652
3653 case QCBOR_TYPE_BIGFLOAT:
3654 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3655 return ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
3656 pItem->val.expAndMantissa.nExponent,
3657 puValue,
3658 Exponentitate2);
3659 } else {
3660 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3661 }
3662 break;
3663
3664 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
3665 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3666 // TODO: Would be better to convert to unsigned
3667 int64_t nMantissa;
3668 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3669 if(uErr != QCBOR_SUCCESS) {
3670 return uErr;
3671 }
3672 return ExponentitateNU(nMantissa,
3673 pItem->val.expAndMantissa.nExponent,
3674 puValue,
3675 Exponentitate10);
3676 } else {
3677 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3678 }
3679 break;
3680
3681 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
3682 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3683 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3684 } else {
3685 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3686 }
3687 break;
3688
3689 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
3690 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3691 // TODO: Would be better to convert to unsigned
3692 int64_t nMantissa;
3693 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3694 if(uErr != QCBOR_SUCCESS) {
3695 return uErr;
3696 }
3697 return ExponentitateNU(nMantissa,
3698 pItem->val.expAndMantissa.nExponent,
3699 puValue,
3700 Exponentitate2);
3701 } else {
3702 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3703 }
3704 break;
3705
3706 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
3707 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3708 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3709 } else {
3710 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3711 }
3712 break;
3713#endif
3714 default:
3715 return QCBOR_ERR_UNEXPECTED_TYPE;
3716 }
3717}
3718
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003719/*
3720 Public function, see header qcbor/qcbor_decode.h file
3721*/
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003722void QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003723{
3724 QCBORItem Item;
3725
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003726 QCBORDecode_GetUInt64ConvertInternal(pMe, uOptions, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003727
Laurence Lundbladef6c86662020-05-12 02:08:00 -07003728 if(pMe->uLastError == QCBOR_SUCCESS) {
3729 // The above conversion succeeded
3730 return;
3731 }
3732
3733 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3734 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07003735 return;
3736 }
3737
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003738 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003739}
3740
Laurence Lundbladec4537442020-04-14 18:53:22 -07003741
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003742/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003743 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003744*/
3745void QCBORDecode_GetUint64ConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, uint64_t *puValue)
3746{
3747 QCBORItem Item;
3748
3749 QCBORDecode_GetUint64ConvertInternalInMapN(pMe, nLabel, uOptions, puValue, &Item);
3750
3751 if(pMe->uLastError == QCBOR_SUCCESS) {
3752 // The above conversion succeeded
3753 return;
3754 }
3755
3756 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3757 // The above conversion failed in a way that code below can't correct
3758 return;
3759 }
3760
3761 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
3762}
3763
3764
3765/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003766 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003767*/
3768void QCBORDecode_GetUint64ConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, uint64_t *puValue)
3769{
3770 QCBORItem Item;
3771 QCBORDecode_GetUint64ConvertInternalInMapSZ(pMe, szLabel, uOptions, puValue, &Item);
3772
3773 if(pMe->uLastError == QCBOR_SUCCESS) {
3774 // The above conversion succeeded
3775 return;
3776 }
3777
3778 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3779 // The above conversion failed in a way that code below can't correct
3780 return;
3781 }
3782
3783 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
3784}
3785
3786
3787static QCBORError ConvertDouble(const QCBORItem *pItem, uint32_t uOptions, double *pdValue)
3788{
3789 switch(pItem->uDataType) {
3790 // TODO: float when ifdefs are set
3791 case QCBOR_TYPE_DOUBLE:
3792 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3793 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3794 *pdValue = pItem->val.dfnum;
3795 } else {
3796 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3797 }
3798 }
3799 break;
3800
3801 case QCBOR_TYPE_INT64:
3802 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
3803 // TODO: how does this work?
3804 *pdValue = (double)pItem->val.int64;
3805
3806 } else {
3807 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3808 }
3809 break;
3810
3811 case QCBOR_TYPE_UINT64:
3812 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
3813 *pdValue = (double)pItem->val.uint64;
3814 } else {
3815 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3816 }
3817 break;
3818
3819 default:
3820 return QCBOR_ERR_UNEXPECTED_TYPE;
3821 }
3822
3823 return QCBOR_SUCCESS;
3824}
3825
3826
3827
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003828void QCBORDecode_GetDoubleConvertInternal(QCBORDecodeContext *pMe,
3829 uint32_t uOptions,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003830 double *pdValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003831 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003832{
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003833 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003834 return;
3835 }
3836
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003837 QCBORItem Item;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003838
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003839 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003840 if(uError) {
3841 pMe->uLastError = (uint8_t)uError;
3842 return;
3843 }
3844
3845 if(pItem) {
3846 *pItem = Item;
3847 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07003848
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003849 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003850}
Laurence Lundbladec4537442020-04-14 18:53:22 -07003851
Laurence Lundbladec4537442020-04-14 18:53:22 -07003852
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003853void QCBORDecode_GetDoubleConvertInternalInMapN(QCBORDecodeContext *pMe,
3854 int64_t nLabel,
3855 uint32_t uOptions,
3856 double *pdValue,
3857 QCBORItem *pItem)
3858{
3859 QCBORItem Item;
3860 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
3861
3862 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
3863}
3864
3865void QCBORDecode_GetDoubleConvertInternalInMapSZ(QCBORDecodeContext *pMe,
3866 const char * szLabel,
3867 uint32_t uOptions,
3868 double *pdValue,
3869 QCBORItem *pItem)
3870{
3871 if(pMe->uLastError != QCBOR_SUCCESS) {
3872 return;
3873 }
3874
3875 QCBORItem Item;
3876 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3877
3878 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
3879}
3880
3881
3882
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003883static double ConvertBigNumToDouble(const UsefulBufC BigNum)
3884{
3885 double dResult;
3886
3887 dResult = 0.0;
3888 const uint8_t *pByte = BigNum.ptr;
3889 size_t uLen = BigNum.len;
3890 /* This will overflow and become the float value INFINITY if the number
3891 is too large to fit. No error will be logged.
3892 TODO: should an error be logged? */
3893 while(uLen--) {
3894 dResult = (dResult * 256.0) + (double)*pByte++;
3895 }
3896
3897 return dResult;
3898}
3899
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003900static QCBORError DoubleConvertAll(const QCBORItem *pItem, uint32_t uOptions, double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003901{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003902 /*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003903 https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
3904
3905 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003906 switch(pItem->uDataType) {
3907 // TODO: type float
3908 case QCBOR_TYPE_DECIMAL_FRACTION:
3909 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3910 // TODO: rounding and overflow errors
3911 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
3912 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
3913 } else {
3914 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3915 }
3916 break;
3917
3918 case QCBOR_TYPE_BIGFLOAT:
3919 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
3920 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
3921 exp2((double)pItem->val.expAndMantissa.nExponent);
3922 } else {
3923 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3924 }
3925 break;
3926
3927 case QCBOR_TYPE_POSBIGNUM:
3928 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3929 *pdValue = ConvertBigNumToDouble(pItem->val.bigNum);
3930 } else {
3931 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3932 }
3933 break;
3934
3935 case QCBOR_TYPE_NEGBIGNUM:
3936 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07003937 *pdValue = -1-ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003938 } else {
3939 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3940 }
3941 break;
3942
3943 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
3944 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3945 double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
3946 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
3947 } else {
3948 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3949 }
3950 break;
3951
3952 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
3953 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3954 double dMantissa = -ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
3955 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
3956 } else {
3957 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3958 }
3959 break;
3960
3961 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
3962 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3963 double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
3964 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
3965 } else {
3966 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3967 }
3968 break;
3969
3970 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
3971 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07003972 double dMantissa = -1-ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003973 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
3974 } else {
3975 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3976 }
3977 break;
3978
3979 default:
3980 return QCBOR_ERR_UNEXPECTED_TYPE;
3981 }
3982
3983 return QCBOR_SUCCESS;
3984}
3985
3986
3987/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003988 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003989*/
3990void QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, double *pdValue)
3991{
3992
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003993 QCBORItem Item;
3994
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003995 QCBORDecode_GetDoubleConvertInternal(pMe, uOptions, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003996
3997 if(pMe->uLastError == QCBOR_SUCCESS) {
3998 // The above conversion succeeded
3999 return;
4000 }
4001
4002 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
4003 // The above conversion failed in a way that code below can't correct
4004 return;
4005 }
4006
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004007 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004008}
4009
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004010
4011/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004012 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004013*/
4014void QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, double *pdValue)
4015{
4016 QCBORItem Item;
4017
4018 QCBORDecode_GetDoubleConvertInternalInMapN(pMe, nLabel, uOptions, pdValue, &Item);
4019
4020 if(pMe->uLastError == QCBOR_SUCCESS) {
4021 // The above conversion succeeded
4022 return;
4023 }
4024
4025 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
4026 // The above conversion failed in a way that code below can't correct
4027 return;
4028 }
4029
4030 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
4031}
4032
4033
4034/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004035 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004036*/
4037void QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, double *pdValue)
4038{
4039 QCBORItem Item;
4040 QCBORDecode_GetDoubleConvertInternalInMapSZ(pMe, szLabel, uOptions, pdValue, &Item);
4041
4042 if(pMe->uLastError == QCBOR_SUCCESS) {
4043 // The above conversion succeeded
4044 return;
4045 }
4046
4047 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
4048 // The above conversion failed in a way that code below can't correct
4049 return;
4050 }
4051
4052 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
4053}
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004054
4055
4056void FarfDecimalFraction(QCBORDecodeContext *pMe,
4057 uint8_t uTagRequirement,
4058 QCBORItem *pItem,
4059 int64_t *pnMantissa,
4060 int64_t *pnExponent)
4061{
4062 QCBORError uErr;
4063
4064 if(pItem->uDataType == QCBOR_TYPE_ARRAY) {
4065 if(uTagRequirement == QCBOR_TAGSPEC_MATCH_TAG_CONTENT_TYPE) {
4066 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4067 return;
4068 }
4069 uErr = QCBORDecode_MantissaAndExponent(pMe, pItem);
4070 if(uErr != QCBOR_SUCCESS) {
4071 pMe->uLastError = (uint8_t)uErr;
4072 return;
4073 }
4074 }
4075
4076 if(uTagRequirement == QCBOR_TAGSPEC_MATCH_TAG_CONTENT_TYPE) {
4077 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4078 return;
4079 }
4080
4081 switch (pItem->uDataType) {
4082
4083 case QCBOR_TYPE_DECIMAL_FRACTION:
4084 *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
4085 *pnExponent = pItem->val.expAndMantissa.nExponent;
4086 break;
4087
4088 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
4089 *pnExponent = pItem->val.expAndMantissa.nExponent;
4090
4091 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
4092 if(uErr != QCBOR_SUCCESS) {
4093 pMe->uLastError = (uint8_t)uErr;
4094 }
4095 break;
4096
4097 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
4098 *pnExponent = pItem->val.expAndMantissa.nExponent;
4099
4100 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
4101 if(uErr != QCBOR_SUCCESS) {
4102 pMe->uLastError = (uint8_t)uErr;
4103 }
4104 break;
4105
4106 default:
4107 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4108 }
4109}
4110
4111void QCBORDecode_GetDecimalFractionN(QCBORDecodeContext *pMe,
4112 uint8_t uTagRequirement,
4113 int64_t nLabel,
4114 int64_t *pnMantissa,
4115 int64_t *pnExponent)
4116{
4117 QCBORItem Item;
4118
4119 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
4120 FarfDecimalFraction(pMe, uTagRequirement, &Item, pnMantissa, pnExponent);
4121}
4122
4123
4124
4125void QCBORDecode_GetDecimalFractionSZ(QCBORDecodeContext *pMe,
4126 uint8_t uTagRequirement,
4127 const char *szLabel,
4128 int64_t *pnMantissa,
4129 int64_t *pnExponent)
4130{
4131 QCBORItem Item;
4132
4133 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4134
4135 FarfDecimalFraction(pMe, uTagRequirement, &Item, pnMantissa, pnExponent);
4136}
4137
4138
4139UsefulBufC ConvertIntToBigNum(uint64_t uInt, UsefulBuf Buffer)
4140{
4141 while(uInt & 0xff0000000000UL) {
4142 uInt = uInt << 8;
4143 };
4144
4145 UsefulOutBuf UOB;
4146
4147 UsefulOutBuf_Init(&UOB, Buffer);
4148
4149 while(uInt) {
4150 UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff0000000000UL) >> 56));
4151 uInt = uInt << 8;
4152 }
4153
4154 return UsefulOutBuf_OutUBuf(&UOB);
4155}
4156
4157
4158void QCBORDecode_GetDecimalFractionBigN(QCBORDecodeContext *pMe,
4159 uint8_t uTagRequirement,
4160 int64_t nLabel,
4161 UsefulBuf pBufferForMantissa,
4162 UsefulBufC *pMantissa,
4163 bool *pbIsNegative,
4164 int64_t *pnExponent)
4165{
4166 QCBORItem Item;
4167 QCBORError uErr;
4168
4169 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
4170
4171 if(Item.uDataType == QCBOR_TYPE_ARRAY) {
4172 uErr = QCBORDecode_MantissaAndExponent(pMe, &Item);
4173 if(uErr != QCBOR_SUCCESS) {
4174 pMe->uLastError = (uint8_t)uErr;
4175 return;
4176 }
4177 }
4178
4179 uint64_t uMantissa;
4180
4181 switch (Item.uDataType) {
4182
4183 case QCBOR_TYPE_DECIMAL_FRACTION:
4184 if(Item.val.expAndMantissa.Mantissa.nInt >= 0) {
4185 uMantissa = (uint64_t)Item.val.expAndMantissa.Mantissa.nInt;
4186 *pbIsNegative = false;
4187 } else {
4188 uMantissa = (uint64_t)-Item.val.expAndMantissa.Mantissa.nInt;
4189 *pbIsNegative = true;
4190 }
4191 *pMantissa = ConvertIntToBigNum(uMantissa, pBufferForMantissa);
4192 *pnExponent = Item.val.expAndMantissa.nExponent;
4193 break;
4194
4195 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
4196 *pnExponent = Item.val.expAndMantissa.nExponent;
4197 *pMantissa = Item.val.expAndMantissa.Mantissa.bigNum;
4198 *pbIsNegative = false;
4199 break;
4200
4201 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
4202 *pnExponent = Item.val.expAndMantissa.nExponent;
4203 *pMantissa = Item.val.expAndMantissa.Mantissa.bigNum;
4204 *pbIsNegative = true;
4205 break;
4206
4207 default:
4208 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4209 }
4210}