blob: 0bd481b6687355afa47156d3b0094ec646b16cc5 [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
135inline static bool InBoundMode(const QCBORDecodeNesting *pNesting)
136{
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 Lundblade24d509a2020-06-06 18:43:15 -0700169 if(pNesting->pCurrentMap && InBoundMode(pNesting)) {
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700170 if(pNesting->pCurrentMap->uCount == 0) {
Laurence Lundblade937ea812020-05-08 11:38:23 -0700171 // TODO: won't work for indefinite length
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700172 // In map mode and consumed all items, so it is the end
173 return true;
174 } else {
175 // In map mode, all items not consumed, so it is NOT the end
176 return false;
177 }
178 } else {
Laurence Lundblade937ea812020-05-08 11:38:23 -0700179 // Not in map mode. The end is determined in other ways.
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700180 return false;
181 }
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700182}
183
184
Laurence Lundbladeee851742020-01-08 08:37:05 -0800185inline static int
186DecodeNesting_IsIndefiniteLength(const QCBORDecodeNesting *pNesting)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700187{
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700188 return pNesting->pCurrent->uCount == UINT16_MAX;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700189 //return pNesting->pCurrent->uType & QCBOR_NEST_TYPE_IS_INDEFINITE;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700190}
191
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700192inline static int
193DecodeNesting_InMapMode(const QCBORDecodeNesting *pNesting)
194{
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700195 return (bool)InBoundMode(pNesting);
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700196}
197
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700198
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800199
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700200inline static uint8_t
201DecodeNesting_GetMapModeLevel(QCBORDecodeNesting *pNesting)
202{
203 // Check in DecodeNesting_Descend and never having
204 // QCBOR_MAX_ARRAY_NESTING > 255 gaurantees cast is safe
205 return (uint8_t)(pNesting->pCurrentMap - &(pNesting->pMapsAndArrays[0]));
206}
207
Laurence Lundbladeee851742020-01-08 08:37:05 -0800208inline static int
209DecodeNesting_TypeIsMap(const QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700210{
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700211 if(DecodeNesting_IsAtTop(pNesting)) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700212 return 0;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700213 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800214
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700215 return CBOR_MAJOR_TYPE_MAP == pNesting->pCurrent->uMajorType;
216}
217
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800218// Process a break. This will either ascend the nesting or error out
Laurence Lundbladeee851742020-01-08 08:37:05 -0800219inline static QCBORError
220DecodeNesting_BreakAscend(QCBORDecodeNesting *pNesting)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700221{
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800222 // breaks must always occur when there is nesting
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700223 if(DecodeNesting_IsAtTop(pNesting)) {
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800224 return QCBOR_ERR_BAD_BREAK;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700225 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800226
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800227 // breaks can only occur when the map/array is indefinite length
228 if(!DecodeNesting_IsIndefiniteLength(pNesting)) {
229 return QCBOR_ERR_BAD_BREAK;
230 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800231
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700232 if(InBoundMode(pNesting)) {
233 return QCBOR_SUCCESS;
234 }
235
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800236 // if all OK, the break reduces the level of nesting
237 pNesting->pCurrent--;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800238
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800239 return QCBOR_SUCCESS;
240}
241
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700242// Called on every single item except breaks including decode of a map/array
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700243/* Decrements the map/array counter if possible. If decrement
244 closed out a map or array, then level up in nesting and decrement
245 again, until, the top is reached or the end of a map mode is reached
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700246
247 return 1 if leveld up, 0 if not
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700248 */
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700249inline static int
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700250DecodeNesting_DecrementCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800251{
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700252 int nReturn = 0;
253
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700254 while(!DecodeNesting_IsAtTop(pNesting)) {
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700255 // Not at the top level, so there is decrementing to be done.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800256
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700257 if(DecodeNesting_IsIndefiniteLength(pNesting)) {
258 // Indefinite lengths not handled here
259 break;
Laurence Lundblade9e3651c2018-10-10 11:49:55 +0800260 }
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700261
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700262 pNesting->pCurrent->uCount--;
263
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700264 if(pNesting->pCurrent->uCount != 0) {
265 // Did not close out an array or map, so nothing further
266 break;
267 }
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700268
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700269 if(InBoundMode(pNesting)) {
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700270 // In map mode the level-up must be done explicitly
271 break;
272 }
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700273
274 // Closed out an array or map so level up
275 pNesting->pCurrent--;
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700276 /*if(pNesting->pCurrent->uMapMode) {
277 // Bring the current map level along if new level is a map
278 // TODO: must search up until a mapmode level is found.
279 pNesting->pCurrentMap = pNesting->pCurrent;
280 } */
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700281
282 // Continue with loop to see if closing out this doesn't close out more
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700283 nReturn = 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700284 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700285 return nReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700286}
287
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700288inline static void
289DecodeNesting_EnterMapMode(QCBORDecodeNesting *pNesting, size_t uOffset)
290{
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700291 /* Have descended into this is called. The job here is just to mark it in bounded mode */
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700292 pNesting->pCurrentMap = pNesting->pCurrent;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700293 pNesting->pCurrentMap->uType |= QCBOR_NEST_TYPE_IS_BOUND;
294 // Cast to uint32_t is safe because QCBOR restricts encoded input to < UINT32_MAX
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700295 pNesting->pCurrentMap->uOffset = (uint32_t)uOffset;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700296}
297
298inline static void
299DecodeNesting_Exit(QCBORDecodeNesting *pNesting)
300{
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700301 pNesting->pCurrentMap->uType &= ~QCBOR_NEST_TYPE_IS_BOUND;
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700302 pNesting->pCurrent = pNesting->pCurrentMap - 1; // TODO error check
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700303
304 DecodeNesting_DecrementCount(pNesting);
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700305
306 while(1) {
307 pNesting->pCurrentMap--;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700308 if(InBoundMode(pNesting)) {
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700309 break;
310 }
311 if(pNesting->pCurrentMap == &(pNesting->pMapsAndArrays[0])) {
312 break;
313 }
314 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700315}
316
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800317// Called on every map/array
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700318QCBORError
Laurence Lundbladeee851742020-01-08 08:37:05 -0800319DecodeNesting_Descend(QCBORDecodeNesting *pNesting, QCBORItem *pItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700320{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700321 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800322
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800323 if(pItem->val.uCount == 0) {
324 // Nothing to do for empty definite lenth arrays. They are just are
325 // effectively the same as an item that is not a map or array
326 goto Done;
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530327 // Empty indefinite length maps and arrays are handled elsewhere
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800328 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800329
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800330 // Error out if arrays is too long to handle
331 if(pItem->val.uCount != UINT16_MAX && pItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700332 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
333 goto Done;
334 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800335
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800336 // Error out if nesting is too deep
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700337 if(pNesting->pCurrent >= &(pNesting->pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING])) {
338 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
339 goto Done;
340 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800341
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800342 // The actual descend
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700343 pNesting->pCurrent++;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800344
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800345 // Record a few details for this nesting level
346 pNesting->pCurrent->uMajorType = pItem->uDataType;
347 pNesting->pCurrent->uCount = pItem->val.uCount;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700348 pNesting->pCurrent->uSaveCount = pItem->val.uCount;
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700349 pNesting->pCurrent->uMapMode = 0;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800350
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700351Done:
352 return nReturn;;
353}
354
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700355inline static QCBORError
356DecodeNesting_Descend2(QCBORDecodeNesting *pNesting, uint8_t uQCBORType, uint64_t uCount, uint32_t uEndOffset)
357{
358 QCBORError nReturn = QCBOR_SUCCESS;
359
360 if(uCount == 0) {
361 // Nothing to do for empty definite lenth arrays. They are just are
362 // effectively the same as an item that is not a map or array
363 goto Done;
364 // Empty indefinite length maps and arrays are handled elsewhere
365 }
366
367 // Error out if arrays is too long to handle
368 if(uCount != UINT16_MAX && uCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
369 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
370 goto Done;
371 }
372
373 // Error out if nesting is too deep
374 if(pNesting->pCurrent >= &(pNesting->pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING])) {
375 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
376 goto Done;
377 }
378
379 // The actual descend
380 pNesting->pCurrent++;
381
382 // Fill in the new level fully
383 pNesting->pCurrent->uMajorType = uQCBORType;
384 pNesting->pCurrent->uCount = (uint16_t)uCount;
385 pNesting->pCurrent->uSaveCount = (uint16_t)uCount;
386 pNesting->pCurrent->uEndOffset = uEndOffset;
387 pNesting->pCurrent->uMapMode = 0;
388
389Done:
390 return nReturn;;
391}
392
393
394
Laurence Lundbladeee851742020-01-08 08:37:05 -0800395inline static void
396DecodeNesting_Init(QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700397{
398 pNesting->pCurrent = &(pNesting->pMapsAndArrays[0]);
399}
400
401
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700402static void DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting, QCBORDecodeNesting *pSave)
403{
404 *pSave = *pNesting;
405 pNesting->pCurrent = pNesting->pCurrentMap;
406
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700407 if(!DecodeNesting_IsIndefiniteLength(pNesting)) {
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700408 pNesting->pCurrent->uCount = pNesting->pCurrent->uSaveCount;
409 }
410}
411
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700412static inline void DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting, QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700413{
414 *pNesting = *pSave;
415}
416
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700417QCBORError DecodeNesting_EnterBstr(QCBORDecodeNesting *pNesting, uint32_t uEndOffset)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700418{
419 QCBORError uReturn ;
420
421 // Error out if nesting is too deep
422 if(pNesting->pCurrent >= &(pNesting->pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING])) {
423 uReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
424 goto Done;
425 }
426
427 // The actual descend
428 pNesting->pCurrent++;
429
430 // Record a few details for this nesting level
431 pNesting->pCurrent->uMajorType = 1; // TODO the right value for a bstr
432 pNesting->pCurrent->uCount = 0xffff;
433 pNesting->pCurrent->uSaveCount = 0xffff;
434 pNesting->pCurrent->uType = 0;
435
436 uReturn = QCBOR_SUCCESS;
437
438Done:
439 return uReturn;
440
441
442}
443
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700444
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700445
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700446
Laurence Lundbladeee851742020-01-08 08:37:05 -0800447/*===========================================================================
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800448 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
449
450 The following four functions are pretty wrappers for invocation of
451 the string allocator supplied by the caller.
452
Laurence Lundbladeee851742020-01-08 08:37:05 -0800453 ===========================================================================*/
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800454
Laurence Lundbladeee851742020-01-08 08:37:05 -0800455static inline void
456StringAllocator_Free(const QCORInternalAllocator *pMe, void *pMem)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800457{
458 (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, 0);
459}
460
Laurence Lundbladeee851742020-01-08 08:37:05 -0800461// StringAllocator_Reallocate called with pMem NULL is
462// equal to StringAllocator_Allocate()
463static inline UsefulBuf
464StringAllocator_Reallocate(const QCORInternalAllocator *pMe,
465 void *pMem,
466 size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800467{
468 return (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, uSize);
469}
470
Laurence Lundbladeee851742020-01-08 08:37:05 -0800471static inline UsefulBuf
472StringAllocator_Allocate(const QCORInternalAllocator *pMe, size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800473{
474 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
475}
476
Laurence Lundbladeee851742020-01-08 08:37:05 -0800477static inline void
478StringAllocator_Destruct(const QCORInternalAllocator *pMe)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800479{
480 if(pMe->pfAllocator) {
481 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
482 }
483}
484
485
486
Laurence Lundbladeee851742020-01-08 08:37:05 -0800487/*===========================================================================
488 QCBORDecode -- The main implementation of CBOR decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700489
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800490 See qcbor/qcbor_decode.h for definition of the object
491 used here: QCBORDecodeContext
Laurence Lundbladeee851742020-01-08 08:37:05 -0800492 ===========================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700493/*
494 Public function, see header file
495 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800496void QCBORDecode_Init(QCBORDecodeContext *me,
497 UsefulBufC EncodedCBOR,
498 QCBORDecodeMode nDecodeMode)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700499{
500 memset(me, 0, sizeof(QCBORDecodeContext));
501 UsefulInputBuf_Init(&(me->InBuf), EncodedCBOR);
Laurence Lundbladeee851742020-01-08 08:37:05 -0800502 // Don't bother with error check on decode mode. If a bad value is
503 // passed it will just act as if the default normal mode of 0 was set.
Laurence Lundbladee6bcef12020-04-01 10:56:27 -0700504 me->uDecodeMode = (uint8_t)nDecodeMode;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700505 DecodeNesting_Init(&(me->nesting));
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700506 for(int i = 0; i < QCBOR_NUM_MAPPED_TAGS; i++) {
507 me->auMappedTags[i] = 0xffff;
508 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700509}
510
511
512/*
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700513 Public function, see header file
514 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800515void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
516 QCBORStringAllocate pfAllocateFunction,
517 void *pAllocateContext,
518 bool bAllStrings)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700519{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800520 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
521 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
522 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700523}
524
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800525
526/*
527 Public function, see header file
528 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800529void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *me,
530 const QCBORTagListIn *pTagList)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700531{
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700532 // This does nothing now. It is retained for backwards compatibility
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700533}
534
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700535
536/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800537 This decodes the fundamental part of a CBOR data item, the type and
538 number
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800539
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700540 This is the Counterpart to InsertEncodedTypeAndNumber().
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800541
Laurence Lundbladeee851742020-01-08 08:37:05 -0800542 This does the network->host byte order conversion. The conversion
543 here also results in the conversion for floats in addition to that
544 for lengths, tags and integer values.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800545
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700546 This returns:
547 pnMajorType -- the major type for the item
Laurence Lundbladeee851742020-01-08 08:37:05 -0800548
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800549 puArgument -- the "number" which is used a the value for integers,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800550 tags and floats and length for strings and arrays
551
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800552 pnAdditionalInfo -- Pass this along to know what kind of float or
Laurence Lundbladeee851742020-01-08 08:37:05 -0800553 if length is indefinite
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800554
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800555 The int type is preferred to uint8_t for some variables as this
556 avoids integer promotions, can reduce code size and makes
557 static analyzers happier.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700558 */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800559inline static QCBORError DecodeTypeAndNumber(UsefulInputBuf *pUInBuf,
560 int *pnMajorType,
561 uint64_t *puArgument,
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800562 int *pnAdditionalInfo)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700563{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700564 QCBORError nReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800565
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700566 // Get the initial byte that every CBOR data item has
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800567 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800568
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700569 // Break down the initial byte
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800570 const int nTmpMajorType = nInitialByte >> 5;
571 const int nAdditionalInfo = nInitialByte & 0x1f;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800572
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800573 // Where the number or argument accumulates
574 uint64_t uArgument;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800575
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800576 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700577 // Need to get 1,2,4 or 8 additional argument bytes. Map
578 // LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800579 static const uint8_t aIterate[] = {1,2,4,8};
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800580
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800581 // Loop getting all the bytes in the argument
582 uArgument = 0;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800583 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800584 // This shift and add gives the endian conversion
585 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
586 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800587 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800588 // The reserved and thus-far unused additional info values
589 nReturn = QCBOR_ERR_UNSUPPORTED;
590 goto Done;
591 } else {
592 // Less than 24, additional info is argument or 31, an indefinite length
593 // No more bytes to get
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800594 uArgument = (uint64_t)nAdditionalInfo;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700595 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800596
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700597 if(UsefulInputBuf_GetError(pUInBuf)) {
598 nReturn = QCBOR_ERR_HIT_END;
599 goto Done;
600 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800601
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700602 // All successful if we got here.
603 nReturn = QCBOR_SUCCESS;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800604 *pnMajorType = nTmpMajorType;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800605 *puArgument = uArgument;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800606 *pnAdditionalInfo = nAdditionalInfo;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800607
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700608Done:
609 return nReturn;
610}
611
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800612
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700613/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800614 CBOR doesn't explicitly specify two's compliment for integers but all
615 CPUs use it these days and the test vectors in the RFC are so. All
616 integers in the CBOR structure are positive and the major type
617 indicates positive or negative. CBOR can express positive integers
618 up to 2^x - 1 where x is the number of bits and negative integers
619 down to 2^x. Note that negative numbers can be one more away from
620 zero than positive. Stdint, as far as I can tell, uses two's
621 compliment to represent negative integers.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800622
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700623 See http://www.unix.org/whitepapers/64bit.html for reasons int isn't
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800624 used carefully here, and in particular why it isn't used in the interface.
625 Also see
626 https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers
627
628 Int is used for values that need less than 16-bits and would be subject
629 to integer promotion and complaining by static analyzers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700630 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800631inline static QCBORError
632DecodeInteger(int nMajorType, uint64_t uNumber, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700633{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700634 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800635
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700636 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
637 if (uNumber <= INT64_MAX) {
638 pDecodedItem->val.int64 = (int64_t)uNumber;
639 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800640
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700641 } else {
642 pDecodedItem->val.uint64 = uNumber;
643 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800644
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700645 }
646 } else {
647 if(uNumber <= INT64_MAX) {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800648 // CBOR's representation of negative numbers lines up with the
649 // two-compliment representation. A negative integer has one
650 // more in range than a positive integer. INT64_MIN is
651 // equal to (-INT64_MAX) - 1.
652 pDecodedItem->val.int64 = (-(int64_t)uNumber) - 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700653 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800654
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700655 } else {
656 // C can't represent a negative integer in this range
Laurence Lundblade21d1d812019-09-28 22:47:49 -1000657 // so it is an error.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700658 nReturn = QCBOR_ERR_INT_OVERFLOW;
659 }
660 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800661
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700662 return nReturn;
663}
664
665// Make sure #define value line up as DecodeSimple counts on this.
666#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
667#error QCBOR_TYPE_FALSE macro value wrong
668#endif
669
670#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
671#error QCBOR_TYPE_TRUE macro value wrong
672#endif
673
674#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
675#error QCBOR_TYPE_NULL macro value wrong
676#endif
677
678#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
679#error QCBOR_TYPE_UNDEF macro value wrong
680#endif
681
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700682#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
683#error QCBOR_TYPE_BREAK macro value wrong
684#endif
685
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700686#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
687#error QCBOR_TYPE_DOUBLE macro value wrong
688#endif
689
690#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
691#error QCBOR_TYPE_FLOAT macro value wrong
692#endif
693
694/*
695 Decode true, false, floats, break...
696 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800697inline static QCBORError
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800698DecodeSimple(int nAdditionalInfo, uint64_t uNumber, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700699{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700700 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800701
Laurence Lundbladeee851742020-01-08 08:37:05 -0800702 // uAdditionalInfo is 5 bits from the initial byte compile time checks
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800703 // above make sure uAdditionalInfo values line up with uDataType values.
704 // DecodeTypeAndNumber never returns a major type > 1f so cast is safe
705 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800706
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800707 switch(nAdditionalInfo) {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800708 // No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they are
709 // caught before this is called.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800710
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700711 case HALF_PREC_FLOAT:
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700712 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uNumber);
713 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700714 break;
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700715 case SINGLE_PREC_FLOAT:
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700716 pDecodedItem->val.dfnum = (double)UsefulBufUtil_CopyUint32ToFloat((uint32_t)uNumber);
717 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700718 break;
719 case DOUBLE_PREC_FLOAT:
720 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uNumber);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700721 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700722 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800723
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700724 case CBOR_SIMPLEV_FALSE: // 20
725 case CBOR_SIMPLEV_TRUE: // 21
726 case CBOR_SIMPLEV_NULL: // 22
727 case CBOR_SIMPLEV_UNDEF: // 23
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700728 case CBOR_SIMPLE_BREAK: // 31
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700729 break; // nothing to do
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800730
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700731 case CBOR_SIMPLEV_ONEBYTE: // 24
732 if(uNumber <= CBOR_SIMPLE_BREAK) {
733 // This takes out f8 00 ... f8 1f which should be encoded as e0 … f7
Laurence Lundblade077475f2019-04-26 09:06:33 -0700734 nReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700735 goto Done;
736 }
Laurence Lundblade5e390822019-01-06 12:35:01 -0800737 /* FALLTHROUGH */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700738 // fall through intentionally
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800739
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700740 default: // 0-19
741 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
Laurence Lundbladeee851742020-01-08 08:37:05 -0800742 /*
743 DecodeTypeAndNumber will make uNumber equal to
744 uAdditionalInfo when uAdditionalInfo is < 24 This cast is
745 safe because the 2, 4 and 8 byte lengths of uNumber are in
746 the double/float cases above
747 */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700748 pDecodedItem->val.uSimple = (uint8_t)uNumber;
749 break;
750 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800751
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700752Done:
753 return nReturn;
754}
755
756
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700757/*
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530758 Decode text and byte strings. Call the string allocator if asked to.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700759 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800760inline static QCBORError DecodeBytes(const QCORInternalAllocator *pAllocator,
761 int nMajorType,
762 uint64_t uStrLen,
763 UsefulInputBuf *pUInBuf,
764 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700765{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700766 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800767
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800768 // CBOR lengths can be 64 bits, but size_t is not 64 bits on all CPUs.
769 // This check makes the casts to size_t below safe.
770
771 // 4 bytes less than the largest sizeof() so this can be tested by
772 // putting a SIZE_MAX length in the CBOR test input (no one will
773 // care the limit on strings is 4 bytes shorter).
774 if(uStrLen > SIZE_MAX-4) {
775 nReturn = QCBOR_ERR_STRING_TOO_LONG;
776 goto Done;
777 }
778
779 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, (size_t)uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530780 if(UsefulBuf_IsNULLC(Bytes)) {
781 // Failed to get the bytes for this string item
782 nReturn = QCBOR_ERR_HIT_END;
783 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700784 }
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530785
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800786 if(pAllocator) {
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530787 // We are asked to use string allocator to make a copy
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800788 UsefulBuf NewMem = StringAllocator_Allocate(pAllocator, (size_t)uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530789 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade30816f22018-11-10 13:40:22 +0700790 nReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530791 goto Done;
792 }
793 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800794 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530795 } else {
796 // Normal case with no string allocator
797 pDecodedItem->val.string = Bytes;
798 }
Laurence Lundbladeee851742020-01-08 08:37:05 -0800799 const bool bIsBstr = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING);
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800800 // Cast because ternary operator causes promotion to integer
801 pDecodedItem->uDataType = (uint8_t)(bIsBstr ? QCBOR_TYPE_BYTE_STRING
802 : QCBOR_TYPE_TEXT_STRING);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800803
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530804Done:
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700805 return nReturn;
806}
807
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700808
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800809
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700810
811
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700812
813
Laurence Lundbladeee851742020-01-08 08:37:05 -0800814// Make sure the constants align as this is assumed by
815// the GetAnItem() implementation
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700816#if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
817#error QCBOR_TYPE_ARRAY value not lined up with major type
818#endif
819#if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
820#error QCBOR_TYPE_MAP value not lined up with major type
821#endif
822
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700823/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800824 This gets a single data item and decodes it including preceding
825 optional tagging. This does not deal with arrays and maps and nesting
826 except to decode the data item introducing them. Arrays and maps are
827 handled at the next level up in GetNext().
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800828
Laurence Lundbladeee851742020-01-08 08:37:05 -0800829 Errors detected here include: an array that is too long to decode,
830 hit end of buffer unexpectedly, a few forms of invalid encoded CBOR
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700831 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800832static QCBORError GetNext_Item(UsefulInputBuf *pUInBuf,
833 QCBORItem *pDecodedItem,
834 const QCORInternalAllocator *pAllocator)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700835{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700836 QCBORError nReturn;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800837
Laurence Lundbladeee851742020-01-08 08:37:05 -0800838 /*
839 Get the major type and the number. Number could be length of more
840 bytes or the value depending on the major type nAdditionalInfo is
841 an encoding of the length of the uNumber and is needed to decode
842 floats and doubles
843 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800844 int nMajorType;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700845 uint64_t uNumber;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800846 int nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800847
Laurence Lundblade4b09f632019-10-09 14:34:59 -0700848 memset(pDecodedItem, 0, sizeof(QCBORItem));
849
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800850 nReturn = DecodeTypeAndNumber(pUInBuf, &nMajorType, &uNumber, &nAdditionalInfo);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800851
Laurence Lundbladeee851742020-01-08 08:37:05 -0800852 // Error out here if we got into trouble on the type and number. The
853 // code after this will not work if the type and number is not good.
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700854 if(nReturn) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700855 goto Done;
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700856 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800857
Laurence Lundbladeee851742020-01-08 08:37:05 -0800858 // At this point the major type and the value are valid. We've got
859 // the type and the number that starts every CBOR data item.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800860 switch (nMajorType) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700861 case CBOR_MAJOR_TYPE_POSITIVE_INT: // Major type 0
862 case CBOR_MAJOR_TYPE_NEGATIVE_INT: // Major type 1
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800863 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700864 nReturn = QCBOR_ERR_BAD_INT;
865 } else {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800866 nReturn = DecodeInteger(nMajorType, uNumber, pDecodedItem);
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700867 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700868 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800869
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700870 case CBOR_MAJOR_TYPE_BYTE_STRING: // Major type 2
871 case CBOR_MAJOR_TYPE_TEXT_STRING: // Major type 3
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800872 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
873 const bool bIsBstr = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING);
874 pDecodedItem->uDataType = (uint8_t)(bIsBstr ? QCBOR_TYPE_BYTE_STRING
875 : QCBOR_TYPE_TEXT_STRING);
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530876 pDecodedItem->val.string = (UsefulBufC){NULL, SIZE_MAX};
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700877 } else {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800878 nReturn = DecodeBytes(pAllocator, nMajorType, uNumber, pUInBuf, pDecodedItem);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700879 }
880 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800881
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700882 case CBOR_MAJOR_TYPE_ARRAY: // Major type 4
883 case CBOR_MAJOR_TYPE_MAP: // Major type 5
884 // Record the number of items in the array or map
885 if(uNumber > QCBOR_MAX_ITEMS_IN_ARRAY) {
886 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
887 goto Done;
888 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800889 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530890 pDecodedItem->val.uCount = UINT16_MAX; // Indicate indefinite length
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700891 } else {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800892 // type conversion OK because of check above
893 pDecodedItem->val.uCount = (uint16_t)uNumber;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700894 }
Laurence Lundbladeee851742020-01-08 08:37:05 -0800895 // C preproc #if above makes sure constants for major types align
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800896 // DecodeTypeAndNumber never returns a major type > 7 so cast is safe
897 pDecodedItem->uDataType = (uint8_t)nMajorType;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700898 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800899
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700900 case CBOR_MAJOR_TYPE_OPTIONAL: // Major type 6, optional prepended tags
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800901 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700902 nReturn = QCBOR_ERR_BAD_INT;
903 } else {
904 pDecodedItem->val.uTagV = uNumber;
905 pDecodedItem->uDataType = QCBOR_TYPE_OPTTAG;
906 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700907 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800908
Laurence Lundbladeee851742020-01-08 08:37:05 -0800909 case CBOR_MAJOR_TYPE_SIMPLE:
910 // Major type 7, float, double, true, false, null...
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800911 nReturn = DecodeSimple(nAdditionalInfo, uNumber, pDecodedItem);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700912 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800913
Laurence Lundbladeee851742020-01-08 08:37:05 -0800914 default:
915 // Never happens because DecodeTypeAndNumber() should never return > 7
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700916 nReturn = QCBOR_ERR_UNSUPPORTED;
917 break;
918 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800919
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700920Done:
921 return nReturn;
922}
923
924
925
926/*
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800927 This layer deals with indefinite length strings. It pulls all the
Laurence Lundbladeee851742020-01-08 08:37:05 -0800928 individual chunk items together into one QCBORItem using the string
929 allocator.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800930
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530931 Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700932 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800933static inline QCBORError
934GetNext_FullItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700935{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700936 // Stack usage; int/ptr 2 UsefulBuf 2 QCBORItem -- 96
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700937
938 // Get pointer to string allocator. First use is to pass it to
939 // GetNext_Item() when option is set to allocate for *every* string.
940 // Second use here is to allocate space to coallese indefinite
941 // length string items into one.
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800942 const QCORInternalAllocator *pAllocator = me->StringAllocator.pfAllocator ?
943 &(me->StringAllocator) :
944 NULL;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800945
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700946 QCBORError nReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800947 nReturn = GetNext_Item(&(me->InBuf),
948 pDecodedItem,
949 me->bStringAllocateAll ? pAllocator: NULL);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700950 if(nReturn) {
951 goto Done;
952 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800953
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700954 // To reduce code size by removing support for indefinite length strings, the
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530955 // code in this function from here down can be eliminated. Run tests, except
956 // indefinite length string tests, to be sure all is OK if this is removed.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800957
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800958 // Only do indefinite length processing on strings
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700959 const uint8_t uStringType = pDecodedItem->uDataType;
960 if(uStringType!= QCBOR_TYPE_BYTE_STRING && uStringType != QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700961 goto Done; // no need to do any work here on non-string types
962 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800963
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800964 // Is this a string with an indefinite length?
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530965 if(pDecodedItem->val.string.len != SIZE_MAX) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800966 goto Done; // length is not indefinite, so no work to do here
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700967 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800968
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530969 // Can't do indefinite length strings without a string allocator
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800970 if(pAllocator == NULL) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700971 nReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
972 goto Done;
973 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800974
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700975 // Loop getting chunk of indefinite string
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700976 UsefulBufC FullString = NULLUsefulBufC;
977
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700978 for(;;) {
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700979 // Get item for next chunk
980 QCBORItem StringChunkItem;
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700981 // NULL string allocator passed here. Do not need to allocate
982 // chunks even if bStringAllocateAll is set.
Laurence Lundbladefae26bf2019-02-18 11:15:43 -0800983 nReturn = GetNext_Item(&(me->InBuf), &StringChunkItem, NULL);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700984 if(nReturn) {
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700985 break; // Error getting the next chunk
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700986 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800987
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530988 // See if it is a marker at end of indefinite length string
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700989 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800990 // String is complete
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700991 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +0530992 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700993 break;
994 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800995
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700996 // Match data type of chunk to type at beginning.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530997 // Also catches error of other non-string types that don't belong.
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700998 // Also catches indefinite length strings inside indefinite length strings
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800999 if(StringChunkItem.uDataType != uStringType ||
1000 StringChunkItem.val.string.len == SIZE_MAX) {
Laurence Lundblade30816f22018-11-10 13:40:22 +07001001 nReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001002 break;
1003 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001004
Laurence Lundblade471a3fd2018-10-18 21:27:45 +05301005 // Alloc new buffer or expand previously allocated buffer so it can fit
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001006 // The first time throurgh FullString.ptr is NULL and this is
1007 // equivalent to StringAllocator_Allocate()
1008 UsefulBuf NewMem = StringAllocator_Reallocate(pAllocator,
1009 UNCONST_POINTER(FullString.ptr),
1010 FullString.len + StringChunkItem.val.string.len);
1011
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001012 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301013 // Allocation of memory for the string failed
Laurence Lundblade30816f22018-11-10 13:40:22 +07001014 nReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001015 break;
1016 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001017
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001018 // Copy new string chunk at the end of string so far.
1019 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001020 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001021
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001022 if(nReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
1023 // Getting the item failed, clean up the allocated memory
1024 StringAllocator_Free(pAllocator, UNCONST_POINTER(FullString.ptr));
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001025 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001026
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001027Done:
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001028 return nReturn;
1029}
1030
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001031
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001032uint64_t ConvertTag(QCBORDecodeContext *me, uint16_t uTagVal) {
1033 if(uTagVal < 0xfff0) {
1034 return uTagVal;
1035 } else {
1036 // TODO constant and error check
1037 int x = uTagVal - 0xfff0;
1038 return me->auMappedTags[x];
1039 }
1040}
1041
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001042/*
Laurence Lundblade59289e52019-12-30 13:44:37 -08001043 Gets all optional tag data items preceding a data item that is not an
1044 optional tag and records them as bits in the tag map.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001045 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001046static QCBORError
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001047GetNext_TaggedItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001048{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001049 // Stack usage: int/ptr: 3 -- 24
Laurence Lundblade30816f22018-11-10 13:40:22 +07001050 QCBORError nReturn;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001051
1052 uint16_t auTags[QCBOR_MAX_TAGS_PER_ITEM] = {0xffff, 0xffff, 0xffff, 0xffff};
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001053
Laurence Lundblade59289e52019-12-30 13:44:37 -08001054 // Loop fetching items until the item fetched is not a tag
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001055 for(;;) {
1056 nReturn = GetNext_FullItem(me, pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001057 if(nReturn) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001058 goto Done; // Error out of the loop
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001059 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001060
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001061 if(pDecodedItem->uDataType != QCBOR_TYPE_OPTTAG) {
1062 // Successful exit from loop; maybe got some tags, maybe not
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001063 memcpy(pDecodedItem->uTags, auTags, sizeof(auTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001064 break;
1065 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001066
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001067 // Is there room for the tag in the tags list?
1068 size_t uTagIndex;
1069 for(uTagIndex = 0; uTagIndex < QCBOR_MAX_TAGS_PER_ITEM; uTagIndex++) {
1070 if(auTags[uTagIndex] == 0xffff) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001071 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001072 }
1073 }
1074 if(uTagIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
1075 return 99; // TODO error code
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001076 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001077
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001078 // Is the tag > 16 bits?
1079 if(pDecodedItem->val.uTagV > 0xffff) {
1080 size_t uTagMapIndex;
1081 // Is there room in the tag map?
1082 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
1083 if(me->auMappedTags[uTagMapIndex] == 0xffff) {
1084 break;
1085 }
1086 if(me->auMappedTags[uTagMapIndex] == pDecodedItem->val.uTagV) {
1087 break;
1088 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001089 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001090 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
1091 // No room for the tag
1092 return 97; // TODO error code
1093 }
1094
1095 // Cover the case where tag is new and were it is already in the map
1096 me->auMappedTags[uTagMapIndex] = pDecodedItem->val.uTagV;
1097 auTags[uTagIndex] = (uint16_t)(uTagMapIndex + 0xfff0); // TODO proper constant and cast
1098
1099 } else {
1100 auTags[uTagIndex] = (uint16_t)pDecodedItem->val.uTagV;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001101 }
1102 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001103
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001104Done:
1105 return nReturn;
1106}
1107
1108
1109/*
Laurence Lundbladeee851742020-01-08 08:37:05 -08001110 This layer takes care of map entries. It combines the label and data
1111 items into one QCBORItem.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001112 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001113static inline QCBORError
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001114GetNext_MapEntry(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001115{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001116 // Stack use: int/ptr 1, QCBORItem -- 56
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001117 QCBORError nReturn = GetNext_TaggedItem(me, pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001118 if(nReturn)
1119 goto Done;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001120
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001121 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001122 // Break can't be a map entry
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001123 goto Done;
1124 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001125
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001126 if(me->uDecodeMode != QCBOR_DECODE_MODE_MAP_AS_ARRAY) {
1127 // In a map and caller wants maps decoded, not treated as arrays
1128
1129 if(DecodeNesting_TypeIsMap(&(me->nesting))) {
1130 // If in a map and the right decoding mode, get the label
1131
Laurence Lundbladeee851742020-01-08 08:37:05 -08001132 // Save label in pDecodedItem and get the next which will
1133 // be the real data
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001134 QCBORItem LabelItem = *pDecodedItem;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001135 nReturn = GetNext_TaggedItem(me, pDecodedItem);
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001136 if(nReturn)
1137 goto Done;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001138
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301139 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001140
1141 if(LabelItem.uDataType == QCBOR_TYPE_TEXT_STRING) {
1142 // strings are always good labels
1143 pDecodedItem->label.string = LabelItem.val.string;
1144 pDecodedItem->uLabelType = QCBOR_TYPE_TEXT_STRING;
1145 } else if (QCBOR_DECODE_MODE_MAP_STRINGS_ONLY == me->uDecodeMode) {
Laurence Lundbladeee851742020-01-08 08:37:05 -08001146 // It's not a string and we only want strings
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001147 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
1148 goto Done;
1149 } else if(LabelItem.uDataType == QCBOR_TYPE_INT64) {
1150 pDecodedItem->label.int64 = LabelItem.val.int64;
1151 pDecodedItem->uLabelType = QCBOR_TYPE_INT64;
1152 } else if(LabelItem.uDataType == QCBOR_TYPE_UINT64) {
1153 pDecodedItem->label.uint64 = LabelItem.val.uint64;
1154 pDecodedItem->uLabelType = QCBOR_TYPE_UINT64;
1155 } else if(LabelItem.uDataType == QCBOR_TYPE_BYTE_STRING) {
1156 pDecodedItem->label.string = LabelItem.val.string;
1157 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
1158 pDecodedItem->uLabelType = QCBOR_TYPE_BYTE_STRING;
1159 } else {
1160 // label is not an int or a string. It is an arrray
1161 // or a float or such and this implementation doesn't handle that.
1162 // Also, tags on labels are ignored.
1163 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
1164 goto Done;
1165 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001166 }
1167 } else {
1168 if(pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001169 if(pDecodedItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
1170 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
1171 goto Done;
1172 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001173 // Decoding a map as an array
1174 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001175 // Cast is safe because of check against QCBOR_MAX_ITEMS_IN_ARRAY/2
1176 // Cast is needed because of integer promotion
1177 pDecodedItem->val.uCount = (uint16_t)(pDecodedItem->val.uCount * 2);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001178 }
1179 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001180
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001181Done:
1182 return nReturn;
1183}
1184
1185
1186/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001187 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001188 TODO: correct this comment
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001189 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001190static QCBORError
1191QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001192{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001193 // Stack ptr/int: 2, QCBORItem : 64
1194
Laurence Lundblade30816f22018-11-10 13:40:22 +07001195 QCBORError nReturn;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001196 /* === First figure out if at the end of traversal === */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001197
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001198 /* Case 1. Out of bytes to consume.
1199
1200 This is either the end of the top-level CBOR that was give
1201 to QCBORDecode_Init() or the end of a tag 24 bstr wrapped CBOR.
1202 It is detected by all bytes being consumed from the UsefulInputBuf.
1203
1204 To go back out of the tag 24 bstr wrapped item, the caller must
1205 explicitly call Exit() which will reset the UsefulInputBuf
1206 to the next highest bstr wrapped or the top level.
1207
1208 This is always the end condition that QCBORDecode_Finish()
1209 considers complete.
1210
1211 TODO: can the DecodeNesting_IsAtTop be removed? QCBORDecode_Finish()
1212 will perform this check.
1213
1214 */
Laurence Lundblade937ea812020-05-08 11:38:23 -07001215 /* For a pre-order traversal a non-error end occurs when there
1216 are no more bytes to consume and the nesting level is at the top.
1217 If it's not at the top, then the CBOR is not well formed. This error
1218 is caught elsewhere.
1219
1220 This handles the end of CBOR sequences as well as non-sequences. */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001221 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf)) == 0 && DecodeNesting_IsAtTop(&(me->nesting))) {
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001222 nReturn = QCBOR_ERR_NO_MORE_ITEMS;
1223 goto Done;
1224 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07001225
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001226
1227 /* Case 2. End of map or array in bounded mode
1228
1229 The caller is attempting traveral of a bounded map or array and
1230 has got to the end of it.
1231
1232 The caller must explicitly exit the bounded mode map or array
1233 to get past this condition.
1234
1235 To complete a decode of the full input CBOR, the caller must
1236 exit all maps and arrays in bounded mode and this is never
1237 the successful end of decoding.
1238
1239 */
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001240 /* It is also an end of the input when in map mode and the cursor
Laurence Lundblade937ea812020-05-08 11:38:23 -07001241 is at the end of the map */
1242
1243
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07001244 // This is to handle map and array mode
Laurence Lundblade937ea812020-05-08 11:38:23 -07001245 if(DecodeNesting_AtEnd(&(me->nesting))) {
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07001246 nReturn = QCBOR_ERR_NO_MORE_ITEMS;
1247 goto Done;
1248 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001249
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001250 /* === Not at the end; get another item === */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001251 nReturn = GetNext_MapEntry(me, pDecodedItem);
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001252 if(nReturn) {
1253 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001254 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301255
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001256 // Breaks ending arrays/maps are always processed at the end of this function.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301257 // They should never show up here.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301258 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade6de37062018-10-15 12:22:42 +05301259 nReturn = QCBOR_ERR_BAD_BREAK;
1260 goto Done;
Laurence Lundblade5b8c5852018-10-14 21:11:42 +05301261 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001262
Laurence Lundblade6de37062018-10-15 12:22:42 +05301263 // Record the nesting level for this data item before processing any of
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301264 // decrementing and descending.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301265 pDecodedItem->uNestingLevel = DecodeNesting_GetLevel(&(me->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001266
Laurence Lundblade6de37062018-10-15 12:22:42 +05301267 // Process the item just received for descent or decrement, and
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001268 // ascend if decrements are enough to close out a definite length array/map
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001269 if(IsMapOrArray(pDecodedItem->uDataType) && pDecodedItem->val.uCount != 0) {
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001270 // If the new item is array or map, the nesting level descends
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001271 nReturn = DecodeNesting_Descend2(&(me->nesting), pDecodedItem->uDataType, pDecodedItem->val.uCount, 0L);
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001272 // Maps and arrays do count in as items in the map/array that encloses
1273 // them so a decrement needs to be done for them too, but that is done
1274 // only when all the items in them have been processed, not when they
Laurence Lundblade9916b1b2019-09-07 22:33:25 -07001275 // are opened with the exception of an empty map or array.
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001276 }
1277
1278 if(!IsMapOrArray(pDecodedItem->uDataType) || pDecodedItem->val.uCount == 0) {
1279 // Decrement happns for non-aggregate and empty aggregate
1280
1281 // TODO: what about empty indefinite?
1282
1283
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001284 /* === Figure out if item got closed out maps or arrays === */
1285
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001286 /*
1287 This needs to decrement, check for end and ascend
1288 the tree until an an ascend is not possible or the bounded
1289 limit is reached or the end of the encoded CBOR input
1290 is reached. For
1291 definite length maps and arrays the end is by count. For
1292 indefinite it is by a break.
1293
1294 Also state needs to be set that can tell the code at the
1295 beginning of this function that the end was reached.
1296
1297 This is complicated...
1298
1299
1300 This will handle an indefinite length array
1301 inside a definte length array inside an indefinite
1302 length array...
1303
1304 */
1305
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001306 // Decrement the count of items in the enclosing map/array
1307 // If the count in the enclosing map/array goes to zero, that
Laurence Lundblade6de37062018-10-15 12:22:42 +05301308 // triggers a decrement in the map/array above that and
1309 // an ascend in nesting level.
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001310 while(1) {
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001311 if(DecodeNesting_IsIndefiniteLength(&(me->nesting))) {
1312 while(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) {
1313 // Peek forward one item to see if it is a break.
1314 QCBORItem Peek;
1315 size_t uPeek = UsefulInputBuf_Tell(&(me->InBuf));
1316 nReturn = GetNext_Item(&(me->InBuf), &Peek, NULL);
1317 if(nReturn != QCBOR_SUCCESS) {
1318 goto Done;
1319 }
1320 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
1321 // It is not a break, rewind so it can be processed normally.
1322 UsefulInputBuf_Seek(&(me->InBuf), uPeek);
1323 goto Done2;
1324 }
1325 // It is a break. Ascend one nesting level.
1326 // The break is consumed.
1327 nReturn = DecodeNesting_BreakAscend(&(me->nesting));
1328 if(nReturn != QCBOR_SUCCESS) {
1329 // break occured outside of an indefinite length array/map
1330 goto Done;
1331 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001332 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001333 goto Done2; // Out of bytes to decode
1334 } else {
1335 if(DecodeNesting_DecrementCount(&(me->nesting)) == 0) {
1336 /* There was no level up. Did not consume to the
1337 end of an array or map so done with the work. */
1338 goto Done2;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001339 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05301340 }
1341 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001342
1343 Done2:
1344 if(nReturn) {
1345 goto Done;
1346 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05301347 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001348
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001349
1350 /* === Tell the caller the nest level of the next item === */
1351
Laurence Lundblade6de37062018-10-15 12:22:42 +05301352 // Tell the caller what level is next. This tells them what maps/arrays
1353 // were closed out and makes it possible for them to reconstruct
1354 // the tree with just the information returned by GetNext
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07001355 // TODO: pull this into DecodeNesting_GetLevel
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001356 if(InBoundMode(&(me->nesting)) && me->nesting.pCurrent->uCount == 0) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001357 // At end of a map / array in map mode, so next nest is 0 to
1358 // indicate this end.
1359 pDecodedItem->uNextNestLevel = 0;
1360 } else {
1361 pDecodedItem->uNextNestLevel = DecodeNesting_GetLevel(&(me->nesting));
1362 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001363
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001364Done:
Laurence Lundbladee9482dd2019-10-11 12:58:46 -07001365 if(nReturn != QCBOR_SUCCESS) {
1366 // Make sure uDataType and uLabelType are QCBOR_TYPE_NONE
1367 memset(pDecodedItem, 0, sizeof(QCBORItem));
1368 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001369 return nReturn;
1370}
1371
1372
Laurence Lundblade59289e52019-12-30 13:44:37 -08001373/*
1374 Mostly just assign the right data type for the date string.
1375 */
1376inline static QCBORError DecodeDateString(QCBORItem *pDecodedItem)
1377{
1378 // Stack Use: UsefulBuf 1 16
1379 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1380 return QCBOR_ERR_BAD_OPT_TAG;
1381 }
1382
1383 const UsefulBufC Temp = pDecodedItem->val.string;
1384 pDecodedItem->val.dateString = Temp;
1385 pDecodedItem->uDataType = QCBOR_TYPE_DATE_STRING;
1386 return QCBOR_SUCCESS;
1387}
1388
1389
1390/*
1391 Mostly just assign the right data type for the bignum.
1392 */
1393inline static QCBORError DecodeBigNum(QCBORItem *pDecodedItem)
1394{
1395 // Stack Use: UsefulBuf 1 -- 16
1396 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1397 return QCBOR_ERR_BAD_OPT_TAG;
1398 }
1399 const UsefulBufC Temp = pDecodedItem->val.string;
1400 pDecodedItem->val.bigNum = Temp;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001401 const bool bIsPosBigNum = (bool)(pDecodedItem->uTags[0] == CBOR_TAG_POS_BIGNUM);
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001402 pDecodedItem->uDataType = (uint8_t)(bIsPosBigNum ? QCBOR_TYPE_POSBIGNUM
1403 : QCBOR_TYPE_NEGBIGNUM);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001404 return QCBOR_SUCCESS;
1405}
1406
1407
1408/*
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001409 Mostly just assign the right data type for the bignum.
1410 */
1411inline static QCBORError DecodeUUID(QCBORItem *pDecodedItem)
1412{
1413 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1414 return QCBOR_ERR_BAD_OPT_TAG;
1415 }
1416 pDecodedItem->uDataType = QCBOR_TYPE_UUID;
1417 return QCBOR_SUCCESS;
1418}
1419
1420
1421/*
Laurence Lundbladeee851742020-01-08 08:37:05 -08001422 The epoch formatted date. Turns lots of different forms of encoding
1423 date into uniform one
Laurence Lundblade59289e52019-12-30 13:44:37 -08001424 */
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001425static QCBORError DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08001426{
1427 // Stack usage: 1
1428 QCBORError nReturn = QCBOR_SUCCESS;
1429
1430 pDecodedItem->val.epochDate.fSecondsFraction = 0;
1431
1432 switch (pDecodedItem->uDataType) {
1433
1434 case QCBOR_TYPE_INT64:
1435 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
1436 break;
1437
1438 case QCBOR_TYPE_UINT64:
1439 if(pDecodedItem->val.uint64 > INT64_MAX) {
1440 nReturn = QCBOR_ERR_DATE_OVERFLOW;
1441 goto Done;
1442 }
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001443 pDecodedItem->val.epochDate.nSeconds = (int64_t)pDecodedItem->val.uint64;
Laurence Lundblade59289e52019-12-30 13:44:37 -08001444 break;
1445
1446 case QCBOR_TYPE_DOUBLE:
1447 {
1448 // This comparison needs to be done as a float before
1449 // conversion to an int64_t to be able to detect doubles
1450 // that are too large to fit into an int64_t. A double
1451 // has 52 bits of preceision. An int64_t has 63. Casting
1452 // INT64_MAX to a double actually causes a round up which
1453 // is bad and wrong for the comparison because it will
1454 // allow conversion of doubles that can't fit into a
1455 // uint64_t. To remedy this INT64_MAX - 0x7ff is used as
1456 // the cutoff point as if that rounds up in conversion to
1457 // double it will still be less than INT64_MAX. 0x7ff is
1458 // picked because it has 11 bits set.
1459 //
1460 // INT64_MAX seconds is on the order of 10 billion years,
1461 // and the earth is less than 5 billion years old, so for
1462 // most uses this conversion error won't occur even though
1463 // doubles can go much larger.
1464 //
1465 // Without the 0x7ff there is a ~30 minute range of time
1466 // values 10 billion years in the past and in the future
1467 // where this this code would go wrong.
1468 const double d = pDecodedItem->val.dfnum;
1469 if(d > (double)(INT64_MAX - 0x7ff)) {
1470 nReturn = QCBOR_ERR_DATE_OVERFLOW;
1471 goto Done;
1472 }
1473 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
1474 pDecodedItem->val.epochDate.fSecondsFraction = d - (double)pDecodedItem->val.epochDate.nSeconds;
1475 }
1476 break;
1477
1478 default:
1479 nReturn = QCBOR_ERR_BAD_OPT_TAG;
1480 goto Done;
1481 }
1482 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
1483
1484Done:
1485 return nReturn;
1486}
1487
1488
1489#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
1490/*
1491 Decode decimal fractions and big floats.
1492
1493 When called pDecodedItem must be the array that is tagged as a big
1494 float or decimal fraction, the array that has the two members, the
1495 exponent and mantissa.
1496
1497 This will fetch and decode the exponent and mantissa and put the
1498 result back into pDecodedItem.
1499 */
1500inline static QCBORError
1501QCBORDecode_MantissaAndExponent(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
1502{
1503 QCBORError nReturn;
1504
1505 // --- Make sure it is an array; track nesting level of members ---
1506 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
1507 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1508 goto Done;
1509 }
1510
1511 // A check for pDecodedItem->val.uCount == 2 would work for
Laurence Lundbladeee851742020-01-08 08:37:05 -08001512 // definite length arrays, but not for indefnite. Instead remember
1513 // the nesting level the two integers must be at, which is one
1514 // deeper than that of the array.
Laurence Lundblade59289e52019-12-30 13:44:37 -08001515 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
1516
1517 // --- Is it a decimal fraction or a bigfloat? ---
1518 const bool bIsTaggedDecimalFraction = QCBORDecode_IsTagged(me, pDecodedItem, CBOR_TAG_DECIMAL_FRACTION);
1519 pDecodedItem->uDataType = bIsTaggedDecimalFraction ? QCBOR_TYPE_DECIMAL_FRACTION : QCBOR_TYPE_BIGFLOAT;
1520
1521 // --- Get the exponent ---
1522 QCBORItem exponentItem;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001523 nReturn = QCBORDecode_GetNextMapOrArray(me, &exponentItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001524 if(nReturn != QCBOR_SUCCESS) {
1525 goto Done;
1526 }
1527 if(exponentItem.uNestingLevel != nNestLevel) {
1528 // Array is empty or a map/array encountered when expecting an int
1529 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1530 goto Done;
1531 }
1532 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
1533 // Data arriving as an unsigned int < INT64_MAX has been converted
1534 // to QCBOR_TYPE_INT64 and thus handled here. This is also means
1535 // that the only data arriving here of type QCBOR_TYPE_UINT64 data
1536 // will be too large for this to handle and thus an error that will
1537 // get handled in the next else.
1538 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
1539 } else {
1540 // Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX
1541 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1542 goto Done;
1543 }
1544
1545 // --- Get the mantissa ---
1546 QCBORItem mantissaItem;
1547 nReturn = QCBORDecode_GetNextWithTags(me, &mantissaItem, NULL);
1548 if(nReturn != QCBOR_SUCCESS) {
1549 goto Done;
1550 }
1551 if(mantissaItem.uNestingLevel != nNestLevel) {
1552 // Mantissa missing or map/array encountered when expecting number
1553 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1554 goto Done;
1555 }
1556 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
1557 // Data arriving as an unsigned int < INT64_MAX has been converted
1558 // to QCBOR_TYPE_INT64 and thus handled here. This is also means
1559 // that the only data arriving here of type QCBOR_TYPE_UINT64 data
1560 // will be too large for this to handle and thus an error that
1561 // will get handled in an else below.
1562 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
1563 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM || mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
1564 // Got a good big num mantissa
1565 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
1566 // Depends on numbering of QCBOR_TYPE_XXX
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001567 pDecodedItem->uDataType = (uint8_t)(pDecodedItem->uDataType +
1568 mantissaItem.uDataType - QCBOR_TYPE_POSBIGNUM +
1569 1);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001570 } else {
1571 // Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX
1572 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1573 goto Done;
1574 }
1575
1576 // --- Check that array only has the two numbers ---
1577 if(mantissaItem.uNextNestLevel == nNestLevel) {
1578 // Extra items in the decimal fraction / big num
1579 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1580 goto Done;
1581 }
1582
1583Done:
1584
1585 return nReturn;
1586}
1587#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
1588
1589
1590/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001591 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08001592 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001593QCBORError
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001594QCBORDecode_GetNext(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08001595{
1596 QCBORError nReturn;
1597
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001598 nReturn = QCBORDecode_GetNextMapOrArray(me, pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001599 if(nReturn != QCBOR_SUCCESS) {
1600 goto Done;
1601 }
1602
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001603 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM; i++) {
1604 switch(pDecodedItem->uTags[i] ) {
1605 case 0xffff:
1606 // The end of the tag list or no tags
1607 // Successful exit from the loop.
1608 goto Done;
Laurence Lundblade59289e52019-12-30 13:44:37 -08001609
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001610 case CBOR_TAG_DATE_STRING:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001611 nReturn = DecodeDateString(pDecodedItem);
1612 break;
1613
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001614 case CBOR_TAG_DATE_EPOCH:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001615 nReturn = DecodeDateEpoch(pDecodedItem);
1616 break;
1617
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001618 case CBOR_TAG_POS_BIGNUM:
1619 case CBOR_TAG_NEG_BIGNUM:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001620 nReturn = DecodeBigNum(pDecodedItem);
1621 break;
1622
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001623 #ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
1624 case CBOR_TAG_DECIMAL_FRACTION:
1625 case CBOR_TAG_BIGFLOAT:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001626 // For aggregate tagged types, what goes into pTags is only collected
1627 // from the surrounding data item, not the contents, so pTags is not
1628 // passed on here.
1629
1630 nReturn = QCBORDecode_MantissaAndExponent(me, pDecodedItem);
1631 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001632 #endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08001633
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001634 case CBOR_TAG_BIN_UUID:
1635 nReturn = DecodeUUID(pDecodedItem);
1636
1637 default:
1638 // A tag that is not understood
1639 // A successful exit from the loop
1640 goto Done;
1641
1642 }
1643 if(nReturn != QCBOR_SUCCESS) {
1644 goto Done;
1645 }
Laurence Lundblade59289e52019-12-30 13:44:37 -08001646 }
1647
1648Done:
1649 if(nReturn != QCBOR_SUCCESS) {
1650 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
1651 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
1652 }
1653 return nReturn;
1654}
1655
1656
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001657QCBORError QCBORDecode_PeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
1658{
1659 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
1660
1661 QCBORError uErr = QCBORDecode_GetNext(pMe, pDecodedItem);
1662
1663 UsefulInputBuf_Seek(&(pMe->InBuf), uOffset);
1664
1665 return uErr;
1666}
1667
1668
Laurence Lundblade59289e52019-12-30 13:44:37 -08001669/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001670 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08001671 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001672QCBORError
1673QCBORDecode_GetNextWithTags(QCBORDecodeContext *me,
1674 QCBORItem *pDecodedItem,
1675 QCBORTagListOut *pTags)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001676{
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001677 QCBORError nReturn;
1678
1679 nReturn = QCBORDecode_GetNext(me, pDecodedItem);
1680 if(nReturn != QCBOR_SUCCESS) {
1681 return nReturn;
1682 }
1683
1684 if(pTags != NULL) {
1685 pTags->uNumUsed = 0;
1686 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM; i++) {
1687 if(pDecodedItem->uTags[i] == 0xffff) {
1688 break;
1689 }
1690 if(pTags->uNumUsed >= pTags->uNumAllocated) {
1691 return QCBOR_ERR_TOO_MANY_TAGS;
1692 }
1693 pTags->puTags[pTags->uNumUsed] = ConvertTag(me, pDecodedItem->uTags[i]);
1694 pTags->uNumUsed++;
1695 }
1696 }
1697
1698 return QCBOR_SUCCESS;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001699}
1700
1701
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001702/*
Laurence Lundblade6de37062018-10-15 12:22:42 +05301703 Decoding items is done in 5 layered functions, one calling the
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301704 next one down. If a layer has no work to do for a particular item
1705 it returns quickly.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001706
Laurence Lundblade59289e52019-12-30 13:44:37 -08001707 - QCBORDecode_GetNext, GetNextWithTags -- The top layer processes
1708 tagged data items, turning them into the local C representation.
1709 For the most simple it is just associating a QCBOR_TYPE with the data. For
1710 the complex ones that an aggregate of data items, there is some further
1711 decoding and a little bit of recursion.
1712
1713 - QCBORDecode_GetNextMapOrArray - This manages the beginnings and
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301714 ends of maps and arrays. It tracks descending into and ascending
Laurence Lundblade6de37062018-10-15 12:22:42 +05301715 out of maps/arrays. It processes all breaks that terminate
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001716 indefinite length maps and arrays.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001717
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301718 - GetNext_MapEntry -- This handles the combining of two
1719 items, the label and the data, that make up a map entry.
1720 It only does work on maps. It combines the label and data
1721 items into one labeled item.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001722
Laurence Lundblade59289e52019-12-30 13:44:37 -08001723 - GetNext_TaggedItem -- This decodes type 6 tagging. It turns the
1724 tags into bit flags associated with the data item. No actual decoding
1725 of the contents of the tagged item is performed here.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001726
Laurence Lundblade59289e52019-12-30 13:44:37 -08001727 - GetNext_FullItem -- This assembles the sub-items that make up
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301728 an indefinte length string into one string item. It uses the
Laurence Lundblade6de37062018-10-15 12:22:42 +05301729 string allocater to create contiguous space for the item. It
1730 processes all breaks that are part of indefinite length strings.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001731
Laurence Lundblade59289e52019-12-30 13:44:37 -08001732 - GetNext_Item -- This decodes the atomic data items in CBOR. Each
1733 atomic data item has a "major type", an integer "argument" and optionally
1734 some content. For text and byte strings, the content is the bytes
1735 that make up the string. These are the smallest data items that are
1736 considered to be well-formed. The content may also be other data items in
1737 the case of aggregate types. They are not handled in this layer.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001738
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001739 Roughly this takes 300 bytes of stack for vars. Need to
1740 evaluate this more carefully and correctly.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001741
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301742 */
1743
1744
1745/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001746 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001747 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001748int QCBORDecode_IsTagged(QCBORDecodeContext *me,
1749 const QCBORItem *pItem,
1750 uint64_t uTag)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001751{
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001752 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM; i++ ) {
1753 if(pItem->uTags[i] == 0xffff) {
1754 break;
1755 }
1756 if(ConvertTag(me, pItem->uTags[i]) == uTag) {
1757 return 1;
1758 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001759 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001760
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001761 return 0;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001762}
1763
1764
1765/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001766 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001767 */
Laurence Lundblade30816f22018-11-10 13:40:22 +07001768QCBORError QCBORDecode_Finish(QCBORDecodeContext *me)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001769{
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001770 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001771
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001772 // Error out if all the maps/arrays are not closed out
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001773 if(!DecodeNesting_IsAtTop(&(me->nesting))) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001774 nReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
1775 goto Done;
1776 }
1777
1778 // Error out if not all the bytes are consumed
1779 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) {
1780 nReturn = QCBOR_ERR_EXTRA_BYTES;
1781 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001782
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001783Done:
Laurence Lundblade6de37062018-10-15 12:22:42 +05301784 // Call the destructor for the string allocator if there is one.
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001785 // Always called, even if there are errors; always have to clean up
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001786 StringAllocator_Destruct(&(me->StringAllocator));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001787
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001788 return nReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001789}
1790
1791
1792
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001793/*
1794
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001795Decoder errors handled in this file
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001796
Laurence Lundbladeee851742020-01-08 08:37:05 -08001797 - Hit end of input before it was expected while decoding type and
1798 number QCBOR_ERR_HIT_END
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001799
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001800 - negative integer that is too large for C QCBOR_ERR_INT_OVERFLOW
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001801
Laurence Lundbladeee851742020-01-08 08:37:05 -08001802 - Hit end of input while decoding a text or byte string
1803 QCBOR_ERR_HIT_END
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001804
Laurence Lundbladeee851742020-01-08 08:37:05 -08001805 - Encountered conflicting tags -- e.g., an item is tagged both a date
1806 string and an epoch date QCBOR_ERR_UNSUPPORTED
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001807
Laurence Lundbladeee851742020-01-08 08:37:05 -08001808 - Encontered an array or mapp that has too many items
1809 QCBOR_ERR_ARRAY_TOO_LONG
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001810
Laurence Lundbladeee851742020-01-08 08:37:05 -08001811 - Encountered array/map nesting that is too deep
1812 QCBOR_ERR_ARRAY_NESTING_TOO_DEEP
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001813
Laurence Lundbladeee851742020-01-08 08:37:05 -08001814 - An epoch date > INT64_MAX or < INT64_MIN was encountered
1815 QCBOR_ERR_DATE_OVERFLOW
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001816
Laurence Lundbladeee851742020-01-08 08:37:05 -08001817 - The type of a map label is not a string or int
1818 QCBOR_ERR_MAP_LABEL_TYPE
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001819
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001820 - Hit end with arrays or maps still open -- QCBOR_ERR_EXTRA_BYTES
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001821
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001822 */
1823
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001824
1825
Laurence Lundbladef6531662018-12-04 10:42:22 +09001826
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001827/* ===========================================================================
1828 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001829
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001830 This implements a simple sting allocator for indefinite length
1831 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
1832 implements the function type QCBORStringAllocate and allows easy
1833 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09001834
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001835 This particular allocator is built-in for convenience. The caller
1836 can implement their own. All of this following code will get
1837 dead-stripped if QCBORDecode_SetMemPool() is not called.
1838
1839 This is a very primitive memory allocator. It does not track
1840 individual allocations, only a high-water mark. A free or
1841 reallocation must be of the last chunk allocated.
1842
1843 The size of the pool and offset to free memory are packed into the
1844 first 8 bytes of the memory pool so we don't have to keep them in
1845 the decode context. Since the address of the pool may not be
1846 aligned, they have to be packed and unpacked as if they were
1847 serialized data of the wire or such.
1848
1849 The sizes packed in are uint32_t to be the same on all CPU types
1850 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08001851 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001852
1853
Laurence Lundbladeee851742020-01-08 08:37:05 -08001854static inline int
1855MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001856{
1857 // Use of UsefulInputBuf is overkill, but it is convenient.
1858 UsefulInputBuf UIB;
1859
Laurence Lundbladeee851742020-01-08 08:37:05 -08001860 // Just assume the size here. It was checked during SetUp so
1861 // the assumption is safe.
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001862 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem, QCBOR_DECODE_MIN_MEM_POOL_SIZE});
1863 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
1864 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
1865 return UsefulInputBuf_GetError(&UIB);
1866}
1867
1868
Laurence Lundbladeee851742020-01-08 08:37:05 -08001869static inline int
1870MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001871{
1872 // Use of UsefulOutBuf is overkill, but convenient. The
1873 // length check performed here is useful.
1874 UsefulOutBuf UOB;
1875
1876 UsefulOutBuf_Init(&UOB, Pool);
1877 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
1878 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
1879 return UsefulOutBuf_GetError(&UOB);
1880}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001881
1882
1883/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001884 Internal function for an allocation, reallocation free and destuct.
1885
1886 Having only one function rather than one each per mode saves space in
1887 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001888
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001889 Code Reviewers: THIS FUNCTION DOES POINTER MATH
1890 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001891static UsefulBuf
1892MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001893{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001894 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001895
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001896 uint32_t uPoolSize;
1897 uint32_t uFreeOffset;
1898
1899 if(uNewSize > UINT32_MAX) {
1900 // This allocator is only good up to 4GB. This check should
1901 // optimize out if sizeof(size_t) == sizeof(uint32_t)
1902 goto Done;
1903 }
1904 const uint32_t uNewSize32 = (uint32_t)uNewSize;
1905
1906 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
1907 goto Done;
1908 }
1909
1910 if(uNewSize) {
1911 if(pMem) {
1912 // REALLOCATION MODE
1913 // Calculate pointer to the end of the memory pool. It is
1914 // assumed that pPool + uPoolSize won't wrap around by
1915 // assuming the caller won't pass a pool buffer in that is
1916 // not in legitimate memory space.
1917 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
1918
1919 // Check that the pointer for reallocation is in the range of the
1920 // pool. This also makes sure that pointer math further down
1921 // doesn't wrap under or over.
1922 if(pMem >= pPool && pMem < pPoolEnd) {
1923 // Offset to start of chunk for reallocation. This won't
1924 // wrap under because of check that pMem >= pPool. Cast
1925 // is safe because the pool is always less than UINT32_MAX
1926 // because of check in QCBORDecode_SetMemPool().
1927 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
1928
1929 // Check to see if the allocation will fit. uPoolSize -
1930 // uMemOffset will not wrap under because of check that
1931 // pMem is in the range of the uPoolSize by check above.
1932 if(uNewSize <= uPoolSize - uMemOffset) {
1933 ReturnValue.ptr = pMem;
1934 ReturnValue.len = uNewSize;
1935
1936 // Addition won't wrap around over because uNewSize was
1937 // checked to be sure it is less than the pool size.
1938 uFreeOffset = uMemOffset + uNewSize32;
1939 }
1940 }
1941 } else {
1942 // ALLOCATION MODE
1943 // uPoolSize - uFreeOffset will not underflow because this
1944 // pool implementation makes sure uFreeOffset is always
1945 // smaller than uPoolSize through this check here and
1946 // reallocation case.
1947 if(uNewSize <= uPoolSize - uFreeOffset) {
1948 ReturnValue.len = uNewSize;
1949 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001950 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001951 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001952 }
1953 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001954 if(pMem) {
1955 // FREE MODE
1956 // Cast is safe because of limit on pool size in
1957 // QCBORDecode_SetMemPool()
1958 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
1959 } else {
1960 // DESTRUCT MODE
1961 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001962 }
1963 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001964
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001965 UsefulBuf Pool = {pPool, uPoolSize};
1966 MemPool_Pack(Pool, uFreeOffset);
1967
1968Done:
1969 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001970}
1971
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001972
Laurence Lundbladef6531662018-12-04 10:42:22 +09001973/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001974 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09001975 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001976QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
1977 UsefulBuf Pool,
1978 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001979{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001980 // The pool size and free mem offset are packed into the beginning
1981 // of the pool memory. This compile time check make sure the
1982 // constant in the header is correct. This check should optimize
1983 // down to nothing.
1984 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundblade30816f22018-11-10 13:40:22 +07001985 return QCBOR_ERR_BUFFER_TOO_SMALL;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001986 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001987
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001988 // The pool size and free offset packed in to the beginning of pool
1989 // memory are only 32-bits. This check will optimize out on 32-bit
1990 // machines.
1991 if(Pool.len > UINT32_MAX) {
1992 return QCBOR_ERR_BUFFER_TOO_LARGE;
1993 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001994
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001995 // This checks that the pool buffer given is big enough.
1996 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
1997 return QCBOR_ERR_BUFFER_TOO_SMALL;
1998 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001999
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002000 pMe->StringAllocator.pfAllocator = MemPool_Function;
2001 pMe->StringAllocator.pAllocateCxt = Pool.ptr;
2002 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002003
Laurence Lundblade30816f22018-11-10 13:40:22 +07002004 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002005}
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002006
Laurence Lundblade1341c592020-04-11 14:19:05 -07002007#include <stdio.h>
2008void printdecode(QCBORDecodeContext *pMe, const char *szName)
2009{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002010 printf("---%s--%d--%d--\nLevel Count Type Offset SaveCount MapMode\n",
2011 szName,
2012 (uint32_t)pMe->InBuf.cursor,
2013 (uint32_t)pMe->InBuf.UB.len);
Laurence Lundblade64b607e2020-05-13 13:05:57 -07002014 for(int i = 0; i < QCBOR_MAX_ARRAY_NESTING; i++) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002015 if(&(pMe->nesting.pMapsAndArrays[i]) > pMe->nesting.pCurrent) {
2016 break;
2017 }
Laurence Lundblade64b607e2020-05-13 13:05:57 -07002018 printf("%2s %2d %5d %s %6u %2d %d\n",
2019 pMe->nesting.pCurrentMap == &(pMe->nesting.pMapsAndArrays[i]) ? "->": " ",
Laurence Lundblade1341c592020-04-11 14:19:05 -07002020 i,
2021 pMe->nesting.pMapsAndArrays[i].uCount,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002022 pMe->nesting.pMapsAndArrays[i].uMajorType == QCBOR_TYPE_MAP ? " map" :
2023 (pMe->nesting.pMapsAndArrays[i].uMajorType == QCBOR_TYPE_ARRAY ? "array" :
2024 (pMe->nesting.pMapsAndArrays[i].uMajorType == QCBOR_TYPE_NONE ? " none" : "?????")),
Laurence Lundblade1341c592020-04-11 14:19:05 -07002025 pMe->nesting.pMapsAndArrays[i].uOffset,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002026 pMe->nesting.pMapsAndArrays[i].uSaveCount,
2027 pMe->nesting.pMapsAndArrays[i].uMapMode
Laurence Lundblade1341c592020-04-11 14:19:05 -07002028 );
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002029
Laurence Lundblade1341c592020-04-11 14:19:05 -07002030 }
Laurence Lundblade64b607e2020-05-13 13:05:57 -07002031 printf("\n");
Laurence Lundblade1341c592020-04-11 14:19:05 -07002032}
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002033
2034
2035/*
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002036 *
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002037 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002038static inline QCBORError
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002039ConsumeItem(QCBORDecodeContext *pMe,
2040 const QCBORItem *pItemToConsume,
2041 uint_fast8_t *puNextNestLevel)
2042{
Laurence Lundblade1341c592020-04-11 14:19:05 -07002043 QCBORError nReturn;
2044 QCBORItem Item;
2045
2046 printdecode(pMe, "ConsumeItem");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002047
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002048 if(IsMapOrArray(pItemToConsume->uDataType)) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002049 /* There is only real work to do for maps and arrays */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002050
Laurence Lundblade1341c592020-04-11 14:19:05 -07002051 /* This works for definite and indefinite length
2052 * maps and arrays by using the nesting level
2053 */
2054 do {
2055 nReturn = QCBORDecode_GetNext(pMe, &Item);
2056 if(nReturn != QCBOR_SUCCESS) {
2057 goto Done;
2058 }
2059 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002060
Laurence Lundblade1341c592020-04-11 14:19:05 -07002061 if(puNextNestLevel != NULL) {
2062 *puNextNestLevel = Item.uNextNestLevel;
2063 }
2064 nReturn = QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002065
Laurence Lundblade1341c592020-04-11 14:19:05 -07002066 } else {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002067 /* item_to_consume is not a map or array */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002068 if(puNextNestLevel != NULL) {
2069 /* Just pass the nesting level through */
2070 *puNextNestLevel = pItemToConsume->uNextNestLevel;
2071 }
2072 nReturn = QCBOR_SUCCESS;
2073 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002074
2075Done:
2076 return nReturn;
2077}
2078
2079
Laurence Lundblade1341c592020-04-11 14:19:05 -07002080/* Return true if the labels in Item1 and Item2 are the same.
2081 Works only for integer and string labels. Returns false
2082 for any other type. */
2083static inline bool
2084MatchLabel(QCBORItem Item1, QCBORItem Item2)
2085{
2086 if(Item1.uLabelType == QCBOR_TYPE_INT64) {
2087 if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
2088 return true;
2089 }
2090 } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002091 if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002092 return true;
2093 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002094 } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002095 if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
2096 return true;
2097 }
2098 } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
2099 if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
2100 return true;
2101 }
2102 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002103
Laurence Lundblade1341c592020-04-11 14:19:05 -07002104 /* Other label types are never matched */
2105 return false;
2106}
2107
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002108static inline bool
2109MatchType(QCBORItem Item1, QCBORItem Item2)
2110{
2111 if(Item1.uDataType == Item2.uDataType) {
2112 return true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002113 } else if(Item1.uDataType == QCBOR_TYPE_ANY) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002114 return true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002115 } else if(Item2.uDataType == QCBOR_TYPE_ANY) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002116 return true;
2117 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002118 return false;
2119}
2120
2121
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002122/**
2123 \brief Search a map for a set of items
2124
2125 @param[in] pMe The decode context to search.
2126 @param[in,out] pItemArray The items to search for and the items found.
2127 @param[in] pCBContext Context for the not-found item call back
2128 @param[in] pfCallback Function to call on items not matched in pItemArray
2129
2130 @retval QCBOR_ERR_NOT_ENTERED Trying to search without having entered a map
2131
2132 @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.
2133
2134 @retval QCBOR_ERR_UNEXPECTED_TYPE The label was matched, but not the type.
2135
2136 @retval Also errors returned by QCBORDecode_GetNext().
2137
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002138 On input pItemArray contains a list of labels and data types
2139 of items to be found.
2140
2141 On output the fully retrieved items are filled in with
2142 values and such. The label was matched, so it never changes.
2143
2144 If an item was not found, its data type is set to none.
2145
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002146 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002147static QCBORError
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002148MapSearch(QCBORDecodeContext *pMe,
2149 QCBORItem *pItemArray,
2150 size_t *puOffset,
2151 size_t *puEndOffset,
2152 void *pCBContext,
2153 QCBORItemCallback pfCallback)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002154{
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002155 QCBORError uReturn;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002156
2157 // TODO: what if pre-order cursor is not at the same level as map? This should be OK.
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002158 if(!DecodeNesting_InMapMode(&(pMe->nesting))) {
2159 return QCBOR_ERR_NOT_ENTERED;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002160 }
2161
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002162 QCBORDecodeNesting SaveNesting;
2163 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002164
2165 UsefulInputBuf_Seek(&(pMe->InBuf), pMe->nesting.pCurrent->uOffset);
2166
2167 /* Loop over all the items in the map. They could be
2168 * deeply nested and this should handle both definite
2169 * and indefinite length maps and arrays, so this
2170 * adds some complexity. */
Laurence Lundblade64b607e2020-05-13 13:05:57 -07002171 const uint8_t uMapNestLevel = DecodeNesting_GetMapModeLevel(&(pMe->nesting));
Laurence Lundblade1341c592020-04-11 14:19:05 -07002172
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002173 uint_fast8_t uNextNestLevel;
2174
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002175 uint64_t uFoundItemBitMap = 0;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002176
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002177 /* Iterate over items in the map / array */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002178 do {
2179 /* Remember offset because sometims we have to return it */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002180 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002181
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002182 /* Get the item */
2183 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002184 uReturn = QCBORDecode_GetNext(pMe, &Item);
2185 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002186 /* Got non-well-formed CBOR */
2187 goto Done;
2188 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002189
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002190 /* See if item has one of the labels that are of interest */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002191 int nIndex;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002192 QCBORItem *pIterator;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002193 for(pIterator = pItemArray, nIndex = 0; pIterator->uLabelType != 0; pIterator++, nIndex++) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002194 if(MatchLabel(Item, *pIterator)) {
2195 // A label match has been found
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002196 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
2197 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002198 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002199 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002200 /* Also try to match its type */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002201 if(!MatchType(Item, *pIterator)) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002202 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002203 goto Done;
2204 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002205
2206 /* Successful match. Return the item. */
2207 *pIterator = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002208 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002209 if(puOffset) {
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002210 *puOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002211 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002212 } else {
2213 /* Call the call back on unmatched labels */
2214 /* It is tempting to do duplicate detection here, but that would
2215 require dynamic memory allocation because the number of labels
2216 that might be encountered is unbounded.
2217 */
2218 if(pfCallback) {
2219 uReturn = (*pfCallback)(pCBContext, &Item);
2220 if(uReturn != QCBOR_SUCCESS) {
2221 goto Done;
2222 }
2223 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002224 }
2225 }
2226
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002227 /* Consume the item whether matched or not. This
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002228 does the work of traversing maps and array and
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002229 everything in them. In this loop only the
2230 items at the current nesting level are examined
2231 to match the labels. */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002232 uReturn = ConsumeItem(pMe, &Item, &uNextNestLevel);
2233 if(uReturn) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002234 goto Done;
2235 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002236
2237 } while (uNextNestLevel >= uMapNestLevel);
2238
2239
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002240 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002241
2242 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
2243 // Cast OK because encoded CBOR is limited to UINT32_MAX
2244 pMe->uMapEndOffset = (uint32_t)uEndOffset;
2245 // TODO: is zero *puOffset OK?
2246 if(puEndOffset) {
2247 *puEndOffset = uEndOffset;
2248 }
2249
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002250 /* For all items not found, set the data type to QCBOR_TYPE_NONE */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002251 int i;
2252 QCBORItem *pIterator;
2253 for(pIterator = pItemArray, i = 0; pIterator->uLabelType != 0; pIterator++, i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002254 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002255 pIterator->uDataType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002256 }
2257 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002258
2259Done:
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002260 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002261
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002262 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002263}
2264
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002265
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002266
2267
Laurence Lundblade34691b92020-05-18 22:25:25 -07002268void QCBORDecode_ExitMapMode(QCBORDecodeContext *pMe, uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002269{
Laurence Lundblade1341c592020-04-11 14:19:05 -07002270 size_t uEndOffset;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002271
Laurence Lundblade34691b92020-05-18 22:25:25 -07002272 (void)uType; // TODO: error check
2273
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002274/*
Laurence Lundblade1341c592020-04-11 14:19:05 -07002275 if(pMe->uMapEndOffset) {
2276 uEndOffset = pMe->uMapEndOffset;
2277 // It is only valid once.
2278 pMe->uMapEndOffset = 0;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002279 } else { */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002280 QCBORItem Dummy;
2281
2282 Dummy.uLabelType = QCBOR_TYPE_NONE;
2283
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002284 QCBORError nReturn = MapSearch(pMe, &Dummy, NULL, &uEndOffset, NULL, NULL);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002285
2286 (void)nReturn; // TODO:
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002287// }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002288
2289 printdecode(pMe, "start exit");
2290 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
2291
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002292 DecodeNesting_Exit(&(pMe->nesting));
Laurence Lundblade1341c592020-04-11 14:19:05 -07002293 printdecode(pMe, "end exit");
2294
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002295}
2296
2297
Laurence Lundblade5e87da62020-06-07 03:24:28 -07002298void QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe, uint8_t uTagRequirement, UsefulBufC *pBstr)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002299{
2300 QCBORItem Item;
2301 QCBORDecode_GetNext(pMe, &Item);
2302 // Need to set UIB cursor to start of bstr and UIB length to end of bstr
2303
2304}
2305
2306//void QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pCtx, int64_t uLabel, UsefulBufC *pBstr);
2307
2308//void QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pCtx, const char *szLabel, UsefulBufC *pBstr);
2309
2310void QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pCtx)
2311{
2312 // Need to set the cursor to end of the bstr and length to the next length
2313 // above in the nesting tree (or the top level length).
2314
2315}
2316
2317
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002318void QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
2319 int64_t nLabel,
2320 uint8_t uQcborType,
2321 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002322{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002323 if(pMe->uLastError != QCBOR_SUCCESS) {
2324 return;
2325 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002326
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002327 QCBORItem OneItemSeach[2];
2328 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
2329 OneItemSeach[0].label.int64 = nLabel;
2330 OneItemSeach[0].uDataType = uQcborType;
2331 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07002332
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002333 QCBORError nReturn = MapSearch(pMe, OneItemSeach, NULL, NULL, NULL, NULL);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002334 if(nReturn) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002335 pMe->uLastError = (uint8_t)nReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002336 }
2337
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002338 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
2339 pMe->uLastError = QCBOR_ERR_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002340 }
2341
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002342 *pItem = OneItemSeach[0];
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002343}
2344
2345
Laurence Lundbladeda095972020-06-06 18:35:33 -07002346void QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
2347 const char *szLabel,
2348 uint8_t uQcborType,
2349 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002350{
Laurence Lundbladeda095972020-06-06 18:35:33 -07002351 if(pMe->uLastError != QCBOR_SUCCESS) {
2352 return;
2353 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002354
Laurence Lundbladed02ea8e2020-06-06 18:38:19 -07002355
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002356 QCBORItem OneItemSeach[2];
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002357
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002358 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2359 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
2360 OneItemSeach[0].uDataType = uQcborType;
2361 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07002362
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002363 QCBORError nReturn = MapSearch(pMe, OneItemSeach, NULL, NULL, NULL, NULL);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002364 if(nReturn) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07002365 pMe->uLastError = (uint8_t)nReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002366 }
2367
Laurence Lundbladeda095972020-06-06 18:35:33 -07002368
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002369 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07002370 pMe->uLastError = QCBOR_ERR_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002371 }
2372
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002373 *pItem = OneItemSeach[0];
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002374}
2375
2376
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002377static QCBORError CheckTagRequirement(const TagSpecification TagSpec, uint8_t uDataType)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002378{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002379 if(TagSpec.uTagRequirement == QCBOR_TAGSPEC_MATCH_TAG) {
2380 /* Must match the tag */
2381 if(uDataType == TagSpec.uTaggedType) {
2382 return QCBOR_SUCCESS;
2383 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002384 } else {
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002385 /* QCBOR_TAGSPEC_MATCH_TAG_CONTENT_TYPE or QCBOR_TAGSPEC_MATCH_EITHER */
2386 /* Must check all the possible types for the tag content */
2387 for(size_t i = 0; i < sizeof(TagSpec.uAllowedContentTypes); i++) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002388 if(uDataType == TagSpec.uAllowedContentTypes[i]) {
2389 return QCBOR_SUCCESS;
2390 }
2391 }
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002392 /* Didn't match any of the tag content types */
2393 /* Check the tag for the either case */
2394 if(TagSpec.uTagRequirement == QCBOR_TAGSPEC_MATCH_EITHER) {
2395 if(uDataType == TagSpec.uTaggedType) {
2396 return QCBOR_SUCCESS;
2397 }
2398 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002399 }
2400
2401 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002402}
2403
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002404
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002405void QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
2406 int64_t nLabel,
2407 TagSpecification TagSpec,
2408 QCBORItem *pItem)
2409{
2410 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
2411 if(pMe->uLastError != QCBOR_SUCCESS) {
2412 return;
2413 }
2414
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002415 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem->uDataType);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002416}
2417
2418void QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
2419 const char *szLabel,
2420 TagSpecification TagSpec,
2421 QCBORItem *pItem)
2422{
2423 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
2424 if(pMe->uLastError != QCBOR_SUCCESS) {
2425 return;
2426 }
2427
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002428 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem->uDataType);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002429}
2430
2431void QCBORDecode_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
2432 int64_t nLabel,
2433 TagSpecification TagSpec,
2434 UsefulBufC *pString)
2435{
2436 QCBORItem Item;
2437 QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
2438 if(pMe->uLastError == QCBOR_SUCCESS) {
2439 *pString = Item.val.string;
2440 }
2441}
2442
2443void QCBORDecode_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
2444 const char * szLabel,
2445 TagSpecification TagSpec,
2446 UsefulBufC *pString)
2447{
2448 QCBORItem Item;
2449 QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
2450 if(pMe->uLastError == QCBOR_SUCCESS) {
2451 *pString = Item.val.string;
2452 }
2453}
Laurence Lundblade1341c592020-04-11 14:19:05 -07002454
Laurence Lundblade1341c592020-04-11 14:19:05 -07002455
Laurence Lundblade34691b92020-05-18 22:25:25 -07002456static void SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07002457{
Laurence Lundblade34691b92020-05-18 22:25:25 -07002458 if(pMe->uLastError != QCBOR_SUCCESS) {
2459 // Already in error state; do nothing.
2460 return;
2461 }
2462
2463 size_t uOffset;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002464 pMe->uLastError = (uint8_t)MapSearch(pMe, pSearch, &uOffset, NULL, NULL, NULL);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002465 if(pMe->uLastError != QCBOR_SUCCESS) {
2466 return;
2467 }
2468
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002469 /* Need to get the current pre-order nesting level and cursor to be
2470 at the first item in the map/array just entered.
2471
2472 Also need to current map nesting level and start cursor to
2473 be at the right place.
2474
2475 The UsefulInBuf offset could be anywhere, so no assumption is
2476 made about it.
2477
2478 No assumption is made about the pre-order nesting level either.
2479
2480 However the map mode nesting level is assumed to be one above
2481 the map level that is being entered.
2482 */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002483 /* Seek to the data item that is the map or array */
2484 UsefulInputBuf_Seek(&(pMe->InBuf), uOffset);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002485 pMe->nesting.pCurrent = pMe->nesting.pCurrentMap; // TODO: part of DecodeNesting
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002486
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002487 // TODO: check error?
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002488 QCBORDecode_EnterBoundedMode(pMe, pSearch->uDataType);
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002489
Laurence Lundblade34691b92020-05-18 22:25:25 -07002490 printdecode(pMe, "FinishEnter");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002491}
2492
2493
Laurence Lundblade34691b92020-05-18 22:25:25 -07002494void QCBORDecode_EnterMapInMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002495{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002496 QCBORItem OneItemSeach[2];
2497 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
2498 OneItemSeach[0].label.int64 = nLabel;
2499 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
2500 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002501
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002502 /* The map to enter was found, now finish of entering it. */
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002503 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002504}
2505
2506
Laurence Lundblade34691b92020-05-18 22:25:25 -07002507void QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002508{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002509 QCBORItem OneItemSeach[2];
2510 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2511 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
2512 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
2513 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002514
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002515 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002516}
2517
2518
Laurence Lundblade34691b92020-05-18 22:25:25 -07002519void QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07002520{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002521 QCBORItem OneItemSeach[2];
2522 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
2523 OneItemSeach[0].label.int64 = nLabel;
2524 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
2525 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002526
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002527 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002528}
2529
2530
2531void QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
2532{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002533 QCBORItem OneItemSeach[2];
2534 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2535 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
2536 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
2537 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002538
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002539 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002540}
2541
2542
2543
2544
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002545
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002546/* Next item must be map or this generates an error */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002547void QCBORDecode_EnterBoundedMode(QCBORDecodeContext *pMe, uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002548{
Laurence Lundblade34691b92020-05-18 22:25:25 -07002549 if(pMe->uLastError != QCBOR_SUCCESS) {
2550 // Already in error state; do nothing.
2551 return;
2552 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002553
2554 /* Get the data item that is the map that is being searched */
Laurence Lundblade34691b92020-05-18 22:25:25 -07002555 QCBORItem Item;
Laurence Lundblade986017c2020-05-23 19:25:02 -07002556 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002557 if(pMe->uLastError != QCBOR_SUCCESS) {
2558 return;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002559 }
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002560 if(Item.uDataType != uType) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07002561 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
2562 return;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002563 }
2564
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002565 DecodeNesting_EnterMapMode(&(pMe->nesting), UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002566
Laurence Lundblade34691b92020-05-18 22:25:25 -07002567 printdecode(pMe, "EnterMapModeDone");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002568}
2569
2570
2571
2572QCBORError QCBORDecode_GetItemsInMap(QCBORDecodeContext *pCtx, QCBORItem *pItemList)
2573{
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002574 return MapSearch(pCtx, pItemList, NULL, NULL, NULL, NULL);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002575}
2576
2577
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002578QCBORError QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pCtx, QCBORItem *pItemList, void *pCallbackCtx, QCBORItemCallback pfCB)
2579{
2580 return MapSearch(pCtx, pItemList, NULL, NULL, pCallbackCtx, pfCB);
2581}
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002582
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002583
2584
Laurence Lundblade1341c592020-04-11 14:19:05 -07002585void QCBORDecode_RewindMap(QCBORDecodeContext *pMe)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002586{
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002587 // TODO: check for map mode; test this
Laurence Lundblade1341c592020-04-11 14:19:05 -07002588 pMe->nesting.pCurrent->uCount = pMe->nesting.pCurrent->uSaveCount;
2589 UsefulInputBuf_Seek(&(pMe->InBuf), pMe->nesting.pCurrent->uOffset);
2590}
2591
2592
Laurence Lundblade1341c592020-04-11 14:19:05 -07002593
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002594void QCBORDecode_EnterBstr(QCBORDecodeContext *pMe)
2595{
2596 if(pMe->uLastError != QCBOR_SUCCESS) {
2597 // Already in error state; do nothing.
2598 return;
2599 }
2600
2601 /* Get the data item that is the map that is being searched */
2602 QCBORItem Item;
2603 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
2604 if(pMe->uLastError != QCBOR_SUCCESS) {
2605 return;
2606 }
2607 if(Item.uDataType != QCBOR_TYPE_BYTE_STRING) {
2608 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
2609 return;
2610 }
2611
2612 // TODO: check for tag 24
2613
2614 // Need to move UIB input cursor to the right place
2615
2616 // Really this is a subtraction and an assignment; not much code
2617 // There is a range check in the seek.
2618 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
2619
2620 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset - Item.val.string.len);
2621
2622 UsefulInputBuf_SetBufferLen(&(pMe->InBuf), uEndOffset);
2623
2624 // TODO: comment on cast
2625 pMe->uLastError = (uint8_t)DecodeNesting_Descend2(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING, UINT16_MAX, (uint32_t)uEndOffset);
2626}
2627
2628
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002629
Laurence Lundbladee6430642020-03-14 21:15:44 -07002630
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002631
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002632
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002633
Laurence Lundblade11a064e2020-05-07 13:13:42 -07002634
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002635
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002636static QCBORError InterpretBool(const QCBORItem *pItem, bool *pBool)
2637{
2638 switch(pItem->uDataType) {
2639 case QCBOR_TYPE_TRUE:
2640 *pBool = true;
2641 return QCBOR_SUCCESS;
2642 break;
2643
2644 case QCBOR_TYPE_FALSE:
2645 *pBool = false;
2646 return QCBOR_SUCCESS;
2647 break;
2648
2649 default:
2650 return QCBOR_ERR_UNEXPECTED_TYPE;
2651 break;
2652 }
2653}
Laurence Lundbladee6430642020-03-14 21:15:44 -07002654
Laurence Lundbladec4537442020-04-14 18:53:22 -07002655void QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002656{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002657 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002658 // Already in error state, do nothing
Laurence Lundbladee6430642020-03-14 21:15:44 -07002659 return;
2660 }
2661
Laurence Lundbladec4537442020-04-14 18:53:22 -07002662 QCBORError nError;
2663 QCBORItem Item;
2664
2665 nError = QCBORDecode_GetNext(pMe, &Item);
2666 if(nError != QCBOR_SUCCESS) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002667 pMe->uLastError = (uint8_t)nError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002668 return;
2669 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002670 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002671}
2672
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002673void QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe, int64_t nLabel, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002674{
2675 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002676 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002677
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002678 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002679}
2680
2681
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002682void QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, bool *pValue)
2683{
2684 QCBORItem Item;
2685 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
2686
2687 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
2688}
2689
2690
2691
2692void QCBORDecode_GetTaggedStringInternal(QCBORDecodeContext *pMe, TagSpecification TagSpec, UsefulBufC *pBstr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002693{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002694 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002695 // Already in error state, do nothing
2696 return;
2697 }
2698
2699 QCBORError nError;
2700 QCBORItem Item;
2701
2702 nError = QCBORDecode_GetNext(pMe, &Item);
2703 if(nError != QCBOR_SUCCESS) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002704 pMe->uLastError = (uint8_t)nError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002705 return;
2706 }
2707
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002708 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, Item.uDataType);
2709
2710 if(pMe->uLastError == QCBOR_SUCCESS) {
2711 *pBstr = Item.val.string;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002712 }
2713}
2714
Laurence Lundbladec4537442020-04-14 18:53:22 -07002715
2716
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002717
2718static QCBORError ConvertBigNum(const QCBORItem *pItem, UsefulBufC *pValue, bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002719{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002720 *pbIsNegative = false;
2721
2722 bool bMustBeTagged = true; // TODO: fix this
2723
2724 switch(pItem->uDataType) {
2725 case QCBOR_TYPE_BYTE_STRING:
2726 // TODO: check that there is no tag here?
2727 if(bMustBeTagged) {
2728 return QCBOR_ERR_UNEXPECTED_TYPE;
2729 } else {
2730 *pValue = pItem->val.string;
2731 return QCBOR_SUCCESS;
2732 }
2733 break;
2734
2735 case QCBOR_TYPE_POSBIGNUM:
2736 *pValue = pItem->val.string;
2737 return QCBOR_SUCCESS;
2738 break;
2739
2740 case QCBOR_TYPE_NEGBIGNUM:
2741 *pbIsNegative = true;
2742 *pValue = pItem->val.string;
2743 return QCBOR_SUCCESS;
2744 break;
2745
2746 default:
2747 return QCBOR_ERR_UNEXPECTED_TYPE;
2748 break;
2749 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002750}
2751
2752
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002753/**
2754 @param[in] bMustBeTagged If \c true, then the data item must be tagged as either
2755 a positive or negative bignum. If \c false, then it only must be a byte string and bIsNegative
2756 will always be false on the asumption that it is positive, but it can be interpretted as
2757 negative if the the sign is know from other context.
2758 @param[out] pValue The bytes that make up the big num
2759 @param[out] pbIsNegative \c true if tagged as a negative big num. \c false otherwise.
2760
2761 if bMustBeTagged is false, then this will succeed if the data item is a plain byte string,
2762 a positive big num or a negative big num.
2763
2764 */
2765void QCBORDecode_GetBignum(QCBORDecodeContext *pMe, bool bMustBeTagged, UsefulBufC *pValue, bool *pbIsNegative)
2766{
2767 if(pMe->uLastError != QCBOR_SUCCESS) {
2768 // Already in error state, do nothing
2769 return;
2770 }
2771
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002772 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002773 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
2774 if(uError != QCBOR_SUCCESS) {
2775 pMe->uLastError = (uint8_t)uError;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002776 return;
2777 }
2778
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002779 pMe->uLastError = (uint8_t)ConvertBigNum(&Item, pValue, pbIsNegative);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002780}
2781
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002782void QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe, int64_t nLabel, bool bMustBeTagged, UsefulBufC *pValue, bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002783{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002784 QCBORItem Item;
2785 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002786
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002787 pMe->uLastError = (uint8_t)ConvertBigNum(&Item, pValue, pbIsNegative);
Laurence Lundbladec4537442020-04-14 18:53:22 -07002788}
2789
Laurence Lundbladec4537442020-04-14 18:53:22 -07002790
2791
2792
Laurence Lundbladee6430642020-03-14 21:15:44 -07002793
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002794typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002795
2796
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002797// The main exponentiator that works on only positive numbers
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002798static QCBORError Exponentitate10(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002799{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002800 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002801
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002802 if(uResult != 0) {
2803 /* This loop will run a maximum of 19 times because
2804 * UINT64_MAX < 10 ^^ 19. More than that will cause
2805 * exit with the overflow error
2806 */
2807 for(; nExponent > 0; nExponent--) {
2808 if(uResult > UINT64_MAX / 10) {
2809 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Error overflow
2810 }
2811 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002812 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002813
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002814 for(; nExponent < 0; nExponent++) {
2815 uResult = uResult / 10;
2816 if(uResult == 0) {
2817 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Underflow error
2818 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002819 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002820 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002821 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07002822
2823 *puResult = uResult;
2824
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002825 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002826}
2827
2828
Laurence Lundbladee6430642020-03-14 21:15:44 -07002829/* Convert a decimal fraction to an int64_t without using
2830 floating point or math libraries. Most decimal fractions
2831 will not fit in an int64_t and this will error out with
2832 under or overflow
2833 */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002834static QCBORError Exponentitate2(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002835{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002836 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002837
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002838 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002839
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002840 /* This loop will run a maximum of 64 times because
Laurence Lundbladee6430642020-03-14 21:15:44 -07002841 * INT64_MAX < 2^31. More than that will cause
2842 * exist with the overflow error
2843 */
2844 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002845 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002846 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Error overflow
Laurence Lundbladee6430642020-03-14 21:15:44 -07002847 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002848 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002849 nExponent--;
2850 }
2851
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002852 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002853 if(uResult == 0) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002854 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Underflow error
2855 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002856 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002857 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002858 }
2859
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002860 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002861
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002862 return QCBOR_SUCCESS;
2863}
2864
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002865/*
2866 Compute value with signed mantissa and signed result. Works with exponent of 2 or 10 based on exponentiator.
2867 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002868static inline QCBORError ExponentiateNN(int64_t nMantissa, int64_t nExponent, int64_t *pnResult, fExponentiator pfExp)
2869{
2870 uint64_t uResult;
2871
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002872 // Take the absolute value of the mantissa and convert to unsigned.
2873 // TODO: this should be possible in one intruction
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002874 uint64_t uMantissa = nMantissa > 0 ? (uint64_t)nMantissa : (uint64_t)-nMantissa;
2875
2876 // Do the exponentiation of the positive mantissa
2877 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
2878 if(uReturn) {
2879 return uReturn;
2880 }
2881
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002882
Laurence Lundblade983500d2020-05-14 11:49:34 -07002883 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
2884 of INT64_MIN. This assumes two's compliment representation where
2885 INT64_MIN is one increment farther from 0 than INT64_MAX.
2886 Trying to write -INT64_MIN doesn't work to get this because the
2887 compiler tries to work with an int64_t which can't represent
2888 -INT64_MIN.
2889 */
2890 uint64_t uMax = nMantissa > 0 ? INT64_MAX : (uint64_t)INT64_MAX+1;
2891
2892 // Error out if too large
2893 if(uResult > uMax) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002894 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
2895 }
2896
2897 // Casts are safe because of checks above
2898 *pnResult = nMantissa > 0 ? (int64_t)uResult : -(int64_t)uResult;
2899
2900 return QCBOR_SUCCESS;
2901}
2902
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002903/*
2904 Compute value with signed mantissa and unsigned result. Works with exponent of 2 or 10 based on exponentiator.
2905 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002906static inline QCBORError ExponentitateNU(int64_t nMantissa, int64_t nExponent, uint64_t *puResult, fExponentiator pfExp)
2907{
2908 if(nMantissa < 0) {
2909 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
2910 }
2911
2912 // Cast to unsigned is OK because of check for negative
2913 // Cast to unsigned is OK because UINT64_MAX > INT64_MAX
2914 // Exponentiation is straight forward
2915 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
2916}
2917
2918
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002919#include <math.h>
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002920
2921
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002922static QCBORError ConvertBigNumToUnsigned(const UsefulBufC BigNum, uint64_t uMax, uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002923{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002924 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002925
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002926 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002927 const uint8_t *pByte = BigNum.ptr;
2928 size_t uLen = BigNum.len;
2929 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07002930 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002931 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002932 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07002933 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002934 }
2935
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002936 *pResult = uResult;
2937 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002938}
2939
Laurence Lundblade887add82020-05-17 05:50:34 -07002940static inline QCBORError ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum, uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002941{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002942 return ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002943}
2944
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002945static inline QCBORError ConvertPositiveBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002946{
2947 uint64_t uResult;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002948 QCBORError uError = ConvertBigNumToUnsigned(BigNum, INT64_MAX, &uResult);
2949 if(uError) {
2950 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002951 }
2952 /* Cast is safe because ConvertBigNum is told to limit to INT64_MAX */
2953 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002954 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002955}
2956
2957
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002958static inline QCBORError ConvertNegativeBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002959{
2960 uint64_t uResult;
Laurence Lundbladeda095972020-06-06 18:35:33 -07002961 /* negaative int furthest from zero is INT64_MIN
2962 which is expressed as -INT64_MAX-1. The value of
2963 a negative bignum is -n-1, one further from zero
2964 than the positive bignum */
2965
2966 /* say INT64_MIN is -2; then INT64_MAX is 1.
2967 Then -n-1 <= INT64_MIN.
2968 Then -n -1 <= -INT64_MAX - 1
2969 THen n <= INT64_MAX. */
2970 QCBORError uError = ConvertBigNumToUnsigned(BigNum, INT64_MAX, &uResult);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002971 if(uError) {
2972 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002973 }
2974 /* Cast is safe because ConvertBigNum is told to limit to INT64_MAX */
Laurence Lundblade887add82020-05-17 05:50:34 -07002975 // TODO: this code is incorrect. See RFC 7049
Laurence Lundbladeda095972020-06-06 18:35:33 -07002976 uResult++; // this is the -1 in -n-1
Laurence Lundbladee6430642020-03-14 21:15:44 -07002977 *pResult = -(int64_t)uResult;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002978 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002979}
2980
Laurence Lundbladef6c86662020-05-12 02:08:00 -07002981#include "fenv.h"
Laurence Lundbladec4537442020-04-14 18:53:22 -07002982
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002983
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002984/*
2985Convert a integers and floats to an int64_t.
2986
2987\param[in] uOptions Bit mask list of conversion options.
2988
2989\retval QCBOR_ERR_CONVERSION_NOT_REQUESTED Conversion, possible, but not requested in uOptions.
2990
2991\retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
2992
2993\retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large or too small.
2994
2995*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002996static QCBORError ConvertInt64(const QCBORItem *pItem, uint32_t uOptions, int64_t *pnValue)
2997{
2998 switch(pItem->uDataType) {
2999 // TODO: float when ifdefs are set
3000 case QCBOR_TYPE_DOUBLE:
3001 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3002 // TODO: what about under/overflow here?
3003 // Invokes the floating-point HW and/or compiler-added libraries
3004 feclearexcept(FE_ALL_EXCEPT);
3005 *pnValue = llround(pItem->val.dfnum);
3006 if(fetestexcept(FE_INVALID)) {
3007 // TODO: better error code
3008 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3009 }
3010 } else {
3011 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3012 }
3013 break;
3014
3015 case QCBOR_TYPE_INT64:
3016 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
3017 *pnValue = pItem->val.int64;
3018 } else {
3019 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3020 }
3021 break;
3022
3023 case QCBOR_TYPE_UINT64:
3024 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
3025 if(pItem->val.uint64 < INT64_MAX) {
3026 *pnValue = pItem->val.int64;
3027 } else {
3028 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3029 }
3030 } else {
3031 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3032 }
3033 break;
3034
3035 default:
3036 return QCBOR_ERR_UNEXPECTED_TYPE;
3037 }
3038 return QCBOR_SUCCESS;
3039}
3040
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003041
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003042void QCBORDecode_GetInt64ConvertInternal(QCBORDecodeContext *pMe,
3043 uint32_t uOptions,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003044 int64_t *pnValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003045 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003046{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07003047 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003048 return;
3049 }
3050
Laurence Lundbladee6430642020-03-14 21:15:44 -07003051 QCBORItem Item;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003052 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
3053 if(uError) {
3054 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003055 return;
3056 }
3057
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003058 if(pItem) {
3059 *pItem = Item;
3060 }
3061
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003062 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003063}
3064
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003065
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003066void QCBORDecode_GetInt64ConvertInternalInMapN(QCBORDecodeContext *pMe,
3067 int64_t nLabel,
3068 uint32_t uOptions,
3069 int64_t *pnValue,
3070 QCBORItem *pItem)
3071{
3072 QCBORItem Item;
3073 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
3074
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003075 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003076}
3077
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003078
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003079void QCBORDecode_GetInt64ConvertInternalInMapSZ(QCBORDecodeContext *pMe,
3080 const char * szLabel,
3081 uint32_t uOptions,
3082 int64_t *pnValue,
3083 QCBORItem *pItem)
3084{
3085 if(pMe->uLastError != QCBOR_SUCCESS) {
3086 return;
3087 }
3088
3089 QCBORItem Item;
3090 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3091
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003092 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003093}
3094
3095
3096
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003097/*
3098 Convert a large variety of integer types to an int64_t.
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003099
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003100 \param[in] uOptions Bit mask list of conversion options.
3101
3102 \retval QCBOR_ERR_CONVERSION_NOT_REQUESTED Conversion, possible, but not requested in uOptions.
3103
3104 \retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
3105
3106 \retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large or too small.
3107
3108 */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003109static QCBORError Int64ConvertAll(const QCBORItem *pItem, uint32_t uOptions, int64_t *pnValue)
3110{
3111 QCBORError uErr;
3112
3113 switch(pItem->uDataType) {
3114
3115 case QCBOR_TYPE_POSBIGNUM:
3116 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3117 return ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003118 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003119 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003120 }
3121 break;
3122
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003123 case QCBOR_TYPE_NEGBIGNUM:
3124 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3125 return ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003126 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003127 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003128 }
3129 break;
3130
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003131#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
3132 case QCBOR_TYPE_DECIMAL_FRACTION:
3133 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3134 return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
3135 pItem->val.expAndMantissa.nExponent,
3136 pnValue,
3137 &Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003138 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003139 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3140 }
3141 break;
3142
3143 case QCBOR_TYPE_BIGFLOAT:
3144 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3145 return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
3146 pItem->val.expAndMantissa.nExponent,
3147 pnValue,
3148 Exponentitate2);
3149 } else {
3150 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3151 }
3152 break;
3153
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003154 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
3155 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3156 int64_t nMantissa;
3157 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3158 if(uErr) {
3159 return uErr;
3160 }
3161 return ExponentiateNN(nMantissa,
3162 pItem->val.expAndMantissa.nExponent,
3163 pnValue,
3164 Exponentitate10);
3165 } else {
3166 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3167 }
3168 break;
3169
3170 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
3171 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3172 int64_t nMantissa;
3173 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3174 if(uErr) {
3175 return uErr;
3176 }
3177 return ExponentiateNN(nMantissa,
3178 pItem->val.expAndMantissa.nExponent,
3179 pnValue,
3180 Exponentitate10);
3181 } else {
3182 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3183 }
3184 break;
3185
3186 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
3187 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3188 int64_t nMantissa;
3189 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3190 if(uErr) {
3191 return uErr;
3192 }
3193 return ExponentiateNN(nMantissa,
3194 pItem->val.expAndMantissa.nExponent,
3195 pnValue,
3196 Exponentitate2);
3197 } else {
3198 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3199 }
3200 break;
3201
3202 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
3203 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3204 int64_t nMantissa;
3205 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3206 if(uErr) {
3207 return uErr;
3208 }
3209 return ExponentiateNN(nMantissa,
3210 pItem->val.expAndMantissa.nExponent,
3211 pnValue,
3212 Exponentitate2);
3213 } else {
3214 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003215 }
3216 break;
3217
Laurence Lundbladec4537442020-04-14 18:53:22 -07003218 default:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003219 return QCBOR_ERR_UNEXPECTED_TYPE;
3220#endif
Laurence Lundbladec4537442020-04-14 18:53:22 -07003221 }
3222}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003223
3224
Laurence Lundbladec4537442020-04-14 18:53:22 -07003225/*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003226 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003227 */
3228void QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003229{
3230 QCBORItem Item;
3231
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003232 QCBORDecode_GetInt64ConvertInternal(pMe, uOptions, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003233
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003234 if(pMe->uLastError == QCBOR_SUCCESS) {
3235 // The above conversion succeeded
3236 return;
3237 }
3238
Laurence Lundbladef6c86662020-05-12 02:08:00 -07003239 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003240 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07003241 return;
3242 }
3243
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003244 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003245}
3246
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003247
3248/*
3249Public function, see header qcbor/qcbor_decode.h file
3250*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003251void QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, int64_t *pnValue)
3252{
3253 QCBORItem Item;
3254
3255 QCBORDecode_GetInt64ConvertInternalInMapN(pMe, nLabel, uOptions, pnValue, &Item);
3256
3257 if(pMe->uLastError == QCBOR_SUCCESS) {
3258 // The above conversion succeeded
3259 return;
3260 }
3261
3262 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3263 // The above conversion failed in a way that code below can't correct
3264 return;
3265 }
3266
3267 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
3268}
3269
3270
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003271/*
3272Public function, see header qcbor/qcbor_decode.h file
3273*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003274void QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, int64_t *pnValue)
3275{
3276 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003277 QCBORDecode_GetInt64ConvertInternalInMapSZ(pMe, szLabel, uOptions, pnValue, &Item);
3278
3279 if(pMe->uLastError == QCBOR_SUCCESS) {
3280 // The above conversion succeeded
3281 return;
3282 }
3283
3284 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3285 // The above conversion failed in a way that code below can't correct
3286 return;
3287 }
3288
3289 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
3290}
3291
3292
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003293static QCBORError ConvertUint64(const QCBORItem *pItem, uint32_t uOptions, uint64_t *puValue)
3294{
3295 switch(pItem->uDataType) {
3296 // TODO: type flaot
3297 case QCBOR_TYPE_DOUBLE:
3298 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3299 feclearexcept(FE_ALL_EXCEPT);
3300 double dRounded = round(pItem->val.dfnum);
3301 // TODO: over/underflow
3302 if(fetestexcept(FE_INVALID)) {
3303 // TODO: better error code
3304 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3305 } else if(isnan(dRounded)) {
3306 // TODO: better error code
3307 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3308 } else if(dRounded >= 0) {
3309 *puValue = (uint64_t)dRounded;
3310 } else {
3311 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3312 }
3313 } else {
3314 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3315 }
3316 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003317
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003318 case QCBOR_TYPE_INT64:
3319 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
3320 if(pItem->val.int64 >= 0) {
3321 *puValue = (uint64_t)pItem->val.int64;
3322 } else {
3323 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3324 }
3325 } else {
3326 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3327 }
3328 break;
3329
3330 case QCBOR_TYPE_UINT64:
3331 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
3332 *puValue = pItem->val.uint64;
3333 } else {
3334 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3335 }
3336 break;
3337
3338 default:
3339 return QCBOR_ERR_UNEXPECTED_TYPE;
3340 }
3341 return QCBOR_SUCCESS;
3342}
Laurence Lundbladec4537442020-04-14 18:53:22 -07003343
3344
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003345void QCBORDecode_GetUInt64ConvertInternal(QCBORDecodeContext *pMe,
3346 uint32_t uOptions,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003347 uint64_t *puValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003348 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003349{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003350 if(pMe->uLastError != QCBOR_SUCCESS) {
3351 return;
3352 }
3353
Laurence Lundbladec4537442020-04-14 18:53:22 -07003354 QCBORItem Item;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003355
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003356 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
3357 if(uError) {
3358 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003359 return;
3360 }
3361
Laurence Lundbladea826c502020-05-10 21:07:00 -07003362 if(pItem) {
3363 *pItem = Item;
3364 }
3365
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003366 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003367}
3368
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003369
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003370void QCBORDecode_GetUint64ConvertInternalInMapN(QCBORDecodeContext *pMe,
3371 int64_t nLabel,
3372 uint32_t uOptions,
3373 uint64_t *puValue,
3374 QCBORItem *pItem)
3375{
3376 QCBORItem Item;
3377 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
3378
3379 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
3380}
3381
3382
3383void QCBORDecode_GetUint64ConvertInternalInMapSZ(QCBORDecodeContext *pMe,
3384 const char * szLabel,
3385 uint32_t uOptions,
3386 uint64_t *puValue,
3387 QCBORItem *pItem)
3388{
3389 if(pMe->uLastError != QCBOR_SUCCESS) {
3390 return;
3391 }
3392
3393 QCBORItem Item;
3394 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3395
3396 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
3397}
3398
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003399/*
3400 Public function, see header qcbor/qcbor_decode.h file
3401*/
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003402static QCBORError Uint64ConvertAll(const QCBORItem *pItem, uint32_t uOptions, uint64_t *puValue)
3403{
3404 QCBORError uErr;
3405
3406 switch(pItem->uDataType) {
3407
3408 case QCBOR_TYPE_POSBIGNUM:
3409 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3410 return ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
3411 } else {
3412 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3413 }
3414 break;
3415
3416 case QCBOR_TYPE_NEGBIGNUM:
3417 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3418 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3419 } else {
3420 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3421 }
3422 break;
3423
3424#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
3425
3426 case QCBOR_TYPE_DECIMAL_FRACTION:
3427 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3428 return ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
3429 pItem->val.expAndMantissa.nExponent,
3430 puValue,
3431 Exponentitate10);
3432 } else {
3433 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3434 }
3435 break;
3436
3437 case QCBOR_TYPE_BIGFLOAT:
3438 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3439 return ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
3440 pItem->val.expAndMantissa.nExponent,
3441 puValue,
3442 Exponentitate2);
3443 } else {
3444 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3445 }
3446 break;
3447
3448 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
3449 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3450 // TODO: Would be better to convert to unsigned
3451 int64_t nMantissa;
3452 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3453 if(uErr != QCBOR_SUCCESS) {
3454 return uErr;
3455 }
3456 return ExponentitateNU(nMantissa,
3457 pItem->val.expAndMantissa.nExponent,
3458 puValue,
3459 Exponentitate10);
3460 } else {
3461 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3462 }
3463 break;
3464
3465 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
3466 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3467 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3468 } else {
3469 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3470 }
3471 break;
3472
3473 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
3474 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3475 // TODO: Would be better to convert to unsigned
3476 int64_t nMantissa;
3477 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3478 if(uErr != QCBOR_SUCCESS) {
3479 return uErr;
3480 }
3481 return ExponentitateNU(nMantissa,
3482 pItem->val.expAndMantissa.nExponent,
3483 puValue,
3484 Exponentitate2);
3485 } else {
3486 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3487 }
3488 break;
3489
3490 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
3491 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3492 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3493 } else {
3494 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3495 }
3496 break;
3497#endif
3498 default:
3499 return QCBOR_ERR_UNEXPECTED_TYPE;
3500 }
3501}
3502
3503
3504void QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003505{
3506 QCBORItem Item;
3507
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003508 QCBORDecode_GetUInt64ConvertInternal(pMe, uOptions, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003509
Laurence Lundbladef6c86662020-05-12 02:08:00 -07003510 if(pMe->uLastError == QCBOR_SUCCESS) {
3511 // The above conversion succeeded
3512 return;
3513 }
3514
3515 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3516 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07003517 return;
3518 }
3519
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003520 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003521}
3522
Laurence Lundbladec4537442020-04-14 18:53:22 -07003523
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003524/*
3525Public function, see header qcbor/qcbor_decode.h file
3526*/
3527void QCBORDecode_GetUint64ConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, uint64_t *puValue)
3528{
3529 QCBORItem Item;
3530
3531 QCBORDecode_GetUint64ConvertInternalInMapN(pMe, nLabel, uOptions, puValue, &Item);
3532
3533 if(pMe->uLastError == QCBOR_SUCCESS) {
3534 // The above conversion succeeded
3535 return;
3536 }
3537
3538 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3539 // The above conversion failed in a way that code below can't correct
3540 return;
3541 }
3542
3543 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
3544}
3545
3546
3547/*
3548Public function, see header qcbor/qcbor_decode.h file
3549*/
3550void QCBORDecode_GetUint64ConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, uint64_t *puValue)
3551{
3552 QCBORItem Item;
3553 QCBORDecode_GetUint64ConvertInternalInMapSZ(pMe, szLabel, uOptions, puValue, &Item);
3554
3555 if(pMe->uLastError == QCBOR_SUCCESS) {
3556 // The above conversion succeeded
3557 return;
3558 }
3559
3560 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3561 // The above conversion failed in a way that code below can't correct
3562 return;
3563 }
3564
3565 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
3566}
3567
3568
3569static QCBORError ConvertDouble(const QCBORItem *pItem, uint32_t uOptions, double *pdValue)
3570{
3571 switch(pItem->uDataType) {
3572 // TODO: float when ifdefs are set
3573 case QCBOR_TYPE_DOUBLE:
3574 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3575 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3576 *pdValue = pItem->val.dfnum;
3577 } else {
3578 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3579 }
3580 }
3581 break;
3582
3583 case QCBOR_TYPE_INT64:
3584 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
3585 // TODO: how does this work?
3586 *pdValue = (double)pItem->val.int64;
3587
3588 } else {
3589 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3590 }
3591 break;
3592
3593 case QCBOR_TYPE_UINT64:
3594 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
3595 *pdValue = (double)pItem->val.uint64;
3596 } else {
3597 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3598 }
3599 break;
3600
3601 default:
3602 return QCBOR_ERR_UNEXPECTED_TYPE;
3603 }
3604
3605 return QCBOR_SUCCESS;
3606}
3607
3608
3609
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003610void QCBORDecode_GetDoubleConvertInternal(QCBORDecodeContext *pMe,
3611 uint32_t uOptions,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003612 double *pdValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003613 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003614{
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003615 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003616 return;
3617 }
3618
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003619 QCBORItem Item;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003620
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003621 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003622 if(uError) {
3623 pMe->uLastError = (uint8_t)uError;
3624 return;
3625 }
3626
3627 if(pItem) {
3628 *pItem = Item;
3629 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07003630
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003631 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003632}
Laurence Lundbladec4537442020-04-14 18:53:22 -07003633
Laurence Lundbladec4537442020-04-14 18:53:22 -07003634
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003635void QCBORDecode_GetDoubleConvertInternalInMapN(QCBORDecodeContext *pMe,
3636 int64_t nLabel,
3637 uint32_t uOptions,
3638 double *pdValue,
3639 QCBORItem *pItem)
3640{
3641 QCBORItem Item;
3642 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
3643
3644 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
3645}
3646
3647void QCBORDecode_GetDoubleConvertInternalInMapSZ(QCBORDecodeContext *pMe,
3648 const char * szLabel,
3649 uint32_t uOptions,
3650 double *pdValue,
3651 QCBORItem *pItem)
3652{
3653 if(pMe->uLastError != QCBOR_SUCCESS) {
3654 return;
3655 }
3656
3657 QCBORItem Item;
3658 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3659
3660 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
3661}
3662
3663
3664
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003665static double ConvertBigNumToDouble(const UsefulBufC BigNum)
3666{
3667 double dResult;
3668
3669 dResult = 0.0;
3670 const uint8_t *pByte = BigNum.ptr;
3671 size_t uLen = BigNum.len;
3672 /* This will overflow and become the float value INFINITY if the number
3673 is too large to fit. No error will be logged.
3674 TODO: should an error be logged? */
3675 while(uLen--) {
3676 dResult = (dResult * 256.0) + (double)*pByte++;
3677 }
3678
3679 return dResult;
3680}
3681
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003682static QCBORError DoubleConvertAll(const QCBORItem *pItem, uint32_t uOptions, double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003683{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003684 /*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003685 https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
3686
3687 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003688 switch(pItem->uDataType) {
3689 // TODO: type float
3690 case QCBOR_TYPE_DECIMAL_FRACTION:
3691 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3692 // TODO: rounding and overflow errors
3693 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
3694 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
3695 } else {
3696 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3697 }
3698 break;
3699
3700 case QCBOR_TYPE_BIGFLOAT:
3701 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
3702 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
3703 exp2((double)pItem->val.expAndMantissa.nExponent);
3704 } else {
3705 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3706 }
3707 break;
3708
3709 case QCBOR_TYPE_POSBIGNUM:
3710 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3711 *pdValue = ConvertBigNumToDouble(pItem->val.bigNum);
3712 } else {
3713 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3714 }
3715 break;
3716
3717 case QCBOR_TYPE_NEGBIGNUM:
3718 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07003719 *pdValue = -1-ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003720 } else {
3721 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3722 }
3723 break;
3724
3725 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
3726 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3727 double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
3728 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
3729 } else {
3730 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3731 }
3732 break;
3733
3734 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
3735 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3736 double dMantissa = -ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
3737 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
3738 } else {
3739 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3740 }
3741 break;
3742
3743 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
3744 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3745 double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
3746 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
3747 } else {
3748 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3749 }
3750 break;
3751
3752 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
3753 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07003754 double dMantissa = -1-ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003755 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
3756 } else {
3757 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3758 }
3759 break;
3760
3761 default:
3762 return QCBOR_ERR_UNEXPECTED_TYPE;
3763 }
3764
3765 return QCBOR_SUCCESS;
3766}
3767
3768
3769/*
3770 Public function, see header qcbor/qcbor_decode.h file
3771*/
3772void QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, double *pdValue)
3773{
3774
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003775 QCBORItem Item;
3776
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003777 QCBORDecode_GetDoubleConvertInternal(pMe, uOptions, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003778
3779 if(pMe->uLastError == QCBOR_SUCCESS) {
3780 // The above conversion succeeded
3781 return;
3782 }
3783
3784 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3785 // The above conversion failed in a way that code below can't correct
3786 return;
3787 }
3788
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003789 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003790}
3791
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003792
3793/*
3794Public function, see header qcbor/qcbor_decode.h file
3795*/
3796void QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, double *pdValue)
3797{
3798 QCBORItem Item;
3799
3800 QCBORDecode_GetDoubleConvertInternalInMapN(pMe, nLabel, uOptions, pdValue, &Item);
3801
3802 if(pMe->uLastError == QCBOR_SUCCESS) {
3803 // The above conversion succeeded
3804 return;
3805 }
3806
3807 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3808 // The above conversion failed in a way that code below can't correct
3809 return;
3810 }
3811
3812 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
3813}
3814
3815
3816/*
3817Public function, see header qcbor/qcbor_decode.h file
3818*/
3819void QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, double *pdValue)
3820{
3821 QCBORItem Item;
3822 QCBORDecode_GetDoubleConvertInternalInMapSZ(pMe, szLabel, uOptions, pdValue, &Item);
3823
3824 if(pMe->uLastError == QCBOR_SUCCESS) {
3825 // The above conversion succeeded
3826 return;
3827 }
3828
3829 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3830 // The above conversion failed in a way that code below can't correct
3831 return;
3832 }
3833
3834 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
3835}