blob: bc21df9036ffa7cc883690b4e4836645d13e636c [file] [log] [blame]
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001/*==============================================================================
Laurence Lundbladed92a6162018-11-01 11:38:35 +07002 Copyright (c) 2016-2018, The Linux Foundation.
Laurence Lundbladeee851742020-01-08 08:37:05 -08003 Copyright (c) 2018-2020, Laurence Lundblade.
Laurence Lundbladed92a6162018-11-01 11:38:35 +07004 All rights reserved.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08005
Laurence Lundblade0dbc9172018-11-01 14:17:21 +07006Redistribution and use in source and binary forms, with or without
7modification, are permitted provided that the following conditions are
8met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of The Linux Foundation nor the names of its
16 contributors, nor the name "Laurence Lundblade" may be used to
17 endorse or promote products derived from this software without
18 specific prior written permission.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080019
Laurence Lundblade0dbc9172018-11-01 14:17:21 +070020THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
21WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
23ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
24BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
30IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Laurence Lundbladeee851742020-01-08 08:37:05 -080031 =============================================================================*/
Laurence Lundblade624405d2018-09-18 20:10:47 -070032
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080033
Laurence Lundblade844bb5c2020-03-01 17:27:25 -080034#include "qcbor/qcbor_decode.h"
Laurence Lundblade12d32c52018-09-19 11:25:27 -070035#include "ieee754.h"
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070036
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070037
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +053038/*
39 This casts away the const-ness of a pointer, usually so it can be
40 freed or realloced.
41 */
42#define UNCONST_POINTER(ptr) ((void *)(ptr))
43
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070044
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070045
Laurence Lundbladeee851742020-01-08 08:37:05 -080046/*===========================================================================
47 DecodeNesting -- Functions for tracking array/map nesting when decoding
48
Laurence Lundblade844bb5c2020-03-01 17:27:25 -080049 See qcbor/qcbor_decode.h for definition of the object
50 used here: QCBORDecodeNesting
Laurence Lundbladeee851742020-01-08 08:37:05 -080051 ===========================================================================*/
52
Laurence Lundblade9c905e82020-04-25 11:31:38 -070053
54
55/*
56The main mode of decoding is a pre-order travesal of the tree of leaves (numbers, strings...)
57formed by intermediate nodes (arrays and maps). The cursor for the traversal
58 is the byte offset in the encoded input and a leaf counter for definite
59 length maps and arrays. Indefinite length maps and arrays are handled
60 by look ahead for the break.
61
62 The view presented to the caller has tags, labels and the chunks of
63 indefinite length strings aggregated into one decorated data item.
64
65The caller understands the nesting level in pre-order traversal by
66 the fact that a data item that is a map or array is presented to
67 the caller when it is first encountered in the pre-order traversal and that all data items are presented with its nesting level
68 and the nesting level of the next item.
69
70 The caller traverse maps and arrays in a special mode that often more convenient
71 that tracking by nesting level. When an array or map is expected or encountered
72 the EnterMap or EnteryArray can be called.
73
74 When entering a map or array like this, the cursor points to the first
75 item in the map or array. When exiting, it points to the item after
76 the map or array, regardless of whether the items in the map or array were
77 all traversed.
78
79 When in a map or array, the cursor functions as normal, but traversal
80 cannot go past the end of the map or array that was entered. If this
81 is attempted the QCBOR_ERR_NO_MORE_ITEMS error is returned. To
82 go past the end of the map or array ExitMap() or ExitArray() must
83 be called. It can be called any time regardless of the position
84 of the cursor.
85
86 When a map is entered, a special function allows fetching data items
87 by label. This call will traversal the whole map looking for the
88 labeled item. The whole map is traversed so as to detect duplicates.
89 This type of fetching items does not affect the normal traversal
90 cursor.
91
92
93
94
95
96
97
98
99
100
101When a data item is presented to the caller, the nesting level of the data
102 item is presented along with the nesting level of the item that would be
103 next consumed.
104
105
106
107
108
109
110
111
112
113 */
114
Laurence Lundblade6b249302020-04-30 12:38:12 -0700115inline static bool
116// TODO: test Map as array better?
Laurence Lundbladeee851742020-01-08 08:37:05 -0800117IsMapOrArray(uint8_t uDataType)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700118{
Laurence Lundblade6b249302020-04-30 12:38:12 -0700119 return uDataType == QCBOR_TYPE_MAP ||
120 uDataType == QCBOR_TYPE_ARRAY ||
121 uDataType == QCBOR_TYPE_MAP_AS_ARRAY;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700122}
123
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700124
125inline static uint8_t
126DecodeNesting_GetLevel(const QCBORDecodeNesting *pNesting)
127{
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700128 const ptrdiff_t nLevel = pNesting->pCurrent - &(pNesting->pMapsAndArrays[0]);
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700129 // Check in DecodeNesting_Descend and never having
130 // QCBOR_MAX_ARRAY_NESTING > 255 gaurantees cast is safe
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700131 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700132}
133
134
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700135inline static bool DecodeNesting_InBoundedMode(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700136{
137 return pNesting->pCurrent->uType & QCBOR_NEST_TYPE_IS_BOUND;
138}
139
140/*inline static bool IsArray(const QCBORDecodeNesting *pNesting)
141{
142 const unsigned uIndex = DecodeNesting_GetLevel(pNesting);
143
144 return (0x01ULL << ((uIndex * 3) + 1)) & pNesting->uTypeBitMap;
145}
146
147inline static bool IsBstr(const QCBORDecodeNesting *pNesting)
148{
149 const unsigned uIndex = DecodeNesting_GetLevel(pNesting);
150
151 return (0x01ULL << ((uIndex * 3) + 2)) & pNesting->uTypeBitMap;
152}*/
153
154
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700155inline static bool
156DecodeNesting_IsAtTop(const QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700157{
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700158 if(pNesting->pCurrent == &(pNesting->pMapsAndArrays[0])) {
159 return true;
160 } else {
161 return false;
162 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700163}
164
Laurence Lundblade937ea812020-05-08 11:38:23 -0700165// Determine if at the end of a map or array while in map mode
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700166inline static bool
167DecodeNesting_AtEnd(const QCBORDecodeNesting *pNesting)
168{
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700169 if(pNesting->pCurrentMap && DecodeNesting_InBoundedMode(pNesting)) {
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700170 if(pNesting->pCurrentMap->uCount == 0) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700171 // In map mode and consumed all items, so it is the end
172 return true;
173 } else {
174 // In map mode, all items not consumed, so it is NOT the end
175 return false;
176 }
177 } else {
Laurence Lundblade937ea812020-05-08 11:38:23 -0700178 // Not in map mode. The end is determined in other ways.
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700179 return false;
180 }
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700181}
182
183
Laurence Lundbladeee851742020-01-08 08:37:05 -0800184inline static int
185DecodeNesting_IsIndefiniteLength(const QCBORDecodeNesting *pNesting)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700186{
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700187 return pNesting->pCurrent->uCount == UINT16_MAX;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700188 //return pNesting->pCurrent->uType & QCBOR_NEST_TYPE_IS_INDEFINITE;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700189}
190
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800191
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700192inline static uint8_t
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700193DecodeNesting_GetBoundedModeLevel(QCBORDecodeNesting *pNesting)
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700194{
195 // Check in DecodeNesting_Descend and never having
196 // QCBOR_MAX_ARRAY_NESTING > 255 gaurantees cast is safe
197 return (uint8_t)(pNesting->pCurrentMap - &(pNesting->pMapsAndArrays[0]));
198}
199
Laurence Lundbladeee851742020-01-08 08:37:05 -0800200inline static int
201DecodeNesting_TypeIsMap(const QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700202{
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700203 if(DecodeNesting_IsAtTop(pNesting)) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700204 return 0;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700205 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800206
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700207 return CBOR_MAJOR_TYPE_MAP == pNesting->pCurrent->uMajorType;
208}
209
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700210
211// return 1 if closed out an array or map
212inline static int
213DecodeNesting_Decrement(QCBORDecodeNesting *pNesting)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700214{
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700215 pNesting->pCurrent->uCount--;
216
217 if(pNesting->pCurrent->uCount != 0) {
218 return 0;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700219 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800220
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700221 return 1;
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800222}
223
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700224inline static void
225DecodeNesting_Ascend(QCBORDecodeNesting *pNesting)
226{
227 pNesting->pCurrent--;
228}
229
230
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700231// Called on every single item except breaks including decode of a map/array
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700232/* Decrements the map/array counter if possible. If decrement
233 closed out a map or array, then level up in nesting and decrement
234 again, until, the top is reached or the end of a map mode is reached
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700235
236 return 1 if leveld up, 0 if not
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700237 */
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700238inline static int
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700239DecodeNesting_DecrementCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800240{
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700241 int nReturn = 0;
242
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700243 while(!DecodeNesting_IsAtTop(pNesting)) {
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700244 // Not at the top level, so there is decrementing to be done.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800245
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700246 if(DecodeNesting_IsIndefiniteLength(pNesting)) {
247 // Indefinite lengths not handled here
248 break;
Laurence Lundblade9e3651c2018-10-10 11:49:55 +0800249 }
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700250
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700251 pNesting->pCurrent->uCount--;
252
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700253 if(pNesting->pCurrent->uCount != 0) {
254 // Did not close out an array or map, so nothing further
255 break;
256 }
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700257
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700258 if(DecodeNesting_InBoundedMode(pNesting)) {
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700259 // In map mode the level-up must be done explicitly
260 break;
261 }
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700262
263 // Closed out an array or map so level up
264 pNesting->pCurrent--;
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700265 /*if(pNesting->pCurrent->uMapMode) {
266 // Bring the current map level along if new level is a map
267 // TODO: must search up until a mapmode level is found.
268 pNesting->pCurrentMap = pNesting->pCurrent;
269 } */
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700270
271 // Continue with loop to see if closing out this doesn't close out more
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700272 nReturn = 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700273 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700274 return nReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700275}
276
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700277inline static void
278DecodeNesting_EnterMapMode(QCBORDecodeNesting *pNesting, size_t uOffset)
279{
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700280 /* Have descended into this is called. The job here is just to mark it in bounded mode */
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700281 pNesting->pCurrentMap = pNesting->pCurrent;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700282 pNesting->pCurrentMap->uType |= QCBOR_NEST_TYPE_IS_BOUND;
283 // Cast to uint32_t is safe because QCBOR restricts encoded input to < UINT32_MAX
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700284 pNesting->pCurrentMap->uOffset = (uint32_t)uOffset;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700285}
286
287inline static void
288DecodeNesting_Exit(QCBORDecodeNesting *pNesting)
289{
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700290 pNesting->pCurrentMap->uType &= ~QCBOR_NEST_TYPE_IS_BOUND;
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700291 // TODO: rewrite this. Gonna need a lot of code to ascend through indefinite length maps and arrays
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700292 pNesting->pCurrent = pNesting->pCurrentMap - 1; // TODO error check
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700293
294 DecodeNesting_DecrementCount(pNesting);
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700295
296 while(1) {
297 pNesting->pCurrentMap--;
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700298 if(DecodeNesting_InBoundedMode(pNesting)) {
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700299 break;
300 }
301 if(pNesting->pCurrentMap == &(pNesting->pMapsAndArrays[0])) {
302 break;
303 }
304 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700305}
306
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700307
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700308inline static QCBORError
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700309DecodeNesting_Descend(QCBORDecodeNesting *pNesting, uint8_t uQCBORType, uint64_t uCount, uint32_t uEndOffset)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700310{
311 QCBORError nReturn = QCBOR_SUCCESS;
312
313 if(uCount == 0) {
314 // Nothing to do for empty definite lenth arrays. They are just are
315 // effectively the same as an item that is not a map or array
316 goto Done;
317 // Empty indefinite length maps and arrays are handled elsewhere
318 }
319
320 // Error out if arrays is too long to handle
321 if(uCount != UINT16_MAX && uCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
322 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
323 goto Done;
324 }
325
326 // Error out if nesting is too deep
327 if(pNesting->pCurrent >= &(pNesting->pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING])) {
328 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
329 goto Done;
330 }
331
332 // The actual descend
333 pNesting->pCurrent++;
334
335 // Fill in the new level fully
336 pNesting->pCurrent->uMajorType = uQCBORType;
337 pNesting->pCurrent->uCount = (uint16_t)uCount;
338 pNesting->pCurrent->uSaveCount = (uint16_t)uCount;
339 pNesting->pCurrent->uEndOffset = uEndOffset;
340 pNesting->pCurrent->uMapMode = 0;
341
342Done:
343 return nReturn;;
344}
345
346
347
Laurence Lundbladeee851742020-01-08 08:37:05 -0800348inline static void
349DecodeNesting_Init(QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700350{
351 pNesting->pCurrent = &(pNesting->pMapsAndArrays[0]);
352}
353
354
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700355static void DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting, QCBORDecodeNesting *pSave)
356{
357 *pSave = *pNesting;
358 pNesting->pCurrent = pNesting->pCurrentMap;
359
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700360 if(!DecodeNesting_IsIndefiniteLength(pNesting)) {
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700361 pNesting->pCurrent->uCount = pNesting->pCurrent->uSaveCount;
362 }
363}
364
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700365static inline void DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting, QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700366{
367 *pNesting = *pSave;
368}
369
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700370QCBORError DecodeNesting_EnterBstr(QCBORDecodeNesting *pNesting, uint32_t uEndOffset)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700371{
372 QCBORError uReturn ;
373
374 // Error out if nesting is too deep
375 if(pNesting->pCurrent >= &(pNesting->pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING])) {
376 uReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
377 goto Done;
378 }
379
380 // The actual descend
381 pNesting->pCurrent++;
382
383 // Record a few details for this nesting level
384 pNesting->pCurrent->uMajorType = 1; // TODO the right value for a bstr
385 pNesting->pCurrent->uCount = 0xffff;
386 pNesting->pCurrent->uSaveCount = 0xffff;
387 pNesting->pCurrent->uType = 0;
388
389 uReturn = QCBOR_SUCCESS;
390
391Done:
392 return uReturn;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700393}
394
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700395
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700396
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700397
Laurence Lundbladeee851742020-01-08 08:37:05 -0800398/*===========================================================================
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800399 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
400
401 The following four functions are pretty wrappers for invocation of
402 the string allocator supplied by the caller.
403
Laurence Lundbladeee851742020-01-08 08:37:05 -0800404 ===========================================================================*/
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800405
Laurence Lundbladeee851742020-01-08 08:37:05 -0800406static inline void
407StringAllocator_Free(const QCORInternalAllocator *pMe, void *pMem)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800408{
409 (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, 0);
410}
411
Laurence Lundbladeee851742020-01-08 08:37:05 -0800412// StringAllocator_Reallocate called with pMem NULL is
413// equal to StringAllocator_Allocate()
414static inline UsefulBuf
415StringAllocator_Reallocate(const QCORInternalAllocator *pMe,
416 void *pMem,
417 size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800418{
419 return (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, uSize);
420}
421
Laurence Lundbladeee851742020-01-08 08:37:05 -0800422static inline UsefulBuf
423StringAllocator_Allocate(const QCORInternalAllocator *pMe, size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800424{
425 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
426}
427
Laurence Lundbladeee851742020-01-08 08:37:05 -0800428static inline void
429StringAllocator_Destruct(const QCORInternalAllocator *pMe)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800430{
431 if(pMe->pfAllocator) {
432 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
433 }
434}
435
436
437
Laurence Lundbladeee851742020-01-08 08:37:05 -0800438/*===========================================================================
439 QCBORDecode -- The main implementation of CBOR decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700440
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800441 See qcbor/qcbor_decode.h for definition of the object
442 used here: QCBORDecodeContext
Laurence Lundbladeee851742020-01-08 08:37:05 -0800443 ===========================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700444/*
445 Public function, see header file
446 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800447void QCBORDecode_Init(QCBORDecodeContext *me,
448 UsefulBufC EncodedCBOR,
449 QCBORDecodeMode nDecodeMode)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700450{
451 memset(me, 0, sizeof(QCBORDecodeContext));
452 UsefulInputBuf_Init(&(me->InBuf), EncodedCBOR);
Laurence Lundbladeee851742020-01-08 08:37:05 -0800453 // Don't bother with error check on decode mode. If a bad value is
454 // passed it will just act as if the default normal mode of 0 was set.
Laurence Lundbladee6bcef12020-04-01 10:56:27 -0700455 me->uDecodeMode = (uint8_t)nDecodeMode;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700456 DecodeNesting_Init(&(me->nesting));
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700457 for(int i = 0; i < QCBOR_NUM_MAPPED_TAGS; i++) {
458 me->auMappedTags[i] = 0xffff;
459 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700460}
461
462
463/*
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700464 Public function, see header file
465 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800466void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
467 QCBORStringAllocate pfAllocateFunction,
468 void *pAllocateContext,
469 bool bAllStrings)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700470{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800471 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
472 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
473 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700474}
475
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800476
477/*
478 Public function, see header file
479 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800480void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *me,
481 const QCBORTagListIn *pTagList)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700482{
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700483 // This does nothing now. It is retained for backwards compatibility
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700484}
485
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700486
487/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800488 This decodes the fundamental part of a CBOR data item, the type and
489 number
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800490
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700491 This is the Counterpart to InsertEncodedTypeAndNumber().
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800492
Laurence Lundbladeee851742020-01-08 08:37:05 -0800493 This does the network->host byte order conversion. The conversion
494 here also results in the conversion for floats in addition to that
495 for lengths, tags and integer values.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800496
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700497 This returns:
498 pnMajorType -- the major type for the item
Laurence Lundbladeee851742020-01-08 08:37:05 -0800499
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800500 puArgument -- the "number" which is used a the value for integers,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800501 tags and floats and length for strings and arrays
502
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800503 pnAdditionalInfo -- Pass this along to know what kind of float or
Laurence Lundbladeee851742020-01-08 08:37:05 -0800504 if length is indefinite
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800505
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800506 The int type is preferred to uint8_t for some variables as this
507 avoids integer promotions, can reduce code size and makes
508 static analyzers happier.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700509 */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800510inline static QCBORError DecodeTypeAndNumber(UsefulInputBuf *pUInBuf,
511 int *pnMajorType,
512 uint64_t *puArgument,
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800513 int *pnAdditionalInfo)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700514{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700515 QCBORError nReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800516
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700517 // Get the initial byte that every CBOR data item has
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800518 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800519
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700520 // Break down the initial byte
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800521 const int nTmpMajorType = nInitialByte >> 5;
522 const int nAdditionalInfo = nInitialByte & 0x1f;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800523
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800524 // Where the number or argument accumulates
525 uint64_t uArgument;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800526
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800527 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700528 // Need to get 1,2,4 or 8 additional argument bytes. Map
529 // LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800530 static const uint8_t aIterate[] = {1,2,4,8};
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800531
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800532 // Loop getting all the bytes in the argument
533 uArgument = 0;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800534 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800535 // This shift and add gives the endian conversion
536 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
537 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800538 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800539 // The reserved and thus-far unused additional info values
540 nReturn = QCBOR_ERR_UNSUPPORTED;
541 goto Done;
542 } else {
543 // Less than 24, additional info is argument or 31, an indefinite length
544 // No more bytes to get
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800545 uArgument = (uint64_t)nAdditionalInfo;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700546 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800547
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700548 if(UsefulInputBuf_GetError(pUInBuf)) {
549 nReturn = QCBOR_ERR_HIT_END;
550 goto Done;
551 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800552
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700553 // All successful if we got here.
554 nReturn = QCBOR_SUCCESS;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800555 *pnMajorType = nTmpMajorType;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800556 *puArgument = uArgument;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800557 *pnAdditionalInfo = nAdditionalInfo;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800558
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700559Done:
560 return nReturn;
561}
562
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800563
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700564/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800565 CBOR doesn't explicitly specify two's compliment for integers but all
566 CPUs use it these days and the test vectors in the RFC are so. All
567 integers in the CBOR structure are positive and the major type
568 indicates positive or negative. CBOR can express positive integers
569 up to 2^x - 1 where x is the number of bits and negative integers
570 down to 2^x. Note that negative numbers can be one more away from
571 zero than positive. Stdint, as far as I can tell, uses two's
572 compliment to represent negative integers.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800573
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700574 See http://www.unix.org/whitepapers/64bit.html for reasons int isn't
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800575 used carefully here, and in particular why it isn't used in the interface.
576 Also see
577 https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers
578
579 Int is used for values that need less than 16-bits and would be subject
580 to integer promotion and complaining by static analyzers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700581 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800582inline static QCBORError
583DecodeInteger(int nMajorType, uint64_t uNumber, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700584{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700585 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800586
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700587 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
588 if (uNumber <= INT64_MAX) {
589 pDecodedItem->val.int64 = (int64_t)uNumber;
590 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800591
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700592 } else {
593 pDecodedItem->val.uint64 = uNumber;
594 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800595
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700596 }
597 } else {
598 if(uNumber <= INT64_MAX) {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800599 // CBOR's representation of negative numbers lines up with the
600 // two-compliment representation. A negative integer has one
601 // more in range than a positive integer. INT64_MIN is
602 // equal to (-INT64_MAX) - 1.
603 pDecodedItem->val.int64 = (-(int64_t)uNumber) - 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700604 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800605
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700606 } else {
607 // C can't represent a negative integer in this range
Laurence Lundblade21d1d812019-09-28 22:47:49 -1000608 // so it is an error.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700609 nReturn = QCBOR_ERR_INT_OVERFLOW;
610 }
611 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800612
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700613 return nReturn;
614}
615
616// Make sure #define value line up as DecodeSimple counts on this.
617#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
618#error QCBOR_TYPE_FALSE macro value wrong
619#endif
620
621#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
622#error QCBOR_TYPE_TRUE macro value wrong
623#endif
624
625#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
626#error QCBOR_TYPE_NULL macro value wrong
627#endif
628
629#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
630#error QCBOR_TYPE_UNDEF macro value wrong
631#endif
632
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700633#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
634#error QCBOR_TYPE_BREAK macro value wrong
635#endif
636
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700637#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
638#error QCBOR_TYPE_DOUBLE macro value wrong
639#endif
640
641#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
642#error QCBOR_TYPE_FLOAT macro value wrong
643#endif
644
645/*
646 Decode true, false, floats, break...
647 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800648inline static QCBORError
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800649DecodeSimple(int nAdditionalInfo, uint64_t uNumber, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700650{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700651 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800652
Laurence Lundbladeee851742020-01-08 08:37:05 -0800653 // uAdditionalInfo is 5 bits from the initial byte compile time checks
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800654 // above make sure uAdditionalInfo values line up with uDataType values.
655 // DecodeTypeAndNumber never returns a major type > 1f so cast is safe
656 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800657
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800658 switch(nAdditionalInfo) {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800659 // No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they are
660 // caught before this is called.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800661
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700662 case HALF_PREC_FLOAT:
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700663 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uNumber);
664 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700665 break;
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700666 case SINGLE_PREC_FLOAT:
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700667 pDecodedItem->val.dfnum = (double)UsefulBufUtil_CopyUint32ToFloat((uint32_t)uNumber);
668 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700669 break;
670 case DOUBLE_PREC_FLOAT:
671 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uNumber);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700672 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700673 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800674
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700675 case CBOR_SIMPLEV_FALSE: // 20
676 case CBOR_SIMPLEV_TRUE: // 21
677 case CBOR_SIMPLEV_NULL: // 22
678 case CBOR_SIMPLEV_UNDEF: // 23
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700679 case CBOR_SIMPLE_BREAK: // 31
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700680 break; // nothing to do
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800681
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700682 case CBOR_SIMPLEV_ONEBYTE: // 24
683 if(uNumber <= CBOR_SIMPLE_BREAK) {
684 // This takes out f8 00 ... f8 1f which should be encoded as e0 … f7
Laurence Lundblade077475f2019-04-26 09:06:33 -0700685 nReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700686 goto Done;
687 }
Laurence Lundblade5e390822019-01-06 12:35:01 -0800688 /* FALLTHROUGH */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700689 // fall through intentionally
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800690
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700691 default: // 0-19
692 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
Laurence Lundbladeee851742020-01-08 08:37:05 -0800693 /*
694 DecodeTypeAndNumber will make uNumber equal to
695 uAdditionalInfo when uAdditionalInfo is < 24 This cast is
696 safe because the 2, 4 and 8 byte lengths of uNumber are in
697 the double/float cases above
698 */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700699 pDecodedItem->val.uSimple = (uint8_t)uNumber;
700 break;
701 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800702
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700703Done:
704 return nReturn;
705}
706
707
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700708/*
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530709 Decode text and byte strings. Call the string allocator if asked to.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700710 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800711inline static QCBORError DecodeBytes(const QCORInternalAllocator *pAllocator,
712 int nMajorType,
713 uint64_t uStrLen,
714 UsefulInputBuf *pUInBuf,
715 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700716{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700717 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800718
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800719 // CBOR lengths can be 64 bits, but size_t is not 64 bits on all CPUs.
720 // This check makes the casts to size_t below safe.
721
722 // 4 bytes less than the largest sizeof() so this can be tested by
723 // putting a SIZE_MAX length in the CBOR test input (no one will
724 // care the limit on strings is 4 bytes shorter).
725 if(uStrLen > SIZE_MAX-4) {
726 nReturn = QCBOR_ERR_STRING_TOO_LONG;
727 goto Done;
728 }
729
730 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, (size_t)uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530731 if(UsefulBuf_IsNULLC(Bytes)) {
732 // Failed to get the bytes for this string item
733 nReturn = QCBOR_ERR_HIT_END;
734 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700735 }
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530736
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800737 if(pAllocator) {
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530738 // We are asked to use string allocator to make a copy
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800739 UsefulBuf NewMem = StringAllocator_Allocate(pAllocator, (size_t)uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530740 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade30816f22018-11-10 13:40:22 +0700741 nReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530742 goto Done;
743 }
744 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800745 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530746 } else {
747 // Normal case with no string allocator
748 pDecodedItem->val.string = Bytes;
749 }
Laurence Lundbladeee851742020-01-08 08:37:05 -0800750 const bool bIsBstr = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING);
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800751 // Cast because ternary operator causes promotion to integer
752 pDecodedItem->uDataType = (uint8_t)(bIsBstr ? QCBOR_TYPE_BYTE_STRING
753 : QCBOR_TYPE_TEXT_STRING);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800754
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530755Done:
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700756 return nReturn;
757}
758
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700759
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800760
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700761
762
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700763
764
Laurence Lundbladeee851742020-01-08 08:37:05 -0800765// Make sure the constants align as this is assumed by
766// the GetAnItem() implementation
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700767#if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
768#error QCBOR_TYPE_ARRAY value not lined up with major type
769#endif
770#if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
771#error QCBOR_TYPE_MAP value not lined up with major type
772#endif
773
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700774/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800775 This gets a single data item and decodes it including preceding
776 optional tagging. This does not deal with arrays and maps and nesting
777 except to decode the data item introducing them. Arrays and maps are
778 handled at the next level up in GetNext().
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800779
Laurence Lundbladeee851742020-01-08 08:37:05 -0800780 Errors detected here include: an array that is too long to decode,
781 hit end of buffer unexpectedly, a few forms of invalid encoded CBOR
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700782 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800783static QCBORError GetNext_Item(UsefulInputBuf *pUInBuf,
784 QCBORItem *pDecodedItem,
785 const QCORInternalAllocator *pAllocator)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700786{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700787 QCBORError nReturn;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800788
Laurence Lundbladeee851742020-01-08 08:37:05 -0800789 /*
790 Get the major type and the number. Number could be length of more
791 bytes or the value depending on the major type nAdditionalInfo is
792 an encoding of the length of the uNumber and is needed to decode
793 floats and doubles
794 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800795 int nMajorType;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700796 uint64_t uNumber;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800797 int nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800798
Laurence Lundblade4b09f632019-10-09 14:34:59 -0700799 memset(pDecodedItem, 0, sizeof(QCBORItem));
800
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800801 nReturn = DecodeTypeAndNumber(pUInBuf, &nMajorType, &uNumber, &nAdditionalInfo);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800802
Laurence Lundbladeee851742020-01-08 08:37:05 -0800803 // Error out here if we got into trouble on the type and number. The
804 // code after this will not work if the type and number is not good.
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700805 if(nReturn) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700806 goto Done;
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700807 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800808
Laurence Lundbladeee851742020-01-08 08:37:05 -0800809 // At this point the major type and the value are valid. We've got
810 // the type and the number that starts every CBOR data item.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800811 switch (nMajorType) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700812 case CBOR_MAJOR_TYPE_POSITIVE_INT: // Major type 0
813 case CBOR_MAJOR_TYPE_NEGATIVE_INT: // Major type 1
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800814 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700815 nReturn = QCBOR_ERR_BAD_INT;
816 } else {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800817 nReturn = DecodeInteger(nMajorType, uNumber, pDecodedItem);
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700818 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700819 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800820
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700821 case CBOR_MAJOR_TYPE_BYTE_STRING: // Major type 2
822 case CBOR_MAJOR_TYPE_TEXT_STRING: // Major type 3
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800823 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
824 const bool bIsBstr = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING);
825 pDecodedItem->uDataType = (uint8_t)(bIsBstr ? QCBOR_TYPE_BYTE_STRING
826 : QCBOR_TYPE_TEXT_STRING);
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530827 pDecodedItem->val.string = (UsefulBufC){NULL, SIZE_MAX};
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700828 } else {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800829 nReturn = DecodeBytes(pAllocator, nMajorType, uNumber, pUInBuf, pDecodedItem);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700830 }
831 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800832
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700833 case CBOR_MAJOR_TYPE_ARRAY: // Major type 4
834 case CBOR_MAJOR_TYPE_MAP: // Major type 5
835 // Record the number of items in the array or map
836 if(uNumber > QCBOR_MAX_ITEMS_IN_ARRAY) {
837 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
838 goto Done;
839 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800840 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530841 pDecodedItem->val.uCount = UINT16_MAX; // Indicate indefinite length
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700842 } else {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800843 // type conversion OK because of check above
844 pDecodedItem->val.uCount = (uint16_t)uNumber;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700845 }
Laurence Lundbladeee851742020-01-08 08:37:05 -0800846 // C preproc #if above makes sure constants for major types align
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800847 // DecodeTypeAndNumber never returns a major type > 7 so cast is safe
848 pDecodedItem->uDataType = (uint8_t)nMajorType;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700849 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800850
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700851 case CBOR_MAJOR_TYPE_OPTIONAL: // Major type 6, optional prepended tags
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800852 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700853 nReturn = QCBOR_ERR_BAD_INT;
854 } else {
855 pDecodedItem->val.uTagV = uNumber;
856 pDecodedItem->uDataType = QCBOR_TYPE_OPTTAG;
857 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700858 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800859
Laurence Lundbladeee851742020-01-08 08:37:05 -0800860 case CBOR_MAJOR_TYPE_SIMPLE:
861 // Major type 7, float, double, true, false, null...
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800862 nReturn = DecodeSimple(nAdditionalInfo, uNumber, pDecodedItem);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700863 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800864
Laurence Lundbladeee851742020-01-08 08:37:05 -0800865 default:
866 // Never happens because DecodeTypeAndNumber() should never return > 7
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700867 nReturn = QCBOR_ERR_UNSUPPORTED;
868 break;
869 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800870
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700871Done:
872 return nReturn;
873}
874
875
876
877/*
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800878 This layer deals with indefinite length strings. It pulls all the
Laurence Lundbladeee851742020-01-08 08:37:05 -0800879 individual chunk items together into one QCBORItem using the string
880 allocator.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800881
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530882 Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700883 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800884static inline QCBORError
885GetNext_FullItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700886{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700887 // Stack usage; int/ptr 2 UsefulBuf 2 QCBORItem -- 96
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700888
889 // Get pointer to string allocator. First use is to pass it to
890 // GetNext_Item() when option is set to allocate for *every* string.
891 // Second use here is to allocate space to coallese indefinite
892 // length string items into one.
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800893 const QCORInternalAllocator *pAllocator = me->StringAllocator.pfAllocator ?
894 &(me->StringAllocator) :
895 NULL;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800896
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700897 QCBORError nReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800898 nReturn = GetNext_Item(&(me->InBuf),
899 pDecodedItem,
900 me->bStringAllocateAll ? pAllocator: NULL);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700901 if(nReturn) {
902 goto Done;
903 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800904
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700905 // To reduce code size by removing support for indefinite length strings, the
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530906 // code in this function from here down can be eliminated. Run tests, except
907 // indefinite length string tests, to be sure all is OK if this is removed.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800908
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800909 // Only do indefinite length processing on strings
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700910 const uint8_t uStringType = pDecodedItem->uDataType;
911 if(uStringType!= QCBOR_TYPE_BYTE_STRING && uStringType != QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700912 goto Done; // no need to do any work here on non-string types
913 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800914
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800915 // Is this a string with an indefinite length?
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530916 if(pDecodedItem->val.string.len != SIZE_MAX) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800917 goto Done; // length is not indefinite, so no work to do here
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700918 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800919
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530920 // Can't do indefinite length strings without a string allocator
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800921 if(pAllocator == NULL) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700922 nReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
923 goto Done;
924 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800925
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700926 // Loop getting chunk of indefinite string
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700927 UsefulBufC FullString = NULLUsefulBufC;
928
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700929 for(;;) {
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700930 // Get item for next chunk
931 QCBORItem StringChunkItem;
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700932 // NULL string allocator passed here. Do not need to allocate
933 // chunks even if bStringAllocateAll is set.
Laurence Lundbladefae26bf2019-02-18 11:15:43 -0800934 nReturn = GetNext_Item(&(me->InBuf), &StringChunkItem, NULL);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700935 if(nReturn) {
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700936 break; // Error getting the next chunk
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700937 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800938
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530939 // See if it is a marker at end of indefinite length string
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700940 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800941 // String is complete
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700942 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +0530943 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700944 break;
945 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800946
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700947 // Match data type of chunk to type at beginning.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530948 // Also catches error of other non-string types that don't belong.
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700949 // Also catches indefinite length strings inside indefinite length strings
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800950 if(StringChunkItem.uDataType != uStringType ||
951 StringChunkItem.val.string.len == SIZE_MAX) {
Laurence Lundblade30816f22018-11-10 13:40:22 +0700952 nReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700953 break;
954 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800955
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530956 // Alloc new buffer or expand previously allocated buffer so it can fit
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800957 // The first time throurgh FullString.ptr is NULL and this is
958 // equivalent to StringAllocator_Allocate()
959 UsefulBuf NewMem = StringAllocator_Reallocate(pAllocator,
960 UNCONST_POINTER(FullString.ptr),
961 FullString.len + StringChunkItem.val.string.len);
962
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700963 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530964 // Allocation of memory for the string failed
Laurence Lundblade30816f22018-11-10 13:40:22 +0700965 nReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700966 break;
967 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800968
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700969 // Copy new string chunk at the end of string so far.
970 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700971 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800972
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800973 if(nReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
974 // Getting the item failed, clean up the allocated memory
975 StringAllocator_Free(pAllocator, UNCONST_POINTER(FullString.ptr));
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700976 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800977
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700978Done:
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700979 return nReturn;
980}
981
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700982
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700983uint64_t ConvertTag(QCBORDecodeContext *me, uint16_t uTagVal) {
984 if(uTagVal < 0xfff0) {
985 return uTagVal;
986 } else {
987 // TODO constant and error check
988 int x = uTagVal - 0xfff0;
989 return me->auMappedTags[x];
990 }
991}
992
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700993/*
Laurence Lundblade59289e52019-12-30 13:44:37 -0800994 Gets all optional tag data items preceding a data item that is not an
995 optional tag and records them as bits in the tag map.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700996 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800997static QCBORError
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700998GetNext_TaggedItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700999{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001000 // Stack usage: int/ptr: 3 -- 24
Laurence Lundblade30816f22018-11-10 13:40:22 +07001001 QCBORError nReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001002
1003 uint16_t auTags[QCBOR_MAX_TAGS_PER_ITEM] = {0xffff, 0xffff, 0xffff, 0xffff};
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001004
Laurence Lundblade59289e52019-12-30 13:44:37 -08001005 // Loop fetching items until the item fetched is not a tag
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001006 for(;;) {
1007 nReturn = GetNext_FullItem(me, pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001008 if(nReturn) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001009 goto Done; // Error out of the loop
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001010 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001011
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001012 if(pDecodedItem->uDataType != QCBOR_TYPE_OPTTAG) {
1013 // Successful exit from loop; maybe got some tags, maybe not
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001014 memcpy(pDecodedItem->uTags, auTags, sizeof(auTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001015 break;
1016 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001017
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001018 // Is there room for the tag in the tags list?
1019 size_t uTagIndex;
1020 for(uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) {
1021 if(auTags[uTagIndex] == 0xffff) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001022 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001023 }
1024 }
1025 if(uTagIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
1026 return 99; // TODO error code
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001027 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001028
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001029 // Is the tag > 16 bits?
1030 if(pDecodedItem->val.uTagV > 0xffff) {
1031 size_t uTagMapIndex;
1032 // Is there room in the tag map?
1033 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
1034 if(me->auMappedTags[uTagMapIndex] == 0xffff) {
1035 break;
1036 }
1037 if(me->auMappedTags[uTagMapIndex] == pDecodedItem->val.uTagV) {
1038 break;
1039 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001040 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001041 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
1042 // No room for the tag
1043 return 97; // TODO error code
1044 }
1045
1046 // Cover the case where tag is new and were it is already in the map
1047 me->auMappedTags[uTagMapIndex] = pDecodedItem->val.uTagV;
1048 auTags[uTagIndex] = (uint16_t)(uTagMapIndex + 0xfff0); // TODO proper constant and cast
1049
1050 } else {
1051 auTags[uTagIndex] = (uint16_t)pDecodedItem->val.uTagV;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001052 }
1053 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001054
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001055Done:
1056 return nReturn;
1057}
1058
1059
1060/*
Laurence Lundbladeee851742020-01-08 08:37:05 -08001061 This layer takes care of map entries. It combines the label and data
1062 items into one QCBORItem.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001063 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001064static inline QCBORError
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001065GetNext_MapEntry(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001066{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001067 // Stack use: int/ptr 1, QCBORItem -- 56
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001068 QCBORError nReturn = GetNext_TaggedItem(me, pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001069 if(nReturn)
1070 goto Done;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001071
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001072 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001073 // Break can't be a map entry
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001074 goto Done;
1075 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001076
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001077 if(me->uDecodeMode != QCBOR_DECODE_MODE_MAP_AS_ARRAY) {
1078 // In a map and caller wants maps decoded, not treated as arrays
1079
1080 if(DecodeNesting_TypeIsMap(&(me->nesting))) {
1081 // If in a map and the right decoding mode, get the label
1082
Laurence Lundbladeee851742020-01-08 08:37:05 -08001083 // Save label in pDecodedItem and get the next which will
1084 // be the real data
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001085 QCBORItem LabelItem = *pDecodedItem;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001086 nReturn = GetNext_TaggedItem(me, pDecodedItem);
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001087 if(nReturn)
1088 goto Done;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001089
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301090 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001091
1092 if(LabelItem.uDataType == QCBOR_TYPE_TEXT_STRING) {
1093 // strings are always good labels
1094 pDecodedItem->label.string = LabelItem.val.string;
1095 pDecodedItem->uLabelType = QCBOR_TYPE_TEXT_STRING;
1096 } else if (QCBOR_DECODE_MODE_MAP_STRINGS_ONLY == me->uDecodeMode) {
Laurence Lundbladeee851742020-01-08 08:37:05 -08001097 // It's not a string and we only want strings
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001098 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
1099 goto Done;
1100 } else if(LabelItem.uDataType == QCBOR_TYPE_INT64) {
1101 pDecodedItem->label.int64 = LabelItem.val.int64;
1102 pDecodedItem->uLabelType = QCBOR_TYPE_INT64;
1103 } else if(LabelItem.uDataType == QCBOR_TYPE_UINT64) {
1104 pDecodedItem->label.uint64 = LabelItem.val.uint64;
1105 pDecodedItem->uLabelType = QCBOR_TYPE_UINT64;
1106 } else if(LabelItem.uDataType == QCBOR_TYPE_BYTE_STRING) {
1107 pDecodedItem->label.string = LabelItem.val.string;
1108 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
1109 pDecodedItem->uLabelType = QCBOR_TYPE_BYTE_STRING;
1110 } else {
1111 // label is not an int or a string. It is an arrray
1112 // or a float or such and this implementation doesn't handle that.
1113 // Also, tags on labels are ignored.
1114 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
1115 goto Done;
1116 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001117 }
1118 } else {
1119 if(pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001120 if(pDecodedItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
1121 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
1122 goto Done;
1123 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001124 // Decoding a map as an array
1125 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001126 // Cast is safe because of check against QCBOR_MAX_ITEMS_IN_ARRAY/2
1127 // Cast is needed because of integer promotion
1128 pDecodedItem->val.uCount = (uint16_t)(pDecodedItem->val.uCount * 2);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001129 }
1130 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001131
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001132Done:
1133 return nReturn;
1134}
1135
1136
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001137static QCBORError
1138NextIsBreak(UsefulInputBuf *pUIB, bool *pbNextIsBreak)
1139{
1140 *pbNextIsBreak = false;
1141 if(UsefulInputBuf_BytesUnconsumed(pUIB) != 0) {
1142 // TODO: use the Peek method?
1143 QCBORItem Peek;
1144 size_t uPeek = UsefulInputBuf_Tell(pUIB);
1145 QCBORError uReturn = GetNext_Item(pUIB, &Peek, NULL);
1146 if(uReturn != QCBOR_SUCCESS) {
1147 return uReturn;
1148 }
1149 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
1150 // It is not a break, rewind so it can be processed normally.
1151 UsefulInputBuf_Seek(pUIB, uPeek);
1152 } else {
1153 *pbNextIsBreak = true;
1154 }
1155 }
1156
1157 return QCBOR_SUCCESS;
1158}
1159
1160
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001161/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001162 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001163 TODO: correct this comment
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001164 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001165static QCBORError
1166QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001167{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001168 QCBORError uReturn;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001169 /* === First figure out if at the end of traversal === */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001170
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001171 /* Case 1. Out of bytes to consume.
1172
1173 This is either the end of the top-level CBOR that was give
1174 to QCBORDecode_Init() or the end of a tag 24 bstr wrapped CBOR.
1175 It is detected by all bytes being consumed from the UsefulInputBuf.
1176
1177 To go back out of the tag 24 bstr wrapped item, the caller must
1178 explicitly call Exit() which will reset the UsefulInputBuf
1179 to the next highest bstr wrapped or the top level.
1180
1181 This is always the end condition that QCBORDecode_Finish()
1182 considers complete.
1183
1184 TODO: can the DecodeNesting_IsAtTop be removed? QCBORDecode_Finish()
1185 will perform this check.
1186
1187 */
Laurence Lundblade937ea812020-05-08 11:38:23 -07001188 /* For a pre-order traversal a non-error end occurs when there
1189 are no more bytes to consume and the nesting level is at the top.
1190 If it's not at the top, then the CBOR is not well formed. This error
1191 is caught elsewhere.
1192
1193 This handles the end of CBOR sequences as well as non-sequences. */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001194 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf)) == 0 && DecodeNesting_IsAtTop(&(me->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001195 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001196 goto Done;
1197 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07001198
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001199
1200 /* Case 2. End of map or array in bounded mode
1201
1202 The caller is attempting traveral of a bounded map or array and
1203 has got to the end of it.
1204
1205 The caller must explicitly exit the bounded mode map or array
1206 to get past this condition.
1207
1208 To complete a decode of the full input CBOR, the caller must
1209 exit all maps and arrays in bounded mode and this is never
1210 the successful end of decoding.
1211
1212 */
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001213 /* It is also an end of the input when in map mode and the cursor
Laurence Lundblade937ea812020-05-08 11:38:23 -07001214 is at the end of the map */
1215
1216
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001217 // This is to handle bounded mode
Laurence Lundblade937ea812020-05-08 11:38:23 -07001218 if(DecodeNesting_AtEnd(&(me->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001219 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07001220 goto Done;
1221 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001222
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001223 /* === Not at the end; get another item === */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001224 uReturn = GetNext_MapEntry(me, pDecodedItem);
1225 if(uReturn) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001226 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001227 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301228
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001229 // Breaks ending arrays/maps are always processed at the end of this function.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301230 // They should never show up here.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301231 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001232 uReturn = QCBOR_ERR_BAD_BREAK;
Laurence Lundblade6de37062018-10-15 12:22:42 +05301233 goto Done;
Laurence Lundblade5b8c5852018-10-14 21:11:42 +05301234 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001235
Laurence Lundblade6de37062018-10-15 12:22:42 +05301236 // Record the nesting level for this data item before processing any of
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301237 // decrementing and descending.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301238 pDecodedItem->uNestingLevel = DecodeNesting_GetLevel(&(me->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001239
Laurence Lundblade6de37062018-10-15 12:22:42 +05301240 // Process the item just received for descent or decrement, and
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001241 // ascend if decrements are enough to close out a definite length array/map
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001242 if(IsMapOrArray(pDecodedItem->uDataType) && pDecodedItem->val.uCount != 0) {
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001243 // If the new item is array or map, the nesting level descends
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001244 uReturn = DecodeNesting_Descend(&(me->nesting), pDecodedItem->uDataType, pDecodedItem->val.uCount, 0L);
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001245 // Maps and arrays do count in as items in the map/array that encloses
1246 // them so a decrement needs to be done for them too, but that is done
1247 // only when all the items in them have been processed, not when they
Laurence Lundblade9916b1b2019-09-07 22:33:25 -07001248 // are opened with the exception of an empty map or array.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001249 if(uReturn != QCBOR_SUCCESS) {
1250 goto Done;
1251 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001252 }
1253
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001254 if(!IsMapOrArray(pDecodedItem->uDataType) ||
1255 pDecodedItem->val.uCount == 0 || pDecodedItem->val.uCount == UINT16_MAX) {
1256 /* The following cases are handled here:
1257 - A non-aggregate like an integer or string
1258 - An empty definite length map or array
1259 - An indefinite length map or array that might be empty or might not.
1260 */
1261
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001262
1263
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001264 /* === Figure out if item got closed out maps or arrays === */
1265
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001266 /*
1267 This needs to decrement, check for end and ascend
1268 the tree until an an ascend is not possible or the bounded
1269 limit is reached or the end of the encoded CBOR input
1270 is reached. For
1271 definite length maps and arrays the end is by count. For
1272 indefinite it is by a break.
1273
1274 Also state needs to be set that can tell the code at the
1275 beginning of this function that the end was reached.
1276
1277 This is complicated...
1278
1279
1280 This will handle an indefinite length array
1281 inside a definte length array inside an indefinite
1282 length array...
1283
1284 */
1285
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001286 // Decrement the count of items in the enclosing map/array
1287 // If the count in the enclosing map/array goes to zero, that
Laurence Lundblade6de37062018-10-15 12:22:42 +05301288 // triggers a decrement in the map/array above that and
1289 // an ascend in nesting level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001290 /* If the just consumed item is at the end of a map or
1291 array ascend in the nesting tracking. That may
1292 in turn may be the end of the above nesting level
1293 and so on up to the end of the whole encoded CBOR.
1294
1295 Each level could be a definite or indefinte length
1296 map or array. These are handled very differently.
1297
1298 */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001299 while(1) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001300
1301 /* three cases:
1302 1) at top
1303 2) not at top and in indefinite
1304 3) not at top and not in indefinite */
1305
1306 if(!DecodeNesting_IsAtTop(&(me->nesting)) && !DecodeNesting_IsIndefiniteLength(&(me->nesting))) {
1307 /* The simple cases of a non-aggregate type or an empty
1308 definite-length array. Decrement the counter and
1309 if nothing was closed out, all is done.
1310 case 3
1311 */
1312 if(!DecodeNesting_Decrement(&(me->nesting))) {
1313 // Done leveling up
1314 break;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001315 }
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001316
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001317 } else {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001318 /* cases 1 and 2 */
1319 /* either at the top or in an indefinite length map / array */
1320 /* The cases of an
1321 1) indefinite length level
1322 2) a sequence (at the top and not in error)
1323 3) the error case of extra breaks after reaching the top level
1324 For all of these we have to see if next is a break.
1325 */
1326 bool bIsBreak = false;
1327 uReturn = NextIsBreak(&(me->InBuf), &bIsBreak);
1328 if(uReturn != QCBOR_SUCCESS) {
1329 goto Done;
1330 }
1331
1332 if(bIsBreak) {
1333 if(DecodeNesting_IsAtTop(&(me->nesting))) {
1334 uReturn = QCBOR_ERR_BAD_BREAK;
1335 goto Done;
1336 } else {
1337 // A break ending an indefinite length array
1338 // continue with loop and ascend
1339 }
1340
1341 } else {
1342 // Just an item in either an indefinte length amap/arry or in sequence at top level.
1343 break;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001344 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05301345 }
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001346
1347 if(DecodeNesting_InBoundedMode(&(me->nesting))) {
1348 /* Can't ascend because we are in bounded mode where ascent has to be explicit */
1349 /* Set the count to zero for indefinite length arrays to indicate cursor is at end of bounded map / array */
1350 me->nesting.pCurrent->uCount = 0;
1351 break;
1352 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001353
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001354 DecodeNesting_Ascend(&(me->nesting));
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001355 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05301356 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001357
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001358
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001359
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001360 /* === Tell the caller the nest level of the next item === */
1361
Laurence Lundblade6de37062018-10-15 12:22:42 +05301362 // Tell the caller what level is next. This tells them what maps/arrays
1363 // were closed out and makes it possible for them to reconstruct
1364 // the tree with just the information returned by GetNext
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07001365 // TODO: pull this into DecodeNesting_GetLevel
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001366 if(DecodeNesting_InBoundedMode(&(me->nesting)) && me->nesting.pCurrent->uCount == 0) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001367 // At end of a map / array in map mode, so next nest is 0 to
1368 // indicate this end.
1369 pDecodedItem->uNextNestLevel = 0;
1370 } else {
1371 pDecodedItem->uNextNestLevel = DecodeNesting_GetLevel(&(me->nesting));
1372 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001373
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001374Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001375 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundbladee9482dd2019-10-11 12:58:46 -07001376 // Make sure uDataType and uLabelType are QCBOR_TYPE_NONE
1377 memset(pDecodedItem, 0, sizeof(QCBORItem));
1378 }
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001379 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001380}
1381
1382
Laurence Lundblade59289e52019-12-30 13:44:37 -08001383/*
1384 Mostly just assign the right data type for the date string.
1385 */
1386inline static QCBORError DecodeDateString(QCBORItem *pDecodedItem)
1387{
1388 // Stack Use: UsefulBuf 1 16
1389 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1390 return QCBOR_ERR_BAD_OPT_TAG;
1391 }
1392
1393 const UsefulBufC Temp = pDecodedItem->val.string;
1394 pDecodedItem->val.dateString = Temp;
1395 pDecodedItem->uDataType = QCBOR_TYPE_DATE_STRING;
1396 return QCBOR_SUCCESS;
1397}
1398
1399
1400/*
1401 Mostly just assign the right data type for the bignum.
1402 */
1403inline static QCBORError DecodeBigNum(QCBORItem *pDecodedItem)
1404{
1405 // Stack Use: UsefulBuf 1 -- 16
1406 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1407 return QCBOR_ERR_BAD_OPT_TAG;
1408 }
1409 const UsefulBufC Temp = pDecodedItem->val.string;
1410 pDecodedItem->val.bigNum = Temp;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001411 const bool bIsPosBigNum = (bool)(pDecodedItem->uTags[0] == CBOR_TAG_POS_BIGNUM);
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001412 pDecodedItem->uDataType = (uint8_t)(bIsPosBigNum ? QCBOR_TYPE_POSBIGNUM
1413 : QCBOR_TYPE_NEGBIGNUM);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001414 return QCBOR_SUCCESS;
1415}
1416
1417
1418/*
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001419 */
1420inline static QCBORError DecodeUUID(QCBORItem *pDecodedItem)
1421{
1422 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1423 return QCBOR_ERR_BAD_OPT_TAG;
1424 }
1425 pDecodedItem->uDataType = QCBOR_TYPE_UUID;
1426 return QCBOR_SUCCESS;
1427}
1428
1429
1430/*
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001431 */
1432inline static QCBORError DecodeURI(QCBORItem *pDecodedItem)
1433{
1434 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1435 return QCBOR_ERR_BAD_OPT_TAG;
1436 }
1437 pDecodedItem->uDataType = QCBOR_TYPE_URI;
1438 return QCBOR_SUCCESS;
1439}
1440
1441
1442inline static QCBORError DecodeRegex(QCBORItem *pDecodedItem)
1443{
1444 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1445 return QCBOR_ERR_BAD_OPT_TAG;
1446 }
1447 pDecodedItem->uDataType = QCBOR_TYPE_REGEX;
1448 return QCBOR_SUCCESS;
1449}
1450
1451
1452inline static QCBORError DecodeB64URL(QCBORItem *pDecodedItem)
1453{
1454 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1455 return QCBOR_ERR_BAD_OPT_TAG;
1456 }
1457 pDecodedItem->uDataType = QCBOR_TYPE_BASE64URL;
1458 return QCBOR_SUCCESS;
1459}
1460
1461
1462inline static QCBORError DecodeB64(QCBORItem *pDecodedItem)
1463{
1464 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1465 return QCBOR_ERR_BAD_OPT_TAG;
1466 }
1467 pDecodedItem->uDataType = QCBOR_TYPE_BASE64;
1468 return QCBOR_SUCCESS;
1469}
1470
1471
1472inline static QCBORError DecodeMIME(QCBORItem *pDecodedItem)
1473{
1474 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING &&
1475 pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1476 return QCBOR_ERR_BAD_OPT_TAG;
1477 }
1478 pDecodedItem->uDataType = QCBOR_TYPE_MIME;
1479 return QCBOR_SUCCESS;
1480}
1481
1482/*
Laurence Lundbladeee851742020-01-08 08:37:05 -08001483 The epoch formatted date. Turns lots of different forms of encoding
1484 date into uniform one
Laurence Lundblade59289e52019-12-30 13:44:37 -08001485 */
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001486static QCBORError DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08001487{
1488 // Stack usage: 1
1489 QCBORError nReturn = QCBOR_SUCCESS;
1490
1491 pDecodedItem->val.epochDate.fSecondsFraction = 0;
1492
1493 switch (pDecodedItem->uDataType) {
1494
1495 case QCBOR_TYPE_INT64:
1496 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
1497 break;
1498
1499 case QCBOR_TYPE_UINT64:
1500 if(pDecodedItem->val.uint64 > INT64_MAX) {
1501 nReturn = QCBOR_ERR_DATE_OVERFLOW;
1502 goto Done;
1503 }
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001504 pDecodedItem->val.epochDate.nSeconds = (int64_t)pDecodedItem->val.uint64;
Laurence Lundblade59289e52019-12-30 13:44:37 -08001505 break;
1506
1507 case QCBOR_TYPE_DOUBLE:
1508 {
1509 // This comparison needs to be done as a float before
1510 // conversion to an int64_t to be able to detect doubles
1511 // that are too large to fit into an int64_t. A double
1512 // has 52 bits of preceision. An int64_t has 63. Casting
1513 // INT64_MAX to a double actually causes a round up which
1514 // is bad and wrong for the comparison because it will
1515 // allow conversion of doubles that can't fit into a
1516 // uint64_t. To remedy this INT64_MAX - 0x7ff is used as
1517 // the cutoff point as if that rounds up in conversion to
1518 // double it will still be less than INT64_MAX. 0x7ff is
1519 // picked because it has 11 bits set.
1520 //
1521 // INT64_MAX seconds is on the order of 10 billion years,
1522 // and the earth is less than 5 billion years old, so for
1523 // most uses this conversion error won't occur even though
1524 // doubles can go much larger.
1525 //
1526 // Without the 0x7ff there is a ~30 minute range of time
1527 // values 10 billion years in the past and in the future
1528 // where this this code would go wrong.
1529 const double d = pDecodedItem->val.dfnum;
1530 if(d > (double)(INT64_MAX - 0x7ff)) {
1531 nReturn = QCBOR_ERR_DATE_OVERFLOW;
1532 goto Done;
1533 }
1534 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
1535 pDecodedItem->val.epochDate.fSecondsFraction = d - (double)pDecodedItem->val.epochDate.nSeconds;
1536 }
1537 break;
1538
1539 default:
1540 nReturn = QCBOR_ERR_BAD_OPT_TAG;
1541 goto Done;
1542 }
1543 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
1544
1545Done:
1546 return nReturn;
1547}
1548
1549
1550#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
1551/*
1552 Decode decimal fractions and big floats.
1553
1554 When called pDecodedItem must be the array that is tagged as a big
1555 float or decimal fraction, the array that has the two members, the
1556 exponent and mantissa.
1557
1558 This will fetch and decode the exponent and mantissa and put the
1559 result back into pDecodedItem.
1560 */
1561inline static QCBORError
1562QCBORDecode_MantissaAndExponent(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
1563{
1564 QCBORError nReturn;
1565
1566 // --- Make sure it is an array; track nesting level of members ---
1567 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
1568 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1569 goto Done;
1570 }
1571
1572 // A check for pDecodedItem->val.uCount == 2 would work for
Laurence Lundbladeee851742020-01-08 08:37:05 -08001573 // definite length arrays, but not for indefnite. Instead remember
1574 // the nesting level the two integers must be at, which is one
1575 // deeper than that of the array.
Laurence Lundblade59289e52019-12-30 13:44:37 -08001576 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
1577
1578 // --- Is it a decimal fraction or a bigfloat? ---
1579 const bool bIsTaggedDecimalFraction = QCBORDecode_IsTagged(me, pDecodedItem, CBOR_TAG_DECIMAL_FRACTION);
1580 pDecodedItem->uDataType = bIsTaggedDecimalFraction ? QCBOR_TYPE_DECIMAL_FRACTION : QCBOR_TYPE_BIGFLOAT;
1581
1582 // --- Get the exponent ---
1583 QCBORItem exponentItem;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001584 nReturn = QCBORDecode_GetNextMapOrArray(me, &exponentItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001585 if(nReturn != QCBOR_SUCCESS) {
1586 goto Done;
1587 }
1588 if(exponentItem.uNestingLevel != nNestLevel) {
1589 // Array is empty or a map/array encountered when expecting an int
1590 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1591 goto Done;
1592 }
1593 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
1594 // Data arriving as an unsigned int < INT64_MAX has been converted
1595 // to QCBOR_TYPE_INT64 and thus handled here. This is also means
1596 // that the only data arriving here of type QCBOR_TYPE_UINT64 data
1597 // will be too large for this to handle and thus an error that will
1598 // get handled in the next else.
1599 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
1600 } else {
1601 // Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX
1602 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1603 goto Done;
1604 }
1605
1606 // --- Get the mantissa ---
1607 QCBORItem mantissaItem;
1608 nReturn = QCBORDecode_GetNextWithTags(me, &mantissaItem, NULL);
1609 if(nReturn != QCBOR_SUCCESS) {
1610 goto Done;
1611 }
1612 if(mantissaItem.uNestingLevel != nNestLevel) {
1613 // Mantissa missing or map/array encountered when expecting number
1614 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1615 goto Done;
1616 }
1617 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
1618 // Data arriving as an unsigned int < INT64_MAX has been converted
1619 // to QCBOR_TYPE_INT64 and thus handled here. This is also means
1620 // that the only data arriving here of type QCBOR_TYPE_UINT64 data
1621 // will be too large for this to handle and thus an error that
1622 // will get handled in an else below.
1623 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
1624 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM || mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
1625 // Got a good big num mantissa
1626 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
1627 // Depends on numbering of QCBOR_TYPE_XXX
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001628 pDecodedItem->uDataType = (uint8_t)(pDecodedItem->uDataType +
1629 mantissaItem.uDataType - QCBOR_TYPE_POSBIGNUM +
1630 1);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001631 } else {
1632 // Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX
1633 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1634 goto Done;
1635 }
1636
1637 // --- Check that array only has the two numbers ---
1638 if(mantissaItem.uNextNestLevel == nNestLevel) {
1639 // Extra items in the decimal fraction / big num
1640 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1641 goto Done;
1642 }
1643
1644Done:
1645
1646 return nReturn;
1647}
1648#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
1649
1650
1651/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001652 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08001653 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001654QCBORError
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001655QCBORDecode_GetNext(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08001656{
1657 QCBORError nReturn;
1658
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001659 nReturn = QCBORDecode_GetNextMapOrArray(me, pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001660 if(nReturn != QCBOR_SUCCESS) {
1661 goto Done;
1662 }
1663
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001664 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM; i++) {
1665 switch(pDecodedItem->uTags[i] ) {
1666 case 0xffff:
1667 // The end of the tag list or no tags
1668 // Successful exit from the loop.
1669 goto Done;
Laurence Lundblade59289e52019-12-30 13:44:37 -08001670
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001671 case CBOR_TAG_DATE_STRING:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001672 nReturn = DecodeDateString(pDecodedItem);
1673 break;
1674
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001675 case CBOR_TAG_DATE_EPOCH:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001676 nReturn = DecodeDateEpoch(pDecodedItem);
1677 break;
1678
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001679 case CBOR_TAG_POS_BIGNUM:
1680 case CBOR_TAG_NEG_BIGNUM:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001681 nReturn = DecodeBigNum(pDecodedItem);
1682 break;
1683
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001684 #ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
1685 case CBOR_TAG_DECIMAL_FRACTION:
1686 case CBOR_TAG_BIGFLOAT:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001687 // For aggregate tagged types, what goes into pTags is only collected
1688 // from the surrounding data item, not the contents, so pTags is not
1689 // passed on here.
1690
1691 nReturn = QCBORDecode_MantissaAndExponent(me, pDecodedItem);
1692 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001693 #endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08001694
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001695 case CBOR_TAG_BIN_UUID:
1696 nReturn = DecodeUUID(pDecodedItem);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001697 break;
1698
1699 case CBOR_TAG_URI:
1700 nReturn = DecodeURI(pDecodedItem);
1701 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001702
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001703 case CBOR_TAG_REGEX:
1704 nReturn = DecodeRegex(pDecodedItem);
1705 break;
1706
1707
1708 case CBOR_TAG_B64:
1709 nReturn = DecodeB64(pDecodedItem);
1710 break;
1711
1712
1713 case CBOR_TAG_B64URL:
1714 nReturn = DecodeB64URL(pDecodedItem);
1715 break;
1716
1717 case CBOR_TAG_MIME:
1718 case CBOR_TAG_BINARY_MIME:
1719// TODO: should binary and text MIME be distinguished?
1720 nReturn = DecodeMIME(pDecodedItem);
1721 break;
1722
1723
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001724 default:
1725 // A tag that is not understood
1726 // A successful exit from the loop
1727 goto Done;
1728
1729 }
1730 if(nReturn != QCBOR_SUCCESS) {
1731 goto Done;
1732 }
Laurence Lundblade59289e52019-12-30 13:44:37 -08001733 }
1734
1735Done:
1736 if(nReturn != QCBOR_SUCCESS) {
1737 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
1738 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
1739 }
1740 return nReturn;
1741}
1742
1743
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001744QCBORError QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
1745{
1746 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
1747
1748 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
1749
1750 UsefulInputBuf_Seek(&(pMe->InBuf), uOffset);
1751
1752 return uErr;
1753}
1754
1755
Laurence Lundblade59289e52019-12-30 13:44:37 -08001756/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001757 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08001758 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001759QCBORError
1760QCBORDecode_GetNextWithTags(QCBORDecodeContext *me,
1761 QCBORItem *pDecodedItem,
1762 QCBORTagListOut *pTags)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001763{
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001764 QCBORError nReturn;
1765
1766 nReturn = QCBORDecode_GetNext(me, pDecodedItem);
1767 if(nReturn != QCBOR_SUCCESS) {
1768 return nReturn;
1769 }
1770
1771 if(pTags != NULL) {
1772 pTags->uNumUsed = 0;
1773 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM; i++) {
1774 if(pDecodedItem->uTags[i] == 0xffff) {
1775 break;
1776 }
1777 if(pTags->uNumUsed >= pTags->uNumAllocated) {
1778 return QCBOR_ERR_TOO_MANY_TAGS;
1779 }
1780 pTags->puTags[pTags->uNumUsed] = ConvertTag(me, pDecodedItem->uTags[i]);
1781 pTags->uNumUsed++;
1782 }
1783 }
1784
1785 return QCBOR_SUCCESS;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001786}
1787
1788
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001789/*
Laurence Lundblade6de37062018-10-15 12:22:42 +05301790 Decoding items is done in 5 layered functions, one calling the
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301791 next one down. If a layer has no work to do for a particular item
1792 it returns quickly.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001793
Laurence Lundblade59289e52019-12-30 13:44:37 -08001794 - QCBORDecode_GetNext, GetNextWithTags -- The top layer processes
1795 tagged data items, turning them into the local C representation.
1796 For the most simple it is just associating a QCBOR_TYPE with the data. For
1797 the complex ones that an aggregate of data items, there is some further
1798 decoding and a little bit of recursion.
1799
1800 - QCBORDecode_GetNextMapOrArray - This manages the beginnings and
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301801 ends of maps and arrays. It tracks descending into and ascending
Laurence Lundblade6de37062018-10-15 12:22:42 +05301802 out of maps/arrays. It processes all breaks that terminate
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001803 indefinite length maps and arrays.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001804
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301805 - GetNext_MapEntry -- This handles the combining of two
1806 items, the label and the data, that make up a map entry.
1807 It only does work on maps. It combines the label and data
1808 items into one labeled item.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001809
Laurence Lundblade59289e52019-12-30 13:44:37 -08001810 - GetNext_TaggedItem -- This decodes type 6 tagging. It turns the
1811 tags into bit flags associated with the data item. No actual decoding
1812 of the contents of the tagged item is performed here.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001813
Laurence Lundblade59289e52019-12-30 13:44:37 -08001814 - GetNext_FullItem -- This assembles the sub-items that make up
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301815 an indefinte length string into one string item. It uses the
Laurence Lundblade6de37062018-10-15 12:22:42 +05301816 string allocater to create contiguous space for the item. It
1817 processes all breaks that are part of indefinite length strings.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001818
Laurence Lundblade59289e52019-12-30 13:44:37 -08001819 - GetNext_Item -- This decodes the atomic data items in CBOR. Each
1820 atomic data item has a "major type", an integer "argument" and optionally
1821 some content. For text and byte strings, the content is the bytes
1822 that make up the string. These are the smallest data items that are
1823 considered to be well-formed. The content may also be other data items in
1824 the case of aggregate types. They are not handled in this layer.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001825
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001826 Roughly this takes 300 bytes of stack for vars. Need to
1827 evaluate this more carefully and correctly.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001828
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301829 */
1830
1831
1832/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001833 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001834 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001835int QCBORDecode_IsTagged(QCBORDecodeContext *me,
1836 const QCBORItem *pItem,
1837 uint64_t uTag)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001838{
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001839 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM; i++ ) {
1840 if(pItem->uTags[i] == 0xffff) {
1841 break;
1842 }
1843 if(ConvertTag(me, pItem->uTags[i]) == uTag) {
1844 return 1;
1845 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001846 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001847
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001848 return 0;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001849}
1850
1851
1852/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001853 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001854 */
Laurence Lundblade30816f22018-11-10 13:40:22 +07001855QCBORError QCBORDecode_Finish(QCBORDecodeContext *me)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001856{
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001857 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001858
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001859 // Error out if all the maps/arrays are not closed out
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001860 if(!DecodeNesting_IsAtTop(&(me->nesting))) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001861 nReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
1862 goto Done;
1863 }
1864
1865 // Error out if not all the bytes are consumed
1866 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) {
1867 nReturn = QCBOR_ERR_EXTRA_BYTES;
1868 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001869
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001870Done:
Laurence Lundblade6de37062018-10-15 12:22:42 +05301871 // Call the destructor for the string allocator if there is one.
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001872 // Always called, even if there are errors; always have to clean up
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001873 StringAllocator_Destruct(&(me->StringAllocator));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001874
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001875 return nReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001876}
1877
1878
1879
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001880/*
1881
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001882Decoder errors handled in this file
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001883
Laurence Lundbladeee851742020-01-08 08:37:05 -08001884 - Hit end of input before it was expected while decoding type and
1885 number QCBOR_ERR_HIT_END
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001886
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001887 - negative integer that is too large for C QCBOR_ERR_INT_OVERFLOW
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001888
Laurence Lundbladeee851742020-01-08 08:37:05 -08001889 - Hit end of input while decoding a text or byte string
1890 QCBOR_ERR_HIT_END
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001891
Laurence Lundbladeee851742020-01-08 08:37:05 -08001892 - Encountered conflicting tags -- e.g., an item is tagged both a date
1893 string and an epoch date QCBOR_ERR_UNSUPPORTED
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001894
Laurence Lundbladeee851742020-01-08 08:37:05 -08001895 - Encontered an array or mapp that has too many items
1896 QCBOR_ERR_ARRAY_TOO_LONG
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001897
Laurence Lundbladeee851742020-01-08 08:37:05 -08001898 - Encountered array/map nesting that is too deep
1899 QCBOR_ERR_ARRAY_NESTING_TOO_DEEP
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001900
Laurence Lundbladeee851742020-01-08 08:37:05 -08001901 - An epoch date > INT64_MAX or < INT64_MIN was encountered
1902 QCBOR_ERR_DATE_OVERFLOW
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001903
Laurence Lundbladeee851742020-01-08 08:37:05 -08001904 - The type of a map label is not a string or int
1905 QCBOR_ERR_MAP_LABEL_TYPE
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001906
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001907 - Hit end with arrays or maps still open -- QCBOR_ERR_EXTRA_BYTES
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001908
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001909 */
1910
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001911
1912
Laurence Lundbladef6531662018-12-04 10:42:22 +09001913
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001914/* ===========================================================================
1915 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001916
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001917 This implements a simple sting allocator for indefinite length
1918 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
1919 implements the function type QCBORStringAllocate and allows easy
1920 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09001921
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001922 This particular allocator is built-in for convenience. The caller
1923 can implement their own. All of this following code will get
1924 dead-stripped if QCBORDecode_SetMemPool() is not called.
1925
1926 This is a very primitive memory allocator. It does not track
1927 individual allocations, only a high-water mark. A free or
1928 reallocation must be of the last chunk allocated.
1929
1930 The size of the pool and offset to free memory are packed into the
1931 first 8 bytes of the memory pool so we don't have to keep them in
1932 the decode context. Since the address of the pool may not be
1933 aligned, they have to be packed and unpacked as if they were
1934 serialized data of the wire or such.
1935
1936 The sizes packed in are uint32_t to be the same on all CPU types
1937 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08001938 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001939
1940
Laurence Lundbladeee851742020-01-08 08:37:05 -08001941static inline int
1942MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001943{
1944 // Use of UsefulInputBuf is overkill, but it is convenient.
1945 UsefulInputBuf UIB;
1946
Laurence Lundbladeee851742020-01-08 08:37:05 -08001947 // Just assume the size here. It was checked during SetUp so
1948 // the assumption is safe.
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001949 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem, QCBOR_DECODE_MIN_MEM_POOL_SIZE});
1950 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
1951 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
1952 return UsefulInputBuf_GetError(&UIB);
1953}
1954
1955
Laurence Lundbladeee851742020-01-08 08:37:05 -08001956static inline int
1957MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001958{
1959 // Use of UsefulOutBuf is overkill, but convenient. The
1960 // length check performed here is useful.
1961 UsefulOutBuf UOB;
1962
1963 UsefulOutBuf_Init(&UOB, Pool);
1964 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
1965 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
1966 return UsefulOutBuf_GetError(&UOB);
1967}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001968
1969
1970/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001971 Internal function for an allocation, reallocation free and destuct.
1972
1973 Having only one function rather than one each per mode saves space in
1974 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001975
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001976 Code Reviewers: THIS FUNCTION DOES POINTER MATH
1977 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001978static UsefulBuf
1979MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001980{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001981 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001982
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001983 uint32_t uPoolSize;
1984 uint32_t uFreeOffset;
1985
1986 if(uNewSize > UINT32_MAX) {
1987 // This allocator is only good up to 4GB. This check should
1988 // optimize out if sizeof(size_t) == sizeof(uint32_t)
1989 goto Done;
1990 }
1991 const uint32_t uNewSize32 = (uint32_t)uNewSize;
1992
1993 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
1994 goto Done;
1995 }
1996
1997 if(uNewSize) {
1998 if(pMem) {
1999 // REALLOCATION MODE
2000 // Calculate pointer to the end of the memory pool. It is
2001 // assumed that pPool + uPoolSize won't wrap around by
2002 // assuming the caller won't pass a pool buffer in that is
2003 // not in legitimate memory space.
2004 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
2005
2006 // Check that the pointer for reallocation is in the range of the
2007 // pool. This also makes sure that pointer math further down
2008 // doesn't wrap under or over.
2009 if(pMem >= pPool && pMem < pPoolEnd) {
2010 // Offset to start of chunk for reallocation. This won't
2011 // wrap under because of check that pMem >= pPool. Cast
2012 // is safe because the pool is always less than UINT32_MAX
2013 // because of check in QCBORDecode_SetMemPool().
2014 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
2015
2016 // Check to see if the allocation will fit. uPoolSize -
2017 // uMemOffset will not wrap under because of check that
2018 // pMem is in the range of the uPoolSize by check above.
2019 if(uNewSize <= uPoolSize - uMemOffset) {
2020 ReturnValue.ptr = pMem;
2021 ReturnValue.len = uNewSize;
2022
2023 // Addition won't wrap around over because uNewSize was
2024 // checked to be sure it is less than the pool size.
2025 uFreeOffset = uMemOffset + uNewSize32;
2026 }
2027 }
2028 } else {
2029 // ALLOCATION MODE
2030 // uPoolSize - uFreeOffset will not underflow because this
2031 // pool implementation makes sure uFreeOffset is always
2032 // smaller than uPoolSize through this check here and
2033 // reallocation case.
2034 if(uNewSize <= uPoolSize - uFreeOffset) {
2035 ReturnValue.len = uNewSize;
2036 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08002037 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002038 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002039 }
2040 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002041 if(pMem) {
2042 // FREE MODE
2043 // Cast is safe because of limit on pool size in
2044 // QCBORDecode_SetMemPool()
2045 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
2046 } else {
2047 // DESTRUCT MODE
2048 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002049 }
2050 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002051
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002052 UsefulBuf Pool = {pPool, uPoolSize};
2053 MemPool_Pack(Pool, uFreeOffset);
2054
2055Done:
2056 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002057}
2058
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002059
Laurence Lundbladef6531662018-12-04 10:42:22 +09002060/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08002061 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09002062 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08002063QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
2064 UsefulBuf Pool,
2065 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002066{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002067 // The pool size and free mem offset are packed into the beginning
2068 // of the pool memory. This compile time check make sure the
2069 // constant in the header is correct. This check should optimize
2070 // down to nothing.
2071 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundblade30816f22018-11-10 13:40:22 +07002072 return QCBOR_ERR_BUFFER_TOO_SMALL;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002073 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002074
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002075 // The pool size and free offset packed in to the beginning of pool
2076 // memory are only 32-bits. This check will optimize out on 32-bit
2077 // machines.
2078 if(Pool.len > UINT32_MAX) {
2079 return QCBOR_ERR_BUFFER_TOO_LARGE;
2080 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002081
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002082 // This checks that the pool buffer given is big enough.
2083 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
2084 return QCBOR_ERR_BUFFER_TOO_SMALL;
2085 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002086
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002087 pMe->StringAllocator.pfAllocator = MemPool_Function;
2088 pMe->StringAllocator.pAllocateCxt = Pool.ptr;
2089 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002090
Laurence Lundblade30816f22018-11-10 13:40:22 +07002091 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002092}
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002093
Laurence Lundblade1341c592020-04-11 14:19:05 -07002094#include <stdio.h>
2095void printdecode(QCBORDecodeContext *pMe, const char *szName)
2096{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002097 printf("---%s--%d--%d--\nLevel Count Type Offset SaveCount MapMode\n",
2098 szName,
2099 (uint32_t)pMe->InBuf.cursor,
2100 (uint32_t)pMe->InBuf.UB.len);
Laurence Lundblade64b607e2020-05-13 13:05:57 -07002101 for(int i = 0; i < QCBOR_MAX_ARRAY_NESTING; i++) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002102 if(&(pMe->nesting.pMapsAndArrays[i]) > pMe->nesting.pCurrent) {
2103 break;
2104 }
Laurence Lundblade64b607e2020-05-13 13:05:57 -07002105 printf("%2s %2d %5d %s %6u %2d %d\n",
2106 pMe->nesting.pCurrentMap == &(pMe->nesting.pMapsAndArrays[i]) ? "->": " ",
Laurence Lundblade1341c592020-04-11 14:19:05 -07002107 i,
2108 pMe->nesting.pMapsAndArrays[i].uCount,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002109 pMe->nesting.pMapsAndArrays[i].uMajorType == QCBOR_TYPE_MAP ? " map" :
2110 (pMe->nesting.pMapsAndArrays[i].uMajorType == QCBOR_TYPE_ARRAY ? "array" :
2111 (pMe->nesting.pMapsAndArrays[i].uMajorType == QCBOR_TYPE_NONE ? " none" : "?????")),
Laurence Lundblade1341c592020-04-11 14:19:05 -07002112 pMe->nesting.pMapsAndArrays[i].uOffset,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002113 pMe->nesting.pMapsAndArrays[i].uSaveCount,
2114 pMe->nesting.pMapsAndArrays[i].uMapMode
Laurence Lundblade1341c592020-04-11 14:19:05 -07002115 );
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002116
Laurence Lundblade1341c592020-04-11 14:19:05 -07002117 }
Laurence Lundblade64b607e2020-05-13 13:05:57 -07002118 printf("\n");
Laurence Lundblade1341c592020-04-11 14:19:05 -07002119}
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002120
2121
2122/*
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002123 *
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002124 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002125static inline QCBORError
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002126ConsumeItem(QCBORDecodeContext *pMe,
2127 const QCBORItem *pItemToConsume,
2128 uint_fast8_t *puNextNestLevel)
2129{
Laurence Lundblade1341c592020-04-11 14:19:05 -07002130 QCBORError nReturn;
2131 QCBORItem Item;
2132
2133 printdecode(pMe, "ConsumeItem");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002134
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002135 if(IsMapOrArray(pItemToConsume->uDataType)) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002136 /* There is only real work to do for maps and arrays */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002137
Laurence Lundblade1341c592020-04-11 14:19:05 -07002138 /* This works for definite and indefinite length
2139 * maps and arrays by using the nesting level
2140 */
2141 do {
2142 nReturn = QCBORDecode_GetNext(pMe, &Item);
2143 if(nReturn != QCBOR_SUCCESS) {
2144 goto Done;
2145 }
2146 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002147
Laurence Lundblade1341c592020-04-11 14:19:05 -07002148 if(puNextNestLevel != NULL) {
2149 *puNextNestLevel = Item.uNextNestLevel;
2150 }
2151 nReturn = QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002152
Laurence Lundblade1341c592020-04-11 14:19:05 -07002153 } else {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002154 /* item_to_consume is not a map or array */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002155 if(puNextNestLevel != NULL) {
2156 /* Just pass the nesting level through */
2157 *puNextNestLevel = pItemToConsume->uNextNestLevel;
2158 }
2159 nReturn = QCBOR_SUCCESS;
2160 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002161
2162Done:
2163 return nReturn;
2164}
2165
2166
Laurence Lundblade1341c592020-04-11 14:19:05 -07002167/* Return true if the labels in Item1 and Item2 are the same.
2168 Works only for integer and string labels. Returns false
2169 for any other type. */
2170static inline bool
2171MatchLabel(QCBORItem Item1, QCBORItem Item2)
2172{
2173 if(Item1.uLabelType == QCBOR_TYPE_INT64) {
2174 if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
2175 return true;
2176 }
2177 } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002178 if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002179 return true;
2180 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002181 } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002182 if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
2183 return true;
2184 }
2185 } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
2186 if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
2187 return true;
2188 }
2189 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002190
Laurence Lundblade1341c592020-04-11 14:19:05 -07002191 /* Other label types are never matched */
2192 return false;
2193}
2194
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002195static inline bool
2196MatchType(QCBORItem Item1, QCBORItem Item2)
2197{
2198 if(Item1.uDataType == Item2.uDataType) {
2199 return true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002200 } else if(Item1.uDataType == QCBOR_TYPE_ANY) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002201 return true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002202 } else if(Item2.uDataType == QCBOR_TYPE_ANY) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002203 return true;
2204 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002205 return false;
2206}
2207
2208
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002209/**
2210 \brief Search a map for a set of items
2211
2212 @param[in] pMe The decode context to search.
2213 @param[in,out] pItemArray The items to search for and the items found.
2214 @param[in] pCBContext Context for the not-found item call back
2215 @param[in] pfCallback Function to call on items not matched in pItemArray
2216
2217 @retval QCBOR_ERR_NOT_ENTERED Trying to search without having entered a map
2218
2219 @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.
2220
2221 @retval QCBOR_ERR_UNEXPECTED_TYPE The label was matched, but not the type.
2222
2223 @retval Also errors returned by QCBORDecode_GetNext().
2224
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002225 On input pItemArray contains a list of labels and data types
2226 of items to be found.
2227
2228 On output the fully retrieved items are filled in with
2229 values and such. The label was matched, so it never changes.
2230
2231 If an item was not found, its data type is set to none.
2232
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002233 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002234static QCBORError
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002235MapSearch(QCBORDecodeContext *pMe,
2236 QCBORItem *pItemArray,
2237 size_t *puOffset,
2238 size_t *puEndOffset,
2239 void *pCBContext,
2240 QCBORItemCallback pfCallback)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002241{
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002242 QCBORError uReturn;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002243
2244 // TODO: what if pre-order cursor is not at the same level as map? This should be OK.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002245 if(!DecodeNesting_InBoundedMode(&(pMe->nesting))) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002246 return QCBOR_ERR_NOT_ENTERED;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002247 }
2248
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002249 QCBORDecodeNesting SaveNesting;
2250 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002251
2252 UsefulInputBuf_Seek(&(pMe->InBuf), pMe->nesting.pCurrent->uOffset);
2253
2254 /* Loop over all the items in the map. They could be
2255 * deeply nested and this should handle both definite
2256 * and indefinite length maps and arrays, so this
2257 * adds some complexity. */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002258 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Laurence Lundblade1341c592020-04-11 14:19:05 -07002259
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002260 uint_fast8_t uNextNestLevel;
2261
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002262 uint64_t uFoundItemBitMap = 0;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002263
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002264 /* Iterate over items in the map / array */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002265 do {
2266 /* Remember offset because sometims we have to return it */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002267 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002268
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002269 /* Get the item */
2270 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002271 uReturn = QCBORDecode_GetNext(pMe, &Item);
2272 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002273 /* Got non-well-formed CBOR */
2274 goto Done;
2275 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002276
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002277 /* See if item has one of the labels that are of interest */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002278 int nIndex;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002279 QCBORItem *pIterator;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002280 for(pIterator = pItemArray, nIndex = 0; pIterator->uLabelType != 0; pIterator++, nIndex++) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002281 if(MatchLabel(Item, *pIterator)) {
2282 // A label match has been found
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002283 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
2284 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002285 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002286 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002287 /* Also try to match its type */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002288 if(!MatchType(Item, *pIterator)) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002289 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002290 goto Done;
2291 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002292
2293 /* Successful match. Return the item. */
2294 *pIterator = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002295 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002296 if(puOffset) {
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002297 *puOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002298 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002299 } else {
2300 /* Call the call back on unmatched labels */
2301 /* It is tempting to do duplicate detection here, but that would
2302 require dynamic memory allocation because the number of labels
2303 that might be encountered is unbounded.
2304 */
2305 if(pfCallback) {
2306 uReturn = (*pfCallback)(pCBContext, &Item);
2307 if(uReturn != QCBOR_SUCCESS) {
2308 goto Done;
2309 }
2310 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002311 }
2312 }
2313
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002314 /* Consume the item whether matched or not. This
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002315 does the work of traversing maps and array and
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002316 everything in them. In this loop only the
2317 items at the current nesting level are examined
2318 to match the labels. */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002319 uReturn = ConsumeItem(pMe, &Item, &uNextNestLevel);
2320 if(uReturn) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002321 goto Done;
2322 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002323
2324 } while (uNextNestLevel >= uMapNestLevel);
2325
2326
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002327 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002328
2329 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
2330 // Cast OK because encoded CBOR is limited to UINT32_MAX
2331 pMe->uMapEndOffset = (uint32_t)uEndOffset;
2332 // TODO: is zero *puOffset OK?
2333 if(puEndOffset) {
2334 *puEndOffset = uEndOffset;
2335 }
2336
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002337 /* For all items not found, set the data type to QCBOR_TYPE_NONE */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002338 int i;
2339 QCBORItem *pIterator;
2340 for(pIterator = pItemArray, i = 0; pIterator->uLabelType != 0; pIterator++, i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002341 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002342 pIterator->uDataType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002343 }
2344 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002345
2346Done:
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002347 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002348
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002349 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002350}
2351
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002352
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002353
2354
Laurence Lundblade34691b92020-05-18 22:25:25 -07002355void QCBORDecode_ExitMapMode(QCBORDecodeContext *pMe, uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002356{
Laurence Lundblade1341c592020-04-11 14:19:05 -07002357 size_t uEndOffset;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002358
Laurence Lundblade34691b92020-05-18 22:25:25 -07002359 (void)uType; // TODO: error check
2360
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002361/*
Laurence Lundblade1341c592020-04-11 14:19:05 -07002362 if(pMe->uMapEndOffset) {
2363 uEndOffset = pMe->uMapEndOffset;
2364 // It is only valid once.
2365 pMe->uMapEndOffset = 0;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002366 } else { */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002367 QCBORItem Dummy;
2368
2369 Dummy.uLabelType = QCBOR_TYPE_NONE;
2370
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002371 QCBORError nReturn = MapSearch(pMe, &Dummy, NULL, &uEndOffset, NULL, NULL);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002372
2373 (void)nReturn; // TODO:
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002374// }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002375
2376 printdecode(pMe, "start exit");
2377 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
2378
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002379 DecodeNesting_Exit(&(pMe->nesting));
Laurence Lundblade1341c592020-04-11 14:19:05 -07002380 printdecode(pMe, "end exit");
2381
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002382}
2383
2384
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002385void QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe, uint8_t uTagRequirement, UsefulBufC *pBstr)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002386{
2387 QCBORItem Item;
2388 QCBORDecode_GetNext(pMe, &Item);
2389 // Need to set UIB cursor to start of bstr and UIB length to end of bstr
2390
2391}
2392
2393//void QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pCtx, int64_t uLabel, UsefulBufC *pBstr);
2394
2395//void QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pCtx, const char *szLabel, UsefulBufC *pBstr);
2396
2397void QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pCtx)
2398{
2399 // Need to set the cursor to end of the bstr and length to the next length
2400 // above in the nesting tree (or the top level length).
2401
2402}
2403
2404
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002405void QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
2406 int64_t nLabel,
2407 uint8_t uQcborType,
2408 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002409{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002410 if(pMe->uLastError != QCBOR_SUCCESS) {
2411 return;
2412 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002413
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002414 QCBORItem OneItemSeach[2];
2415 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
2416 OneItemSeach[0].label.int64 = nLabel;
2417 OneItemSeach[0].uDataType = uQcborType;
2418 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07002419
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002420 QCBORError nReturn = MapSearch(pMe, OneItemSeach, NULL, NULL, NULL, NULL);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002421 if(nReturn) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002422 pMe->uLastError = (uint8_t)nReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002423 }
2424
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002425 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
2426 pMe->uLastError = QCBOR_ERR_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002427 }
2428
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002429 *pItem = OneItemSeach[0];
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002430}
2431
2432
Laurence Lundbladeda095972020-06-06 18:35:33 -07002433void QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
2434 const char *szLabel,
2435 uint8_t uQcborType,
2436 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002437{
Laurence Lundbladeda095972020-06-06 18:35:33 -07002438 if(pMe->uLastError != QCBOR_SUCCESS) {
2439 return;
2440 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002441
Laurence Lundbladed02ea8e2020-06-06 18:38:19 -07002442
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002443 QCBORItem OneItemSeach[2];
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002444
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002445 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2446 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
2447 OneItemSeach[0].uDataType = uQcborType;
2448 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07002449
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002450 QCBORError nReturn = MapSearch(pMe, OneItemSeach, NULL, NULL, NULL, NULL);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002451 if(nReturn) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07002452 pMe->uLastError = (uint8_t)nReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002453 }
2454
Laurence Lundbladeda095972020-06-06 18:35:33 -07002455
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002456 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07002457 pMe->uLastError = QCBOR_ERR_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002458 }
2459
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002460 *pItem = OneItemSeach[0];
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002461}
2462
2463
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002464static QCBORError CheckTagRequirement(const TagSpecification TagSpec, uint8_t uDataType)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002465{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002466 if(TagSpec.uTagRequirement == QCBOR_TAGSPEC_MATCH_TAG) {
2467 /* Must match the tag */
2468 if(uDataType == TagSpec.uTaggedType) {
2469 return QCBOR_SUCCESS;
2470 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002471 } else {
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002472 /* QCBOR_TAGSPEC_MATCH_TAG_CONTENT_TYPE or QCBOR_TAGSPEC_MATCH_EITHER */
2473 /* Must check all the possible types for the tag content */
2474 for(size_t i = 0; i < sizeof(TagSpec.uAllowedContentTypes); i++) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002475 if(uDataType == TagSpec.uAllowedContentTypes[i]) {
2476 return QCBOR_SUCCESS;
2477 }
2478 }
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002479 /* Didn't match any of the tag content types */
2480 /* Check the tag for the either case */
2481 if(TagSpec.uTagRequirement == QCBOR_TAGSPEC_MATCH_EITHER) {
2482 if(uDataType == TagSpec.uTaggedType) {
2483 return QCBOR_SUCCESS;
2484 }
2485 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002486 }
2487
2488 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002489}
2490
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002491
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002492void QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
2493 int64_t nLabel,
2494 TagSpecification TagSpec,
2495 QCBORItem *pItem)
2496{
2497 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
2498 if(pMe->uLastError != QCBOR_SUCCESS) {
2499 return;
2500 }
2501
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002502 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem->uDataType);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002503}
2504
2505void QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
2506 const char *szLabel,
2507 TagSpecification TagSpec,
2508 QCBORItem *pItem)
2509{
2510 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
2511 if(pMe->uLastError != QCBOR_SUCCESS) {
2512 return;
2513 }
2514
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002515 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem->uDataType);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002516}
2517
2518void QCBORDecode_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
2519 int64_t nLabel,
2520 TagSpecification TagSpec,
2521 UsefulBufC *pString)
2522{
2523 QCBORItem Item;
2524 QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
2525 if(pMe->uLastError == QCBOR_SUCCESS) {
2526 *pString = Item.val.string;
2527 }
2528}
2529
2530void QCBORDecode_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
2531 const char * szLabel,
2532 TagSpecification TagSpec,
2533 UsefulBufC *pString)
2534{
2535 QCBORItem Item;
2536 QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
2537 if(pMe->uLastError == QCBOR_SUCCESS) {
2538 *pString = Item.val.string;
2539 }
2540}
Laurence Lundblade1341c592020-04-11 14:19:05 -07002541
Laurence Lundblade1341c592020-04-11 14:19:05 -07002542
Laurence Lundblade34691b92020-05-18 22:25:25 -07002543static void SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07002544{
Laurence Lundblade34691b92020-05-18 22:25:25 -07002545 if(pMe->uLastError != QCBOR_SUCCESS) {
2546 // Already in error state; do nothing.
2547 return;
2548 }
2549
2550 size_t uOffset;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002551 pMe->uLastError = (uint8_t)MapSearch(pMe, pSearch, &uOffset, NULL, NULL, NULL);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002552 if(pMe->uLastError != QCBOR_SUCCESS) {
2553 return;
2554 }
2555
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002556 /* Need to get the current pre-order nesting level and cursor to be
2557 at the first item in the map/array just entered.
2558
2559 Also need to current map nesting level and start cursor to
2560 be at the right place.
2561
2562 The UsefulInBuf offset could be anywhere, so no assumption is
2563 made about it.
2564
2565 No assumption is made about the pre-order nesting level either.
2566
2567 However the map mode nesting level is assumed to be one above
2568 the map level that is being entered.
2569 */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002570 /* Seek to the data item that is the map or array */
2571 UsefulInputBuf_Seek(&(pMe->InBuf), uOffset);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002572 pMe->nesting.pCurrent = pMe->nesting.pCurrentMap; // TODO: part of DecodeNesting
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002573
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002574 // TODO: check error?
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002575 QCBORDecode_EnterBoundedMode(pMe, pSearch->uDataType);
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002576
Laurence Lundblade34691b92020-05-18 22:25:25 -07002577 printdecode(pMe, "FinishEnter");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002578}
2579
2580
Laurence Lundblade34691b92020-05-18 22:25:25 -07002581void QCBORDecode_EnterMapInMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002582{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002583 QCBORItem OneItemSeach[2];
2584 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
2585 OneItemSeach[0].label.int64 = nLabel;
2586 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
2587 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002588
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002589 /* The map to enter was found, now finish of entering it. */
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002590 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002591}
2592
2593
Laurence Lundblade34691b92020-05-18 22:25:25 -07002594void QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002595{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002596 QCBORItem OneItemSeach[2];
2597 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2598 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
2599 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
2600 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002601
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002602 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002603}
2604
2605
Laurence Lundblade34691b92020-05-18 22:25:25 -07002606void QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07002607{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002608 QCBORItem OneItemSeach[2];
2609 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
2610 OneItemSeach[0].label.int64 = nLabel;
2611 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
2612 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002613
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002614 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002615}
2616
2617
2618void QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
2619{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002620 QCBORItem OneItemSeach[2];
2621 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2622 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
2623 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
2624 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002625
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002626 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002627}
2628
2629
2630
2631
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002632
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002633/* Next item must be map or this generates an error */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002634void QCBORDecode_EnterBoundedMode(QCBORDecodeContext *pMe, uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002635{
Laurence Lundblade34691b92020-05-18 22:25:25 -07002636 if(pMe->uLastError != QCBOR_SUCCESS) {
2637 // Already in error state; do nothing.
2638 return;
2639 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002640
2641 /* Get the data item that is the map that is being searched */
Laurence Lundblade34691b92020-05-18 22:25:25 -07002642 QCBORItem Item;
Laurence Lundblade986017c2020-05-23 19:25:02 -07002643 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002644 if(pMe->uLastError != QCBOR_SUCCESS) {
2645 return;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002646 }
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002647 if(Item.uDataType != uType) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07002648 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
2649 return;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002650 }
2651
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002652 DecodeNesting_EnterMapMode(&(pMe->nesting), UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002653
Laurence Lundblade34691b92020-05-18 22:25:25 -07002654 printdecode(pMe, "EnterMapModeDone");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002655}
2656
2657
2658
2659QCBORError QCBORDecode_GetItemsInMap(QCBORDecodeContext *pCtx, QCBORItem *pItemList)
2660{
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002661 return MapSearch(pCtx, pItemList, NULL, NULL, NULL, NULL);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002662}
2663
2664
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002665QCBORError QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pCtx, QCBORItem *pItemList, void *pCallbackCtx, QCBORItemCallback pfCB)
2666{
2667 return MapSearch(pCtx, pItemList, NULL, NULL, pCallbackCtx, pfCB);
2668}
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002669
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002670
2671
Laurence Lundblade1341c592020-04-11 14:19:05 -07002672void QCBORDecode_RewindMap(QCBORDecodeContext *pMe)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002673{
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002674 // TODO: check for map mode; test this
Laurence Lundblade1341c592020-04-11 14:19:05 -07002675 pMe->nesting.pCurrent->uCount = pMe->nesting.pCurrent->uSaveCount;
2676 UsefulInputBuf_Seek(&(pMe->InBuf), pMe->nesting.pCurrent->uOffset);
2677}
2678
2679
Laurence Lundblade1341c592020-04-11 14:19:05 -07002680
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002681void QCBORDecode_EnterBstr(QCBORDecodeContext *pMe)
2682{
2683 if(pMe->uLastError != QCBOR_SUCCESS) {
2684 // Already in error state; do nothing.
2685 return;
2686 }
2687
2688 /* Get the data item that is the map that is being searched */
2689 QCBORItem Item;
2690 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
2691 if(pMe->uLastError != QCBOR_SUCCESS) {
2692 return;
2693 }
2694 if(Item.uDataType != QCBOR_TYPE_BYTE_STRING) {
2695 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
2696 return;
2697 }
2698
2699 // TODO: check for tag 24
2700
2701 // Need to move UIB input cursor to the right place
2702
2703 // Really this is a subtraction and an assignment; not much code
2704 // There is a range check in the seek.
2705 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
2706
2707 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset - Item.val.string.len);
2708
2709 UsefulInputBuf_SetBufferLen(&(pMe->InBuf), uEndOffset);
2710
2711 // TODO: comment on cast
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002712 pMe->uLastError = (uint8_t)DecodeNesting_Descend(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING, UINT16_MAX, (uint32_t)uEndOffset);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002713}
2714
2715
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002716
Laurence Lundbladee6430642020-03-14 21:15:44 -07002717
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002718
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002719
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002720
Laurence Lundblade11a064e2020-05-07 13:13:42 -07002721
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002722
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002723static QCBORError InterpretBool(const QCBORItem *pItem, bool *pBool)
2724{
2725 switch(pItem->uDataType) {
2726 case QCBOR_TYPE_TRUE:
2727 *pBool = true;
2728 return QCBOR_SUCCESS;
2729 break;
2730
2731 case QCBOR_TYPE_FALSE:
2732 *pBool = false;
2733 return QCBOR_SUCCESS;
2734 break;
2735
2736 default:
2737 return QCBOR_ERR_UNEXPECTED_TYPE;
2738 break;
2739 }
2740}
Laurence Lundbladee6430642020-03-14 21:15:44 -07002741
Laurence Lundbladec4537442020-04-14 18:53:22 -07002742void QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002743{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002744 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002745 // Already in error state, do nothing
Laurence Lundbladee6430642020-03-14 21:15:44 -07002746 return;
2747 }
2748
Laurence Lundbladec4537442020-04-14 18:53:22 -07002749 QCBORError nError;
2750 QCBORItem Item;
2751
2752 nError = QCBORDecode_GetNext(pMe, &Item);
2753 if(nError != QCBOR_SUCCESS) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002754 pMe->uLastError = (uint8_t)nError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002755 return;
2756 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002757 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002758}
2759
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002760void QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe, int64_t nLabel, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002761{
2762 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002763 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002764
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002765 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002766}
2767
2768
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002769void QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, bool *pValue)
2770{
2771 QCBORItem Item;
2772 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
2773
2774 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
2775}
2776
2777
2778
2779void QCBORDecode_GetTaggedStringInternal(QCBORDecodeContext *pMe, TagSpecification TagSpec, UsefulBufC *pBstr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002780{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002781 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002782 // Already in error state, do nothing
2783 return;
2784 }
2785
2786 QCBORError nError;
2787 QCBORItem Item;
2788
2789 nError = QCBORDecode_GetNext(pMe, &Item);
2790 if(nError != QCBOR_SUCCESS) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002791 pMe->uLastError = (uint8_t)nError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002792 return;
2793 }
2794
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002795 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, Item.uDataType);
2796
2797 if(pMe->uLastError == QCBOR_SUCCESS) {
2798 *pBstr = Item.val.string;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002799 }
2800}
2801
Laurence Lundbladec4537442020-04-14 18:53:22 -07002802
2803
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002804
2805static QCBORError ConvertBigNum(const QCBORItem *pItem, UsefulBufC *pValue, bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002806{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002807 *pbIsNegative = false;
2808
2809 bool bMustBeTagged = true; // TODO: fix this
2810
2811 switch(pItem->uDataType) {
2812 case QCBOR_TYPE_BYTE_STRING:
2813 // TODO: check that there is no tag here?
2814 if(bMustBeTagged) {
2815 return QCBOR_ERR_UNEXPECTED_TYPE;
2816 } else {
2817 *pValue = pItem->val.string;
2818 return QCBOR_SUCCESS;
2819 }
2820 break;
2821
2822 case QCBOR_TYPE_POSBIGNUM:
2823 *pValue = pItem->val.string;
2824 return QCBOR_SUCCESS;
2825 break;
2826
2827 case QCBOR_TYPE_NEGBIGNUM:
2828 *pbIsNegative = true;
2829 *pValue = pItem->val.string;
2830 return QCBOR_SUCCESS;
2831 break;
2832
2833 default:
2834 return QCBOR_ERR_UNEXPECTED_TYPE;
2835 break;
2836 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002837}
2838
2839
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002840/**
2841 @param[in] bMustBeTagged If \c true, then the data item must be tagged as either
2842 a positive or negative bignum. If \c false, then it only must be a byte string and bIsNegative
2843 will always be false on the asumption that it is positive, but it can be interpretted as
2844 negative if the the sign is know from other context.
2845 @param[out] pValue The bytes that make up the big num
2846 @param[out] pbIsNegative \c true if tagged as a negative big num. \c false otherwise.
2847
2848 if bMustBeTagged is false, then this will succeed if the data item is a plain byte string,
2849 a positive big num or a negative big num.
2850
2851 */
2852void QCBORDecode_GetBignum(QCBORDecodeContext *pMe, bool bMustBeTagged, UsefulBufC *pValue, bool *pbIsNegative)
2853{
2854 if(pMe->uLastError != QCBOR_SUCCESS) {
2855 // Already in error state, do nothing
2856 return;
2857 }
2858
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002859 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002860 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
2861 if(uError != QCBOR_SUCCESS) {
2862 pMe->uLastError = (uint8_t)uError;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002863 return;
2864 }
2865
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002866 pMe->uLastError = (uint8_t)ConvertBigNum(&Item, pValue, pbIsNegative);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002867}
2868
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002869void QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe, int64_t nLabel, bool bMustBeTagged, UsefulBufC *pValue, bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002870{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002871 QCBORItem Item;
2872 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002873
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002874 pMe->uLastError = (uint8_t)ConvertBigNum(&Item, pValue, pbIsNegative);
Laurence Lundbladec4537442020-04-14 18:53:22 -07002875}
2876
Laurence Lundbladec4537442020-04-14 18:53:22 -07002877
2878
2879
Laurence Lundbladee6430642020-03-14 21:15:44 -07002880
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002881typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002882
2883
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002884// The main exponentiator that works on only positive numbers
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002885static QCBORError Exponentitate10(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002886{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002887 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002888
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002889 if(uResult != 0) {
2890 /* This loop will run a maximum of 19 times because
2891 * UINT64_MAX < 10 ^^ 19. More than that will cause
2892 * exit with the overflow error
2893 */
2894 for(; nExponent > 0; nExponent--) {
2895 if(uResult > UINT64_MAX / 10) {
2896 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Error overflow
2897 }
2898 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002899 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002900
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002901 for(; nExponent < 0; nExponent++) {
2902 uResult = uResult / 10;
2903 if(uResult == 0) {
2904 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Underflow error
2905 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002906 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002907 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002908 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07002909
2910 *puResult = uResult;
2911
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002912 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002913}
2914
2915
Laurence Lundbladee6430642020-03-14 21:15:44 -07002916/* Convert a decimal fraction to an int64_t without using
2917 floating point or math libraries. Most decimal fractions
2918 will not fit in an int64_t and this will error out with
2919 under or overflow
2920 */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002921static QCBORError Exponentitate2(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002922{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002923 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002924
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002925 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002926
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002927 /* This loop will run a maximum of 64 times because
Laurence Lundbladee6430642020-03-14 21:15:44 -07002928 * INT64_MAX < 2^31. More than that will cause
2929 * exist with the overflow error
2930 */
2931 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002932 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002933 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Error overflow
Laurence Lundbladee6430642020-03-14 21:15:44 -07002934 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002935 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002936 nExponent--;
2937 }
2938
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002939 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002940 if(uResult == 0) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002941 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Underflow error
2942 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002943 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002944 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002945 }
2946
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002947 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002948
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002949 return QCBOR_SUCCESS;
2950}
2951
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002952/*
2953 Compute value with signed mantissa and signed result. Works with exponent of 2 or 10 based on exponentiator.
2954 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002955static inline QCBORError ExponentiateNN(int64_t nMantissa, int64_t nExponent, int64_t *pnResult, fExponentiator pfExp)
2956{
2957 uint64_t uResult;
2958
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002959 // Take the absolute value of the mantissa and convert to unsigned.
2960 // TODO: this should be possible in one intruction
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002961 uint64_t uMantissa = nMantissa > 0 ? (uint64_t)nMantissa : (uint64_t)-nMantissa;
2962
2963 // Do the exponentiation of the positive mantissa
2964 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
2965 if(uReturn) {
2966 return uReturn;
2967 }
2968
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002969
Laurence Lundblade983500d2020-05-14 11:49:34 -07002970 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
2971 of INT64_MIN. This assumes two's compliment representation where
2972 INT64_MIN is one increment farther from 0 than INT64_MAX.
2973 Trying to write -INT64_MIN doesn't work to get this because the
2974 compiler tries to work with an int64_t which can't represent
2975 -INT64_MIN.
2976 */
2977 uint64_t uMax = nMantissa > 0 ? INT64_MAX : (uint64_t)INT64_MAX+1;
2978
2979 // Error out if too large
2980 if(uResult > uMax) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002981 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
2982 }
2983
2984 // Casts are safe because of checks above
2985 *pnResult = nMantissa > 0 ? (int64_t)uResult : -(int64_t)uResult;
2986
2987 return QCBOR_SUCCESS;
2988}
2989
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002990/*
2991 Compute value with signed mantissa and unsigned result. Works with exponent of 2 or 10 based on exponentiator.
2992 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002993static inline QCBORError ExponentitateNU(int64_t nMantissa, int64_t nExponent, uint64_t *puResult, fExponentiator pfExp)
2994{
2995 if(nMantissa < 0) {
2996 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
2997 }
2998
2999 // Cast to unsigned is OK because of check for negative
3000 // Cast to unsigned is OK because UINT64_MAX > INT64_MAX
3001 // Exponentiation is straight forward
3002 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
3003}
3004
3005
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003006#include <math.h>
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003007
3008
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003009static QCBORError ConvertBigNumToUnsigned(const UsefulBufC BigNum, uint64_t uMax, uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003010{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003011 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003012
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003013 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003014 const uint8_t *pByte = BigNum.ptr;
3015 size_t uLen = BigNum.len;
3016 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07003017 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003018 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003019 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07003020 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003021 }
3022
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003023 *pResult = uResult;
3024 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003025}
3026
Laurence Lundblade887add82020-05-17 05:50:34 -07003027static inline QCBORError ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum, uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003028{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003029 return ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003030}
3031
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003032static inline QCBORError ConvertPositiveBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003033{
3034 uint64_t uResult;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003035 QCBORError uError = ConvertBigNumToUnsigned(BigNum, INT64_MAX, &uResult);
3036 if(uError) {
3037 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003038 }
3039 /* Cast is safe because ConvertBigNum is told to limit to INT64_MAX */
3040 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003041 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003042}
3043
3044
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003045static inline QCBORError ConvertNegativeBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003046{
3047 uint64_t uResult;
Laurence Lundbladeda095972020-06-06 18:35:33 -07003048 /* negaative int furthest from zero is INT64_MIN
3049 which is expressed as -INT64_MAX-1. The value of
3050 a negative bignum is -n-1, one further from zero
3051 than the positive bignum */
3052
3053 /* say INT64_MIN is -2; then INT64_MAX is 1.
3054 Then -n-1 <= INT64_MIN.
3055 Then -n -1 <= -INT64_MAX - 1
3056 THen n <= INT64_MAX. */
3057 QCBORError uError = ConvertBigNumToUnsigned(BigNum, INT64_MAX, &uResult);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003058 if(uError) {
3059 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003060 }
3061 /* Cast is safe because ConvertBigNum is told to limit to INT64_MAX */
Laurence Lundblade887add82020-05-17 05:50:34 -07003062 // TODO: this code is incorrect. See RFC 7049
Laurence Lundbladeda095972020-06-06 18:35:33 -07003063 uResult++; // this is the -1 in -n-1
Laurence Lundbladee6430642020-03-14 21:15:44 -07003064 *pResult = -(int64_t)uResult;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003065 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003066}
3067
Laurence Lundbladef6c86662020-05-12 02:08:00 -07003068#include "fenv.h"
Laurence Lundbladec4537442020-04-14 18:53:22 -07003069
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003070
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003071/*
3072Convert a integers and floats to an int64_t.
3073
3074\param[in] uOptions Bit mask list of conversion options.
3075
3076\retval QCBOR_ERR_CONVERSION_NOT_REQUESTED Conversion, possible, but not requested in uOptions.
3077
3078\retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
3079
3080\retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large or too small.
3081
3082*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003083static QCBORError ConvertInt64(const QCBORItem *pItem, uint32_t uOptions, int64_t *pnValue)
3084{
3085 switch(pItem->uDataType) {
3086 // TODO: float when ifdefs are set
3087 case QCBOR_TYPE_DOUBLE:
3088 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3089 // TODO: what about under/overflow here?
3090 // Invokes the floating-point HW and/or compiler-added libraries
3091 feclearexcept(FE_ALL_EXCEPT);
3092 *pnValue = llround(pItem->val.dfnum);
3093 if(fetestexcept(FE_INVALID)) {
3094 // TODO: better error code
3095 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3096 }
3097 } else {
3098 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3099 }
3100 break;
3101
3102 case QCBOR_TYPE_INT64:
3103 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
3104 *pnValue = pItem->val.int64;
3105 } else {
3106 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3107 }
3108 break;
3109
3110 case QCBOR_TYPE_UINT64:
3111 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
3112 if(pItem->val.uint64 < INT64_MAX) {
3113 *pnValue = pItem->val.int64;
3114 } else {
3115 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3116 }
3117 } else {
3118 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3119 }
3120 break;
3121
3122 default:
3123 return QCBOR_ERR_UNEXPECTED_TYPE;
3124 }
3125 return QCBOR_SUCCESS;
3126}
3127
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003128
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003129void QCBORDecode_GetInt64ConvertInternal(QCBORDecodeContext *pMe,
3130 uint32_t uOptions,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003131 int64_t *pnValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003132 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003133{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07003134 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003135 return;
3136 }
3137
Laurence Lundbladee6430642020-03-14 21:15:44 -07003138 QCBORItem Item;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003139 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
3140 if(uError) {
3141 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003142 return;
3143 }
3144
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003145 if(pItem) {
3146 *pItem = Item;
3147 }
3148
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003149 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003150}
3151
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003152
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003153void QCBORDecode_GetInt64ConvertInternalInMapN(QCBORDecodeContext *pMe,
3154 int64_t nLabel,
3155 uint32_t uOptions,
3156 int64_t *pnValue,
3157 QCBORItem *pItem)
3158{
3159 QCBORItem Item;
3160 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
3161
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003162 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003163}
3164
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003165
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003166void QCBORDecode_GetInt64ConvertInternalInMapSZ(QCBORDecodeContext *pMe,
3167 const char * szLabel,
3168 uint32_t uOptions,
3169 int64_t *pnValue,
3170 QCBORItem *pItem)
3171{
3172 if(pMe->uLastError != QCBOR_SUCCESS) {
3173 return;
3174 }
3175
3176 QCBORItem Item;
3177 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3178
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003179 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003180}
3181
3182
3183
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003184/*
3185 Convert a large variety of integer types to an int64_t.
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003186
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003187 \param[in] uOptions Bit mask list of conversion options.
3188
3189 \retval QCBOR_ERR_CONVERSION_NOT_REQUESTED Conversion, possible, but not requested in uOptions.
3190
3191 \retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
3192
3193 \retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large or too small.
3194
3195 */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003196static QCBORError Int64ConvertAll(const QCBORItem *pItem, uint32_t uOptions, int64_t *pnValue)
3197{
3198 QCBORError uErr;
3199
3200 switch(pItem->uDataType) {
3201
3202 case QCBOR_TYPE_POSBIGNUM:
3203 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3204 return ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003205 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003206 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003207 }
3208 break;
3209
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003210 case QCBOR_TYPE_NEGBIGNUM:
3211 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3212 return ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003213 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003214 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003215 }
3216 break;
3217
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003218#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
3219 case QCBOR_TYPE_DECIMAL_FRACTION:
3220 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3221 return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
3222 pItem->val.expAndMantissa.nExponent,
3223 pnValue,
3224 &Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003225 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003226 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3227 }
3228 break;
3229
3230 case QCBOR_TYPE_BIGFLOAT:
3231 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3232 return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
3233 pItem->val.expAndMantissa.nExponent,
3234 pnValue,
3235 Exponentitate2);
3236 } else {
3237 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3238 }
3239 break;
3240
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003241 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
3242 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3243 int64_t nMantissa;
3244 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3245 if(uErr) {
3246 return uErr;
3247 }
3248 return ExponentiateNN(nMantissa,
3249 pItem->val.expAndMantissa.nExponent,
3250 pnValue,
3251 Exponentitate10);
3252 } else {
3253 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3254 }
3255 break;
3256
3257 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
3258 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3259 int64_t nMantissa;
3260 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3261 if(uErr) {
3262 return uErr;
3263 }
3264 return ExponentiateNN(nMantissa,
3265 pItem->val.expAndMantissa.nExponent,
3266 pnValue,
3267 Exponentitate10);
3268 } else {
3269 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3270 }
3271 break;
3272
3273 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
3274 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3275 int64_t nMantissa;
3276 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3277 if(uErr) {
3278 return uErr;
3279 }
3280 return ExponentiateNN(nMantissa,
3281 pItem->val.expAndMantissa.nExponent,
3282 pnValue,
3283 Exponentitate2);
3284 } else {
3285 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3286 }
3287 break;
3288
3289 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
3290 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3291 int64_t nMantissa;
3292 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3293 if(uErr) {
3294 return uErr;
3295 }
3296 return ExponentiateNN(nMantissa,
3297 pItem->val.expAndMantissa.nExponent,
3298 pnValue,
3299 Exponentitate2);
3300 } else {
3301 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003302 }
3303 break;
3304
Laurence Lundbladec4537442020-04-14 18:53:22 -07003305 default:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003306 return QCBOR_ERR_UNEXPECTED_TYPE;
3307#endif
Laurence Lundbladec4537442020-04-14 18:53:22 -07003308 }
3309}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003310
3311
Laurence Lundbladec4537442020-04-14 18:53:22 -07003312/*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003313 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003314 */
3315void QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003316{
3317 QCBORItem Item;
3318
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003319 QCBORDecode_GetInt64ConvertInternal(pMe, uOptions, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003320
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003321 if(pMe->uLastError == QCBOR_SUCCESS) {
3322 // The above conversion succeeded
3323 return;
3324 }
3325
Laurence Lundbladef6c86662020-05-12 02:08:00 -07003326 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003327 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07003328 return;
3329 }
3330
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003331 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003332}
3333
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003334
3335/*
3336Public function, see header qcbor/qcbor_decode.h file
3337*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003338void QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, int64_t *pnValue)
3339{
3340 QCBORItem Item;
3341
3342 QCBORDecode_GetInt64ConvertInternalInMapN(pMe, nLabel, uOptions, pnValue, &Item);
3343
3344 if(pMe->uLastError == QCBOR_SUCCESS) {
3345 // The above conversion succeeded
3346 return;
3347 }
3348
3349 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3350 // The above conversion failed in a way that code below can't correct
3351 return;
3352 }
3353
3354 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
3355}
3356
3357
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003358/*
3359Public function, see header qcbor/qcbor_decode.h file
3360*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003361void QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, int64_t *pnValue)
3362{
3363 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003364 QCBORDecode_GetInt64ConvertInternalInMapSZ(pMe, szLabel, uOptions, pnValue, &Item);
3365
3366 if(pMe->uLastError == QCBOR_SUCCESS) {
3367 // The above conversion succeeded
3368 return;
3369 }
3370
3371 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3372 // The above conversion failed in a way that code below can't correct
3373 return;
3374 }
3375
3376 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
3377}
3378
3379
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003380static QCBORError ConvertUint64(const QCBORItem *pItem, uint32_t uOptions, uint64_t *puValue)
3381{
3382 switch(pItem->uDataType) {
3383 // TODO: type flaot
3384 case QCBOR_TYPE_DOUBLE:
3385 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3386 feclearexcept(FE_ALL_EXCEPT);
3387 double dRounded = round(pItem->val.dfnum);
3388 // TODO: over/underflow
3389 if(fetestexcept(FE_INVALID)) {
3390 // TODO: better error code
3391 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3392 } else if(isnan(dRounded)) {
3393 // TODO: better error code
3394 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3395 } else if(dRounded >= 0) {
3396 *puValue = (uint64_t)dRounded;
3397 } else {
3398 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3399 }
3400 } else {
3401 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3402 }
3403 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003404
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003405 case QCBOR_TYPE_INT64:
3406 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
3407 if(pItem->val.int64 >= 0) {
3408 *puValue = (uint64_t)pItem->val.int64;
3409 } else {
3410 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3411 }
3412 } else {
3413 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3414 }
3415 break;
3416
3417 case QCBOR_TYPE_UINT64:
3418 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
3419 *puValue = pItem->val.uint64;
3420 } else {
3421 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3422 }
3423 break;
3424
3425 default:
3426 return QCBOR_ERR_UNEXPECTED_TYPE;
3427 }
3428 return QCBOR_SUCCESS;
3429}
Laurence Lundbladec4537442020-04-14 18:53:22 -07003430
3431
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003432void QCBORDecode_GetUInt64ConvertInternal(QCBORDecodeContext *pMe,
3433 uint32_t uOptions,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003434 uint64_t *puValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003435 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003436{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003437 if(pMe->uLastError != QCBOR_SUCCESS) {
3438 return;
3439 }
3440
Laurence Lundbladec4537442020-04-14 18:53:22 -07003441 QCBORItem Item;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003442
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003443 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
3444 if(uError) {
3445 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003446 return;
3447 }
3448
Laurence Lundbladea826c502020-05-10 21:07:00 -07003449 if(pItem) {
3450 *pItem = Item;
3451 }
3452
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003453 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003454}
3455
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003456
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003457void QCBORDecode_GetUint64ConvertInternalInMapN(QCBORDecodeContext *pMe,
3458 int64_t nLabel,
3459 uint32_t uOptions,
3460 uint64_t *puValue,
3461 QCBORItem *pItem)
3462{
3463 QCBORItem Item;
3464 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
3465
3466 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
3467}
3468
3469
3470void QCBORDecode_GetUint64ConvertInternalInMapSZ(QCBORDecodeContext *pMe,
3471 const char * szLabel,
3472 uint32_t uOptions,
3473 uint64_t *puValue,
3474 QCBORItem *pItem)
3475{
3476 if(pMe->uLastError != QCBOR_SUCCESS) {
3477 return;
3478 }
3479
3480 QCBORItem Item;
3481 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3482
3483 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
3484}
3485
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003486/*
3487 Public function, see header qcbor/qcbor_decode.h file
3488*/
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003489static QCBORError Uint64ConvertAll(const QCBORItem *pItem, uint32_t uOptions, uint64_t *puValue)
3490{
3491 QCBORError uErr;
3492
3493 switch(pItem->uDataType) {
3494
3495 case QCBOR_TYPE_POSBIGNUM:
3496 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3497 return ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
3498 } else {
3499 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3500 }
3501 break;
3502
3503 case QCBOR_TYPE_NEGBIGNUM:
3504 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3505 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3506 } else {
3507 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3508 }
3509 break;
3510
3511#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
3512
3513 case QCBOR_TYPE_DECIMAL_FRACTION:
3514 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3515 return ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
3516 pItem->val.expAndMantissa.nExponent,
3517 puValue,
3518 Exponentitate10);
3519 } else {
3520 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3521 }
3522 break;
3523
3524 case QCBOR_TYPE_BIGFLOAT:
3525 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3526 return ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
3527 pItem->val.expAndMantissa.nExponent,
3528 puValue,
3529 Exponentitate2);
3530 } else {
3531 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3532 }
3533 break;
3534
3535 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
3536 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3537 // TODO: Would be better to convert to unsigned
3538 int64_t nMantissa;
3539 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3540 if(uErr != QCBOR_SUCCESS) {
3541 return uErr;
3542 }
3543 return ExponentitateNU(nMantissa,
3544 pItem->val.expAndMantissa.nExponent,
3545 puValue,
3546 Exponentitate10);
3547 } else {
3548 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3549 }
3550 break;
3551
3552 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
3553 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3554 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3555 } else {
3556 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3557 }
3558 break;
3559
3560 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
3561 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3562 // TODO: Would be better to convert to unsigned
3563 int64_t nMantissa;
3564 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3565 if(uErr != QCBOR_SUCCESS) {
3566 return uErr;
3567 }
3568 return ExponentitateNU(nMantissa,
3569 pItem->val.expAndMantissa.nExponent,
3570 puValue,
3571 Exponentitate2);
3572 } else {
3573 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3574 }
3575 break;
3576
3577 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
3578 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3579 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3580 } else {
3581 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3582 }
3583 break;
3584#endif
3585 default:
3586 return QCBOR_ERR_UNEXPECTED_TYPE;
3587 }
3588}
3589
3590
3591void QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003592{
3593 QCBORItem Item;
3594
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003595 QCBORDecode_GetUInt64ConvertInternal(pMe, uOptions, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003596
Laurence Lundbladef6c86662020-05-12 02:08:00 -07003597 if(pMe->uLastError == QCBOR_SUCCESS) {
3598 // The above conversion succeeded
3599 return;
3600 }
3601
3602 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3603 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07003604 return;
3605 }
3606
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003607 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003608}
3609
Laurence Lundbladec4537442020-04-14 18:53:22 -07003610
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003611/*
3612Public function, see header qcbor/qcbor_decode.h file
3613*/
3614void QCBORDecode_GetUint64ConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, uint64_t *puValue)
3615{
3616 QCBORItem Item;
3617
3618 QCBORDecode_GetUint64ConvertInternalInMapN(pMe, nLabel, uOptions, puValue, &Item);
3619
3620 if(pMe->uLastError == QCBOR_SUCCESS) {
3621 // The above conversion succeeded
3622 return;
3623 }
3624
3625 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3626 // The above conversion failed in a way that code below can't correct
3627 return;
3628 }
3629
3630 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
3631}
3632
3633
3634/*
3635Public function, see header qcbor/qcbor_decode.h file
3636*/
3637void QCBORDecode_GetUint64ConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, uint64_t *puValue)
3638{
3639 QCBORItem Item;
3640 QCBORDecode_GetUint64ConvertInternalInMapSZ(pMe, szLabel, uOptions, puValue, &Item);
3641
3642 if(pMe->uLastError == QCBOR_SUCCESS) {
3643 // The above conversion succeeded
3644 return;
3645 }
3646
3647 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3648 // The above conversion failed in a way that code below can't correct
3649 return;
3650 }
3651
3652 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
3653}
3654
3655
3656static QCBORError ConvertDouble(const QCBORItem *pItem, uint32_t uOptions, double *pdValue)
3657{
3658 switch(pItem->uDataType) {
3659 // TODO: float when ifdefs are set
3660 case QCBOR_TYPE_DOUBLE:
3661 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3662 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3663 *pdValue = pItem->val.dfnum;
3664 } else {
3665 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3666 }
3667 }
3668 break;
3669
3670 case QCBOR_TYPE_INT64:
3671 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
3672 // TODO: how does this work?
3673 *pdValue = (double)pItem->val.int64;
3674
3675 } else {
3676 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3677 }
3678 break;
3679
3680 case QCBOR_TYPE_UINT64:
3681 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
3682 *pdValue = (double)pItem->val.uint64;
3683 } else {
3684 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3685 }
3686 break;
3687
3688 default:
3689 return QCBOR_ERR_UNEXPECTED_TYPE;
3690 }
3691
3692 return QCBOR_SUCCESS;
3693}
3694
3695
3696
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003697void QCBORDecode_GetDoubleConvertInternal(QCBORDecodeContext *pMe,
3698 uint32_t uOptions,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003699 double *pdValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003700 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003701{
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003702 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003703 return;
3704 }
3705
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003706 QCBORItem Item;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003707
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003708 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003709 if(uError) {
3710 pMe->uLastError = (uint8_t)uError;
3711 return;
3712 }
3713
3714 if(pItem) {
3715 *pItem = Item;
3716 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07003717
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003718 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003719}
Laurence Lundbladec4537442020-04-14 18:53:22 -07003720
Laurence Lundbladec4537442020-04-14 18:53:22 -07003721
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003722void QCBORDecode_GetDoubleConvertInternalInMapN(QCBORDecodeContext *pMe,
3723 int64_t nLabel,
3724 uint32_t uOptions,
3725 double *pdValue,
3726 QCBORItem *pItem)
3727{
3728 QCBORItem Item;
3729 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
3730
3731 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
3732}
3733
3734void QCBORDecode_GetDoubleConvertInternalInMapSZ(QCBORDecodeContext *pMe,
3735 const char * szLabel,
3736 uint32_t uOptions,
3737 double *pdValue,
3738 QCBORItem *pItem)
3739{
3740 if(pMe->uLastError != QCBOR_SUCCESS) {
3741 return;
3742 }
3743
3744 QCBORItem Item;
3745 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3746
3747 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
3748}
3749
3750
3751
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003752static double ConvertBigNumToDouble(const UsefulBufC BigNum)
3753{
3754 double dResult;
3755
3756 dResult = 0.0;
3757 const uint8_t *pByte = BigNum.ptr;
3758 size_t uLen = BigNum.len;
3759 /* This will overflow and become the float value INFINITY if the number
3760 is too large to fit. No error will be logged.
3761 TODO: should an error be logged? */
3762 while(uLen--) {
3763 dResult = (dResult * 256.0) + (double)*pByte++;
3764 }
3765
3766 return dResult;
3767}
3768
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003769static QCBORError DoubleConvertAll(const QCBORItem *pItem, uint32_t uOptions, double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003770{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003771 /*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003772 https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
3773
3774 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003775 switch(pItem->uDataType) {
3776 // TODO: type float
3777 case QCBOR_TYPE_DECIMAL_FRACTION:
3778 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3779 // TODO: rounding and overflow errors
3780 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
3781 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
3782 } else {
3783 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3784 }
3785 break;
3786
3787 case QCBOR_TYPE_BIGFLOAT:
3788 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
3789 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
3790 exp2((double)pItem->val.expAndMantissa.nExponent);
3791 } else {
3792 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3793 }
3794 break;
3795
3796 case QCBOR_TYPE_POSBIGNUM:
3797 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3798 *pdValue = ConvertBigNumToDouble(pItem->val.bigNum);
3799 } else {
3800 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3801 }
3802 break;
3803
3804 case QCBOR_TYPE_NEGBIGNUM:
3805 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07003806 *pdValue = -1-ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003807 } else {
3808 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3809 }
3810 break;
3811
3812 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
3813 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3814 double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
3815 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
3816 } else {
3817 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3818 }
3819 break;
3820
3821 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
3822 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3823 double dMantissa = -ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
3824 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
3825 } else {
3826 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3827 }
3828 break;
3829
3830 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
3831 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3832 double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
3833 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
3834 } else {
3835 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3836 }
3837 break;
3838
3839 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
3840 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07003841 double dMantissa = -1-ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003842 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
3843 } else {
3844 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3845 }
3846 break;
3847
3848 default:
3849 return QCBOR_ERR_UNEXPECTED_TYPE;
3850 }
3851
3852 return QCBOR_SUCCESS;
3853}
3854
3855
3856/*
3857 Public function, see header qcbor/qcbor_decode.h file
3858*/
3859void QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, double *pdValue)
3860{
3861
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003862 QCBORItem Item;
3863
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003864 QCBORDecode_GetDoubleConvertInternal(pMe, uOptions, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003865
3866 if(pMe->uLastError == QCBOR_SUCCESS) {
3867 // The above conversion succeeded
3868 return;
3869 }
3870
3871 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3872 // The above conversion failed in a way that code below can't correct
3873 return;
3874 }
3875
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003876 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003877}
3878
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003879
3880/*
3881Public function, see header qcbor/qcbor_decode.h file
3882*/
3883void QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, double *pdValue)
3884{
3885 QCBORItem Item;
3886
3887 QCBORDecode_GetDoubleConvertInternalInMapN(pMe, nLabel, uOptions, pdValue, &Item);
3888
3889 if(pMe->uLastError == QCBOR_SUCCESS) {
3890 // The above conversion succeeded
3891 return;
3892 }
3893
3894 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3895 // The above conversion failed in a way that code below can't correct
3896 return;
3897 }
3898
3899 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
3900}
3901
3902
3903/*
3904Public function, see header qcbor/qcbor_decode.h file
3905*/
3906void QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, double *pdValue)
3907{
3908 QCBORItem Item;
3909 QCBORDecode_GetDoubleConvertInternalInMapSZ(pMe, szLabel, uOptions, pdValue, &Item);
3910
3911 if(pMe->uLastError == QCBOR_SUCCESS) {
3912 // The above conversion succeeded
3913 return;
3914 }
3915
3916 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3917 // The above conversion failed in a way that code below can't correct
3918 return;
3919 }
3920
3921 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
3922}