blob: 05059e4a741945bd07b482a944261ec3c27334d1 [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 Lundblade2b843b52020-06-16 20:51:03 -0700210inline static bool
211DecodeNesting_BoundedIsType(const QCBORDecodeNesting *pNesting, uint8_t uType)
212{
213 if(pNesting->pCurrentMap->uMajorType == uType) {
214 return true;
215 } else {
216 return false;
217 }
218}
219
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700220
221// return 1 if closed out an array or map
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700222inline static void
223DecodeNesting_DecrementX(QCBORDecodeNesting *pNesting)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700224{
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700225 pNesting->pCurrent->uCount--;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700226}
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700227
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700228inline static bool
229DecodeNesting_IsEndOfDefiniteLengthMapOrArray(QCBORDecodeNesting *pNesting)
230{
231 if(pNesting->pCurrent->uCount == 0) {
232 return true;
233 } else {
234 return false;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700235 }
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800236}
237
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700238inline static void
239DecodeNesting_Ascend(QCBORDecodeNesting *pNesting)
240{
241 pNesting->pCurrent--;
242}
243
244
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700245
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700246
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700247inline static void
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700248DecodeNesting_EnterBoundedMode(QCBORDecodeNesting *pNesting, size_t uOffset)
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700249{
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700250 /* Have descended into this is called. The job here is just to mark it in bounded mode */
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700251 pNesting->pCurrentMap = pNesting->pCurrent;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700252 pNesting->pCurrentMap->uType |= QCBOR_NEST_TYPE_IS_BOUND;
253 // Cast to uint32_t is safe because QCBOR restricts encoded input to < UINT32_MAX
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700254 pNesting->pCurrentMap->uOffset = (uint32_t)uOffset;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700255}
256
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700257
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700258
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700259
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700260inline static QCBORError
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700261DecodeNesting_Descend(QCBORDecodeNesting *pNesting, uint8_t uQCBORType, uint64_t uCount, uint32_t uEndOffset)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700262{
263 QCBORError nReturn = QCBOR_SUCCESS;
264
265 if(uCount == 0) {
266 // Nothing to do for empty definite lenth arrays. They are just are
267 // effectively the same as an item that is not a map or array
268 goto Done;
269 // Empty indefinite length maps and arrays are handled elsewhere
270 }
271
272 // Error out if arrays is too long to handle
273 if(uCount != UINT16_MAX && uCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
274 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
275 goto Done;
276 }
277
278 // Error out if nesting is too deep
279 if(pNesting->pCurrent >= &(pNesting->pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING])) {
280 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
281 goto Done;
282 }
283
284 // The actual descend
285 pNesting->pCurrent++;
286
287 // Fill in the new level fully
288 pNesting->pCurrent->uMajorType = uQCBORType;
289 pNesting->pCurrent->uCount = (uint16_t)uCount;
290 pNesting->pCurrent->uSaveCount = (uint16_t)uCount;
291 pNesting->pCurrent->uEndOffset = uEndOffset;
292 pNesting->pCurrent->uMapMode = 0;
293
294Done:
295 return nReturn;;
296}
297
298
299
Laurence Lundbladeee851742020-01-08 08:37:05 -0800300inline static void
301DecodeNesting_Init(QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700302{
303 pNesting->pCurrent = &(pNesting->pMapsAndArrays[0]);
304}
305
306
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700307static void DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting, QCBORDecodeNesting *pSave)
308{
309 *pSave = *pNesting;
310 pNesting->pCurrent = pNesting->pCurrentMap;
311
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700312 if(!DecodeNesting_IsIndefiniteLength(pNesting)) {
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700313 pNesting->pCurrent->uCount = pNesting->pCurrent->uSaveCount;
314 }
315}
316
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700317static inline void DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting, QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700318{
319 *pNesting = *pSave;
320}
321
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700322QCBORError DecodeNesting_EnterBstr(QCBORDecodeNesting *pNesting, uint32_t uEndOffset)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700323{
324 QCBORError uReturn ;
325
326 // Error out if nesting is too deep
327 if(pNesting->pCurrent >= &(pNesting->pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING])) {
328 uReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
329 goto Done;
330 }
331
332 // The actual descend
333 pNesting->pCurrent++;
334
335 // Record a few details for this nesting level
336 pNesting->pCurrent->uMajorType = 1; // TODO the right value for a bstr
337 pNesting->pCurrent->uCount = 0xffff;
338 pNesting->pCurrent->uSaveCount = 0xffff;
339 pNesting->pCurrent->uType = 0;
340
341 uReturn = QCBOR_SUCCESS;
342
343Done:
344 return uReturn;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700345}
346
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700347
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700348
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700349
Laurence Lundbladeee851742020-01-08 08:37:05 -0800350/*===========================================================================
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800351 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
352
353 The following four functions are pretty wrappers for invocation of
354 the string allocator supplied by the caller.
355
Laurence Lundbladeee851742020-01-08 08:37:05 -0800356 ===========================================================================*/
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800357
Laurence Lundbladeee851742020-01-08 08:37:05 -0800358static inline void
359StringAllocator_Free(const QCORInternalAllocator *pMe, void *pMem)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800360{
361 (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, 0);
362}
363
Laurence Lundbladeee851742020-01-08 08:37:05 -0800364// StringAllocator_Reallocate called with pMem NULL is
365// equal to StringAllocator_Allocate()
366static inline UsefulBuf
367StringAllocator_Reallocate(const QCORInternalAllocator *pMe,
368 void *pMem,
369 size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800370{
371 return (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, uSize);
372}
373
Laurence Lundbladeee851742020-01-08 08:37:05 -0800374static inline UsefulBuf
375StringAllocator_Allocate(const QCORInternalAllocator *pMe, size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800376{
377 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
378}
379
Laurence Lundbladeee851742020-01-08 08:37:05 -0800380static inline void
381StringAllocator_Destruct(const QCORInternalAllocator *pMe)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800382{
383 if(pMe->pfAllocator) {
384 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
385 }
386}
387
388
389
Laurence Lundbladeee851742020-01-08 08:37:05 -0800390/*===========================================================================
391 QCBORDecode -- The main implementation of CBOR decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700392
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800393 See qcbor/qcbor_decode.h for definition of the object
394 used here: QCBORDecodeContext
Laurence Lundbladeee851742020-01-08 08:37:05 -0800395 ===========================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700396/*
397 Public function, see header file
398 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800399void QCBORDecode_Init(QCBORDecodeContext *me,
400 UsefulBufC EncodedCBOR,
401 QCBORDecodeMode nDecodeMode)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700402{
403 memset(me, 0, sizeof(QCBORDecodeContext));
404 UsefulInputBuf_Init(&(me->InBuf), EncodedCBOR);
Laurence Lundbladeee851742020-01-08 08:37:05 -0800405 // Don't bother with error check on decode mode. If a bad value is
406 // passed it will just act as if the default normal mode of 0 was set.
Laurence Lundbladee6bcef12020-04-01 10:56:27 -0700407 me->uDecodeMode = (uint8_t)nDecodeMode;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700408 DecodeNesting_Init(&(me->nesting));
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700409 for(int i = 0; i < QCBOR_NUM_MAPPED_TAGS; i++) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -0700410 me->auMappedTags[i] = CBOR_TAG_INVALID16;
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700411 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700412}
413
414
415/*
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700416 Public function, see header file
417 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800418void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
419 QCBORStringAllocate pfAllocateFunction,
420 void *pAllocateContext,
421 bool bAllStrings)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700422{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800423 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
424 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
425 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700426}
427
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800428
429/*
430 Public function, see header file
431 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800432void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *me,
433 const QCBORTagListIn *pTagList)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700434{
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700435 // This does nothing now. It is retained for backwards compatibility
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700436}
437
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700438
439/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800440 This decodes the fundamental part of a CBOR data item, the type and
441 number
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800442
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700443 This is the Counterpart to InsertEncodedTypeAndNumber().
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800444
Laurence Lundbladeee851742020-01-08 08:37:05 -0800445 This does the network->host byte order conversion. The conversion
446 here also results in the conversion for floats in addition to that
447 for lengths, tags and integer values.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800448
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700449 This returns:
450 pnMajorType -- the major type for the item
Laurence Lundbladeee851742020-01-08 08:37:05 -0800451
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800452 puArgument -- the "number" which is used a the value for integers,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800453 tags and floats and length for strings and arrays
454
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800455 pnAdditionalInfo -- Pass this along to know what kind of float or
Laurence Lundbladeee851742020-01-08 08:37:05 -0800456 if length is indefinite
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800457
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800458 The int type is preferred to uint8_t for some variables as this
459 avoids integer promotions, can reduce code size and makes
460 static analyzers happier.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700461 */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800462inline static QCBORError DecodeTypeAndNumber(UsefulInputBuf *pUInBuf,
463 int *pnMajorType,
464 uint64_t *puArgument,
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800465 int *pnAdditionalInfo)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700466{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700467 QCBORError nReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800468
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700469 // Get the initial byte that every CBOR data item has
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800470 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800471
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700472 // Break down the initial byte
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800473 const int nTmpMajorType = nInitialByte >> 5;
474 const int nAdditionalInfo = nInitialByte & 0x1f;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800475
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800476 // Where the number or argument accumulates
477 uint64_t uArgument;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800478
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800479 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700480 // Need to get 1,2,4 or 8 additional argument bytes. Map
481 // LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800482 static const uint8_t aIterate[] = {1,2,4,8};
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800483
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800484 // Loop getting all the bytes in the argument
485 uArgument = 0;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800486 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800487 // This shift and add gives the endian conversion
488 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
489 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800490 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800491 // The reserved and thus-far unused additional info values
492 nReturn = QCBOR_ERR_UNSUPPORTED;
493 goto Done;
494 } else {
495 // Less than 24, additional info is argument or 31, an indefinite length
496 // No more bytes to get
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800497 uArgument = (uint64_t)nAdditionalInfo;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700498 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800499
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700500 if(UsefulInputBuf_GetError(pUInBuf)) {
501 nReturn = QCBOR_ERR_HIT_END;
502 goto Done;
503 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800504
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700505 // All successful if we got here.
506 nReturn = QCBOR_SUCCESS;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800507 *pnMajorType = nTmpMajorType;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800508 *puArgument = uArgument;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800509 *pnAdditionalInfo = nAdditionalInfo;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800510
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700511Done:
512 return nReturn;
513}
514
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800515
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700516/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800517 CBOR doesn't explicitly specify two's compliment for integers but all
518 CPUs use it these days and the test vectors in the RFC are so. All
519 integers in the CBOR structure are positive and the major type
520 indicates positive or negative. CBOR can express positive integers
521 up to 2^x - 1 where x is the number of bits and negative integers
522 down to 2^x. Note that negative numbers can be one more away from
523 zero than positive. Stdint, as far as I can tell, uses two's
524 compliment to represent negative integers.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800525
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700526 See http://www.unix.org/whitepapers/64bit.html for reasons int isn't
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800527 used carefully here, and in particular why it isn't used in the interface.
528 Also see
529 https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers
530
531 Int is used for values that need less than 16-bits and would be subject
532 to integer promotion and complaining by static analyzers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700533 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800534inline static QCBORError
535DecodeInteger(int nMajorType, uint64_t uNumber, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700536{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700537 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800538
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700539 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
540 if (uNumber <= INT64_MAX) {
541 pDecodedItem->val.int64 = (int64_t)uNumber;
542 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800543
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700544 } else {
545 pDecodedItem->val.uint64 = uNumber;
546 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800547
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700548 }
549 } else {
550 if(uNumber <= INT64_MAX) {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800551 // CBOR's representation of negative numbers lines up with the
552 // two-compliment representation. A negative integer has one
553 // more in range than a positive integer. INT64_MIN is
554 // equal to (-INT64_MAX) - 1.
555 pDecodedItem->val.int64 = (-(int64_t)uNumber) - 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700556 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800557
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700558 } else {
559 // C can't represent a negative integer in this range
Laurence Lundblade21d1d812019-09-28 22:47:49 -1000560 // so it is an error.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700561 nReturn = QCBOR_ERR_INT_OVERFLOW;
562 }
563 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800564
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700565 return nReturn;
566}
567
568// Make sure #define value line up as DecodeSimple counts on this.
569#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
570#error QCBOR_TYPE_FALSE macro value wrong
571#endif
572
573#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
574#error QCBOR_TYPE_TRUE macro value wrong
575#endif
576
577#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
578#error QCBOR_TYPE_NULL macro value wrong
579#endif
580
581#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
582#error QCBOR_TYPE_UNDEF macro value wrong
583#endif
584
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700585#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
586#error QCBOR_TYPE_BREAK macro value wrong
587#endif
588
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700589#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
590#error QCBOR_TYPE_DOUBLE macro value wrong
591#endif
592
593#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
594#error QCBOR_TYPE_FLOAT macro value wrong
595#endif
596
597/*
598 Decode true, false, floats, break...
599 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800600inline static QCBORError
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800601DecodeSimple(int nAdditionalInfo, uint64_t uNumber, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700602{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700603 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800604
Laurence Lundbladeee851742020-01-08 08:37:05 -0800605 // uAdditionalInfo is 5 bits from the initial byte compile time checks
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800606 // above make sure uAdditionalInfo values line up with uDataType values.
607 // DecodeTypeAndNumber never returns a major type > 1f so cast is safe
608 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800609
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800610 switch(nAdditionalInfo) {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800611 // No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they are
612 // caught before this is called.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800613
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700614 case HALF_PREC_FLOAT:
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700615 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uNumber);
616 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700617 break;
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700618 case SINGLE_PREC_FLOAT:
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700619 pDecodedItem->val.dfnum = (double)UsefulBufUtil_CopyUint32ToFloat((uint32_t)uNumber);
620 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700621 break;
622 case DOUBLE_PREC_FLOAT:
623 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uNumber);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700624 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700625 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800626
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700627 case CBOR_SIMPLEV_FALSE: // 20
628 case CBOR_SIMPLEV_TRUE: // 21
629 case CBOR_SIMPLEV_NULL: // 22
630 case CBOR_SIMPLEV_UNDEF: // 23
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700631 case CBOR_SIMPLE_BREAK: // 31
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700632 break; // nothing to do
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800633
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700634 case CBOR_SIMPLEV_ONEBYTE: // 24
635 if(uNumber <= CBOR_SIMPLE_BREAK) {
636 // This takes out f8 00 ... f8 1f which should be encoded as e0 … f7
Laurence Lundblade077475f2019-04-26 09:06:33 -0700637 nReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700638 goto Done;
639 }
Laurence Lundblade5e390822019-01-06 12:35:01 -0800640 /* FALLTHROUGH */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700641 // fall through intentionally
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800642
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700643 default: // 0-19
644 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
Laurence Lundbladeee851742020-01-08 08:37:05 -0800645 /*
646 DecodeTypeAndNumber will make uNumber equal to
647 uAdditionalInfo when uAdditionalInfo is < 24 This cast is
648 safe because the 2, 4 and 8 byte lengths of uNumber are in
649 the double/float cases above
650 */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700651 pDecodedItem->val.uSimple = (uint8_t)uNumber;
652 break;
653 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800654
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700655Done:
656 return nReturn;
657}
658
659
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700660/*
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530661 Decode text and byte strings. Call the string allocator if asked to.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700662 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800663inline static QCBORError DecodeBytes(const QCORInternalAllocator *pAllocator,
664 int nMajorType,
665 uint64_t uStrLen,
666 UsefulInputBuf *pUInBuf,
667 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700668{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700669 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800670
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800671 // CBOR lengths can be 64 bits, but size_t is not 64 bits on all CPUs.
672 // This check makes the casts to size_t below safe.
673
674 // 4 bytes less than the largest sizeof() so this can be tested by
675 // putting a SIZE_MAX length in the CBOR test input (no one will
676 // care the limit on strings is 4 bytes shorter).
677 if(uStrLen > SIZE_MAX-4) {
678 nReturn = QCBOR_ERR_STRING_TOO_LONG;
679 goto Done;
680 }
681
682 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, (size_t)uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530683 if(UsefulBuf_IsNULLC(Bytes)) {
684 // Failed to get the bytes for this string item
685 nReturn = QCBOR_ERR_HIT_END;
686 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700687 }
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530688
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800689 if(pAllocator) {
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530690 // We are asked to use string allocator to make a copy
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800691 UsefulBuf NewMem = StringAllocator_Allocate(pAllocator, (size_t)uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530692 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade30816f22018-11-10 13:40:22 +0700693 nReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530694 goto Done;
695 }
696 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800697 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530698 } else {
699 // Normal case with no string allocator
700 pDecodedItem->val.string = Bytes;
701 }
Laurence Lundbladeee851742020-01-08 08:37:05 -0800702 const bool bIsBstr = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING);
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800703 // Cast because ternary operator causes promotion to integer
704 pDecodedItem->uDataType = (uint8_t)(bIsBstr ? QCBOR_TYPE_BYTE_STRING
705 : QCBOR_TYPE_TEXT_STRING);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800706
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530707Done:
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700708 return nReturn;
709}
710
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700711
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800712
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700713
714
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700715
716
Laurence Lundbladeee851742020-01-08 08:37:05 -0800717// Make sure the constants align as this is assumed by
718// the GetAnItem() implementation
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700719#if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
720#error QCBOR_TYPE_ARRAY value not lined up with major type
721#endif
722#if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
723#error QCBOR_TYPE_MAP value not lined up with major type
724#endif
725
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700726/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800727 This gets a single data item and decodes it including preceding
728 optional tagging. This does not deal with arrays and maps and nesting
729 except to decode the data item introducing them. Arrays and maps are
730 handled at the next level up in GetNext().
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800731
Laurence Lundbladeee851742020-01-08 08:37:05 -0800732 Errors detected here include: an array that is too long to decode,
733 hit end of buffer unexpectedly, a few forms of invalid encoded CBOR
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700734 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800735static QCBORError GetNext_Item(UsefulInputBuf *pUInBuf,
736 QCBORItem *pDecodedItem,
737 const QCORInternalAllocator *pAllocator)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700738{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700739 QCBORError nReturn;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800740
Laurence Lundbladeee851742020-01-08 08:37:05 -0800741 /*
742 Get the major type and the number. Number could be length of more
743 bytes or the value depending on the major type nAdditionalInfo is
744 an encoding of the length of the uNumber and is needed to decode
745 floats and doubles
746 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800747 int nMajorType;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700748 uint64_t uNumber;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800749 int nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800750
Laurence Lundblade4b09f632019-10-09 14:34:59 -0700751 memset(pDecodedItem, 0, sizeof(QCBORItem));
752
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800753 nReturn = DecodeTypeAndNumber(pUInBuf, &nMajorType, &uNumber, &nAdditionalInfo);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800754
Laurence Lundbladeee851742020-01-08 08:37:05 -0800755 // Error out here if we got into trouble on the type and number. The
756 // code after this will not work if the type and number is not good.
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700757 if(nReturn) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700758 goto Done;
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700759 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800760
Laurence Lundbladeee851742020-01-08 08:37:05 -0800761 // At this point the major type and the value are valid. We've got
762 // the type and the number that starts every CBOR data item.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800763 switch (nMajorType) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700764 case CBOR_MAJOR_TYPE_POSITIVE_INT: // Major type 0
765 case CBOR_MAJOR_TYPE_NEGATIVE_INT: // Major type 1
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800766 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700767 nReturn = QCBOR_ERR_BAD_INT;
768 } else {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800769 nReturn = DecodeInteger(nMajorType, uNumber, pDecodedItem);
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700770 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700771 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800772
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700773 case CBOR_MAJOR_TYPE_BYTE_STRING: // Major type 2
774 case CBOR_MAJOR_TYPE_TEXT_STRING: // Major type 3
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800775 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
776 const bool bIsBstr = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING);
777 pDecodedItem->uDataType = (uint8_t)(bIsBstr ? QCBOR_TYPE_BYTE_STRING
778 : QCBOR_TYPE_TEXT_STRING);
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530779 pDecodedItem->val.string = (UsefulBufC){NULL, SIZE_MAX};
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700780 } else {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800781 nReturn = DecodeBytes(pAllocator, nMajorType, uNumber, pUInBuf, pDecodedItem);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700782 }
783 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800784
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700785 case CBOR_MAJOR_TYPE_ARRAY: // Major type 4
786 case CBOR_MAJOR_TYPE_MAP: // Major type 5
787 // Record the number of items in the array or map
788 if(uNumber > QCBOR_MAX_ITEMS_IN_ARRAY) {
789 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
790 goto Done;
791 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800792 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530793 pDecodedItem->val.uCount = UINT16_MAX; // Indicate indefinite length
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700794 } else {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800795 // type conversion OK because of check above
796 pDecodedItem->val.uCount = (uint16_t)uNumber;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700797 }
Laurence Lundbladeee851742020-01-08 08:37:05 -0800798 // C preproc #if above makes sure constants for major types align
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800799 // DecodeTypeAndNumber never returns a major type > 7 so cast is safe
800 pDecodedItem->uDataType = (uint8_t)nMajorType;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700801 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800802
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700803 case CBOR_MAJOR_TYPE_OPTIONAL: // Major type 6, optional prepended tags
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800804 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700805 nReturn = QCBOR_ERR_BAD_INT;
806 } else {
807 pDecodedItem->val.uTagV = uNumber;
808 pDecodedItem->uDataType = QCBOR_TYPE_OPTTAG;
809 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700810 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800811
Laurence Lundbladeee851742020-01-08 08:37:05 -0800812 case CBOR_MAJOR_TYPE_SIMPLE:
813 // Major type 7, float, double, true, false, null...
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800814 nReturn = DecodeSimple(nAdditionalInfo, uNumber, pDecodedItem);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700815 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800816
Laurence Lundbladeee851742020-01-08 08:37:05 -0800817 default:
818 // Never happens because DecodeTypeAndNumber() should never return > 7
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700819 nReturn = QCBOR_ERR_UNSUPPORTED;
820 break;
821 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800822
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700823Done:
824 return nReturn;
825}
826
827
828
829/*
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800830 This layer deals with indefinite length strings. It pulls all the
Laurence Lundbladeee851742020-01-08 08:37:05 -0800831 individual chunk items together into one QCBORItem using the string
832 allocator.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800833
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530834 Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700835 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800836static inline QCBORError
837GetNext_FullItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700838{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700839 // Stack usage; int/ptr 2 UsefulBuf 2 QCBORItem -- 96
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700840
841 // Get pointer to string allocator. First use is to pass it to
842 // GetNext_Item() when option is set to allocate for *every* string.
843 // Second use here is to allocate space to coallese indefinite
844 // length string items into one.
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800845 const QCORInternalAllocator *pAllocator = me->StringAllocator.pfAllocator ?
846 &(me->StringAllocator) :
847 NULL;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800848
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700849 QCBORError nReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800850 nReturn = GetNext_Item(&(me->InBuf),
851 pDecodedItem,
852 me->bStringAllocateAll ? pAllocator: NULL);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700853 if(nReturn) {
854 goto Done;
855 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800856
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700857 // To reduce code size by removing support for indefinite length strings, the
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530858 // code in this function from here down can be eliminated. Run tests, except
859 // indefinite length string tests, to be sure all is OK if this is removed.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800860
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800861 // Only do indefinite length processing on strings
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700862 const uint8_t uStringType = pDecodedItem->uDataType;
863 if(uStringType!= QCBOR_TYPE_BYTE_STRING && uStringType != QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700864 goto Done; // no need to do any work here on non-string types
865 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800866
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800867 // Is this a string with an indefinite length?
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530868 if(pDecodedItem->val.string.len != SIZE_MAX) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800869 goto Done; // length is not indefinite, so no work to do here
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700870 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800871
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530872 // Can't do indefinite length strings without a string allocator
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800873 if(pAllocator == NULL) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700874 nReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
875 goto Done;
876 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800877
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700878 // Loop getting chunk of indefinite string
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700879 UsefulBufC FullString = NULLUsefulBufC;
880
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700881 for(;;) {
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700882 // Get item for next chunk
883 QCBORItem StringChunkItem;
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700884 // NULL string allocator passed here. Do not need to allocate
885 // chunks even if bStringAllocateAll is set.
Laurence Lundbladefae26bf2019-02-18 11:15:43 -0800886 nReturn = GetNext_Item(&(me->InBuf), &StringChunkItem, NULL);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700887 if(nReturn) {
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700888 break; // Error getting the next chunk
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700889 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800890
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530891 // See if it is a marker at end of indefinite length string
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700892 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800893 // String is complete
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700894 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +0530895 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700896 break;
897 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800898
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700899 // Match data type of chunk to type at beginning.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530900 // Also catches error of other non-string types that don't belong.
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700901 // Also catches indefinite length strings inside indefinite length strings
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800902 if(StringChunkItem.uDataType != uStringType ||
903 StringChunkItem.val.string.len == SIZE_MAX) {
Laurence Lundblade30816f22018-11-10 13:40:22 +0700904 nReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700905 break;
906 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800907
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530908 // Alloc new buffer or expand previously allocated buffer so it can fit
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800909 // The first time throurgh FullString.ptr is NULL and this is
910 // equivalent to StringAllocator_Allocate()
911 UsefulBuf NewMem = StringAllocator_Reallocate(pAllocator,
912 UNCONST_POINTER(FullString.ptr),
913 FullString.len + StringChunkItem.val.string.len);
914
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700915 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530916 // Allocation of memory for the string failed
Laurence Lundblade30816f22018-11-10 13:40:22 +0700917 nReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700918 break;
919 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800920
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700921 // Copy new string chunk at the end of string so far.
922 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700923 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800924
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800925 if(nReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
926 // Getting the item failed, clean up the allocated memory
927 StringAllocator_Free(pAllocator, UNCONST_POINTER(FullString.ptr));
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700928 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800929
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700930Done:
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700931 return nReturn;
932}
933
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700934
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700935uint64_t ConvertTag(QCBORDecodeContext *me, uint16_t uTagVal) {
936 if(uTagVal < 0xfff0) {
937 return uTagVal;
938 } else {
939 // TODO constant and error check
940 int x = uTagVal - 0xfff0;
941 return me->auMappedTags[x];
942 }
943}
944
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700945/*
Laurence Lundblade59289e52019-12-30 13:44:37 -0800946 Gets all optional tag data items preceding a data item that is not an
947 optional tag and records them as bits in the tag map.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700948 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800949static QCBORError
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700950GetNext_TaggedItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700951{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700952 // Stack usage: int/ptr: 3 -- 24
Laurence Lundblade30816f22018-11-10 13:40:22 +0700953 QCBORError nReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700954
Laurence Lundbladec75e68b2020-06-15 20:34:46 -0700955 uint16_t auTags[QCBOR_MAX_TAGS_PER_ITEM] = {CBOR_TAG_INVALID16,
956 CBOR_TAG_INVALID16,
957 CBOR_TAG_INVALID16,
958 CBOR_TAG_INVALID16};
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700959
Laurence Lundblade59289e52019-12-30 13:44:37 -0800960 // Loop fetching items until the item fetched is not a tag
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700961 for(;;) {
962 nReturn = GetNext_FullItem(me, pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700963 if(nReturn) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700964 goto Done; // Error out of the loop
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700965 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800966
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700967 if(pDecodedItem->uDataType != QCBOR_TYPE_OPTTAG) {
968 // Successful exit from loop; maybe got some tags, maybe not
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700969 memcpy(pDecodedItem->uTags, auTags, sizeof(auTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700970 break;
971 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800972
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700973 // Is there room for the tag in the tags list?
974 size_t uTagIndex;
975 for(uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -0700976 if(auTags[uTagIndex] == CBOR_TAG_INVALID16) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700977 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700978 }
979 }
980 if(uTagIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -0700981 return QCBOR_ERR_TOO_MANY_TAGS;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700982 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800983
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700984 // Is the tag > 16 bits?
Laurence Lundbladec75e68b2020-06-15 20:34:46 -0700985 if(pDecodedItem->val.uTagV > CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700986 size_t uTagMapIndex;
987 // Is there room in the tag map?
988 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -0700989 if(me->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700990 break;
991 }
992 if(me->auMappedTags[uTagMapIndex] == pDecodedItem->val.uTagV) {
993 break;
994 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700995 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700996 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
997 // No room for the tag
998 return 97; // TODO error code
999 }
1000
1001 // Cover the case where tag is new and were it is already in the map
1002 me->auMappedTags[uTagMapIndex] = pDecodedItem->val.uTagV;
1003 auTags[uTagIndex] = (uint16_t)(uTagMapIndex + 0xfff0); // TODO proper constant and cast
1004
1005 } else {
1006 auTags[uTagIndex] = (uint16_t)pDecodedItem->val.uTagV;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001007 }
1008 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001009
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001010Done:
1011 return nReturn;
1012}
1013
1014
1015/*
Laurence Lundbladeee851742020-01-08 08:37:05 -08001016 This layer takes care of map entries. It combines the label and data
1017 items into one QCBORItem.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001018 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001019static inline QCBORError
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001020GetNext_MapEntry(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001021{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001022 // Stack use: int/ptr 1, QCBORItem -- 56
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001023 QCBORError nReturn = GetNext_TaggedItem(me, pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001024 if(nReturn)
1025 goto Done;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001026
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001027 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001028 // Break can't be a map entry
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001029 goto Done;
1030 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001031
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001032 if(me->uDecodeMode != QCBOR_DECODE_MODE_MAP_AS_ARRAY) {
1033 // In a map and caller wants maps decoded, not treated as arrays
1034
1035 if(DecodeNesting_TypeIsMap(&(me->nesting))) {
1036 // If in a map and the right decoding mode, get the label
1037
Laurence Lundbladeee851742020-01-08 08:37:05 -08001038 // Save label in pDecodedItem and get the next which will
1039 // be the real data
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001040 QCBORItem LabelItem = *pDecodedItem;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001041 nReturn = GetNext_TaggedItem(me, pDecodedItem);
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001042 if(nReturn)
1043 goto Done;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001044
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301045 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001046
1047 if(LabelItem.uDataType == QCBOR_TYPE_TEXT_STRING) {
1048 // strings are always good labels
1049 pDecodedItem->label.string = LabelItem.val.string;
1050 pDecodedItem->uLabelType = QCBOR_TYPE_TEXT_STRING;
1051 } else if (QCBOR_DECODE_MODE_MAP_STRINGS_ONLY == me->uDecodeMode) {
Laurence Lundbladeee851742020-01-08 08:37:05 -08001052 // It's not a string and we only want strings
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001053 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
1054 goto Done;
1055 } else if(LabelItem.uDataType == QCBOR_TYPE_INT64) {
1056 pDecodedItem->label.int64 = LabelItem.val.int64;
1057 pDecodedItem->uLabelType = QCBOR_TYPE_INT64;
1058 } else if(LabelItem.uDataType == QCBOR_TYPE_UINT64) {
1059 pDecodedItem->label.uint64 = LabelItem.val.uint64;
1060 pDecodedItem->uLabelType = QCBOR_TYPE_UINT64;
1061 } else if(LabelItem.uDataType == QCBOR_TYPE_BYTE_STRING) {
1062 pDecodedItem->label.string = LabelItem.val.string;
1063 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
1064 pDecodedItem->uLabelType = QCBOR_TYPE_BYTE_STRING;
1065 } else {
1066 // label is not an int or a string. It is an arrray
1067 // or a float or such and this implementation doesn't handle that.
1068 // Also, tags on labels are ignored.
1069 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
1070 goto Done;
1071 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001072 }
1073 } else {
1074 if(pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001075 if(pDecodedItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
1076 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
1077 goto Done;
1078 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001079 // Decoding a map as an array
1080 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001081 // Cast is safe because of check against QCBOR_MAX_ITEMS_IN_ARRAY/2
1082 // Cast is needed because of integer promotion
1083 pDecodedItem->val.uCount = (uint16_t)(pDecodedItem->val.uCount * 2);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001084 }
1085 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001086
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001087Done:
1088 return nReturn;
1089}
1090
1091
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001092static QCBORError
1093NextIsBreak(UsefulInputBuf *pUIB, bool *pbNextIsBreak)
1094{
1095 *pbNextIsBreak = false;
1096 if(UsefulInputBuf_BytesUnconsumed(pUIB) != 0) {
1097 // TODO: use the Peek method?
1098 QCBORItem Peek;
1099 size_t uPeek = UsefulInputBuf_Tell(pUIB);
1100 QCBORError uReturn = GetNext_Item(pUIB, &Peek, NULL);
1101 if(uReturn != QCBOR_SUCCESS) {
1102 return uReturn;
1103 }
1104 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
1105 // It is not a break, rewind so it can be processed normally.
1106 UsefulInputBuf_Seek(pUIB, uPeek);
1107 } else {
1108 *pbNextIsBreak = true;
1109 }
1110 }
1111
1112 return QCBOR_SUCCESS;
1113}
1114
1115
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001116/*
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001117 An item was just consumed, now figure out if it was the
1118 end of an array or map that can be closed out. That
1119 may in turn close out another map or array.
1120 */
1121static QCBORError Ascender(QCBORDecodeContext *pMe)
1122{
1123 QCBORError uReturn;
1124
1125 /* This loops ascending nesting levels as long as there is ascending to do */
1126 while(1) {
1127 if(!DecodeNesting_IsAtTop(&(pMe->nesting)) && !DecodeNesting_IsIndefiniteLength(&(pMe->nesting))) {
1128 /* 1st Case: in a definite length array (not a CBOR sequence). Simply
1129 decrement the item count. If it doesn't go to zero, then all is done.
1130 If it does go to zero, the bottom of the loop ascends one nesting level
1131 and the loop continues.
1132 */
1133 DecodeNesting_DecrementX(&(pMe->nesting));
1134 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
1135 /* Didn't close out map or array; all work here is done */
1136 break;
1137 }
1138
1139 } else {
1140 /* 2nd, 3rd, 4th and 5th cases where a check for a following CBOR break must be checked for */
1141 bool bIsBreak = false;
1142 uReturn = NextIsBreak(&(pMe->InBuf), &bIsBreak);
1143 if(uReturn != QCBOR_SUCCESS) {
1144 goto Done;
1145 }
1146
1147 if(bIsBreak) {
1148 if(DecodeNesting_IsAtTop(&(pMe->nesting))) {
1149 /* 2nd case where a break occurs at the top level and thus
1150 in a CBOR sequence. Always an error because break is
1151 not inside an indefinite length map or array. */
1152 uReturn = QCBOR_ERR_BAD_BREAK;
1153 goto Done;
1154 } else {
1155 /* 3rd case, the normal end of an indefinite length map
1156 or array. The bottom of the loop ascends one nesting
1157 level and the loop continues. */
1158 }
1159 } else {
1160 /* 4th case where an indefinite length array is not closed out
1161 and 5th case which is just an item in a CBOR sequence. In either
1162 there is no close out so all work here is done.
1163 */
1164 break;
1165 }
1166 }
1167
1168 /* All items in the level have been consumed. */
1169
1170 /* But ascent in bounded mode is only by explicit call to QCBORDecode_ExitBoundedMode() */
1171 if(DecodeNesting_InBoundedMode(&(pMe->nesting))) {
1172 /* Set the count to zero for indefinite length arrays to indicate cursor is at end of bounded map / array */
1173 pMe->nesting.pCurrent->uCount = 0;
1174 break;
1175 }
1176
1177 /* Finally, actually ascend one level. */
1178 DecodeNesting_Ascend(&(pMe->nesting));
1179 }
1180
1181 uReturn = QCBOR_SUCCESS;
1182
1183Done:
1184 return uReturn;
1185}
1186
1187
1188/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001189 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001190 TODO: correct this comment
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001191 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001192static QCBORError
1193QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001194{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001195 QCBORError uReturn;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001196 /* === First figure out if at the end of traversal === */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001197
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001198 /* Case 1. Out of bytes to consume.
1199
1200 This is either the end of the top-level CBOR that was give
1201 to QCBORDecode_Init() or the end of a tag 24 bstr wrapped CBOR.
1202 It is detected by all bytes being consumed from the UsefulInputBuf.
1203
1204 To go back out of the tag 24 bstr wrapped item, the caller must
1205 explicitly call Exit() which will reset the UsefulInputBuf
1206 to the next highest bstr wrapped or the top level.
1207
1208 This is always the end condition that QCBORDecode_Finish()
1209 considers complete.
1210
1211 TODO: can the DecodeNesting_IsAtTop be removed? QCBORDecode_Finish()
1212 will perform this check.
1213
1214 */
Laurence Lundblade937ea812020-05-08 11:38:23 -07001215 /* For a pre-order traversal a non-error end occurs when there
1216 are no more bytes to consume and the nesting level is at the top.
1217 If it's not at the top, then the CBOR is not well formed. This error
1218 is caught elsewhere.
1219
1220 This handles the end of CBOR sequences as well as non-sequences. */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001221 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf)) == 0 && DecodeNesting_IsAtTop(&(me->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001222 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001223 goto Done;
1224 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07001225
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001226
1227 /* Case 2. End of map or array in bounded mode
1228
1229 The caller is attempting traveral of a bounded map or array and
1230 has got to the end of it.
1231
1232 The caller must explicitly exit the bounded mode map or array
1233 to get past this condition.
1234
1235 To complete a decode of the full input CBOR, the caller must
1236 exit all maps and arrays in bounded mode and this is never
1237 the successful end of decoding.
1238
1239 */
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001240 /* It is also an end of the input when in map mode and the cursor
Laurence Lundblade937ea812020-05-08 11:38:23 -07001241 is at the end of the map */
1242
1243
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001244 // This is to handle bounded mode
Laurence Lundblade937ea812020-05-08 11:38:23 -07001245 if(DecodeNesting_AtEnd(&(me->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001246 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07001247 goto Done;
1248 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001249
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001250 /* === Not at the end; get another item === */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001251 uReturn = GetNext_MapEntry(me, pDecodedItem);
1252 if(uReturn) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001253 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001254 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301255
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001256 // Breaks ending arrays/maps are always processed at the end of this function.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301257 // They should never show up here.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301258 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001259 uReturn = QCBOR_ERR_BAD_BREAK;
Laurence Lundblade6de37062018-10-15 12:22:42 +05301260 goto Done;
Laurence Lundblade5b8c5852018-10-14 21:11:42 +05301261 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001262
Laurence Lundblade6de37062018-10-15 12:22:42 +05301263 // Record the nesting level for this data item before processing any of
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301264 // decrementing and descending.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301265 pDecodedItem->uNestingLevel = DecodeNesting_GetLevel(&(me->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001266
Laurence Lundblade6de37062018-10-15 12:22:42 +05301267 // Process the item just received for descent or decrement, and
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001268 // ascend if decrements are enough to close out a definite length array/map
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001269 if(IsMapOrArray(pDecodedItem->uDataType) && pDecodedItem->val.uCount != 0) {
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001270 // If the new item is array or map, the nesting level descends
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001271 uReturn = DecodeNesting_Descend(&(me->nesting), pDecodedItem->uDataType, pDecodedItem->val.uCount, 0L);
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001272 // Maps and arrays do count in as items in the map/array that encloses
1273 // them so a decrement needs to be done for them too, but that is done
1274 // only when all the items in them have been processed, not when they
Laurence Lundblade9916b1b2019-09-07 22:33:25 -07001275 // are opened with the exception of an empty map or array.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001276 if(uReturn != QCBOR_SUCCESS) {
1277 goto Done;
1278 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001279 }
1280
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001281 if(!IsMapOrArray(pDecodedItem->uDataType) ||
1282 pDecodedItem->val.uCount == 0 || pDecodedItem->val.uCount == UINT16_MAX) {
1283 /* The following cases are handled here:
1284 - A non-aggregate like an integer or string
1285 - An empty definite length map or array
1286 - An indefinite length map or array that might be empty or might not.
1287 */
1288
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001289
1290
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001291 /* === Figure out if item got closed out maps or arrays === */
1292
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001293 /*
1294 This needs to decrement, check for end and ascend
1295 the tree until an an ascend is not possible or the bounded
1296 limit is reached or the end of the encoded CBOR input
1297 is reached. For
1298 definite length maps and arrays the end is by count. For
1299 indefinite it is by a break.
1300
1301 Also state needs to be set that can tell the code at the
1302 beginning of this function that the end was reached.
1303
1304 This is complicated...
1305
1306
1307 This will handle an indefinite length array
1308 inside a definte length array inside an indefinite
1309 length array...
1310
1311 */
1312
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001313 // Decrement the count of items in the enclosing map/array
1314 // If the count in the enclosing map/array goes to zero, that
Laurence Lundblade6de37062018-10-15 12:22:42 +05301315 // triggers a decrement in the map/array above that and
1316 // an ascend in nesting level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001317 /* If the just consumed item is at the end of a map or
1318 array ascend in the nesting tracking. That may
1319 in turn may be the end of the above nesting level
1320 and so on up to the end of the whole encoded CBOR.
1321
1322 Each level could be a definite or indefinte length
1323 map or array. These are handled very differently.
1324
1325 */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001326 uReturn = Ascender(me);
1327 if(uReturn) {
1328 goto Done;
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001329 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05301330 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001331
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001332
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001333
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001334 /* === Tell the caller the nest level of the next item === */
1335
Laurence Lundblade6de37062018-10-15 12:22:42 +05301336 // Tell the caller what level is next. This tells them what maps/arrays
1337 // were closed out and makes it possible for them to reconstruct
1338 // the tree with just the information returned by GetNext
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07001339 // TODO: pull this into DecodeNesting_GetLevel
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001340 if(DecodeNesting_InBoundedMode(&(me->nesting)) && me->nesting.pCurrent->uCount == 0) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001341 // At end of a map / array in map mode, so next nest is 0 to
1342 // indicate this end.
1343 pDecodedItem->uNextNestLevel = 0;
1344 } else {
1345 pDecodedItem->uNextNestLevel = DecodeNesting_GetLevel(&(me->nesting));
1346 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001347
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001348Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001349 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundbladee9482dd2019-10-11 12:58:46 -07001350 // Make sure uDataType and uLabelType are QCBOR_TYPE_NONE
1351 memset(pDecodedItem, 0, sizeof(QCBORItem));
1352 }
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001353 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001354}
1355
1356
Laurence Lundblade59289e52019-12-30 13:44:37 -08001357/*
1358 Mostly just assign the right data type for the date string.
1359 */
1360inline static QCBORError DecodeDateString(QCBORItem *pDecodedItem)
1361{
1362 // Stack Use: UsefulBuf 1 16
1363 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1364 return QCBOR_ERR_BAD_OPT_TAG;
1365 }
1366
1367 const UsefulBufC Temp = pDecodedItem->val.string;
1368 pDecodedItem->val.dateString = Temp;
1369 pDecodedItem->uDataType = QCBOR_TYPE_DATE_STRING;
1370 return QCBOR_SUCCESS;
1371}
1372
1373
1374/*
Laurence Lundbladeee851742020-01-08 08:37:05 -08001375 The epoch formatted date. Turns lots of different forms of encoding
1376 date into uniform one
Laurence Lundblade59289e52019-12-30 13:44:37 -08001377 */
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001378static QCBORError DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08001379{
1380 // Stack usage: 1
1381 QCBORError nReturn = QCBOR_SUCCESS;
1382
1383 pDecodedItem->val.epochDate.fSecondsFraction = 0;
1384
1385 switch (pDecodedItem->uDataType) {
1386
1387 case QCBOR_TYPE_INT64:
1388 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
1389 break;
1390
1391 case QCBOR_TYPE_UINT64:
1392 if(pDecodedItem->val.uint64 > INT64_MAX) {
1393 nReturn = QCBOR_ERR_DATE_OVERFLOW;
1394 goto Done;
1395 }
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001396 pDecodedItem->val.epochDate.nSeconds = (int64_t)pDecodedItem->val.uint64;
Laurence Lundblade59289e52019-12-30 13:44:37 -08001397 break;
1398
1399 case QCBOR_TYPE_DOUBLE:
1400 {
1401 // This comparison needs to be done as a float before
1402 // conversion to an int64_t to be able to detect doubles
1403 // that are too large to fit into an int64_t. A double
1404 // has 52 bits of preceision. An int64_t has 63. Casting
1405 // INT64_MAX to a double actually causes a round up which
1406 // is bad and wrong for the comparison because it will
1407 // allow conversion of doubles that can't fit into a
1408 // uint64_t. To remedy this INT64_MAX - 0x7ff is used as
1409 // the cutoff point as if that rounds up in conversion to
1410 // double it will still be less than INT64_MAX. 0x7ff is
1411 // picked because it has 11 bits set.
1412 //
1413 // INT64_MAX seconds is on the order of 10 billion years,
1414 // and the earth is less than 5 billion years old, so for
1415 // most uses this conversion error won't occur even though
1416 // doubles can go much larger.
1417 //
1418 // Without the 0x7ff there is a ~30 minute range of time
1419 // values 10 billion years in the past and in the future
1420 // where this this code would go wrong.
1421 const double d = pDecodedItem->val.dfnum;
1422 if(d > (double)(INT64_MAX - 0x7ff)) {
1423 nReturn = QCBOR_ERR_DATE_OVERFLOW;
1424 goto Done;
1425 }
1426 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
1427 pDecodedItem->val.epochDate.fSecondsFraction = d - (double)pDecodedItem->val.epochDate.nSeconds;
1428 }
1429 break;
1430
1431 default:
1432 nReturn = QCBOR_ERR_BAD_OPT_TAG;
1433 goto Done;
1434 }
1435 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
1436
1437Done:
1438 return nReturn;
1439}
1440
1441
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001442/*
1443 Mostly just assign the right data type for the bignum.
1444 */
1445inline static QCBORError DecodeBigNum(QCBORItem *pDecodedItem)
1446{
1447 // Stack Use: UsefulBuf 1 -- 16
1448 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1449 return QCBOR_ERR_BAD_OPT_TAG;
1450 }
1451 const UsefulBufC Temp = pDecodedItem->val.string;
1452 pDecodedItem->val.bigNum = Temp;
1453 const bool bIsPosBigNum = (bool)(pDecodedItem->uTags[0] == CBOR_TAG_POS_BIGNUM);
1454 pDecodedItem->uDataType = (uint8_t)(bIsPosBigNum ? QCBOR_TYPE_POSBIGNUM
1455 : QCBOR_TYPE_NEGBIGNUM);
1456 return QCBOR_SUCCESS;
1457}
1458
1459
Laurence Lundblade59289e52019-12-30 13:44:37 -08001460#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
1461/*
1462 Decode decimal fractions and big floats.
1463
1464 When called pDecodedItem must be the array that is tagged as a big
1465 float or decimal fraction, the array that has the two members, the
1466 exponent and mantissa.
1467
1468 This will fetch and decode the exponent and mantissa and put the
1469 result back into pDecodedItem.
1470 */
1471inline static QCBORError
1472QCBORDecode_MantissaAndExponent(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
1473{
1474 QCBORError nReturn;
1475
1476 // --- Make sure it is an array; track nesting level of members ---
1477 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
1478 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1479 goto Done;
1480 }
1481
1482 // A check for pDecodedItem->val.uCount == 2 would work for
Laurence Lundbladeee851742020-01-08 08:37:05 -08001483 // definite length arrays, but not for indefnite. Instead remember
1484 // the nesting level the two integers must be at, which is one
1485 // deeper than that of the array.
Laurence Lundblade59289e52019-12-30 13:44:37 -08001486 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
1487
1488 // --- Is it a decimal fraction or a bigfloat? ---
1489 const bool bIsTaggedDecimalFraction = QCBORDecode_IsTagged(me, pDecodedItem, CBOR_TAG_DECIMAL_FRACTION);
1490 pDecodedItem->uDataType = bIsTaggedDecimalFraction ? QCBOR_TYPE_DECIMAL_FRACTION : QCBOR_TYPE_BIGFLOAT;
1491
1492 // --- Get the exponent ---
1493 QCBORItem exponentItem;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001494 nReturn = QCBORDecode_GetNextMapOrArray(me, &exponentItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001495 if(nReturn != QCBOR_SUCCESS) {
1496 goto Done;
1497 }
1498 if(exponentItem.uNestingLevel != nNestLevel) {
1499 // Array is empty or a map/array encountered when expecting an int
1500 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1501 goto Done;
1502 }
1503 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
1504 // Data arriving as an unsigned int < INT64_MAX has been converted
1505 // to QCBOR_TYPE_INT64 and thus handled here. This is also means
1506 // that the only data arriving here of type QCBOR_TYPE_UINT64 data
1507 // will be too large for this to handle and thus an error that will
1508 // get handled in the next else.
1509 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
1510 } else {
1511 // Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX
1512 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1513 goto Done;
1514 }
1515
1516 // --- Get the mantissa ---
1517 QCBORItem mantissaItem;
1518 nReturn = QCBORDecode_GetNextWithTags(me, &mantissaItem, NULL);
1519 if(nReturn != QCBOR_SUCCESS) {
1520 goto Done;
1521 }
1522 if(mantissaItem.uNestingLevel != nNestLevel) {
1523 // Mantissa missing or map/array encountered when expecting number
1524 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1525 goto Done;
1526 }
1527 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
1528 // Data arriving as an unsigned int < INT64_MAX has been converted
1529 // to QCBOR_TYPE_INT64 and thus handled here. This is also means
1530 // that the only data arriving here of type QCBOR_TYPE_UINT64 data
1531 // will be too large for this to handle and thus an error that
1532 // will get handled in an else below.
1533 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
1534 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM || mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
1535 // Got a good big num mantissa
1536 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
1537 // Depends on numbering of QCBOR_TYPE_XXX
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001538 pDecodedItem->uDataType = (uint8_t)(pDecodedItem->uDataType +
1539 mantissaItem.uDataType - QCBOR_TYPE_POSBIGNUM +
1540 1);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001541 } else {
1542 // Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX
1543 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1544 goto Done;
1545 }
1546
1547 // --- Check that array only has the two numbers ---
1548 if(mantissaItem.uNextNestLevel == nNestLevel) {
1549 // Extra items in the decimal fraction / big num
1550 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1551 goto Done;
1552 }
1553
1554Done:
1555
1556 return nReturn;
1557}
1558#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
1559
1560
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001561
1562/*
1563 */
1564inline static QCBORError DecodeURI(QCBORItem *pDecodedItem)
1565{
1566 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1567 return QCBOR_ERR_BAD_OPT_TAG;
1568 }
1569 pDecodedItem->uDataType = QCBOR_TYPE_URI;
1570 return QCBOR_SUCCESS;
1571}
1572
1573
1574inline static QCBORError DecodeB64URL(QCBORItem *pDecodedItem)
1575{
1576 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1577 return QCBOR_ERR_BAD_OPT_TAG;
1578 }
1579 pDecodedItem->uDataType = QCBOR_TYPE_BASE64URL;
1580 return QCBOR_SUCCESS;
1581}
1582
1583
1584inline static QCBORError DecodeB64(QCBORItem *pDecodedItem)
1585{
1586 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1587 return QCBOR_ERR_BAD_OPT_TAG;
1588 }
1589 pDecodedItem->uDataType = QCBOR_TYPE_BASE64;
1590 return QCBOR_SUCCESS;
1591}
1592
1593
1594inline static QCBORError DecodeRegex(QCBORItem *pDecodedItem)
1595{
1596 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1597 return QCBOR_ERR_BAD_OPT_TAG;
1598 }
1599 pDecodedItem->uDataType = QCBOR_TYPE_REGEX;
1600 return QCBOR_SUCCESS;
1601}
1602
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07001603inline static QCBORError DecodeWrappedCBOR(QCBORItem *pDecodedItem)
1604{
1605 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1606 return QCBOR_ERR_BAD_OPT_TAG;
1607 }
1608 pDecodedItem->uDataType = QBCOR_TYPE_WRAPPED_CBOR;
1609 return QCBOR_SUCCESS;
1610}
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001611
1612inline static QCBORError DecodeMIME(QCBORItem *pDecodedItem)
1613{
1614 if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) {
1615 pDecodedItem->uDataType = QCBOR_TYPE_MIME;
1616 } else if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1617 pDecodedItem->uDataType = QCBOR_TYPE_BINARY_MIME;
1618 } else {
1619 return QCBOR_ERR_BAD_OPT_TAG;
1620 }
1621 return QCBOR_SUCCESS;
1622}
1623
1624
1625/*
1626 */
1627inline static QCBORError DecodeUUID(QCBORItem *pDecodedItem)
1628{
1629 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1630 return QCBOR_ERR_BAD_OPT_TAG;
1631 }
1632 pDecodedItem->uDataType = QCBOR_TYPE_UUID;
1633 return QCBOR_SUCCESS;
1634}
1635
1636
Laurence Lundblade59289e52019-12-30 13:44:37 -08001637/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001638 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08001639 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001640QCBORError
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001641QCBORDecode_GetNext(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08001642{
1643 QCBORError nReturn;
1644
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001645 nReturn = QCBORDecode_GetNextMapOrArray(me, pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001646 if(nReturn != QCBOR_SUCCESS) {
1647 goto Done;
1648 }
1649
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001650 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM; i++) {
1651 switch(pDecodedItem->uTags[i] ) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08001652
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001653 case CBOR_TAG_DATE_STRING:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001654 nReturn = DecodeDateString(pDecodedItem);
1655 break;
1656
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001657 case CBOR_TAG_DATE_EPOCH:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001658 nReturn = DecodeDateEpoch(pDecodedItem);
1659 break;
1660
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001661 case CBOR_TAG_POS_BIGNUM:
1662 case CBOR_TAG_NEG_BIGNUM:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001663 nReturn = DecodeBigNum(pDecodedItem);
1664 break;
1665
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001666 #ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
1667 case CBOR_TAG_DECIMAL_FRACTION:
1668 case CBOR_TAG_BIGFLOAT:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001669 // For aggregate tagged types, what goes into pTags is only collected
1670 // from the surrounding data item, not the contents, so pTags is not
1671 // passed on here.
1672
1673 nReturn = QCBORDecode_MantissaAndExponent(me, pDecodedItem);
1674 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001675 #endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08001676
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07001677 case CBOR_TAG_CBOR:
1678 nReturn = DecodeWrappedCBOR(pDecodedItem);
1679 break;
1680
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001681 case CBOR_TAG_URI:
1682 nReturn = DecodeURI(pDecodedItem);
1683 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001684
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001685 case CBOR_TAG_B64URL:
1686 nReturn = DecodeB64URL(pDecodedItem);
1687 break;
1688
1689 case CBOR_TAG_B64:
1690 nReturn = DecodeB64(pDecodedItem);
1691 break;
1692
1693 case CBOR_TAG_MIME:
1694 case CBOR_TAG_BINARY_MIME:
1695 nReturn = DecodeMIME(pDecodedItem);
1696 break;
1697
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001698 case CBOR_TAG_REGEX:
1699 nReturn = DecodeRegex(pDecodedItem);
1700 break;
1701
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001702 case CBOR_TAG_BIN_UUID:
1703 nReturn = DecodeUUID(pDecodedItem);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001704 break;
1705
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001706 case CBOR_TAG_INVALID16:
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001707 // The end of the tag list or no tags
1708 // Successful exit from the loop.
1709 goto Done;
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001710
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001711 default:
1712 // A tag that is not understood
1713 // A successful exit from the loop
1714 goto Done;
1715
1716 }
1717 if(nReturn != QCBOR_SUCCESS) {
1718 goto Done;
1719 }
Laurence Lundblade59289e52019-12-30 13:44:37 -08001720 }
1721
1722Done:
1723 if(nReturn != QCBOR_SUCCESS) {
1724 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
1725 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
1726 }
1727 return nReturn;
1728}
1729
1730
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001731QCBORError QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
1732{
1733 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
1734
1735 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
1736
1737 UsefulInputBuf_Seek(&(pMe->InBuf), uOffset);
1738
1739 return uErr;
1740}
1741
1742
Laurence Lundblade59289e52019-12-30 13:44:37 -08001743/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001744 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08001745 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001746QCBORError
1747QCBORDecode_GetNextWithTags(QCBORDecodeContext *me,
1748 QCBORItem *pDecodedItem,
1749 QCBORTagListOut *pTags)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001750{
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001751 QCBORError nReturn;
1752
1753 nReturn = QCBORDecode_GetNext(me, pDecodedItem);
1754 if(nReturn != QCBOR_SUCCESS) {
1755 return nReturn;
1756 }
1757
1758 if(pTags != NULL) {
1759 pTags->uNumUsed = 0;
1760 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM; i++) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001761 if(pDecodedItem->uTags[i] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001762 break;
1763 }
1764 if(pTags->uNumUsed >= pTags->uNumAllocated) {
1765 return QCBOR_ERR_TOO_MANY_TAGS;
1766 }
1767 pTags->puTags[pTags->uNumUsed] = ConvertTag(me, pDecodedItem->uTags[i]);
1768 pTags->uNumUsed++;
1769 }
1770 }
1771
1772 return QCBOR_SUCCESS;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001773}
1774
1775
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001776/*
Laurence Lundblade6de37062018-10-15 12:22:42 +05301777 Decoding items is done in 5 layered functions, one calling the
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301778 next one down. If a layer has no work to do for a particular item
1779 it returns quickly.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001780
Laurence Lundblade59289e52019-12-30 13:44:37 -08001781 - QCBORDecode_GetNext, GetNextWithTags -- The top layer processes
1782 tagged data items, turning them into the local C representation.
1783 For the most simple it is just associating a QCBOR_TYPE with the data. For
1784 the complex ones that an aggregate of data items, there is some further
1785 decoding and a little bit of recursion.
1786
1787 - QCBORDecode_GetNextMapOrArray - This manages the beginnings and
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301788 ends of maps and arrays. It tracks descending into and ascending
Laurence Lundblade6de37062018-10-15 12:22:42 +05301789 out of maps/arrays. It processes all breaks that terminate
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001790 indefinite length maps and arrays.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001791
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301792 - GetNext_MapEntry -- This handles the combining of two
1793 items, the label and the data, that make up a map entry.
1794 It only does work on maps. It combines the label and data
1795 items into one labeled item.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001796
Laurence Lundblade59289e52019-12-30 13:44:37 -08001797 - GetNext_TaggedItem -- This decodes type 6 tagging. It turns the
1798 tags into bit flags associated with the data item. No actual decoding
1799 of the contents of the tagged item is performed here.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001800
Laurence Lundblade59289e52019-12-30 13:44:37 -08001801 - GetNext_FullItem -- This assembles the sub-items that make up
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301802 an indefinte length string into one string item. It uses the
Laurence Lundblade6de37062018-10-15 12:22:42 +05301803 string allocater to create contiguous space for the item. It
1804 processes all breaks that are part of indefinite length strings.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001805
Laurence Lundblade59289e52019-12-30 13:44:37 -08001806 - GetNext_Item -- This decodes the atomic data items in CBOR. Each
1807 atomic data item has a "major type", an integer "argument" and optionally
1808 some content. For text and byte strings, the content is the bytes
1809 that make up the string. These are the smallest data items that are
1810 considered to be well-formed. The content may also be other data items in
1811 the case of aggregate types. They are not handled in this layer.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001812
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001813 Roughly this takes 300 bytes of stack for vars. Need to
1814 evaluate this more carefully and correctly.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001815
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301816 */
1817
1818
1819/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001820 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001821 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001822int QCBORDecode_IsTagged(QCBORDecodeContext *me,
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001823 const QCBORItem *pItem,
1824 uint64_t uTag)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001825{
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001826 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM; i++ ) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001827 if(pItem->uTags[i] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001828 break;
1829 }
1830 if(ConvertTag(me, pItem->uTags[i]) == uTag) {
1831 return 1;
1832 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001833 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001834
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001835 return 0;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001836}
1837
1838
1839/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001840 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001841 */
Laurence Lundblade30816f22018-11-10 13:40:22 +07001842QCBORError QCBORDecode_Finish(QCBORDecodeContext *me)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001843{
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001844 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001845
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001846 // Error out if all the maps/arrays are not closed out
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001847 if(!DecodeNesting_IsAtTop(&(me->nesting))) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001848 nReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
1849 goto Done;
1850 }
1851
1852 // Error out if not all the bytes are consumed
1853 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) {
1854 nReturn = QCBOR_ERR_EXTRA_BYTES;
1855 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001856
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001857Done:
Laurence Lundblade6de37062018-10-15 12:22:42 +05301858 // Call the destructor for the string allocator if there is one.
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001859 // Always called, even if there are errors; always have to clean up
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001860 StringAllocator_Destruct(&(me->StringAllocator));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001861
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001862 return nReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001863}
1864
1865
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001866/*
1867Public function, see header qcbor/qcbor_decode.h file
1868*/
Laurence Lundblade2b843b52020-06-16 20:51:03 -07001869uint64_t QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
1870 const QCBORItem *pItem,
1871 unsigned int uIndex)
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001872{
1873 if(uIndex > QCBOR_MAX_TAGS_PER_ITEM) {
1874 return CBOR_TAG_INVALID16;
1875 } else if(pItem->uTags[uIndex] <= QCBOR_LAST_UNMAPPED_TAG) {
1876 return pItem->uTags[uIndex];
1877 } else if(pItem->uTags[uIndex] < QCBOR_NUM_MAPPED_TAGS + QCBOR_LAST_UNMAPPED_TAG) {
1878 return pMe->auMappedTags[pItem->uTags[uIndex] - QCBOR_LAST_UNMAPPED_TAG];
1879 } else {
1880 return CBOR_TAG_INVALID16;
1881 }
1882}
1883
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001884
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001885/*
1886
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001887Decoder errors handled in this file
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001888
Laurence Lundbladeee851742020-01-08 08:37:05 -08001889 - Hit end of input before it was expected while decoding type and
1890 number QCBOR_ERR_HIT_END
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001891
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001892 - negative integer that is too large for C QCBOR_ERR_INT_OVERFLOW
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001893
Laurence Lundbladeee851742020-01-08 08:37:05 -08001894 - Hit end of input while decoding a text or byte string
1895 QCBOR_ERR_HIT_END
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001896
Laurence Lundbladeee851742020-01-08 08:37:05 -08001897 - Encountered conflicting tags -- e.g., an item is tagged both a date
1898 string and an epoch date QCBOR_ERR_UNSUPPORTED
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001899
Laurence Lundbladeee851742020-01-08 08:37:05 -08001900 - Encontered an array or mapp that has too many items
1901 QCBOR_ERR_ARRAY_TOO_LONG
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001902
Laurence Lundbladeee851742020-01-08 08:37:05 -08001903 - Encountered array/map nesting that is too deep
1904 QCBOR_ERR_ARRAY_NESTING_TOO_DEEP
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001905
Laurence Lundbladeee851742020-01-08 08:37:05 -08001906 - An epoch date > INT64_MAX or < INT64_MIN was encountered
1907 QCBOR_ERR_DATE_OVERFLOW
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001908
Laurence Lundbladeee851742020-01-08 08:37:05 -08001909 - The type of a map label is not a string or int
1910 QCBOR_ERR_MAP_LABEL_TYPE
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001911
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001912 - Hit end with arrays or maps still open -- QCBOR_ERR_EXTRA_BYTES
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001913
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001914 */
1915
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001916
1917
Laurence Lundbladef6531662018-12-04 10:42:22 +09001918
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001919/* ===========================================================================
1920 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001921
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001922 This implements a simple sting allocator for indefinite length
1923 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
1924 implements the function type QCBORStringAllocate and allows easy
1925 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09001926
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001927 This particular allocator is built-in for convenience. The caller
1928 can implement their own. All of this following code will get
1929 dead-stripped if QCBORDecode_SetMemPool() is not called.
1930
1931 This is a very primitive memory allocator. It does not track
1932 individual allocations, only a high-water mark. A free or
1933 reallocation must be of the last chunk allocated.
1934
1935 The size of the pool and offset to free memory are packed into the
1936 first 8 bytes of the memory pool so we don't have to keep them in
1937 the decode context. Since the address of the pool may not be
1938 aligned, they have to be packed and unpacked as if they were
1939 serialized data of the wire or such.
1940
1941 The sizes packed in are uint32_t to be the same on all CPU types
1942 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08001943 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001944
1945
Laurence Lundbladeee851742020-01-08 08:37:05 -08001946static inline int
1947MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001948{
1949 // Use of UsefulInputBuf is overkill, but it is convenient.
1950 UsefulInputBuf UIB;
1951
Laurence Lundbladeee851742020-01-08 08:37:05 -08001952 // Just assume the size here. It was checked during SetUp so
1953 // the assumption is safe.
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001954 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem, QCBOR_DECODE_MIN_MEM_POOL_SIZE});
1955 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
1956 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
1957 return UsefulInputBuf_GetError(&UIB);
1958}
1959
1960
Laurence Lundbladeee851742020-01-08 08:37:05 -08001961static inline int
1962MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001963{
1964 // Use of UsefulOutBuf is overkill, but convenient. The
1965 // length check performed here is useful.
1966 UsefulOutBuf UOB;
1967
1968 UsefulOutBuf_Init(&UOB, Pool);
1969 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
1970 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
1971 return UsefulOutBuf_GetError(&UOB);
1972}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001973
1974
1975/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001976 Internal function for an allocation, reallocation free and destuct.
1977
1978 Having only one function rather than one each per mode saves space in
1979 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001980
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001981 Code Reviewers: THIS FUNCTION DOES POINTER MATH
1982 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001983static UsefulBuf
1984MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001985{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001986 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001987
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001988 uint32_t uPoolSize;
1989 uint32_t uFreeOffset;
1990
1991 if(uNewSize > UINT32_MAX) {
1992 // This allocator is only good up to 4GB. This check should
1993 // optimize out if sizeof(size_t) == sizeof(uint32_t)
1994 goto Done;
1995 }
1996 const uint32_t uNewSize32 = (uint32_t)uNewSize;
1997
1998 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
1999 goto Done;
2000 }
2001
2002 if(uNewSize) {
2003 if(pMem) {
2004 // REALLOCATION MODE
2005 // Calculate pointer to the end of the memory pool. It is
2006 // assumed that pPool + uPoolSize won't wrap around by
2007 // assuming the caller won't pass a pool buffer in that is
2008 // not in legitimate memory space.
2009 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
2010
2011 // Check that the pointer for reallocation is in the range of the
2012 // pool. This also makes sure that pointer math further down
2013 // doesn't wrap under or over.
2014 if(pMem >= pPool && pMem < pPoolEnd) {
2015 // Offset to start of chunk for reallocation. This won't
2016 // wrap under because of check that pMem >= pPool. Cast
2017 // is safe because the pool is always less than UINT32_MAX
2018 // because of check in QCBORDecode_SetMemPool().
2019 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
2020
2021 // Check to see if the allocation will fit. uPoolSize -
2022 // uMemOffset will not wrap under because of check that
2023 // pMem is in the range of the uPoolSize by check above.
2024 if(uNewSize <= uPoolSize - uMemOffset) {
2025 ReturnValue.ptr = pMem;
2026 ReturnValue.len = uNewSize;
2027
2028 // Addition won't wrap around over because uNewSize was
2029 // checked to be sure it is less than the pool size.
2030 uFreeOffset = uMemOffset + uNewSize32;
2031 }
2032 }
2033 } else {
2034 // ALLOCATION MODE
2035 // uPoolSize - uFreeOffset will not underflow because this
2036 // pool implementation makes sure uFreeOffset is always
2037 // smaller than uPoolSize through this check here and
2038 // reallocation case.
2039 if(uNewSize <= uPoolSize - uFreeOffset) {
2040 ReturnValue.len = uNewSize;
2041 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08002042 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002043 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002044 }
2045 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002046 if(pMem) {
2047 // FREE MODE
2048 // Cast is safe because of limit on pool size in
2049 // QCBORDecode_SetMemPool()
2050 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
2051 } else {
2052 // DESTRUCT MODE
2053 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002054 }
2055 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002056
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002057 UsefulBuf Pool = {pPool, uPoolSize};
2058 MemPool_Pack(Pool, uFreeOffset);
2059
2060Done:
2061 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002062}
2063
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002064
Laurence Lundbladef6531662018-12-04 10:42:22 +09002065/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08002066 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09002067 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08002068QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
2069 UsefulBuf Pool,
2070 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002071{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002072 // The pool size and free mem offset are packed into the beginning
2073 // of the pool memory. This compile time check make sure the
2074 // constant in the header is correct. This check should optimize
2075 // down to nothing.
2076 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundblade30816f22018-11-10 13:40:22 +07002077 return QCBOR_ERR_BUFFER_TOO_SMALL;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002078 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002079
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002080 // The pool size and free offset packed in to the beginning of pool
2081 // memory are only 32-bits. This check will optimize out on 32-bit
2082 // machines.
2083 if(Pool.len > UINT32_MAX) {
2084 return QCBOR_ERR_BUFFER_TOO_LARGE;
2085 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002086
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002087 // This checks that the pool buffer given is big enough.
2088 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
2089 return QCBOR_ERR_BUFFER_TOO_SMALL;
2090 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002091
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002092 pMe->StringAllocator.pfAllocator = MemPool_Function;
2093 pMe->StringAllocator.pAllocateCxt = Pool.ptr;
2094 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002095
Laurence Lundblade30816f22018-11-10 13:40:22 +07002096 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002097}
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002098
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002099
2100
Laurence Lundblade1341c592020-04-11 14:19:05 -07002101#include <stdio.h>
2102void printdecode(QCBORDecodeContext *pMe, const char *szName)
2103{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002104 printf("---%s--%d--%d--\nLevel Count Type Offset SaveCount MapMode\n",
2105 szName,
2106 (uint32_t)pMe->InBuf.cursor,
2107 (uint32_t)pMe->InBuf.UB.len);
Laurence Lundblade64b607e2020-05-13 13:05:57 -07002108 for(int i = 0; i < QCBOR_MAX_ARRAY_NESTING; i++) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002109 if(&(pMe->nesting.pMapsAndArrays[i]) > pMe->nesting.pCurrent) {
2110 break;
2111 }
Laurence Lundblade64b607e2020-05-13 13:05:57 -07002112 printf("%2s %2d %5d %s %6u %2d %d\n",
2113 pMe->nesting.pCurrentMap == &(pMe->nesting.pMapsAndArrays[i]) ? "->": " ",
Laurence Lundblade1341c592020-04-11 14:19:05 -07002114 i,
2115 pMe->nesting.pMapsAndArrays[i].uCount,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002116 pMe->nesting.pMapsAndArrays[i].uMajorType == QCBOR_TYPE_MAP ? " map" :
2117 (pMe->nesting.pMapsAndArrays[i].uMajorType == QCBOR_TYPE_ARRAY ? "array" :
2118 (pMe->nesting.pMapsAndArrays[i].uMajorType == QCBOR_TYPE_NONE ? " none" : "?????")),
Laurence Lundblade1341c592020-04-11 14:19:05 -07002119 pMe->nesting.pMapsAndArrays[i].uOffset,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002120 pMe->nesting.pMapsAndArrays[i].uSaveCount,
2121 pMe->nesting.pMapsAndArrays[i].uMapMode
Laurence Lundblade1341c592020-04-11 14:19:05 -07002122 );
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002123
Laurence Lundblade1341c592020-04-11 14:19:05 -07002124 }
Laurence Lundblade64b607e2020-05-13 13:05:57 -07002125 printf("\n");
Laurence Lundblade1341c592020-04-11 14:19:05 -07002126}
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002127
2128
2129/*
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002130 Consume an entire map or array (and do next to
2131 nothing for non-aggregate types).
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002132 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002133static inline QCBORError
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002134ConsumeItem(QCBORDecodeContext *pMe,
2135 const QCBORItem *pItemToConsume,
2136 uint_fast8_t *puNextNestLevel)
2137{
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002138 QCBORError uReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002139 QCBORItem Item;
2140
2141 printdecode(pMe, "ConsumeItem");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002142
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002143 if(IsMapOrArray(pItemToConsume->uDataType)) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002144 /* There is only real work to do for maps and arrays */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002145
Laurence Lundblade1341c592020-04-11 14:19:05 -07002146 /* This works for definite and indefinite length
2147 * maps and arrays by using the nesting level
2148 */
2149 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002150 uReturn = QCBORDecode_GetNext(pMe, &Item);
2151 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002152 goto Done;
2153 }
2154 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002155
Laurence Lundblade1341c592020-04-11 14:19:05 -07002156 if(puNextNestLevel != NULL) {
2157 *puNextNestLevel = Item.uNextNestLevel;
2158 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002159 uReturn = QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002160
Laurence Lundblade1341c592020-04-11 14:19:05 -07002161 } else {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002162 /* item_to_consume is not a map or array */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002163 if(puNextNestLevel != NULL) {
2164 /* Just pass the nesting level through */
2165 *puNextNestLevel = pItemToConsume->uNextNestLevel;
2166 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002167 uReturn = QCBOR_SUCCESS;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002168 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002169
2170Done:
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002171 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002172}
2173
2174
Laurence Lundblade1341c592020-04-11 14:19:05 -07002175/* Return true if the labels in Item1 and Item2 are the same.
2176 Works only for integer and string labels. Returns false
2177 for any other type. */
2178static inline bool
2179MatchLabel(QCBORItem Item1, QCBORItem Item2)
2180{
2181 if(Item1.uLabelType == QCBOR_TYPE_INT64) {
2182 if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
2183 return true;
2184 }
2185 } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002186 if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002187 return true;
2188 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002189 } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002190 if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
2191 return true;
2192 }
2193 } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
2194 if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
2195 return true;
2196 }
2197 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002198
Laurence Lundblade1341c592020-04-11 14:19:05 -07002199 /* Other label types are never matched */
2200 return false;
2201}
2202
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002203
2204/*
2205 Returns true if Item1 and Item2 are the same type
2206 or if either are of QCBOR_TYPE_ANY.
2207 */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002208static inline bool
2209MatchType(QCBORItem Item1, QCBORItem Item2)
2210{
2211 if(Item1.uDataType == Item2.uDataType) {
2212 return true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002213 } else if(Item1.uDataType == QCBOR_TYPE_ANY) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002214 return true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002215 } else if(Item2.uDataType == QCBOR_TYPE_ANY) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002216 return true;
2217 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002218 return false;
2219}
2220
2221
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002222/**
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002223 \brief Search a map for a set of items.
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002224
2225 @param[in] pMe The decode context to search.
2226 @param[in,out] pItemArray The items to search for and the items found.
2227 @param[in] pCBContext Context for the not-found item call back
2228 @param[in] pfCallback Function to call on items not matched in pItemArray
2229
2230 @retval QCBOR_ERR_NOT_ENTERED Trying to search without having entered a map
2231
2232 @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.
2233
2234 @retval QCBOR_ERR_UNEXPECTED_TYPE The label was matched, but not the type.
2235
2236 @retval Also errors returned by QCBORDecode_GetNext().
2237
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002238 On input pItemArray contains a list of labels and data types
2239 of items to be found.
2240
2241 On output the fully retrieved items are filled in with
2242 values and such. The label was matched, so it never changes.
2243
2244 If an item was not found, its data type is set to none.
2245
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002246 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002247static QCBORError
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002248MapSearch(QCBORDecodeContext *pMe,
2249 QCBORItem *pItemArray,
2250 size_t *puOffset,
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002251 void *pCBContext,
2252 QCBORItemCallback pfCallback)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002253{
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002254 QCBORError uReturn;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002255
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002256 QCBORDecodeNesting SaveNesting;
2257 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002258
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002259 // Reposition to search from the start of the map / array
2260 UsefulInputBuf_Seek(&(pMe->InBuf), pMe->nesting.pCurrentMap->uOffset);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002261
2262 /* Loop over all the items in the map. They could be
2263 * deeply nested and this should handle both definite
2264 * and indefinite length maps and arrays, so this
2265 * adds some complexity. */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002266 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Laurence Lundblade1341c592020-04-11 14:19:05 -07002267
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002268 uint_fast8_t uNextNestLevel;
2269
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002270 uint64_t uFoundItemBitMap = 0;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002271
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002272 /* Iterate over items in the map / array */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002273 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002274 /* Remember offset of the item because sometimes it has to be returned */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002275 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002276
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002277 /* Get the item */
2278 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002279 uReturn = QCBORDecode_GetNext(pMe, &Item);
2280 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002281 /* Got non-well-formed CBOR */
2282 goto Done;
2283 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002284
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002285 /* See if item has one of the labels that are of interest */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002286 int nIndex;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002287 QCBORItem *pIterator;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002288 for(pIterator = pItemArray, nIndex = 0; pIterator->uLabelType != 0; pIterator++, nIndex++) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002289 if(MatchLabel(Item, *pIterator)) {
2290 // A label match has been found
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002291 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
2292 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002293 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002294 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002295 /* Also try to match its type */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002296 if(!MatchType(Item, *pIterator)) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002297 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002298 goto Done;
2299 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002300
2301 /* Successful match. Return the item. */
2302 *pIterator = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002303 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002304 if(puOffset) {
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002305 *puOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002306 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002307 } else {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002308 /* Call the callback on unmatched labels */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002309 /* It is tempting to do duplicate detection here, but that would
2310 require dynamic memory allocation because the number of labels
2311 that might be encountered is unbounded.
2312 */
2313 if(pfCallback) {
2314 uReturn = (*pfCallback)(pCBContext, &Item);
2315 if(uReturn != QCBOR_SUCCESS) {
2316 goto Done;
2317 }
2318 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002319 }
2320 }
2321
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002322 /* Consume the item whether matched or not. This
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002323 does the work of traversing maps and array and
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002324 everything in them. In this loop only the
2325 items at the current nesting level are examined
2326 to match the labels. */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002327 uReturn = ConsumeItem(pMe, &Item, &uNextNestLevel);
2328 if(uReturn) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002329 goto Done;
2330 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002331
2332 } while (uNextNestLevel >= uMapNestLevel);
2333
2334
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002335 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002336
2337 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
2338 // Cast OK because encoded CBOR is limited to UINT32_MAX
2339 pMe->uMapEndOffset = (uint32_t)uEndOffset;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002340
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002341 /* For all items not found, set the data type to QCBOR_TYPE_NONE */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002342 int i;
2343 QCBORItem *pIterator;
2344 for(pIterator = pItemArray, i = 0; pIterator->uLabelType != 0; pIterator++, i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002345 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002346 pIterator->uDataType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002347 }
2348 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002349
2350Done:
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002351 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002352
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002353 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002354}
2355
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002356
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002357/*
2358Public function, see header qcbor/qcbor_decode.h file
2359*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002360void QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
2361 int64_t nLabel,
2362 uint8_t uQcborType,
2363 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002364{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002365 if(pMe->uLastError != QCBOR_SUCCESS) {
2366 return;
2367 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002368
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002369 QCBORItem OneItemSeach[2];
2370 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
2371 OneItemSeach[0].label.int64 = nLabel;
2372 OneItemSeach[0].uDataType = uQcborType;
2373 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07002374
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002375 QCBORError nReturn = MapSearch(pMe, OneItemSeach, NULL, NULL, NULL);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002376 if(nReturn) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002377 pMe->uLastError = (uint8_t)nReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002378 }
2379
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002380 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
2381 pMe->uLastError = QCBOR_ERR_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002382 }
2383
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002384 *pItem = OneItemSeach[0];
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002385}
2386
2387
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002388/*
2389Public function, see header qcbor/qcbor_decode.h file
2390*/
Laurence Lundbladeda095972020-06-06 18:35:33 -07002391void QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
2392 const char *szLabel,
2393 uint8_t uQcborType,
2394 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002395{
Laurence Lundbladeda095972020-06-06 18:35:33 -07002396 if(pMe->uLastError != QCBOR_SUCCESS) {
2397 return;
2398 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002399
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002400 QCBORItem OneItemSeach[2];
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002401 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2402 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
2403 OneItemSeach[0].uDataType = uQcborType;
2404 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07002405
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002406 QCBORError nReturn = MapSearch(pMe, OneItemSeach, NULL, NULL, NULL);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002407 if(nReturn) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07002408 pMe->uLastError = (uint8_t)nReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002409 }
2410
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002411 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07002412 pMe->uLastError = QCBOR_ERR_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002413 }
2414
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002415 *pItem = OneItemSeach[0];
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002416}
2417
2418
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002419/**
2420 @param[in] TagSpec Specification for matching tags.
2421 @param[in] uDataType A QCBOR data type
2422
2423 @retval QCBOR_SUCCESS \c uDataType is allowed by @c TagSpec
2424 @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec
2425
2426 The data type must be one of the QCBOR_TYPEs, not the IETF CBOR Registered tag value.
2427 */
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002428static QCBORError CheckTagRequirement(const TagSpecification TagSpec, uint8_t uDataType)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002429{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002430 if(TagSpec.uTagRequirement == QCBOR_TAGSPEC_MATCH_TAG) {
2431 /* Must match the tag */
2432 if(uDataType == TagSpec.uTaggedType) {
2433 return QCBOR_SUCCESS;
2434 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002435 } else {
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002436 /* QCBOR_TAGSPEC_MATCH_TAG_CONTENT_TYPE or QCBOR_TAGSPEC_MATCH_EITHER */
2437 /* Must check all the possible types for the tag content */
2438 for(size_t i = 0; i < sizeof(TagSpec.uAllowedContentTypes); i++) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002439 if(uDataType == TagSpec.uAllowedContentTypes[i]) {
2440 return QCBOR_SUCCESS;
2441 }
2442 }
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002443 /* Didn't match any of the tag content types */
2444 /* Check the tag for the either case */
2445 if(TagSpec.uTagRequirement == QCBOR_TAGSPEC_MATCH_EITHER) {
2446 if(uDataType == TagSpec.uTaggedType) {
2447 return QCBOR_SUCCESS;
2448 }
2449 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002450 }
2451
2452 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002453}
2454
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002455
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002456// Semi-private
2457// TODO: inline or collapse with QCBORDecode_GetTaggedStringInMapN?
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002458void QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
2459 int64_t nLabel,
2460 TagSpecification TagSpec,
2461 QCBORItem *pItem)
2462{
2463 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
2464 if(pMe->uLastError != QCBOR_SUCCESS) {
2465 return;
2466 }
2467
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002468 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem->uDataType);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002469}
2470
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002471// Semi-private
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002472void QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
2473 const char *szLabel,
2474 TagSpecification TagSpec,
2475 QCBORItem *pItem)
2476{
2477 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
2478 if(pMe->uLastError != QCBOR_SUCCESS) {
2479 return;
2480 }
2481
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002482 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem->uDataType);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002483}
2484
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002485// Semi-private
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002486void QCBORDecode_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
2487 int64_t nLabel,
2488 TagSpecification TagSpec,
2489 UsefulBufC *pString)
2490{
2491 QCBORItem Item;
2492 QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
2493 if(pMe->uLastError == QCBOR_SUCCESS) {
2494 *pString = Item.val.string;
2495 }
2496}
2497
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002498// Semi-private
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002499void QCBORDecode_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
2500 const char * szLabel,
2501 TagSpecification TagSpec,
2502 UsefulBufC *pString)
2503{
2504 QCBORItem Item;
2505 QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
2506 if(pMe->uLastError == QCBOR_SUCCESS) {
2507 *pString = Item.val.string;
2508 }
2509}
Laurence Lundblade1341c592020-04-11 14:19:05 -07002510
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002511/*
2512Public function, see header qcbor/qcbor_decode.h file
2513*/
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002514QCBORError QCBORDecode_GetItemsInMap(QCBORDecodeContext *pCtx, QCBORItem *pItemList)
2515{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002516 return MapSearch(pCtx, pItemList, NULL, NULL, NULL);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002517}
2518
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002519/*
2520Public function, see header qcbor/qcbor_decode.h file
2521*/
2522QCBORError QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pCtx,
2523 QCBORItem *pItemList,
2524 void *pCallbackCtx,
2525 QCBORItemCallback pfCB)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002526{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002527 return MapSearch(pCtx, pItemList, NULL, pCallbackCtx, pfCB);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002528}
2529
2530
Laurence Lundblade34691b92020-05-18 22:25:25 -07002531static void SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07002532{
Laurence Lundblade34691b92020-05-18 22:25:25 -07002533 if(pMe->uLastError != QCBOR_SUCCESS) {
2534 // Already in error state; do nothing.
2535 return;
2536 }
2537
2538 size_t uOffset;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002539 pMe->uLastError = (uint8_t)MapSearch(pMe, pSearch, &uOffset, NULL, NULL);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002540 if(pMe->uLastError != QCBOR_SUCCESS) {
2541 return;
2542 }
2543
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002544 /* Need to get the current pre-order nesting level and cursor to be
2545 at the first item in the map/array just entered.
2546
2547 Also need to current map nesting level and start cursor to
2548 be at the right place.
2549
2550 The UsefulInBuf offset could be anywhere, so no assumption is
2551 made about it.
2552
2553 No assumption is made about the pre-order nesting level either.
2554
2555 However the map mode nesting level is assumed to be one above
2556 the map level that is being entered.
2557 */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002558 /* Seek to the data item that is the map or array */
2559 UsefulInputBuf_Seek(&(pMe->InBuf), uOffset);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002560 pMe->nesting.pCurrent = pMe->nesting.pCurrentMap; // TODO: part of DecodeNesting
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002561
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002562 // TODO: check error?
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002563 QCBORDecode_EnterBoundedMode(pMe, pSearch->uDataType);
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002564
Laurence Lundblade34691b92020-05-18 22:25:25 -07002565 printdecode(pMe, "FinishEnter");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002566}
2567
2568
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002569/*
2570Public function, see header qcbor/qcbor_decode.h file
2571*/
Laurence Lundblade34691b92020-05-18 22:25:25 -07002572void QCBORDecode_EnterMapInMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002573{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002574 QCBORItem OneItemSeach[2];
2575 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
2576 OneItemSeach[0].label.int64 = nLabel;
2577 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
2578 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002579
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002580 /* The map to enter was found, now finish of entering it. */
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002581 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002582}
2583
2584
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002585/*
2586Public function, see header qcbor/qcbor_decode.h file
2587*/
Laurence Lundblade34691b92020-05-18 22:25:25 -07002588void QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002589{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002590 QCBORItem OneItemSeach[2];
2591 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2592 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
2593 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
2594 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002595
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002596 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002597}
2598
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002599/*
2600Public function, see header qcbor/qcbor_decode.h file
2601*/
Laurence Lundblade34691b92020-05-18 22:25:25 -07002602void QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07002603{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002604 QCBORItem OneItemSeach[2];
2605 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
2606 OneItemSeach[0].label.int64 = nLabel;
2607 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
2608 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002609
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002610 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002611}
2612
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002613/*
2614Public function, see header qcbor/qcbor_decode.h file
2615*/
Laurence Lundblade34691b92020-05-18 22:25:25 -07002616void QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
2617{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002618 QCBORItem OneItemSeach[2];
2619 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2620 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
2621 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
2622 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002623
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002624 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002625}
2626
2627
2628
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002629/* Next item must be map or this generates an error */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002630void QCBORDecode_EnterBoundedMode(QCBORDecodeContext *pMe, uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002631{
Laurence Lundblade34691b92020-05-18 22:25:25 -07002632 if(pMe->uLastError != QCBOR_SUCCESS) {
2633 // Already in error state; do nothing.
2634 return;
2635 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002636
2637 /* Get the data item that is the map that is being searched */
Laurence Lundblade34691b92020-05-18 22:25:25 -07002638 QCBORItem Item;
Laurence Lundblade986017c2020-05-23 19:25:02 -07002639 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002640 if(pMe->uLastError != QCBOR_SUCCESS) {
2641 return;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002642 }
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002643 if(Item.uDataType != uType) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07002644 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
2645 return;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002646 }
2647
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002648 DecodeNesting_EnterBoundedMode(&(pMe->nesting), UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002649
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002650 // TODO: restrict input to less than this or some other invalidation strategy.
2651 pMe->uMapEndOffset = 0xffffffff; // Invalidate the cached map end.
2652
Laurence Lundblade34691b92020-05-18 22:25:25 -07002653 printdecode(pMe, "EnterMapModeDone");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002654}
2655
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002656
2657// Semi-private function
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002658void QCBORDecode_ExitBoundedMode(QCBORDecodeContext *pMe, uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002659{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002660 if(pMe->uLastError != QCBOR_SUCCESS) {
2661 // Already in error state; do nothing.
2662 return;
2663 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002664
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002665 printdecode(pMe, "start exit");
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002666
2667 QCBORError uErr = QCBOR_SUCCESS;
2668
2669 if(!DecodeNesting_BoundedIsType(&(pMe->nesting), uType)){
2670 uErr = QCBOR_ERR_CLOSE_MISMATCH;
2671 goto Done;
2672 }
2673
2674 /* Have to set the offset to the end of the map/array
2675 that is being exited. If there is no cached value,
2676 from previous map search, then do a dummy search. */
2677 if(pMe->uMapEndOffset == 0xffffffff) {
2678 QCBORItem Dummy;
2679 Dummy.uLabelType = QCBOR_TYPE_NONE;
2680 uErr = MapSearch(pMe, &Dummy, NULL, NULL, NULL);
2681 if(uErr != QCBOR_SUCCESS) {
2682 goto Done;
2683 }
2684 }
2685 UsefulInputBuf_Seek(&(pMe->InBuf), pMe->uMapEndOffset);
2686 pMe->uMapEndOffset = 0xffffffff; // Invalidate the cached map end.
2687
2688 /* Before acending, mark this level as no longer in bound mode. */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002689 pMe->nesting.pCurrentMap->uType &= ~QCBOR_NEST_TYPE_IS_BOUND;
2690
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002691 // Always go up one level
2692 // Need error check to know level is bounded mode and not at top level
2693 pMe->nesting.pCurrent = pMe->nesting.pCurrentMap - 1; // TODO error check
2694
2695 uErr = Ascender(pMe);
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002696 if(uErr != QCBOR_SUCCESS) {
2697 goto Done;
2698 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002699
2700 /* Also ascend to the next higest bounded mode level if
2701 there is one. */
2702 while(1) {
2703 pMe->nesting.pCurrentMap--;
2704 if(DecodeNesting_InBoundedMode(&(pMe->nesting))) {
2705 break;
2706 }
2707 if(pMe->nesting.pCurrentMap == &(pMe->nesting.pMapsAndArrays[0])) {
2708 pMe->nesting.pCurrentMap = NULL;
2709 break;
2710 }
2711 }
2712
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002713Done:
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002714 printdecode(pMe, "end exit");
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002715 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002716}
2717
2718
Laurence Lundblade1341c592020-04-11 14:19:05 -07002719void QCBORDecode_RewindMap(QCBORDecodeContext *pMe)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002720{
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002721 // TODO: check for map mode; test this
Laurence Lundblade1341c592020-04-11 14:19:05 -07002722 pMe->nesting.pCurrent->uCount = pMe->nesting.pCurrent->uSaveCount;
2723 UsefulInputBuf_Seek(&(pMe->InBuf), pMe->nesting.pCurrent->uOffset);
2724}
2725
2726
Laurence Lundblade1341c592020-04-11 14:19:05 -07002727
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002728static QCBORError FarfWrappedBstr(QCBORDecodeContext *pMe, const QCBORItem *pItem, uint8_t uTagRequirement, UsefulBufC *pBstr)
2729{
2730 if(pMe->uLastError != QCBOR_SUCCESS) {
2731 // Already in error state; do nothing.
2732 return pMe->uLastError;
2733 }
2734
2735 QCBORError uError = QCBOR_SUCCESS;
2736
2737 if(pItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
2738 uError = QCBOR_ERR_UNEXPECTED_TYPE;
2739 goto Done;;
2740 }
2741
2742 // TODO: check for the other wrapped CBOR
2743 const TagSpecification TagSpec = {uTagRequirement, QBCOR_TYPE_WRAPPED_CBOR, {QCBOR_TYPE_BYTE_STRING, 0,0,0,0,0}};
2744
2745 uError = CheckTagRequirement(TagSpec, pItem->uDataType);
2746 if(uError != QCBOR_SUCCESS) {
2747 goto Done;
2748 }
2749
2750 *pBstr = pItem->val.string;
2751
2752 // Need to move UIB input cursor to the right place
2753
2754 // Really this is a subtraction and an assignment; not much code
2755 // There is a range check in the seek.
2756 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
2757
2758 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset - pItem->val.string.len);
2759
2760 UsefulInputBuf_SetBufferLen(&(pMe->InBuf), uEndOffset);
2761
2762 // TODO: comment on cast
2763 uError = DecodeNesting_Descend(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING, UINT16_MAX, (uint32_t)uEndOffset);
2764
2765Done:
2766 return uError;
2767
2768}
2769
2770
2771void QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe, uint8_t uTagRequirement, UsefulBufC *pBstr)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002772{
2773 if(pMe->uLastError != QCBOR_SUCCESS) {
2774 // Already in error state; do nothing.
2775 return;
2776 }
2777
2778 /* Get the data item that is the map that is being searched */
2779 QCBORItem Item;
2780 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
2781 if(pMe->uLastError != QCBOR_SUCCESS) {
2782 return;
2783 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002784
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002785 pMe->uLastError = (uint8_t)FarfWrappedBstr(pMe, &Item, uTagRequirement, pBstr);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002786}
2787
2788
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002789void QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe, uint8_t uTagRequirement, int64_t nLabel, UsefulBufC *pBstr)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002790{
2791 QCBORItem Item;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002792 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002793
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002794 pMe->uLastError = (uint8_t)FarfWrappedBstr(pMe, &Item, uTagRequirement, pBstr);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002795}
2796
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002797
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002798void QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe, uint8_t uTagRequirement, const char *szLabel, UsefulBufC *pBstr)
2799{
2800 QCBORItem Item;
2801 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
2802
2803 pMe->uLastError = (uint8_t)FarfWrappedBstr(pMe, &Item, uTagRequirement, pBstr);
2804
2805}
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002806
2807void QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pCtx)
2808{
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002809 // TODO: write this code
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002810 // Need to set the cursor to end of the bstr and length to the next length
2811 // above in the nesting tree (or the top level length).
2812
2813}
2814
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002815
Laurence Lundbladee6430642020-03-14 21:15:44 -07002816
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002817
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002818
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002819
Laurence Lundblade11a064e2020-05-07 13:13:42 -07002820
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002821
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002822static QCBORError InterpretBool(const QCBORItem *pItem, bool *pBool)
2823{
2824 switch(pItem->uDataType) {
2825 case QCBOR_TYPE_TRUE:
2826 *pBool = true;
2827 return QCBOR_SUCCESS;
2828 break;
2829
2830 case QCBOR_TYPE_FALSE:
2831 *pBool = false;
2832 return QCBOR_SUCCESS;
2833 break;
2834
2835 default:
2836 return QCBOR_ERR_UNEXPECTED_TYPE;
2837 break;
2838 }
2839}
Laurence Lundbladee6430642020-03-14 21:15:44 -07002840
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002841/*
2842Public function, see header qcbor/qcbor_decode.h file
2843*/
Laurence Lundbladec4537442020-04-14 18:53:22 -07002844void QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002845{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002846 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002847 // Already in error state, do nothing
Laurence Lundbladee6430642020-03-14 21:15:44 -07002848 return;
2849 }
2850
Laurence Lundbladec4537442020-04-14 18:53:22 -07002851 QCBORError nError;
2852 QCBORItem Item;
2853
2854 nError = QCBORDecode_GetNext(pMe, &Item);
2855 if(nError != QCBOR_SUCCESS) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002856 pMe->uLastError = (uint8_t)nError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002857 return;
2858 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002859 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002860}
2861
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002862/*
2863Public function, see header qcbor/qcbor_decode.h file
2864*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002865void QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe, int64_t nLabel, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002866{
2867 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002868 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002869
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002870 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002871}
2872
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002873/*
2874Public function, see header qcbor/qcbor_decode.h file
2875*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002876void QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, bool *pValue)
2877{
2878 QCBORItem Item;
2879 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
2880
2881 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
2882}
2883
2884
2885
2886void QCBORDecode_GetTaggedStringInternal(QCBORDecodeContext *pMe, TagSpecification TagSpec, UsefulBufC *pBstr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002887{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002888 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002889 // Already in error state, do nothing
2890 return;
2891 }
2892
2893 QCBORError nError;
2894 QCBORItem Item;
2895
2896 nError = QCBORDecode_GetNext(pMe, &Item);
2897 if(nError != QCBOR_SUCCESS) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002898 pMe->uLastError = (uint8_t)nError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002899 return;
2900 }
2901
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002902 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, Item.uDataType);
2903
2904 if(pMe->uLastError == QCBOR_SUCCESS) {
2905 *pBstr = Item.val.string;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002906 }
2907}
2908
Laurence Lundbladec4537442020-04-14 18:53:22 -07002909
2910
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002911
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002912static QCBORError ConvertBigNum(uint8_t uTagRequirement, const QCBORItem *pItem, UsefulBufC *pValue, bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002913{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002914 *pbIsNegative = false;
2915
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002916 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 -07002917
2918 switch(pItem->uDataType) {
2919 case QCBOR_TYPE_BYTE_STRING:
2920 // TODO: check that there is no tag here?
2921 if(bMustBeTagged) {
2922 return QCBOR_ERR_UNEXPECTED_TYPE;
2923 } else {
2924 *pValue = pItem->val.string;
2925 return QCBOR_SUCCESS;
2926 }
2927 break;
2928
2929 case QCBOR_TYPE_POSBIGNUM:
2930 *pValue = pItem->val.string;
2931 return QCBOR_SUCCESS;
2932 break;
2933
2934 case QCBOR_TYPE_NEGBIGNUM:
2935 *pbIsNegative = true;
2936 *pValue = pItem->val.string;
2937 return QCBOR_SUCCESS;
2938 break;
2939
2940 default:
2941 return QCBOR_ERR_UNEXPECTED_TYPE;
2942 break;
2943 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002944}
2945
2946
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002947/*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002948 @param[in] bMustBeTagged If \c true, then the data item must be tagged as either
2949 a positive or negative bignum. If \c false, then it only must be a byte string and bIsNegative
2950 will always be false on the asumption that it is positive, but it can be interpretted as
2951 negative if the the sign is know from other context.
2952 @param[out] pValue The bytes that make up the big num
2953 @param[out] pbIsNegative \c true if tagged as a negative big num. \c false otherwise.
2954
2955 if bMustBeTagged is false, then this will succeed if the data item is a plain byte string,
2956 a positive big num or a negative big num.
2957
2958 */
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002959void QCBORDecode_GetBignum(QCBORDecodeContext *pMe, uint8_t uTagRequirement, UsefulBufC *pValue, bool *pbIsNegative)
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002960{
2961 if(pMe->uLastError != QCBOR_SUCCESS) {
2962 // Already in error state, do nothing
2963 return;
2964 }
2965
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002966 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002967 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
2968 if(uError != QCBOR_SUCCESS) {
2969 pMe->uLastError = (uint8_t)uError;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002970 return;
2971 }
2972
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002973 pMe->uLastError = (uint8_t)ConvertBigNum(uTagRequirement, &Item, pValue, pbIsNegative);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002974}
2975
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002976/*
2977Public function, see header qcbor/qcbor_decode.h file
2978*/
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002979void QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint8_t uTagRequirement, UsefulBufC *pValue, bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002980{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002981 QCBORItem Item;
2982 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002983
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002984 pMe->uLastError = (uint8_t)ConvertBigNum(uTagRequirement, &Item, pValue, pbIsNegative);
Laurence Lundbladec4537442020-04-14 18:53:22 -07002985}
2986
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002987/*
2988Public function, see header qcbor/qcbor_decode.h file
2989*/
2990void QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint8_t uTagRequirement, UsefulBufC *pValue, bool *pbIsNegative)
2991{
2992 QCBORItem Item;
2993 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
2994
2995 pMe->uLastError = (uint8_t)ConvertBigNum(uTagRequirement, &Item, pValue, pbIsNegative);
2996}
2997
2998
2999
3000// Semi private
3001QCBORError FarfMIME(uint8_t uTagRequirement, const QCBORItem *pItem, UsefulBufC *pMessage, bool *pbIsNot7Bit)
3002{
3003 const TagSpecification TagSpecText = {uTagRequirement, QCBOR_TYPE_MIME, {QCBOR_TYPE_TEXT_STRING, 0,0,0,0,0}};
3004 const TagSpecification TagSpecBinary = {uTagRequirement, QCBOR_TYPE_BINARY_MIME, {QCBOR_TYPE_BYTE_STRING, 0,0,0,0,0}};
3005
3006 QCBORError uReturn;
3007
3008 if(CheckTagRequirement(TagSpecText, pItem->uDataType)) {
3009 *pMessage = pItem->val.string;
3010 if(pbIsNot7Bit != NULL) {
3011 *pbIsNot7Bit = false;
3012 }
3013 uReturn = QCBOR_SUCCESS;
3014 } else if(CheckTagRequirement(TagSpecBinary, pItem->uDataType)) {
3015 *pMessage = pItem->val.string;
3016 if(pbIsNot7Bit != NULL) {
3017 *pbIsNot7Bit = true;
3018 }
3019 uReturn = QCBOR_SUCCESS;
3020
3021 } else {
3022 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
3023 }
3024
3025 return uReturn;
3026}
3027
3028
3029
3030
3031
Laurence Lundbladec4537442020-04-14 18:53:22 -07003032
3033
3034
Laurence Lundbladee6430642020-03-14 21:15:44 -07003035
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003036typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003037
3038
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003039// The main exponentiator that works on only positive numbers
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003040static QCBORError Exponentitate10(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003041{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003042 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003043
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003044 if(uResult != 0) {
3045 /* This loop will run a maximum of 19 times because
3046 * UINT64_MAX < 10 ^^ 19. More than that will cause
3047 * exit with the overflow error
3048 */
3049 for(; nExponent > 0; nExponent--) {
3050 if(uResult > UINT64_MAX / 10) {
3051 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Error overflow
3052 }
3053 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003054 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07003055
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003056 for(; nExponent < 0; nExponent++) {
3057 uResult = uResult / 10;
3058 if(uResult == 0) {
3059 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Underflow error
3060 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07003061 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07003062 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003063 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07003064
3065 *puResult = uResult;
3066
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003067 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003068}
3069
3070
Laurence Lundbladee6430642020-03-14 21:15:44 -07003071/* Convert a decimal fraction to an int64_t without using
3072 floating point or math libraries. Most decimal fractions
3073 will not fit in an int64_t and this will error out with
3074 under or overflow
3075 */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003076static QCBORError Exponentitate2(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003077{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003078 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003079
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003080 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003081
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003082 /* This loop will run a maximum of 64 times because
Laurence Lundbladee6430642020-03-14 21:15:44 -07003083 * INT64_MAX < 2^31. More than that will cause
3084 * exist with the overflow error
3085 */
3086 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003087 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003088 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Error overflow
Laurence Lundbladee6430642020-03-14 21:15:44 -07003089 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003090 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003091 nExponent--;
3092 }
3093
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003094 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003095 if(uResult == 0) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003096 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Underflow error
3097 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003098 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003099 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003100 }
3101
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003102 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003103
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003104 return QCBOR_SUCCESS;
3105}
3106
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003107/*
3108 Compute value with signed mantissa and signed result. Works with exponent of 2 or 10 based on exponentiator.
3109 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003110static inline QCBORError ExponentiateNN(int64_t nMantissa, int64_t nExponent, int64_t *pnResult, fExponentiator pfExp)
3111{
3112 uint64_t uResult;
3113
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003114 // Take the absolute value of the mantissa and convert to unsigned.
3115 // TODO: this should be possible in one intruction
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003116 uint64_t uMantissa = nMantissa > 0 ? (uint64_t)nMantissa : (uint64_t)-nMantissa;
3117
3118 // Do the exponentiation of the positive mantissa
3119 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
3120 if(uReturn) {
3121 return uReturn;
3122 }
3123
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003124
Laurence Lundblade983500d2020-05-14 11:49:34 -07003125 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
3126 of INT64_MIN. This assumes two's compliment representation where
3127 INT64_MIN is one increment farther from 0 than INT64_MAX.
3128 Trying to write -INT64_MIN doesn't work to get this because the
3129 compiler tries to work with an int64_t which can't represent
3130 -INT64_MIN.
3131 */
3132 uint64_t uMax = nMantissa > 0 ? INT64_MAX : (uint64_t)INT64_MAX+1;
3133
3134 // Error out if too large
3135 if(uResult > uMax) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003136 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3137 }
3138
3139 // Casts are safe because of checks above
3140 *pnResult = nMantissa > 0 ? (int64_t)uResult : -(int64_t)uResult;
3141
3142 return QCBOR_SUCCESS;
3143}
3144
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003145/*
3146 Compute value with signed mantissa and unsigned result. Works with exponent of 2 or 10 based on exponentiator.
3147 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003148static inline QCBORError ExponentitateNU(int64_t nMantissa, int64_t nExponent, uint64_t *puResult, fExponentiator pfExp)
3149{
3150 if(nMantissa < 0) {
3151 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3152 }
3153
3154 // Cast to unsigned is OK because of check for negative
3155 // Cast to unsigned is OK because UINT64_MAX > INT64_MAX
3156 // Exponentiation is straight forward
3157 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
3158}
3159
3160
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003161#include <math.h>
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003162
3163
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003164static QCBORError ConvertBigNumToUnsigned(const UsefulBufC BigNum, uint64_t uMax, uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003165{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003166 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003167
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003168 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003169 const uint8_t *pByte = BigNum.ptr;
3170 size_t uLen = BigNum.len;
3171 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07003172 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003173 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003174 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07003175 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003176 }
3177
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003178 *pResult = uResult;
3179 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003180}
3181
Laurence Lundblade887add82020-05-17 05:50:34 -07003182static inline QCBORError ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum, uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003183{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003184 return ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003185}
3186
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003187static inline QCBORError ConvertPositiveBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003188{
3189 uint64_t uResult;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003190 QCBORError uError = ConvertBigNumToUnsigned(BigNum, INT64_MAX, &uResult);
3191 if(uError) {
3192 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003193 }
3194 /* Cast is safe because ConvertBigNum is told to limit to INT64_MAX */
3195 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003196 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003197}
3198
3199
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003200static inline QCBORError ConvertNegativeBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003201{
3202 uint64_t uResult;
Laurence Lundbladeda095972020-06-06 18:35:33 -07003203 /* negaative int furthest from zero is INT64_MIN
3204 which is expressed as -INT64_MAX-1. The value of
3205 a negative bignum is -n-1, one further from zero
3206 than the positive bignum */
3207
3208 /* say INT64_MIN is -2; then INT64_MAX is 1.
3209 Then -n-1 <= INT64_MIN.
3210 Then -n -1 <= -INT64_MAX - 1
3211 THen n <= INT64_MAX. */
3212 QCBORError uError = ConvertBigNumToUnsigned(BigNum, INT64_MAX, &uResult);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003213 if(uError) {
3214 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003215 }
3216 /* Cast is safe because ConvertBigNum is told to limit to INT64_MAX */
Laurence Lundblade887add82020-05-17 05:50:34 -07003217 // TODO: this code is incorrect. See RFC 7049
Laurence Lundbladeda095972020-06-06 18:35:33 -07003218 uResult++; // this is the -1 in -n-1
Laurence Lundbladee6430642020-03-14 21:15:44 -07003219 *pResult = -(int64_t)uResult;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003220 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003221}
3222
Laurence Lundbladef6c86662020-05-12 02:08:00 -07003223#include "fenv.h"
Laurence Lundbladec4537442020-04-14 18:53:22 -07003224
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003225
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003226/*
3227Convert a integers and floats to an int64_t.
3228
3229\param[in] uOptions Bit mask list of conversion options.
3230
3231\retval QCBOR_ERR_CONVERSION_NOT_REQUESTED Conversion, possible, but not requested in uOptions.
3232
3233\retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
3234
3235\retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large or too small.
3236
3237*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003238static QCBORError ConvertInt64(const QCBORItem *pItem, uint32_t uOptions, int64_t *pnValue)
3239{
3240 switch(pItem->uDataType) {
3241 // TODO: float when ifdefs are set
3242 case QCBOR_TYPE_DOUBLE:
3243 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3244 // TODO: what about under/overflow here?
3245 // Invokes the floating-point HW and/or compiler-added libraries
3246 feclearexcept(FE_ALL_EXCEPT);
3247 *pnValue = llround(pItem->val.dfnum);
3248 if(fetestexcept(FE_INVALID)) {
3249 // TODO: better error code
3250 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3251 }
3252 } else {
3253 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3254 }
3255 break;
3256
3257 case QCBOR_TYPE_INT64:
3258 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
3259 *pnValue = pItem->val.int64;
3260 } else {
3261 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3262 }
3263 break;
3264
3265 case QCBOR_TYPE_UINT64:
3266 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
3267 if(pItem->val.uint64 < INT64_MAX) {
3268 *pnValue = pItem->val.int64;
3269 } else {
3270 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3271 }
3272 } else {
3273 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3274 }
3275 break;
3276
3277 default:
3278 return QCBOR_ERR_UNEXPECTED_TYPE;
3279 }
3280 return QCBOR_SUCCESS;
3281}
3282
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003283
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003284void QCBORDecode_GetInt64ConvertInternal(QCBORDecodeContext *pMe,
3285 uint32_t uOptions,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003286 int64_t *pnValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003287 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003288{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07003289 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003290 return;
3291 }
3292
Laurence Lundbladee6430642020-03-14 21:15:44 -07003293 QCBORItem Item;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003294 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
3295 if(uError) {
3296 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003297 return;
3298 }
3299
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003300 if(pItem) {
3301 *pItem = Item;
3302 }
3303
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003304 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003305}
3306
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003307
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003308void QCBORDecode_GetInt64ConvertInternalInMapN(QCBORDecodeContext *pMe,
3309 int64_t nLabel,
3310 uint32_t uOptions,
3311 int64_t *pnValue,
3312 QCBORItem *pItem)
3313{
3314 QCBORItem Item;
3315 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
3316
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003317 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003318}
3319
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003320
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003321void QCBORDecode_GetInt64ConvertInternalInMapSZ(QCBORDecodeContext *pMe,
3322 const char * szLabel,
3323 uint32_t uOptions,
3324 int64_t *pnValue,
3325 QCBORItem *pItem)
3326{
3327 if(pMe->uLastError != QCBOR_SUCCESS) {
3328 return;
3329 }
3330
3331 QCBORItem Item;
3332 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3333
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003334 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003335}
3336
3337
3338
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003339/*
3340 Convert a large variety of integer types to an int64_t.
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003341
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003342 \param[in] uOptions Bit mask list of conversion options.
3343
3344 \retval QCBOR_ERR_CONVERSION_NOT_REQUESTED Conversion, possible, but not requested in uOptions.
3345
3346 \retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
3347
3348 \retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large or too small.
3349
3350 */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003351static QCBORError Int64ConvertAll(const QCBORItem *pItem, uint32_t uOptions, int64_t *pnValue)
3352{
3353 QCBORError uErr;
3354
3355 switch(pItem->uDataType) {
3356
3357 case QCBOR_TYPE_POSBIGNUM:
3358 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3359 return ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003360 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003361 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003362 }
3363 break;
3364
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003365 case QCBOR_TYPE_NEGBIGNUM:
3366 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3367 return ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003368 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003369 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003370 }
3371 break;
3372
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003373#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
3374 case QCBOR_TYPE_DECIMAL_FRACTION:
3375 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3376 return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
3377 pItem->val.expAndMantissa.nExponent,
3378 pnValue,
3379 &Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003380 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003381 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3382 }
3383 break;
3384
3385 case QCBOR_TYPE_BIGFLOAT:
3386 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3387 return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
3388 pItem->val.expAndMantissa.nExponent,
3389 pnValue,
3390 Exponentitate2);
3391 } else {
3392 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3393 }
3394 break;
3395
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003396 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
3397 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3398 int64_t nMantissa;
3399 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3400 if(uErr) {
3401 return uErr;
3402 }
3403 return ExponentiateNN(nMantissa,
3404 pItem->val.expAndMantissa.nExponent,
3405 pnValue,
3406 Exponentitate10);
3407 } else {
3408 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3409 }
3410 break;
3411
3412 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
3413 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3414 int64_t nMantissa;
3415 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3416 if(uErr) {
3417 return uErr;
3418 }
3419 return ExponentiateNN(nMantissa,
3420 pItem->val.expAndMantissa.nExponent,
3421 pnValue,
3422 Exponentitate10);
3423 } else {
3424 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3425 }
3426 break;
3427
3428 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
3429 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3430 int64_t nMantissa;
3431 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3432 if(uErr) {
3433 return uErr;
3434 }
3435 return ExponentiateNN(nMantissa,
3436 pItem->val.expAndMantissa.nExponent,
3437 pnValue,
3438 Exponentitate2);
3439 } else {
3440 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3441 }
3442 break;
3443
3444 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
3445 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3446 int64_t nMantissa;
3447 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3448 if(uErr) {
3449 return uErr;
3450 }
3451 return ExponentiateNN(nMantissa,
3452 pItem->val.expAndMantissa.nExponent,
3453 pnValue,
3454 Exponentitate2);
3455 } else {
3456 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003457 }
3458 break;
3459
Laurence Lundbladec4537442020-04-14 18:53:22 -07003460 default:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003461 return QCBOR_ERR_UNEXPECTED_TYPE;
3462#endif
Laurence Lundbladec4537442020-04-14 18:53:22 -07003463 }
3464}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003465
3466
Laurence Lundbladec4537442020-04-14 18:53:22 -07003467/*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003468 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003469 */
3470void QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003471{
3472 QCBORItem Item;
3473
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003474 QCBORDecode_GetInt64ConvertInternal(pMe, uOptions, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003475
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003476 if(pMe->uLastError == QCBOR_SUCCESS) {
3477 // The above conversion succeeded
3478 return;
3479 }
3480
Laurence Lundbladef6c86662020-05-12 02:08:00 -07003481 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003482 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07003483 return;
3484 }
3485
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003486 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003487}
3488
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003489
3490/*
3491Public function, see header qcbor/qcbor_decode.h file
3492*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003493void QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, int64_t *pnValue)
3494{
3495 QCBORItem Item;
3496
3497 QCBORDecode_GetInt64ConvertInternalInMapN(pMe, nLabel, uOptions, pnValue, &Item);
3498
3499 if(pMe->uLastError == QCBOR_SUCCESS) {
3500 // The above conversion succeeded
3501 return;
3502 }
3503
3504 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3505 // The above conversion failed in a way that code below can't correct
3506 return;
3507 }
3508
3509 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
3510}
3511
3512
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003513/*
3514Public function, see header qcbor/qcbor_decode.h file
3515*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003516void QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, int64_t *pnValue)
3517{
3518 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003519 QCBORDecode_GetInt64ConvertInternalInMapSZ(pMe, szLabel, uOptions, pnValue, &Item);
3520
3521 if(pMe->uLastError == QCBOR_SUCCESS) {
3522 // The above conversion succeeded
3523 return;
3524 }
3525
3526 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3527 // The above conversion failed in a way that code below can't correct
3528 return;
3529 }
3530
3531 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
3532}
3533
3534
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003535static QCBORError ConvertUint64(const QCBORItem *pItem, uint32_t uOptions, uint64_t *puValue)
3536{
3537 switch(pItem->uDataType) {
3538 // TODO: type flaot
3539 case QCBOR_TYPE_DOUBLE:
3540 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3541 feclearexcept(FE_ALL_EXCEPT);
3542 double dRounded = round(pItem->val.dfnum);
3543 // TODO: over/underflow
3544 if(fetestexcept(FE_INVALID)) {
3545 // TODO: better error code
3546 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3547 } else if(isnan(dRounded)) {
3548 // TODO: better error code
3549 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3550 } else if(dRounded >= 0) {
3551 *puValue = (uint64_t)dRounded;
3552 } else {
3553 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3554 }
3555 } else {
3556 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3557 }
3558 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003559
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003560 case QCBOR_TYPE_INT64:
3561 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
3562 if(pItem->val.int64 >= 0) {
3563 *puValue = (uint64_t)pItem->val.int64;
3564 } else {
3565 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3566 }
3567 } else {
3568 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3569 }
3570 break;
3571
3572 case QCBOR_TYPE_UINT64:
3573 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
3574 *puValue = pItem->val.uint64;
3575 } else {
3576 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3577 }
3578 break;
3579
3580 default:
3581 return QCBOR_ERR_UNEXPECTED_TYPE;
3582 }
3583 return QCBOR_SUCCESS;
3584}
Laurence Lundbladec4537442020-04-14 18:53:22 -07003585
3586
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003587void QCBORDecode_GetUInt64ConvertInternal(QCBORDecodeContext *pMe,
3588 uint32_t uOptions,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003589 uint64_t *puValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003590 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003591{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003592 if(pMe->uLastError != QCBOR_SUCCESS) {
3593 return;
3594 }
3595
Laurence Lundbladec4537442020-04-14 18:53:22 -07003596 QCBORItem Item;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003597
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003598 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
3599 if(uError) {
3600 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003601 return;
3602 }
3603
Laurence Lundbladea826c502020-05-10 21:07:00 -07003604 if(pItem) {
3605 *pItem = Item;
3606 }
3607
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003608 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003609}
3610
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003611
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003612void QCBORDecode_GetInt8ConvertInternal(QCBORDecodeContext *pMe, uint32_t uOptions, int8_t *pnValue, QCBORItem *pItem)
3613{
3614 int64_t uValue;
3615 QCBORDecode_GetInt64ConvertInternal(pMe, uOptions, &uValue, pItem);
3616 if(pMe->uLastError != QCBOR_SUCCESS) {
3617 return;
3618 }
3619
3620 if(QCBOR_Int64ToInt8(uValue, pnValue)) {
3621 pMe->uLastError = QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3622 }
3623}
3624
3625void QCBORDecode_GetInt8ConvertInternalInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, int8_t *pnValue, QCBORItem *pItem)
3626{
3627 int64_t uValue;
3628 QCBORDecode_GetInt64ConvertInternalInMapN(pMe, nLabel, uOptions, &uValue, pItem);
3629 if(pMe->uLastError != QCBOR_SUCCESS) {
3630 return;
3631 }
3632
3633 if(QCBOR_Int64ToInt8(uValue, pnValue)) {
3634 pMe->uLastError = QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3635 }
3636}
3637
3638void QCBORDecode_GetInt8ConvertInternalInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, int8_t *pnValue, QCBORItem *pItem)
3639{
3640 int64_t uValue;
3641 QCBORDecode_GetInt64ConvertInternalInMapSZ(pMe, szLabel, uOptions, &uValue, pItem);
3642 if(pMe->uLastError != QCBOR_SUCCESS) {
3643 return;
3644 }
3645
3646 if(QCBOR_Int64ToInt8(uValue, pnValue)) {
3647 pMe->uLastError = QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3648 }
3649}
3650
3651
3652
3653
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003654void QCBORDecode_GetUint64ConvertInternalInMapN(QCBORDecodeContext *pMe,
3655 int64_t nLabel,
3656 uint32_t uOptions,
3657 uint64_t *puValue,
3658 QCBORItem *pItem)
3659{
3660 QCBORItem Item;
3661 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
3662
3663 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
3664}
3665
3666
3667void QCBORDecode_GetUint64ConvertInternalInMapSZ(QCBORDecodeContext *pMe,
3668 const char * szLabel,
3669 uint32_t uOptions,
3670 uint64_t *puValue,
3671 QCBORItem *pItem)
3672{
3673 if(pMe->uLastError != QCBOR_SUCCESS) {
3674 return;
3675 }
3676
3677 QCBORItem Item;
3678 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3679
3680 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
3681}
3682
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003683/*
3684 Public function, see header qcbor/qcbor_decode.h file
3685*/
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003686static QCBORError Uint64ConvertAll(const QCBORItem *pItem, uint32_t uOptions, uint64_t *puValue)
3687{
3688 QCBORError uErr;
3689
3690 switch(pItem->uDataType) {
3691
3692 case QCBOR_TYPE_POSBIGNUM:
3693 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3694 return ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
3695 } else {
3696 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3697 }
3698 break;
3699
3700 case QCBOR_TYPE_NEGBIGNUM:
3701 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3702 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3703 } else {
3704 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3705 }
3706 break;
3707
3708#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
3709
3710 case QCBOR_TYPE_DECIMAL_FRACTION:
3711 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3712 return ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
3713 pItem->val.expAndMantissa.nExponent,
3714 puValue,
3715 Exponentitate10);
3716 } else {
3717 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3718 }
3719 break;
3720
3721 case QCBOR_TYPE_BIGFLOAT:
3722 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3723 return ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
3724 pItem->val.expAndMantissa.nExponent,
3725 puValue,
3726 Exponentitate2);
3727 } else {
3728 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3729 }
3730 break;
3731
3732 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
3733 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3734 // TODO: Would be better to convert to unsigned
3735 int64_t nMantissa;
3736 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3737 if(uErr != QCBOR_SUCCESS) {
3738 return uErr;
3739 }
3740 return ExponentitateNU(nMantissa,
3741 pItem->val.expAndMantissa.nExponent,
3742 puValue,
3743 Exponentitate10);
3744 } else {
3745 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3746 }
3747 break;
3748
3749 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
3750 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3751 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3752 } else {
3753 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3754 }
3755 break;
3756
3757 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
3758 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3759 // TODO: Would be better to convert to unsigned
3760 int64_t nMantissa;
3761 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3762 if(uErr != QCBOR_SUCCESS) {
3763 return uErr;
3764 }
3765 return ExponentitateNU(nMantissa,
3766 pItem->val.expAndMantissa.nExponent,
3767 puValue,
3768 Exponentitate2);
3769 } else {
3770 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3771 }
3772 break;
3773
3774 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
3775 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3776 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3777 } else {
3778 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3779 }
3780 break;
3781#endif
3782 default:
3783 return QCBOR_ERR_UNEXPECTED_TYPE;
3784 }
3785}
3786
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003787/*
3788 Public function, see header qcbor/qcbor_decode.h file
3789*/
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003790void QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003791{
3792 QCBORItem Item;
3793
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003794 QCBORDecode_GetUInt64ConvertInternal(pMe, uOptions, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003795
Laurence Lundbladef6c86662020-05-12 02:08:00 -07003796 if(pMe->uLastError == QCBOR_SUCCESS) {
3797 // The above conversion succeeded
3798 return;
3799 }
3800
3801 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3802 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07003803 return;
3804 }
3805
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003806 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003807}
3808
Laurence Lundbladec4537442020-04-14 18:53:22 -07003809
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003810/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003811 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003812*/
3813void QCBORDecode_GetUint64ConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, uint64_t *puValue)
3814{
3815 QCBORItem Item;
3816
3817 QCBORDecode_GetUint64ConvertInternalInMapN(pMe, nLabel, uOptions, puValue, &Item);
3818
3819 if(pMe->uLastError == QCBOR_SUCCESS) {
3820 // The above conversion succeeded
3821 return;
3822 }
3823
3824 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3825 // The above conversion failed in a way that code below can't correct
3826 return;
3827 }
3828
3829 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
3830}
3831
3832
3833/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003834 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003835*/
3836void QCBORDecode_GetUint64ConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, uint64_t *puValue)
3837{
3838 QCBORItem Item;
3839 QCBORDecode_GetUint64ConvertInternalInMapSZ(pMe, szLabel, uOptions, puValue, &Item);
3840
3841 if(pMe->uLastError == QCBOR_SUCCESS) {
3842 // The above conversion succeeded
3843 return;
3844 }
3845
3846 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3847 // The above conversion failed in a way that code below can't correct
3848 return;
3849 }
3850
3851 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
3852}
3853
3854
3855static QCBORError ConvertDouble(const QCBORItem *pItem, uint32_t uOptions, double *pdValue)
3856{
3857 switch(pItem->uDataType) {
3858 // TODO: float when ifdefs are set
3859 case QCBOR_TYPE_DOUBLE:
3860 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3861 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3862 *pdValue = pItem->val.dfnum;
3863 } else {
3864 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3865 }
3866 }
3867 break;
3868
3869 case QCBOR_TYPE_INT64:
3870 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
3871 // TODO: how does this work?
3872 *pdValue = (double)pItem->val.int64;
3873
3874 } else {
3875 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3876 }
3877 break;
3878
3879 case QCBOR_TYPE_UINT64:
3880 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
3881 *pdValue = (double)pItem->val.uint64;
3882 } else {
3883 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3884 }
3885 break;
3886
3887 default:
3888 return QCBOR_ERR_UNEXPECTED_TYPE;
3889 }
3890
3891 return QCBOR_SUCCESS;
3892}
3893
3894
3895
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003896void QCBORDecode_GetDoubleConvertInternal(QCBORDecodeContext *pMe,
3897 uint32_t uOptions,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003898 double *pdValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003899 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003900{
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003901 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003902 return;
3903 }
3904
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003905 QCBORItem Item;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003906
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003907 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003908 if(uError) {
3909 pMe->uLastError = (uint8_t)uError;
3910 return;
3911 }
3912
3913 if(pItem) {
3914 *pItem = Item;
3915 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07003916
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003917 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003918}
Laurence Lundbladec4537442020-04-14 18:53:22 -07003919
Laurence Lundbladec4537442020-04-14 18:53:22 -07003920
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003921void QCBORDecode_GetDoubleConvertInternalInMapN(QCBORDecodeContext *pMe,
3922 int64_t nLabel,
3923 uint32_t uOptions,
3924 double *pdValue,
3925 QCBORItem *pItem)
3926{
3927 QCBORItem Item;
3928 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
3929
3930 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
3931}
3932
3933void QCBORDecode_GetDoubleConvertInternalInMapSZ(QCBORDecodeContext *pMe,
3934 const char * szLabel,
3935 uint32_t uOptions,
3936 double *pdValue,
3937 QCBORItem *pItem)
3938{
3939 if(pMe->uLastError != QCBOR_SUCCESS) {
3940 return;
3941 }
3942
3943 QCBORItem Item;
3944 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3945
3946 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
3947}
3948
3949
3950
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003951static double ConvertBigNumToDouble(const UsefulBufC BigNum)
3952{
3953 double dResult;
3954
3955 dResult = 0.0;
3956 const uint8_t *pByte = BigNum.ptr;
3957 size_t uLen = BigNum.len;
3958 /* This will overflow and become the float value INFINITY if the number
3959 is too large to fit. No error will be logged.
3960 TODO: should an error be logged? */
3961 while(uLen--) {
3962 dResult = (dResult * 256.0) + (double)*pByte++;
3963 }
3964
3965 return dResult;
3966}
3967
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003968static QCBORError DoubleConvertAll(const QCBORItem *pItem, uint32_t uOptions, double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003969{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003970 /*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003971 https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
3972
3973 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003974 switch(pItem->uDataType) {
3975 // TODO: type float
3976 case QCBOR_TYPE_DECIMAL_FRACTION:
3977 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3978 // TODO: rounding and overflow errors
3979 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
3980 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
3981 } else {
3982 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3983 }
3984 break;
3985
3986 case QCBOR_TYPE_BIGFLOAT:
3987 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
3988 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
3989 exp2((double)pItem->val.expAndMantissa.nExponent);
3990 } else {
3991 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3992 }
3993 break;
3994
3995 case QCBOR_TYPE_POSBIGNUM:
3996 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3997 *pdValue = ConvertBigNumToDouble(pItem->val.bigNum);
3998 } else {
3999 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4000 }
4001 break;
4002
4003 case QCBOR_TYPE_NEGBIGNUM:
4004 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07004005 *pdValue = -1-ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004006 } else {
4007 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4008 }
4009 break;
4010
4011 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
4012 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
4013 double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
4014 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
4015 } else {
4016 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4017 }
4018 break;
4019
4020 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
4021 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
4022 double dMantissa = -ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
4023 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
4024 } else {
4025 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4026 }
4027 break;
4028
4029 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
4030 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
4031 double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
4032 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
4033 } else {
4034 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4035 }
4036 break;
4037
4038 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
4039 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07004040 double dMantissa = -1-ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004041 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
4042 } else {
4043 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
4044 }
4045 break;
4046
4047 default:
4048 return QCBOR_ERR_UNEXPECTED_TYPE;
4049 }
4050
4051 return QCBOR_SUCCESS;
4052}
4053
4054
4055/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004056 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004057*/
4058void QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, double *pdValue)
4059{
4060
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004061 QCBORItem Item;
4062
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004063 QCBORDecode_GetDoubleConvertInternal(pMe, uOptions, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004064
4065 if(pMe->uLastError == QCBOR_SUCCESS) {
4066 // The above conversion succeeded
4067 return;
4068 }
4069
4070 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
4071 // The above conversion failed in a way that code below can't correct
4072 return;
4073 }
4074
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004075 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004076}
4077
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004078
4079/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004080 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004081*/
4082void QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, double *pdValue)
4083{
4084 QCBORItem Item;
4085
4086 QCBORDecode_GetDoubleConvertInternalInMapN(pMe, nLabel, uOptions, pdValue, &Item);
4087
4088 if(pMe->uLastError == QCBOR_SUCCESS) {
4089 // The above conversion succeeded
4090 return;
4091 }
4092
4093 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
4094 // The above conversion failed in a way that code below can't correct
4095 return;
4096 }
4097
4098 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
4099}
4100
4101
4102/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004103 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004104*/
4105void QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, double *pdValue)
4106{
4107 QCBORItem Item;
4108 QCBORDecode_GetDoubleConvertInternalInMapSZ(pMe, szLabel, uOptions, pdValue, &Item);
4109
4110 if(pMe->uLastError == QCBOR_SUCCESS) {
4111 // The above conversion succeeded
4112 return;
4113 }
4114
4115 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
4116 // The above conversion failed in a way that code below can't correct
4117 return;
4118 }
4119
4120 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
4121}
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004122
4123
4124void FarfDecimalFraction(QCBORDecodeContext *pMe,
4125 uint8_t uTagRequirement,
4126 QCBORItem *pItem,
4127 int64_t *pnMantissa,
4128 int64_t *pnExponent)
4129{
4130 QCBORError uErr;
4131
4132 if(pItem->uDataType == QCBOR_TYPE_ARRAY) {
4133 if(uTagRequirement == QCBOR_TAGSPEC_MATCH_TAG_CONTENT_TYPE) {
4134 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4135 return;
4136 }
4137 uErr = QCBORDecode_MantissaAndExponent(pMe, pItem);
4138 if(uErr != QCBOR_SUCCESS) {
4139 pMe->uLastError = (uint8_t)uErr;
4140 return;
4141 }
4142 }
4143
4144 if(uTagRequirement == QCBOR_TAGSPEC_MATCH_TAG_CONTENT_TYPE) {
4145 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4146 return;
4147 }
4148
4149 switch (pItem->uDataType) {
4150
4151 case QCBOR_TYPE_DECIMAL_FRACTION:
4152 *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
4153 *pnExponent = pItem->val.expAndMantissa.nExponent;
4154 break;
4155
4156 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
4157 *pnExponent = pItem->val.expAndMantissa.nExponent;
4158
4159 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
4160 if(uErr != QCBOR_SUCCESS) {
4161 pMe->uLastError = (uint8_t)uErr;
4162 }
4163 break;
4164
4165 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
4166 *pnExponent = pItem->val.expAndMantissa.nExponent;
4167
4168 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
4169 if(uErr != QCBOR_SUCCESS) {
4170 pMe->uLastError = (uint8_t)uErr;
4171 }
4172 break;
4173
4174 default:
4175 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4176 }
4177}
4178
4179void QCBORDecode_GetDecimalFractionN(QCBORDecodeContext *pMe,
4180 uint8_t uTagRequirement,
4181 int64_t nLabel,
4182 int64_t *pnMantissa,
4183 int64_t *pnExponent)
4184{
4185 QCBORItem Item;
4186
4187 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
4188 FarfDecimalFraction(pMe, uTagRequirement, &Item, pnMantissa, pnExponent);
4189}
4190
4191
4192
4193void QCBORDecode_GetDecimalFractionSZ(QCBORDecodeContext *pMe,
4194 uint8_t uTagRequirement,
4195 const char *szLabel,
4196 int64_t *pnMantissa,
4197 int64_t *pnExponent)
4198{
4199 QCBORItem Item;
4200
4201 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
4202
4203 FarfDecimalFraction(pMe, uTagRequirement, &Item, pnMantissa, pnExponent);
4204}
4205
4206
4207UsefulBufC ConvertIntToBigNum(uint64_t uInt, UsefulBuf Buffer)
4208{
4209 while(uInt & 0xff0000000000UL) {
4210 uInt = uInt << 8;
4211 };
4212
4213 UsefulOutBuf UOB;
4214
4215 UsefulOutBuf_Init(&UOB, Buffer);
4216
4217 while(uInt) {
4218 UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff0000000000UL) >> 56));
4219 uInt = uInt << 8;
4220 }
4221
4222 return UsefulOutBuf_OutUBuf(&UOB);
4223}
4224
4225
4226void QCBORDecode_GetDecimalFractionBigN(QCBORDecodeContext *pMe,
4227 uint8_t uTagRequirement,
4228 int64_t nLabel,
4229 UsefulBuf pBufferForMantissa,
4230 UsefulBufC *pMantissa,
4231 bool *pbIsNegative,
4232 int64_t *pnExponent)
4233{
4234 QCBORItem Item;
4235 QCBORError uErr;
4236
4237 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
4238
4239 if(Item.uDataType == QCBOR_TYPE_ARRAY) {
4240 uErr = QCBORDecode_MantissaAndExponent(pMe, &Item);
4241 if(uErr != QCBOR_SUCCESS) {
4242 pMe->uLastError = (uint8_t)uErr;
4243 return;
4244 }
4245 }
4246
4247 uint64_t uMantissa;
4248
4249 switch (Item.uDataType) {
4250
4251 case QCBOR_TYPE_DECIMAL_FRACTION:
4252 if(Item.val.expAndMantissa.Mantissa.nInt >= 0) {
4253 uMantissa = (uint64_t)Item.val.expAndMantissa.Mantissa.nInt;
4254 *pbIsNegative = false;
4255 } else {
4256 uMantissa = (uint64_t)-Item.val.expAndMantissa.Mantissa.nInt;
4257 *pbIsNegative = true;
4258 }
4259 *pMantissa = ConvertIntToBigNum(uMantissa, pBufferForMantissa);
4260 *pnExponent = Item.val.expAndMantissa.nExponent;
4261 break;
4262
4263 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
4264 *pnExponent = Item.val.expAndMantissa.nExponent;
4265 *pMantissa = Item.val.expAndMantissa.Mantissa.bigNum;
4266 *pbIsNegative = false;
4267 break;
4268
4269 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
4270 *pnExponent = Item.val.expAndMantissa.nExponent;
4271 *pMantissa = Item.val.expAndMantissa.Mantissa.bigNum;
4272 *pbIsNegative = true;
4273 break;
4274
4275 default:
4276 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
4277 }
4278}