blob: 84db9e0db4ab4a8fb7accaa7ca48930b9877880d [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 Lundblade9c905e82020-04-25 11:31:38 -0700124inline static bool
125DecodeNesting_IsAtTop(const QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700126{
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700127 if(pNesting->pCurrent == &(pNesting->pMapsAndArrays[0])) {
128 return true;
129 } else {
130 return false;
131 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700132}
133
Laurence Lundblade937ea812020-05-08 11:38:23 -0700134// Determine if at the end of a map or array while in map mode
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700135inline static bool
136DecodeNesting_AtEnd(const QCBORDecodeNesting *pNesting)
137{
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700138 if(pNesting->pCurrentMap && pNesting->pCurrentMap->uMapMode) {
139 if(pNesting->pCurrentMap->uCount == 0) {
Laurence Lundblade937ea812020-05-08 11:38:23 -0700140 // TODO: won't work for indefinite length
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700141 // In map mode and consumed all items, so it is the end
142 return true;
143 } else {
144 // In map mode, all items not consumed, so it is NOT the end
145 return false;
146 }
147 } else {
Laurence Lundblade937ea812020-05-08 11:38:23 -0700148 // Not in map mode. The end is determined in other ways.
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700149 return false;
150 }
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700151}
152
153
Laurence Lundbladeee851742020-01-08 08:37:05 -0800154inline static int
155DecodeNesting_IsIndefiniteLength(const QCBORDecodeNesting *pNesting)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700156{
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700157 return pNesting->pCurrent->uCount == UINT16_MAX;
158}
159
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700160inline static int
161DecodeNesting_InMapMode(const QCBORDecodeNesting *pNesting)
162{
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700163 return (bool)pNesting->pCurrentMap->uMapMode;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700164}
165
Laurence Lundbladeee851742020-01-08 08:37:05 -0800166inline static uint8_t
167DecodeNesting_GetLevel(QCBORDecodeNesting *pNesting)
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800168{
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800169 // Check in DecodeNesting_Descend and never having
Laurence Lundbladebb87be22020-04-09 19:15:32 -0700170 // QCBOR_MAX_ARRAY_NESTING > 255 gaurantees cast is safe
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800171 return (uint8_t)(pNesting->pCurrent - &(pNesting->pMapsAndArrays[0]));
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800172}
173
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700174inline static uint8_t
175DecodeNesting_GetMapModeLevel(QCBORDecodeNesting *pNesting)
176{
177 // Check in DecodeNesting_Descend and never having
178 // QCBOR_MAX_ARRAY_NESTING > 255 gaurantees cast is safe
179 return (uint8_t)(pNesting->pCurrentMap - &(pNesting->pMapsAndArrays[0]));
180}
181
Laurence Lundbladeee851742020-01-08 08:37:05 -0800182inline static int
183DecodeNesting_TypeIsMap(const QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700184{
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700185 if(DecodeNesting_IsAtTop(pNesting)) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700186 return 0;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700187 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800188
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700189 return CBOR_MAJOR_TYPE_MAP == pNesting->pCurrent->uMajorType;
190}
191
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800192// Process a break. This will either ascend the nesting or error out
Laurence Lundbladeee851742020-01-08 08:37:05 -0800193inline static QCBORError
194DecodeNesting_BreakAscend(QCBORDecodeNesting *pNesting)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700195{
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800196 // breaks must always occur when there is nesting
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700197 if(DecodeNesting_IsAtTop(pNesting)) {
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800198 return QCBOR_ERR_BAD_BREAK;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700199 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800200
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800201 // breaks can only occur when the map/array is indefinite length
202 if(!DecodeNesting_IsIndefiniteLength(pNesting)) {
203 return QCBOR_ERR_BAD_BREAK;
204 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800205
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800206 // if all OK, the break reduces the level of nesting
207 pNesting->pCurrent--;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800208
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800209 return QCBOR_SUCCESS;
210}
211
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700212// Called on every single item except breaks including decode of a map/array
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700213/* Decrements the map/array counter if possible. If decrement
214 closed out a map or array, then level up in nesting and decrement
215 again, until, the top is reached or the end of a map mode is reached
216 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800217inline static void
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700218DecodeNesting_DecrementCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800219{
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700220 while(!DecodeNesting_IsAtTop(pNesting)) {
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700221 // Not at the top level, so there is decrementing to be done.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800222
Laurence Lundblade9e3651c2018-10-10 11:49:55 +0800223 if(!DecodeNesting_IsIndefiniteLength(pNesting)) {
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700224 // Decrement the current nesting level if it is not indefinite.
Laurence Lundblade9e3651c2018-10-10 11:49:55 +0800225 pNesting->pCurrent->uCount--;
226 }
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700227
228 if(pNesting->pCurrent->uCount != 0) {
229 // Did not close out an array or map, so nothing further
230 break;
231 }
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700232
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700233 if(pNesting->pCurrent->uMapMode) {
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700234 // In map mode the level-up must be done explicitly
235 break;
236 }
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700237
238 // Closed out an array or map so level up
239 pNesting->pCurrent--;
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700240 /*if(pNesting->pCurrent->uMapMode) {
241 // Bring the current map level along if new level is a map
242 // TODO: must search up until a mapmode level is found.
243 pNesting->pCurrentMap = pNesting->pCurrent;
244 } */
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700245
246 // Continue with loop to see if closing out this doesn't close out more
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700247 }
248}
249
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700250inline static void
251DecodeNesting_EnterMapMode(QCBORDecodeNesting *pNesting, size_t uOffset)
252{
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700253 pNesting->pCurrentMap = pNesting->pCurrent;
254 pNesting->pCurrentMap->uMapMode = 1;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700255 // Cast to uint32_t is safe because QCBOR onl works on data < UINT32_MAX
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700256 pNesting->pCurrentMap->uOffset = (uint32_t)uOffset;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700257}
258
259inline static void
260DecodeNesting_Exit(QCBORDecodeNesting *pNesting)
261{
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700262 pNesting->pCurrentMap->uMapMode = 0;
263 pNesting->pCurrent = pNesting->pCurrentMap - 1; // TODO error check
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700264
265 DecodeNesting_DecrementCount(pNesting);
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700266
267 while(1) {
268 pNesting->pCurrentMap--;
269 if(pNesting->pCurrentMap->uMapMode) {
270 break;
271 }
272 if(pNesting->pCurrentMap == &(pNesting->pMapsAndArrays[0])) {
273 break;
274 }
275 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700276}
277
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800278// Called on every map/array
Laurence Lundbladeee851742020-01-08 08:37:05 -0800279inline static QCBORError
280DecodeNesting_Descend(QCBORDecodeNesting *pNesting, QCBORItem *pItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700281{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700282 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800283
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800284 if(pItem->val.uCount == 0) {
285 // Nothing to do for empty definite lenth arrays. They are just are
286 // effectively the same as an item that is not a map or array
287 goto Done;
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530288 // Empty indefinite length maps and arrays are handled elsewhere
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800289 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800290
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800291 // Error out if arrays is too long to handle
292 if(pItem->val.uCount != UINT16_MAX && pItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700293 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
294 goto Done;
295 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800296
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800297 // Error out if nesting is too deep
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700298 if(pNesting->pCurrent >= &(pNesting->pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING])) {
299 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
300 goto Done;
301 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800302
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800303 // The actual descend
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700304 pNesting->pCurrent++;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800305
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800306 // Record a few details for this nesting level
307 pNesting->pCurrent->uMajorType = pItem->uDataType;
308 pNesting->pCurrent->uCount = pItem->val.uCount;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700309 pNesting->pCurrent->uSaveCount = pItem->val.uCount;
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700310 pNesting->pCurrent->uMapMode = 0;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800311
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700312Done:
313 return nReturn;;
314}
315
Laurence Lundbladeee851742020-01-08 08:37:05 -0800316inline static void
317DecodeNesting_Init(QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700318{
319 pNesting->pCurrent = &(pNesting->pMapsAndArrays[0]);
320}
321
322
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700323static void DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting, QCBORDecodeNesting *pSave)
324{
325 *pSave = *pNesting;
326 pNesting->pCurrent = pNesting->pCurrentMap;
327
328 if(pNesting->pCurrent->uCount != UINT16_MAX) {
329 pNesting->pCurrent->uCount = pNesting->pCurrent->uSaveCount;
330 }
331}
332
333static void DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting, QCBORDecodeNesting *pSave)
334{
335 *pNesting = *pSave;
336}
337
338
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700339
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700340/*
341 This list of built-in tags. Only add tags here that are
342 clearly established and useful. Once a tag is added here
343 it can't be taken out as that would break backwards compatibility.
344 There are only 48 slots available forever.
345 */
346static const uint16_t spBuiltInTagMap[] = {
Laurence Lundblade59289e52019-12-30 13:44:37 -0800347 CBOR_TAG_DATE_STRING, // See TAG_MAPPER_FIRST_SIX
348 CBOR_TAG_DATE_EPOCH, // See TAG_MAPPER_FIRST_SIX
349 CBOR_TAG_POS_BIGNUM, // See TAG_MAPPER_FIRST_SIX
350 CBOR_TAG_NEG_BIGNUM, // See TAG_MAPPER_FIRST_SIX
351 CBOR_TAG_DECIMAL_FRACTION, // See TAG_MAPPER_FIRST_SIX
352 CBOR_TAG_BIGFLOAT, // See TAG_MAPPER_FIRST_SIX
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700353 CBOR_TAG_COSE_ENCRYPTO,
354 CBOR_TAG_COSE_MAC0,
355 CBOR_TAG_COSE_SIGN1,
356 CBOR_TAG_ENC_AS_B64URL,
357 CBOR_TAG_ENC_AS_B64,
358 CBOR_TAG_ENC_AS_B16,
359 CBOR_TAG_CBOR,
360 CBOR_TAG_URI,
361 CBOR_TAG_B64URL,
362 CBOR_TAG_B64,
363 CBOR_TAG_REGEX,
364 CBOR_TAG_MIME,
365 CBOR_TAG_BIN_UUID,
366 CBOR_TAG_CWT,
367 CBOR_TAG_ENCRYPT,
368 CBOR_TAG_MAC,
369 CBOR_TAG_SIGN,
370 CBOR_TAG_GEO_COORD,
371 CBOR_TAG_CBOR_MAGIC
372};
373
374// This is used in a bit of cleverness in GetNext_TaggedItem() to
375// keep code size down and switch for the internal processing of
Laurence Lundblade59289e52019-12-30 13:44:37 -0800376// these types. This will break if the first six items in
377// spBuiltInTagMap don't have values 0,1,2,3,4,5. That is the
378// mapping is 0 to 0, 1 to 1, 2 to 2 and 3 to 3....
379#define QCBOR_TAGFLAG_DATE_STRING (0x01LL << CBOR_TAG_DATE_STRING)
380#define QCBOR_TAGFLAG_DATE_EPOCH (0x01LL << CBOR_TAG_DATE_EPOCH)
381#define QCBOR_TAGFLAG_POS_BIGNUM (0x01LL << CBOR_TAG_POS_BIGNUM)
382#define QCBOR_TAGFLAG_NEG_BIGNUM (0x01LL << CBOR_TAG_NEG_BIGNUM)
383#define QCBOR_TAGFLAG_DECIMAL_FRACTION (0x01LL << CBOR_TAG_DECIMAL_FRACTION)
384#define QCBOR_TAGFLAG_BIGFLOAT (0x01LL << CBOR_TAG_BIGFLOAT)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700385
Laurence Lundblade59289e52019-12-30 13:44:37 -0800386#define TAG_MAPPER_FIRST_SIX (QCBOR_TAGFLAG_DATE_STRING |\
387 QCBOR_TAGFLAG_DATE_EPOCH |\
388 QCBOR_TAGFLAG_POS_BIGNUM |\
389 QCBOR_TAGFLAG_NEG_BIGNUM |\
390 QCBOR_TAGFLAG_DECIMAL_FRACTION |\
391 QCBOR_TAGFLAG_BIGFLOAT)
392
393#define TAG_MAPPER_FIRST_FOUR (QCBOR_TAGFLAG_DATE_STRING |\
394 QCBOR_TAGFLAG_DATE_EPOCH |\
395 QCBOR_TAGFLAG_POS_BIGNUM |\
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700396 QCBOR_TAGFLAG_NEG_BIGNUM)
397
398#define TAG_MAPPER_TOTAL_TAG_BITS 64 // Number of bits in a uint64_t
399#define TAG_MAPPER_CUSTOM_TAGS_BASE_INDEX (TAG_MAPPER_TOTAL_TAG_BITS - QCBOR_MAX_CUSTOM_TAGS) // 48
400#define TAG_MAPPER_MAX_SIZE_BUILT_IN_TAGS (TAG_MAPPER_TOTAL_TAG_BITS - QCBOR_MAX_CUSTOM_TAGS ) // 48
401
402static inline int TagMapper_LookupBuiltIn(uint64_t uTag)
403{
404 if(sizeof(spBuiltInTagMap)/sizeof(uint16_t) > TAG_MAPPER_MAX_SIZE_BUILT_IN_TAGS) {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800405 /*
406 This is a cross-check to make sure the above array doesn't
407 accidentally get made too big. In normal conditions the above
408 test should optimize out as all the values are known at compile
409 time.
410 */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700411 return -1;
412 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800413
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700414 if(uTag > UINT16_MAX) {
415 // This tag map works only on 16-bit tags
416 return -1;
417 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800418
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700419 for(int nTagBitIndex = 0; nTagBitIndex < (int)(sizeof(spBuiltInTagMap)/sizeof(uint16_t)); nTagBitIndex++) {
420 if(spBuiltInTagMap[nTagBitIndex] == uTag) {
421 return nTagBitIndex;
422 }
423 }
424 return -1; // Indicates no match
425}
426
427static inline int TagMapper_LookupCallerConfigured(const QCBORTagListIn *pCallerConfiguredTagMap, uint64_t uTag)
428{
429 for(int nTagBitIndex = 0; nTagBitIndex < pCallerConfiguredTagMap->uNumTags; nTagBitIndex++) {
430 if(pCallerConfiguredTagMap->puTags[nTagBitIndex] == uTag) {
431 return nTagBitIndex + TAG_MAPPER_CUSTOM_TAGS_BASE_INDEX;
432 }
433 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800434
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700435 return -1; // Indicates no match
436}
437
438/*
439 Find the tag bit index for a given tag value, or error out
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800440
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700441 This and the above functions could probably be optimized and made
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800442 clearer and neater.
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700443 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800444static QCBORError
445TagMapper_Lookup(const QCBORTagListIn *pCallerConfiguredTagMap,
446 uint64_t uTag,
447 uint8_t *puTagBitIndex)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700448{
449 int nTagBitIndex = TagMapper_LookupBuiltIn(uTag);
450 if(nTagBitIndex >= 0) {
451 // Cast is safe because TagMapper_LookupBuiltIn never returns > 47
452 *puTagBitIndex = (uint8_t)nTagBitIndex;
453 return QCBOR_SUCCESS;
454 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800455
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700456 if(pCallerConfiguredTagMap) {
457 if(pCallerConfiguredTagMap->uNumTags > QCBOR_MAX_CUSTOM_TAGS) {
458 return QCBOR_ERR_TOO_MANY_TAGS;
459 }
460 nTagBitIndex = TagMapper_LookupCallerConfigured(pCallerConfiguredTagMap, uTag);
461 if(nTagBitIndex >= 0) {
462 // Cast is safe because TagMapper_LookupBuiltIn never returns > 63
463
464 *puTagBitIndex = (uint8_t)nTagBitIndex;
465 return QCBOR_SUCCESS;
466 }
467 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800468
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700469 return QCBOR_ERR_BAD_OPT_TAG;
470}
471
472
473
Laurence Lundbladeee851742020-01-08 08:37:05 -0800474/*===========================================================================
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800475 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
476
477 The following four functions are pretty wrappers for invocation of
478 the string allocator supplied by the caller.
479
Laurence Lundbladeee851742020-01-08 08:37:05 -0800480 ===========================================================================*/
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800481
Laurence Lundbladeee851742020-01-08 08:37:05 -0800482static inline void
483StringAllocator_Free(const QCORInternalAllocator *pMe, void *pMem)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800484{
485 (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, 0);
486}
487
Laurence Lundbladeee851742020-01-08 08:37:05 -0800488// StringAllocator_Reallocate called with pMem NULL is
489// equal to StringAllocator_Allocate()
490static inline UsefulBuf
491StringAllocator_Reallocate(const QCORInternalAllocator *pMe,
492 void *pMem,
493 size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800494{
495 return (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, uSize);
496}
497
Laurence Lundbladeee851742020-01-08 08:37:05 -0800498static inline UsefulBuf
499StringAllocator_Allocate(const QCORInternalAllocator *pMe, size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800500{
501 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
502}
503
Laurence Lundbladeee851742020-01-08 08:37:05 -0800504static inline void
505StringAllocator_Destruct(const QCORInternalAllocator *pMe)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800506{
507 if(pMe->pfAllocator) {
508 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
509 }
510}
511
512
513
Laurence Lundbladeee851742020-01-08 08:37:05 -0800514/*===========================================================================
515 QCBORDecode -- The main implementation of CBOR decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700516
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800517 See qcbor/qcbor_decode.h for definition of the object
518 used here: QCBORDecodeContext
Laurence Lundbladeee851742020-01-08 08:37:05 -0800519 ===========================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700520/*
521 Public function, see header file
522 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800523void QCBORDecode_Init(QCBORDecodeContext *me,
524 UsefulBufC EncodedCBOR,
525 QCBORDecodeMode nDecodeMode)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700526{
527 memset(me, 0, sizeof(QCBORDecodeContext));
528 UsefulInputBuf_Init(&(me->InBuf), EncodedCBOR);
Laurence Lundbladeee851742020-01-08 08:37:05 -0800529 // Don't bother with error check on decode mode. If a bad value is
530 // passed it will just act as if the default normal mode of 0 was set.
Laurence Lundbladee6bcef12020-04-01 10:56:27 -0700531 me->uDecodeMode = (uint8_t)nDecodeMode;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700532 DecodeNesting_Init(&(me->nesting));
533}
534
535
536/*
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700537 Public function, see header file
538 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800539void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
540 QCBORStringAllocate pfAllocateFunction,
541 void *pAllocateContext,
542 bool bAllStrings)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700543{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800544 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
545 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
546 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700547}
548
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800549
550/*
551 Public function, see header file
552 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800553void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *me,
554 const QCBORTagListIn *pTagList)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700555{
556 me->pCallerConfiguredTagList = pTagList;
557}
558
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700559
560/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800561 This decodes the fundamental part of a CBOR data item, the type and
562 number
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800563
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700564 This is the Counterpart to InsertEncodedTypeAndNumber().
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800565
Laurence Lundbladeee851742020-01-08 08:37:05 -0800566 This does the network->host byte order conversion. The conversion
567 here also results in the conversion for floats in addition to that
568 for lengths, tags and integer values.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800569
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700570 This returns:
571 pnMajorType -- the major type for the item
Laurence Lundbladeee851742020-01-08 08:37:05 -0800572
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800573 puArgument -- the "number" which is used a the value for integers,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800574 tags and floats and length for strings and arrays
575
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800576 pnAdditionalInfo -- Pass this along to know what kind of float or
Laurence Lundbladeee851742020-01-08 08:37:05 -0800577 if length is indefinite
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800578
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800579 The int type is preferred to uint8_t for some variables as this
580 avoids integer promotions, can reduce code size and makes
581 static analyzers happier.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700582 */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800583inline static QCBORError DecodeTypeAndNumber(UsefulInputBuf *pUInBuf,
584 int *pnMajorType,
585 uint64_t *puArgument,
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800586 int *pnAdditionalInfo)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700587{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700588 QCBORError nReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800589
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700590 // Get the initial byte that every CBOR data item has
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800591 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800592
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700593 // Break down the initial byte
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800594 const int nTmpMajorType = nInitialByte >> 5;
595 const int nAdditionalInfo = nInitialByte & 0x1f;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800596
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800597 // Where the number or argument accumulates
598 uint64_t uArgument;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800599
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800600 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800601 // Need to get 1,2,4 or 8 additional argument bytes Map
602 // LEN_IS_ONE_BYTE.. LEN_IS_EIGHT_BYTES to actual length
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800603 static const uint8_t aIterate[] = {1,2,4,8};
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800604
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800605 // Loop getting all the bytes in the argument
606 uArgument = 0;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800607 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800608 // This shift and add gives the endian conversion
609 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
610 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800611 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800612 // The reserved and thus-far unused additional info values
613 nReturn = QCBOR_ERR_UNSUPPORTED;
614 goto Done;
615 } else {
616 // Less than 24, additional info is argument or 31, an indefinite length
617 // No more bytes to get
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800618 uArgument = (uint64_t)nAdditionalInfo;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700619 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800620
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700621 if(UsefulInputBuf_GetError(pUInBuf)) {
622 nReturn = QCBOR_ERR_HIT_END;
623 goto Done;
624 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800625
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700626 // All successful if we got here.
627 nReturn = QCBOR_SUCCESS;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800628 *pnMajorType = nTmpMajorType;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800629 *puArgument = uArgument;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800630 *pnAdditionalInfo = nAdditionalInfo;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800631
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700632Done:
633 return nReturn;
634}
635
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800636
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700637/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800638 CBOR doesn't explicitly specify two's compliment for integers but all
639 CPUs use it these days and the test vectors in the RFC are so. All
640 integers in the CBOR structure are positive and the major type
641 indicates positive or negative. CBOR can express positive integers
642 up to 2^x - 1 where x is the number of bits and negative integers
643 down to 2^x. Note that negative numbers can be one more away from
644 zero than positive. Stdint, as far as I can tell, uses two's
645 compliment to represent negative integers.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800646
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700647 See http://www.unix.org/whitepapers/64bit.html for reasons int isn't
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800648 used carefully here, and in particular why it isn't used in the interface.
649 Also see
650 https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers
651
652 Int is used for values that need less than 16-bits and would be subject
653 to integer promotion and complaining by static analyzers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700654 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800655inline static QCBORError
656DecodeInteger(int nMajorType, uint64_t uNumber, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700657{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700658 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800659
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700660 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
661 if (uNumber <= INT64_MAX) {
662 pDecodedItem->val.int64 = (int64_t)uNumber;
663 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800664
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700665 } else {
666 pDecodedItem->val.uint64 = uNumber;
667 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800668
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700669 }
670 } else {
671 if(uNumber <= INT64_MAX) {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800672 // CBOR's representation of negative numbers lines up with the
673 // two-compliment representation. A negative integer has one
674 // more in range than a positive integer. INT64_MIN is
675 // equal to (-INT64_MAX) - 1.
676 pDecodedItem->val.int64 = (-(int64_t)uNumber) - 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700677 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800678
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700679 } else {
680 // C can't represent a negative integer in this range
Laurence Lundblade21d1d812019-09-28 22:47:49 -1000681 // so it is an error.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700682 nReturn = QCBOR_ERR_INT_OVERFLOW;
683 }
684 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800685
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700686 return nReturn;
687}
688
689// Make sure #define value line up as DecodeSimple counts on this.
690#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
691#error QCBOR_TYPE_FALSE macro value wrong
692#endif
693
694#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
695#error QCBOR_TYPE_TRUE macro value wrong
696#endif
697
698#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
699#error QCBOR_TYPE_NULL macro value wrong
700#endif
701
702#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
703#error QCBOR_TYPE_UNDEF macro value wrong
704#endif
705
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700706#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
707#error QCBOR_TYPE_BREAK macro value wrong
708#endif
709
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700710#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
711#error QCBOR_TYPE_DOUBLE macro value wrong
712#endif
713
714#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
715#error QCBOR_TYPE_FLOAT macro value wrong
716#endif
717
718/*
719 Decode true, false, floats, break...
720 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800721inline static QCBORError
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800722DecodeSimple(int nAdditionalInfo, uint64_t uNumber, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700723{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700724 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800725
Laurence Lundbladeee851742020-01-08 08:37:05 -0800726 // uAdditionalInfo is 5 bits from the initial byte compile time checks
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800727 // above make sure uAdditionalInfo values line up with uDataType values.
728 // DecodeTypeAndNumber never returns a major type > 1f so cast is safe
729 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800730
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800731 switch(nAdditionalInfo) {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800732 // No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they are
733 // caught before this is called.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800734
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700735 case HALF_PREC_FLOAT:
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700736 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uNumber);
737 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700738 break;
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700739 case SINGLE_PREC_FLOAT:
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700740 pDecodedItem->val.dfnum = (double)UsefulBufUtil_CopyUint32ToFloat((uint32_t)uNumber);
741 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700742 break;
743 case DOUBLE_PREC_FLOAT:
744 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uNumber);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700745 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700746 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800747
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700748 case CBOR_SIMPLEV_FALSE: // 20
749 case CBOR_SIMPLEV_TRUE: // 21
750 case CBOR_SIMPLEV_NULL: // 22
751 case CBOR_SIMPLEV_UNDEF: // 23
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700752 case CBOR_SIMPLE_BREAK: // 31
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700753 break; // nothing to do
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800754
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700755 case CBOR_SIMPLEV_ONEBYTE: // 24
756 if(uNumber <= CBOR_SIMPLE_BREAK) {
757 // This takes out f8 00 ... f8 1f which should be encoded as e0 … f7
Laurence Lundblade077475f2019-04-26 09:06:33 -0700758 nReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700759 goto Done;
760 }
Laurence Lundblade5e390822019-01-06 12:35:01 -0800761 /* FALLTHROUGH */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700762 // fall through intentionally
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800763
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700764 default: // 0-19
765 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
Laurence Lundbladeee851742020-01-08 08:37:05 -0800766 /*
767 DecodeTypeAndNumber will make uNumber equal to
768 uAdditionalInfo when uAdditionalInfo is < 24 This cast is
769 safe because the 2, 4 and 8 byte lengths of uNumber are in
770 the double/float cases above
771 */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700772 pDecodedItem->val.uSimple = (uint8_t)uNumber;
773 break;
774 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800775
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700776Done:
777 return nReturn;
778}
779
780
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700781/*
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530782 Decode text and byte strings. Call the string allocator if asked to.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700783 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800784inline static QCBORError DecodeBytes(const QCORInternalAllocator *pAllocator,
785 int nMajorType,
786 uint64_t uStrLen,
787 UsefulInputBuf *pUInBuf,
788 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700789{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700790 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800791
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800792 // CBOR lengths can be 64 bits, but size_t is not 64 bits on all CPUs.
793 // This check makes the casts to size_t below safe.
794
795 // 4 bytes less than the largest sizeof() so this can be tested by
796 // putting a SIZE_MAX length in the CBOR test input (no one will
797 // care the limit on strings is 4 bytes shorter).
798 if(uStrLen > SIZE_MAX-4) {
799 nReturn = QCBOR_ERR_STRING_TOO_LONG;
800 goto Done;
801 }
802
803 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, (size_t)uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530804 if(UsefulBuf_IsNULLC(Bytes)) {
805 // Failed to get the bytes for this string item
806 nReturn = QCBOR_ERR_HIT_END;
807 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700808 }
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530809
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800810 if(pAllocator) {
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530811 // We are asked to use string allocator to make a copy
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800812 UsefulBuf NewMem = StringAllocator_Allocate(pAllocator, (size_t)uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530813 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade30816f22018-11-10 13:40:22 +0700814 nReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530815 goto Done;
816 }
817 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800818 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530819 } else {
820 // Normal case with no string allocator
821 pDecodedItem->val.string = Bytes;
822 }
Laurence Lundbladeee851742020-01-08 08:37:05 -0800823 const bool bIsBstr = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING);
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800824 // Cast because ternary operator causes promotion to integer
825 pDecodedItem->uDataType = (uint8_t)(bIsBstr ? QCBOR_TYPE_BYTE_STRING
826 : QCBOR_TYPE_TEXT_STRING);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800827
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530828Done:
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700829 return nReturn;
830}
831
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700832
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800833
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700834
835
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700836
837
Laurence Lundbladeee851742020-01-08 08:37:05 -0800838// Make sure the constants align as this is assumed by
839// the GetAnItem() implementation
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700840#if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
841#error QCBOR_TYPE_ARRAY value not lined up with major type
842#endif
843#if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
844#error QCBOR_TYPE_MAP value not lined up with major type
845#endif
846
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700847/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800848 This gets a single data item and decodes it including preceding
849 optional tagging. This does not deal with arrays and maps and nesting
850 except to decode the data item introducing them. Arrays and maps are
851 handled at the next level up in GetNext().
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800852
Laurence Lundbladeee851742020-01-08 08:37:05 -0800853 Errors detected here include: an array that is too long to decode,
854 hit end of buffer unexpectedly, a few forms of invalid encoded CBOR
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700855 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800856static QCBORError GetNext_Item(UsefulInputBuf *pUInBuf,
857 QCBORItem *pDecodedItem,
858 const QCORInternalAllocator *pAllocator)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700859{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700860 QCBORError nReturn;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800861
Laurence Lundbladeee851742020-01-08 08:37:05 -0800862 /*
863 Get the major type and the number. Number could be length of more
864 bytes or the value depending on the major type nAdditionalInfo is
865 an encoding of the length of the uNumber and is needed to decode
866 floats and doubles
867 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800868 int nMajorType;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700869 uint64_t uNumber;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800870 int nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800871
Laurence Lundblade4b09f632019-10-09 14:34:59 -0700872 memset(pDecodedItem, 0, sizeof(QCBORItem));
873
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800874 nReturn = DecodeTypeAndNumber(pUInBuf, &nMajorType, &uNumber, &nAdditionalInfo);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800875
Laurence Lundbladeee851742020-01-08 08:37:05 -0800876 // Error out here if we got into trouble on the type and number. The
877 // code after this will not work if the type and number is not good.
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700878 if(nReturn) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700879 goto Done;
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700880 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800881
Laurence Lundbladeee851742020-01-08 08:37:05 -0800882 // At this point the major type and the value are valid. We've got
883 // the type and the number that starts every CBOR data item.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800884 switch (nMajorType) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700885 case CBOR_MAJOR_TYPE_POSITIVE_INT: // Major type 0
886 case CBOR_MAJOR_TYPE_NEGATIVE_INT: // Major type 1
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800887 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700888 nReturn = QCBOR_ERR_BAD_INT;
889 } else {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800890 nReturn = DecodeInteger(nMajorType, uNumber, pDecodedItem);
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700891 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700892 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800893
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700894 case CBOR_MAJOR_TYPE_BYTE_STRING: // Major type 2
895 case CBOR_MAJOR_TYPE_TEXT_STRING: // Major type 3
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800896 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
897 const bool bIsBstr = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING);
898 pDecodedItem->uDataType = (uint8_t)(bIsBstr ? QCBOR_TYPE_BYTE_STRING
899 : QCBOR_TYPE_TEXT_STRING);
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530900 pDecodedItem->val.string = (UsefulBufC){NULL, SIZE_MAX};
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700901 } else {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800902 nReturn = DecodeBytes(pAllocator, nMajorType, uNumber, pUInBuf, pDecodedItem);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700903 }
904 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800905
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700906 case CBOR_MAJOR_TYPE_ARRAY: // Major type 4
907 case CBOR_MAJOR_TYPE_MAP: // Major type 5
908 // Record the number of items in the array or map
909 if(uNumber > QCBOR_MAX_ITEMS_IN_ARRAY) {
910 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
911 goto Done;
912 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800913 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530914 pDecodedItem->val.uCount = UINT16_MAX; // Indicate indefinite length
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700915 } else {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800916 // type conversion OK because of check above
917 pDecodedItem->val.uCount = (uint16_t)uNumber;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700918 }
Laurence Lundbladeee851742020-01-08 08:37:05 -0800919 // C preproc #if above makes sure constants for major types align
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800920 // DecodeTypeAndNumber never returns a major type > 7 so cast is safe
921 pDecodedItem->uDataType = (uint8_t)nMajorType;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700922 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800923
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700924 case CBOR_MAJOR_TYPE_OPTIONAL: // Major type 6, optional prepended tags
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800925 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700926 nReturn = QCBOR_ERR_BAD_INT;
927 } else {
928 pDecodedItem->val.uTagV = uNumber;
929 pDecodedItem->uDataType = QCBOR_TYPE_OPTTAG;
930 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700931 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800932
Laurence Lundbladeee851742020-01-08 08:37:05 -0800933 case CBOR_MAJOR_TYPE_SIMPLE:
934 // Major type 7, float, double, true, false, null...
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800935 nReturn = DecodeSimple(nAdditionalInfo, uNumber, pDecodedItem);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700936 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800937
Laurence Lundbladeee851742020-01-08 08:37:05 -0800938 default:
939 // Never happens because DecodeTypeAndNumber() should never return > 7
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700940 nReturn = QCBOR_ERR_UNSUPPORTED;
941 break;
942 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800943
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700944Done:
945 return nReturn;
946}
947
948
949
950/*
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800951 This layer deals with indefinite length strings. It pulls all the
Laurence Lundbladeee851742020-01-08 08:37:05 -0800952 individual chunk items together into one QCBORItem using the string
953 allocator.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800954
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530955 Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700956 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800957static inline QCBORError
958GetNext_FullItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700959{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700960 // Stack usage; int/ptr 2 UsefulBuf 2 QCBORItem -- 96
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700961
962 // Get pointer to string allocator. First use is to pass it to
963 // GetNext_Item() when option is set to allocate for *every* string.
964 // Second use here is to allocate space to coallese indefinite
965 // length string items into one.
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800966 const QCORInternalAllocator *pAllocator = me->StringAllocator.pfAllocator ?
967 &(me->StringAllocator) :
968 NULL;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800969
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700970 QCBORError nReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800971 nReturn = GetNext_Item(&(me->InBuf),
972 pDecodedItem,
973 me->bStringAllocateAll ? pAllocator: NULL);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700974 if(nReturn) {
975 goto Done;
976 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800977
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700978 // To reduce code size by removing support for indefinite length strings, the
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530979 // code in this function from here down can be eliminated. Run tests, except
980 // indefinite length string tests, to be sure all is OK if this is removed.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800981
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800982 // Only do indefinite length processing on strings
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700983 const uint8_t uStringType = pDecodedItem->uDataType;
984 if(uStringType!= QCBOR_TYPE_BYTE_STRING && uStringType != QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700985 goto Done; // no need to do any work here on non-string types
986 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800987
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800988 // Is this a string with an indefinite length?
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530989 if(pDecodedItem->val.string.len != SIZE_MAX) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800990 goto Done; // length is not indefinite, so no work to do here
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700991 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800992
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530993 // Can't do indefinite length strings without a string allocator
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800994 if(pAllocator == NULL) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700995 nReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
996 goto Done;
997 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800998
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700999 // Loop getting chunk of indefinite string
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001000 UsefulBufC FullString = NULLUsefulBufC;
1001
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001002 for(;;) {
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001003 // Get item for next chunk
1004 QCBORItem StringChunkItem;
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001005 // NULL string allocator passed here. Do not need to allocate
1006 // chunks even if bStringAllocateAll is set.
Laurence Lundbladefae26bf2019-02-18 11:15:43 -08001007 nReturn = GetNext_Item(&(me->InBuf), &StringChunkItem, NULL);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001008 if(nReturn) {
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001009 break; // Error getting the next chunk
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001010 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001011
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301012 // See if it is a marker at end of indefinite length string
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001013 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001014 // String is complete
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001015 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301016 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001017 break;
1018 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001019
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001020 // Match data type of chunk to type at beginning.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301021 // Also catches error of other non-string types that don't belong.
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001022 // Also catches indefinite length strings inside indefinite length strings
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001023 if(StringChunkItem.uDataType != uStringType ||
1024 StringChunkItem.val.string.len == SIZE_MAX) {
Laurence Lundblade30816f22018-11-10 13:40:22 +07001025 nReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001026 break;
1027 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001028
Laurence Lundblade471a3fd2018-10-18 21:27:45 +05301029 // Alloc new buffer or expand previously allocated buffer so it can fit
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001030 // The first time throurgh FullString.ptr is NULL and this is
1031 // equivalent to StringAllocator_Allocate()
1032 UsefulBuf NewMem = StringAllocator_Reallocate(pAllocator,
1033 UNCONST_POINTER(FullString.ptr),
1034 FullString.len + StringChunkItem.val.string.len);
1035
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001036 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301037 // Allocation of memory for the string failed
Laurence Lundblade30816f22018-11-10 13:40:22 +07001038 nReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001039 break;
1040 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001041
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001042 // Copy new string chunk at the end of string so far.
1043 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001044 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001045
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001046 if(nReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
1047 // Getting the item failed, clean up the allocated memory
1048 StringAllocator_Free(pAllocator, UNCONST_POINTER(FullString.ptr));
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001049 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001050
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001051Done:
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001052 return nReturn;
1053}
1054
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001055
1056/*
Laurence Lundblade59289e52019-12-30 13:44:37 -08001057 Gets all optional tag data items preceding a data item that is not an
1058 optional tag and records them as bits in the tag map.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001059 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001060static QCBORError
1061GetNext_TaggedItem(QCBORDecodeContext *me,
1062 QCBORItem *pDecodedItem,
1063 QCBORTagListOut *pTags)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001064{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001065 // Stack usage: int/ptr: 3 -- 24
Laurence Lundblade30816f22018-11-10 13:40:22 +07001066 QCBORError nReturn;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001067 uint64_t uTagBits = 0;
1068 if(pTags) {
1069 pTags->uNumUsed = 0;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001070 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001071
Laurence Lundblade59289e52019-12-30 13:44:37 -08001072 // Loop fetching items until the item fetched is not a tag
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001073 for(;;) {
1074 nReturn = GetNext_FullItem(me, pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001075 if(nReturn) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001076 goto Done; // Error out of the loop
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001077 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001078
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001079 if(pDecodedItem->uDataType != QCBOR_TYPE_OPTTAG) {
1080 // Successful exit from loop; maybe got some tags, maybe not
1081 pDecodedItem->uTagBits = uTagBits;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001082 break;
1083 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001084
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001085 uint8_t uTagBitIndex;
1086 // Tag was mapped, tag was not mapped, error with tag list
1087 switch(TagMapper_Lookup(me->pCallerConfiguredTagList, pDecodedItem->val.uTagV, &uTagBitIndex)) {
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001088
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001089 case QCBOR_SUCCESS:
1090 // Successfully mapped the tag
1091 uTagBits |= 0x01ULL << uTagBitIndex;
1092 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001093
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001094 case QCBOR_ERR_BAD_OPT_TAG:
1095 // Tag is not recognized. Do nothing
1096 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001097
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001098 default:
1099 // Error Condition
1100 goto Done;
1101 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001102
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001103 if(pTags) {
1104 // Caller wants all tags recorded in the provided buffer
1105 if(pTags->uNumUsed >= pTags->uNumAllocated) {
1106 nReturn = QCBOR_ERR_TOO_MANY_TAGS;
1107 goto Done;
1108 }
1109 pTags->puTags[pTags->uNumUsed] = pDecodedItem->val.uTagV;
1110 pTags->uNumUsed++;
1111 }
1112 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001113
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001114Done:
1115 return nReturn;
1116}
1117
1118
1119/*
Laurence Lundbladeee851742020-01-08 08:37:05 -08001120 This layer takes care of map entries. It combines the label and data
1121 items into one QCBORItem.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001122 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001123static inline QCBORError
1124GetNext_MapEntry(QCBORDecodeContext *me,
1125 QCBORItem *pDecodedItem,
1126 QCBORTagListOut *pTags)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001127{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001128 // Stack use: int/ptr 1, QCBORItem -- 56
Laurence Lundblade30816f22018-11-10 13:40:22 +07001129 QCBORError nReturn = GetNext_TaggedItem(me, pDecodedItem, pTags);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001130 if(nReturn)
1131 goto Done;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001132
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001133 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001134 // Break can't be a map entry
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001135 goto Done;
1136 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001137
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001138 if(me->uDecodeMode != QCBOR_DECODE_MODE_MAP_AS_ARRAY) {
1139 // In a map and caller wants maps decoded, not treated as arrays
1140
1141 if(DecodeNesting_TypeIsMap(&(me->nesting))) {
1142 // If in a map and the right decoding mode, get the label
1143
Laurence Lundbladeee851742020-01-08 08:37:05 -08001144 // Save label in pDecodedItem and get the next which will
1145 // be the real data
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001146 QCBORItem LabelItem = *pDecodedItem;
1147 nReturn = GetNext_TaggedItem(me, pDecodedItem, pTags);
1148 if(nReturn)
1149 goto Done;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001150
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301151 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001152
1153 if(LabelItem.uDataType == QCBOR_TYPE_TEXT_STRING) {
1154 // strings are always good labels
1155 pDecodedItem->label.string = LabelItem.val.string;
1156 pDecodedItem->uLabelType = QCBOR_TYPE_TEXT_STRING;
1157 } else if (QCBOR_DECODE_MODE_MAP_STRINGS_ONLY == me->uDecodeMode) {
Laurence Lundbladeee851742020-01-08 08:37:05 -08001158 // It's not a string and we only want strings
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001159 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
1160 goto Done;
1161 } else if(LabelItem.uDataType == QCBOR_TYPE_INT64) {
1162 pDecodedItem->label.int64 = LabelItem.val.int64;
1163 pDecodedItem->uLabelType = QCBOR_TYPE_INT64;
1164 } else if(LabelItem.uDataType == QCBOR_TYPE_UINT64) {
1165 pDecodedItem->label.uint64 = LabelItem.val.uint64;
1166 pDecodedItem->uLabelType = QCBOR_TYPE_UINT64;
1167 } else if(LabelItem.uDataType == QCBOR_TYPE_BYTE_STRING) {
1168 pDecodedItem->label.string = LabelItem.val.string;
1169 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
1170 pDecodedItem->uLabelType = QCBOR_TYPE_BYTE_STRING;
1171 } else {
1172 // label is not an int or a string. It is an arrray
1173 // or a float or such and this implementation doesn't handle that.
1174 // Also, tags on labels are ignored.
1175 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
1176 goto Done;
1177 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001178 }
1179 } else {
1180 if(pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001181 if(pDecodedItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
1182 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
1183 goto Done;
1184 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001185 // Decoding a map as an array
1186 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001187 // Cast is safe because of check against QCBOR_MAX_ITEMS_IN_ARRAY/2
1188 // Cast is needed because of integer promotion
1189 pDecodedItem->val.uCount = (uint16_t)(pDecodedItem->val.uCount * 2);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001190 }
1191 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001192
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001193Done:
1194 return nReturn;
1195}
1196
1197
1198/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001199 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001200 TODO: correct this comment
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001201 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001202QCBORError QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *me,
1203 QCBORItem *pDecodedItem,
1204 QCBORTagListOut *pTags)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001205{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001206 // Stack ptr/int: 2, QCBORItem : 64
1207
Laurence Lundblade30816f22018-11-10 13:40:22 +07001208 QCBORError nReturn;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001209
Laurence Lundblade937ea812020-05-08 11:38:23 -07001210 /* For a pre-order traversal a non-error end occurs when there
1211 are no more bytes to consume and the nesting level is at the top.
1212 If it's not at the top, then the CBOR is not well formed. This error
1213 is caught elsewhere.
1214
1215 This handles the end of CBOR sequences as well as non-sequences. */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001216 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf)) == 0 && DecodeNesting_IsAtTop(&(me->nesting))) {
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001217 nReturn = QCBOR_ERR_NO_MORE_ITEMS;
1218 goto Done;
1219 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07001220
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001221 /* It is also an end of the input when in map mode and the cursor
Laurence Lundblade937ea812020-05-08 11:38:23 -07001222 is at the end of the map */
1223
1224
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07001225 // This is to handle map and array mode
Laurence Lundblade937ea812020-05-08 11:38:23 -07001226 if(DecodeNesting_AtEnd(&(me->nesting))) {
1227// if(UsefulInputBuf_Tell(&(me->InBuf)) != 0 && DecodeNesting_AtEnd(&(me->nesting))) {
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07001228 nReturn = QCBOR_ERR_NO_MORE_ITEMS;
1229 goto Done;
1230 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001231
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001232 nReturn = GetNext_MapEntry(me, pDecodedItem, pTags);
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001233 if(nReturn) {
1234 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001235 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301236
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001237 // Breaks ending arrays/maps are always processed at the end of this function.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301238 // They should never show up here.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301239 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade6de37062018-10-15 12:22:42 +05301240 nReturn = QCBOR_ERR_BAD_BREAK;
1241 goto Done;
Laurence Lundblade5b8c5852018-10-14 21:11:42 +05301242 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001243
Laurence Lundblade6de37062018-10-15 12:22:42 +05301244 // Record the nesting level for this data item before processing any of
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301245 // decrementing and descending.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301246 pDecodedItem->uNestingLevel = DecodeNesting_GetLevel(&(me->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001247
Laurence Lundblade6de37062018-10-15 12:22:42 +05301248 // Process the item just received for descent or decrement, and
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001249 // ascend if decrements are enough to close out a definite length array/map
Laurence Lundblade3a760b02018-10-08 13:46:03 +08001250 if(IsMapOrArray(pDecodedItem->uDataType)) {
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001251 // If the new item is array or map, the nesting level descends
Laurence Lundblade3a760b02018-10-08 13:46:03 +08001252 nReturn = DecodeNesting_Descend(&(me->nesting), pDecodedItem);
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001253 // Maps and arrays do count in as items in the map/array that encloses
1254 // them so a decrement needs to be done for them too, but that is done
1255 // only when all the items in them have been processed, not when they
Laurence Lundblade9916b1b2019-09-07 22:33:25 -07001256 // are opened with the exception of an empty map or array.
1257 if(pDecodedItem->val.uCount == 0) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07001258 DecodeNesting_DecrementCount(&(me->nesting));
Laurence Lundblade9916b1b2019-09-07 22:33:25 -07001259 }
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001260 } else {
1261 // Decrement the count of items in the enclosing map/array
1262 // If the count in the enclosing map/array goes to zero, that
Laurence Lundblade6de37062018-10-15 12:22:42 +05301263 // triggers a decrement in the map/array above that and
1264 // an ascend in nesting level.
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07001265 DecodeNesting_DecrementCount(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001266 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05301267 if(nReturn) {
1268 goto Done;
1269 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001270
Laurence Lundblade6de37062018-10-15 12:22:42 +05301271 // For indefinite length maps/arrays, looking at any and
1272 // all breaks that might terminate them. The equivalent
1273 // for definite length maps/arrays happens in
1274 // DecodeNesting_DecrementCount().
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001275 if(!DecodeNesting_IsAtTop(&(me->nesting)) && DecodeNesting_IsIndefiniteLength(&(me->nesting))) {
Laurence Lundblade6de37062018-10-15 12:22:42 +05301276 while(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) {
1277 // Peek forward one item to see if it is a break.
1278 QCBORItem Peek;
1279 size_t uPeek = UsefulInputBuf_Tell(&(me->InBuf));
1280 nReturn = GetNext_Item(&(me->InBuf), &Peek, NULL);
1281 if(nReturn) {
1282 goto Done;
1283 }
1284 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
1285 // It is not a break, rewind so it can be processed normally.
1286 UsefulInputBuf_Seek(&(me->InBuf), uPeek);
1287 break;
1288 }
1289 // It is a break. Ascend one nesting level.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301290 // The break is consumed.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301291 nReturn = DecodeNesting_BreakAscend(&(me->nesting));
1292 if(nReturn) {
1293 // break occured outside of an indefinite length array/map
1294 goto Done;
1295 }
1296 }
1297 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001298
Laurence Lundblade6de37062018-10-15 12:22:42 +05301299 // Tell the caller what level is next. This tells them what maps/arrays
1300 // were closed out and makes it possible for them to reconstruct
1301 // the tree with just the information returned by GetNext
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07001302 // TODO: pull this into DecodeNesting_GetLevel
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001303 if(me->nesting.pCurrent->uMapMode && me->nesting.pCurrent->uCount == 0) {
1304 // At end of a map / array in map mode, so next nest is 0 to
1305 // indicate this end.
1306 pDecodedItem->uNextNestLevel = 0;
1307 } else {
1308 pDecodedItem->uNextNestLevel = DecodeNesting_GetLevel(&(me->nesting));
1309 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001310
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001311Done:
Laurence Lundbladee9482dd2019-10-11 12:58:46 -07001312 if(nReturn != QCBOR_SUCCESS) {
1313 // Make sure uDataType and uLabelType are QCBOR_TYPE_NONE
1314 memset(pDecodedItem, 0, sizeof(QCBORItem));
1315 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001316 return nReturn;
1317}
1318
1319
Laurence Lundblade59289e52019-12-30 13:44:37 -08001320/*
1321 Mostly just assign the right data type for the date string.
1322 */
1323inline static QCBORError DecodeDateString(QCBORItem *pDecodedItem)
1324{
1325 // Stack Use: UsefulBuf 1 16
1326 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1327 return QCBOR_ERR_BAD_OPT_TAG;
1328 }
1329
1330 const UsefulBufC Temp = pDecodedItem->val.string;
1331 pDecodedItem->val.dateString = Temp;
1332 pDecodedItem->uDataType = QCBOR_TYPE_DATE_STRING;
1333 return QCBOR_SUCCESS;
1334}
1335
1336
1337/*
1338 Mostly just assign the right data type for the bignum.
1339 */
1340inline static QCBORError DecodeBigNum(QCBORItem *pDecodedItem)
1341{
1342 // Stack Use: UsefulBuf 1 -- 16
1343 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1344 return QCBOR_ERR_BAD_OPT_TAG;
1345 }
1346 const UsefulBufC Temp = pDecodedItem->val.string;
1347 pDecodedItem->val.bigNum = Temp;
Laurence Lundbladeee851742020-01-08 08:37:05 -08001348 const bool bIsPosBigNum = (bool)(pDecodedItem->uTagBits & QCBOR_TAGFLAG_POS_BIGNUM);
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001349 pDecodedItem->uDataType = (uint8_t)(bIsPosBigNum ? QCBOR_TYPE_POSBIGNUM
1350 : QCBOR_TYPE_NEGBIGNUM);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001351 return QCBOR_SUCCESS;
1352}
1353
1354
1355/*
Laurence Lundbladeee851742020-01-08 08:37:05 -08001356 The epoch formatted date. Turns lots of different forms of encoding
1357 date into uniform one
Laurence Lundblade59289e52019-12-30 13:44:37 -08001358 */
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001359static QCBORError DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08001360{
1361 // Stack usage: 1
1362 QCBORError nReturn = QCBOR_SUCCESS;
1363
1364 pDecodedItem->val.epochDate.fSecondsFraction = 0;
1365
1366 switch (pDecodedItem->uDataType) {
1367
1368 case QCBOR_TYPE_INT64:
1369 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
1370 break;
1371
1372 case QCBOR_TYPE_UINT64:
1373 if(pDecodedItem->val.uint64 > INT64_MAX) {
1374 nReturn = QCBOR_ERR_DATE_OVERFLOW;
1375 goto Done;
1376 }
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001377 pDecodedItem->val.epochDate.nSeconds = (int64_t)pDecodedItem->val.uint64;
Laurence Lundblade59289e52019-12-30 13:44:37 -08001378 break;
1379
1380 case QCBOR_TYPE_DOUBLE:
1381 {
1382 // This comparison needs to be done as a float before
1383 // conversion to an int64_t to be able to detect doubles
1384 // that are too large to fit into an int64_t. A double
1385 // has 52 bits of preceision. An int64_t has 63. Casting
1386 // INT64_MAX to a double actually causes a round up which
1387 // is bad and wrong for the comparison because it will
1388 // allow conversion of doubles that can't fit into a
1389 // uint64_t. To remedy this INT64_MAX - 0x7ff is used as
1390 // the cutoff point as if that rounds up in conversion to
1391 // double it will still be less than INT64_MAX. 0x7ff is
1392 // picked because it has 11 bits set.
1393 //
1394 // INT64_MAX seconds is on the order of 10 billion years,
1395 // and the earth is less than 5 billion years old, so for
1396 // most uses this conversion error won't occur even though
1397 // doubles can go much larger.
1398 //
1399 // Without the 0x7ff there is a ~30 minute range of time
1400 // values 10 billion years in the past and in the future
1401 // where this this code would go wrong.
1402 const double d = pDecodedItem->val.dfnum;
1403 if(d > (double)(INT64_MAX - 0x7ff)) {
1404 nReturn = QCBOR_ERR_DATE_OVERFLOW;
1405 goto Done;
1406 }
1407 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
1408 pDecodedItem->val.epochDate.fSecondsFraction = d - (double)pDecodedItem->val.epochDate.nSeconds;
1409 }
1410 break;
1411
1412 default:
1413 nReturn = QCBOR_ERR_BAD_OPT_TAG;
1414 goto Done;
1415 }
1416 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
1417
1418Done:
1419 return nReturn;
1420}
1421
1422
1423#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
1424/*
1425 Decode decimal fractions and big floats.
1426
1427 When called pDecodedItem must be the array that is tagged as a big
1428 float or decimal fraction, the array that has the two members, the
1429 exponent and mantissa.
1430
1431 This will fetch and decode the exponent and mantissa and put the
1432 result back into pDecodedItem.
1433 */
1434inline static QCBORError
1435QCBORDecode_MantissaAndExponent(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
1436{
1437 QCBORError nReturn;
1438
1439 // --- Make sure it is an array; track nesting level of members ---
1440 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
1441 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1442 goto Done;
1443 }
1444
1445 // A check for pDecodedItem->val.uCount == 2 would work for
Laurence Lundbladeee851742020-01-08 08:37:05 -08001446 // definite length arrays, but not for indefnite. Instead remember
1447 // the nesting level the two integers must be at, which is one
1448 // deeper than that of the array.
Laurence Lundblade59289e52019-12-30 13:44:37 -08001449 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
1450
1451 // --- Is it a decimal fraction or a bigfloat? ---
1452 const bool bIsTaggedDecimalFraction = QCBORDecode_IsTagged(me, pDecodedItem, CBOR_TAG_DECIMAL_FRACTION);
1453 pDecodedItem->uDataType = bIsTaggedDecimalFraction ? QCBOR_TYPE_DECIMAL_FRACTION : QCBOR_TYPE_BIGFLOAT;
1454
1455 // --- Get the exponent ---
1456 QCBORItem exponentItem;
1457 nReturn = QCBORDecode_GetNextMapOrArray(me, &exponentItem, NULL);
1458 if(nReturn != QCBOR_SUCCESS) {
1459 goto Done;
1460 }
1461 if(exponentItem.uNestingLevel != nNestLevel) {
1462 // Array is empty or a map/array encountered when expecting an int
1463 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1464 goto Done;
1465 }
1466 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
1467 // Data arriving as an unsigned int < INT64_MAX has been converted
1468 // to QCBOR_TYPE_INT64 and thus handled here. This is also means
1469 // that the only data arriving here of type QCBOR_TYPE_UINT64 data
1470 // will be too large for this to handle and thus an error that will
1471 // get handled in the next else.
1472 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
1473 } else {
1474 // Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX
1475 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1476 goto Done;
1477 }
1478
1479 // --- Get the mantissa ---
1480 QCBORItem mantissaItem;
1481 nReturn = QCBORDecode_GetNextWithTags(me, &mantissaItem, NULL);
1482 if(nReturn != QCBOR_SUCCESS) {
1483 goto Done;
1484 }
1485 if(mantissaItem.uNestingLevel != nNestLevel) {
1486 // Mantissa missing or map/array encountered when expecting number
1487 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1488 goto Done;
1489 }
1490 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
1491 // Data arriving as an unsigned int < INT64_MAX has been converted
1492 // to QCBOR_TYPE_INT64 and thus handled here. This is also means
1493 // that the only data arriving here of type QCBOR_TYPE_UINT64 data
1494 // will be too large for this to handle and thus an error that
1495 // will get handled in an else below.
1496 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
1497 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM || mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
1498 // Got a good big num mantissa
1499 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
1500 // Depends on numbering of QCBOR_TYPE_XXX
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001501 pDecodedItem->uDataType = (uint8_t)(pDecodedItem->uDataType +
1502 mantissaItem.uDataType - QCBOR_TYPE_POSBIGNUM +
1503 1);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001504 } else {
1505 // Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX
1506 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1507 goto Done;
1508 }
1509
1510 // --- Check that array only has the two numbers ---
1511 if(mantissaItem.uNextNestLevel == nNestLevel) {
1512 // Extra items in the decimal fraction / big num
1513 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1514 goto Done;
1515 }
1516
1517Done:
1518
1519 return nReturn;
1520}
1521#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
1522
1523
1524/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001525 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08001526 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001527QCBORError
1528QCBORDecode_GetNextWithTags(QCBORDecodeContext *me,
1529 QCBORItem *pDecodedItem,
1530 QCBORTagListOut *pTags)
Laurence Lundblade59289e52019-12-30 13:44:37 -08001531{
1532 QCBORError nReturn;
1533
1534 nReturn = QCBORDecode_GetNextMapOrArray(me, pDecodedItem, pTags);
1535 if(nReturn != QCBOR_SUCCESS) {
1536 goto Done;
1537 }
1538
1539#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
1540#define TAG_MAPPER_FIRST_XXX TAG_MAPPER_FIRST_SIX
1541#else
1542#define TAG_MAPPER_FIRST_XXX TAG_MAPPER_FIRST_FOUR
1543#endif
1544
1545 // Only pay attention to tags this code knows how to decode.
1546 switch(pDecodedItem->uTagBits & TAG_MAPPER_FIRST_XXX) {
1547 case 0:
1548 // No tags at all or none we know about. Nothing to do.
1549 // This is the pass-through path of this function
1550 // that will mostly be taken when decoding any item.
1551 break;
1552
1553 case QCBOR_TAGFLAG_DATE_STRING:
1554 nReturn = DecodeDateString(pDecodedItem);
1555 break;
1556
1557 case QCBOR_TAGFLAG_DATE_EPOCH:
1558 nReturn = DecodeDateEpoch(pDecodedItem);
1559 break;
1560
1561 case QCBOR_TAGFLAG_POS_BIGNUM:
1562 case QCBOR_TAGFLAG_NEG_BIGNUM:
1563 nReturn = DecodeBigNum(pDecodedItem);
1564 break;
1565
1566#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
1567 case QCBOR_TAGFLAG_DECIMAL_FRACTION:
1568 case QCBOR_TAGFLAG_BIGFLOAT:
1569 // For aggregate tagged types, what goes into pTags is only collected
1570 // from the surrounding data item, not the contents, so pTags is not
1571 // passed on here.
1572
1573 nReturn = QCBORDecode_MantissaAndExponent(me, pDecodedItem);
1574 break;
1575#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
1576
1577 default:
1578 // Encountering some mixed-up CBOR like something that
1579 // is tagged as both a string and integer date.
1580 nReturn = QCBOR_ERR_BAD_OPT_TAG;
1581 }
1582
1583Done:
1584 if(nReturn != QCBOR_SUCCESS) {
1585 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
1586 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
1587 }
1588 return nReturn;
1589}
1590
1591
1592/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001593 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08001594 */
Laurence Lundblade30816f22018-11-10 13:40:22 +07001595QCBORError QCBORDecode_GetNext(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001596{
1597 return QCBORDecode_GetNextWithTags(me, pDecodedItem, NULL);
1598}
1599
1600
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001601/*
Laurence Lundblade6de37062018-10-15 12:22:42 +05301602 Decoding items is done in 5 layered functions, one calling the
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301603 next one down. If a layer has no work to do for a particular item
1604 it returns quickly.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001605
Laurence Lundblade59289e52019-12-30 13:44:37 -08001606 - QCBORDecode_GetNext, GetNextWithTags -- The top layer processes
1607 tagged data items, turning them into the local C representation.
1608 For the most simple it is just associating a QCBOR_TYPE with the data. For
1609 the complex ones that an aggregate of data items, there is some further
1610 decoding and a little bit of recursion.
1611
1612 - QCBORDecode_GetNextMapOrArray - This manages the beginnings and
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301613 ends of maps and arrays. It tracks descending into and ascending
Laurence Lundblade6de37062018-10-15 12:22:42 +05301614 out of maps/arrays. It processes all breaks that terminate
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001615 indefinite length maps and arrays.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001616
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301617 - GetNext_MapEntry -- This handles the combining of two
1618 items, the label and the data, that make up a map entry.
1619 It only does work on maps. It combines the label and data
1620 items into one labeled item.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001621
Laurence Lundblade59289e52019-12-30 13:44:37 -08001622 - GetNext_TaggedItem -- This decodes type 6 tagging. It turns the
1623 tags into bit flags associated with the data item. No actual decoding
1624 of the contents of the tagged item is performed here.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001625
Laurence Lundblade59289e52019-12-30 13:44:37 -08001626 - GetNext_FullItem -- This assembles the sub-items that make up
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301627 an indefinte length string into one string item. It uses the
Laurence Lundblade6de37062018-10-15 12:22:42 +05301628 string allocater to create contiguous space for the item. It
1629 processes all breaks that are part of indefinite length strings.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001630
Laurence Lundblade59289e52019-12-30 13:44:37 -08001631 - GetNext_Item -- This decodes the atomic data items in CBOR. Each
1632 atomic data item has a "major type", an integer "argument" and optionally
1633 some content. For text and byte strings, the content is the bytes
1634 that make up the string. These are the smallest data items that are
1635 considered to be well-formed. The content may also be other data items in
1636 the case of aggregate types. They are not handled in this layer.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001637
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001638 Roughly this takes 300 bytes of stack for vars. Need to
1639 evaluate this more carefully and correctly.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001640
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301641 */
1642
1643
1644/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001645 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001646 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001647int QCBORDecode_IsTagged(QCBORDecodeContext *me,
1648 const QCBORItem *pItem,
1649 uint64_t uTag)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001650{
1651 const QCBORTagListIn *pCallerConfiguredTagMap = me->pCallerConfiguredTagList;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001652
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001653 uint8_t uTagBitIndex;
1654 // Do not care about errors in pCallerConfiguredTagMap here. They are
1655 // caught during GetNext() before this is called.
1656 if(TagMapper_Lookup(pCallerConfiguredTagMap, uTag, &uTagBitIndex)) {
1657 return 0;
1658 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001659
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001660 const uint64_t uTagBit = 0x01ULL << uTagBitIndex;
1661 return (uTagBit & pItem->uTagBits) != 0;
1662}
1663
1664
1665/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001666 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001667 */
Laurence Lundblade30816f22018-11-10 13:40:22 +07001668QCBORError QCBORDecode_Finish(QCBORDecodeContext *me)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001669{
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001670 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001671
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001672 // Error out if all the maps/arrays are not closed out
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001673 if(!DecodeNesting_IsAtTop(&(me->nesting))) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001674 nReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
1675 goto Done;
1676 }
1677
1678 // Error out if not all the bytes are consumed
1679 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) {
1680 nReturn = QCBOR_ERR_EXTRA_BYTES;
1681 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001682
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001683Done:
Laurence Lundblade6de37062018-10-15 12:22:42 +05301684 // Call the destructor for the string allocator if there is one.
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001685 // Always called, even if there are errors; always have to clean up
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001686 StringAllocator_Destruct(&(me->StringAllocator));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001687
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001688 return nReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001689}
1690
1691
1692
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001693/*
1694
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001695Decoder errors handled in this file
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001696
Laurence Lundbladeee851742020-01-08 08:37:05 -08001697 - Hit end of input before it was expected while decoding type and
1698 number QCBOR_ERR_HIT_END
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001699
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001700 - negative integer that is too large for C QCBOR_ERR_INT_OVERFLOW
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001701
Laurence Lundbladeee851742020-01-08 08:37:05 -08001702 - Hit end of input while decoding a text or byte string
1703 QCBOR_ERR_HIT_END
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001704
Laurence Lundbladeee851742020-01-08 08:37:05 -08001705 - Encountered conflicting tags -- e.g., an item is tagged both a date
1706 string and an epoch date QCBOR_ERR_UNSUPPORTED
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001707
Laurence Lundbladeee851742020-01-08 08:37:05 -08001708 - Encontered an array or mapp that has too many items
1709 QCBOR_ERR_ARRAY_TOO_LONG
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001710
Laurence Lundbladeee851742020-01-08 08:37:05 -08001711 - Encountered array/map nesting that is too deep
1712 QCBOR_ERR_ARRAY_NESTING_TOO_DEEP
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001713
Laurence Lundbladeee851742020-01-08 08:37:05 -08001714 - An epoch date > INT64_MAX or < INT64_MIN was encountered
1715 QCBOR_ERR_DATE_OVERFLOW
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001716
Laurence Lundbladeee851742020-01-08 08:37:05 -08001717 - The type of a map label is not a string or int
1718 QCBOR_ERR_MAP_LABEL_TYPE
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001719
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001720 - Hit end with arrays or maps still open -- QCBOR_ERR_EXTRA_BYTES
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001721
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001722 */
1723
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001724
1725
Laurence Lundbladef6531662018-12-04 10:42:22 +09001726
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001727/* ===========================================================================
1728 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001729
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001730 This implements a simple sting allocator for indefinite length
1731 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
1732 implements the function type QCBORStringAllocate and allows easy
1733 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09001734
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001735 This particular allocator is built-in for convenience. The caller
1736 can implement their own. All of this following code will get
1737 dead-stripped if QCBORDecode_SetMemPool() is not called.
1738
1739 This is a very primitive memory allocator. It does not track
1740 individual allocations, only a high-water mark. A free or
1741 reallocation must be of the last chunk allocated.
1742
1743 The size of the pool and offset to free memory are packed into the
1744 first 8 bytes of the memory pool so we don't have to keep them in
1745 the decode context. Since the address of the pool may not be
1746 aligned, they have to be packed and unpacked as if they were
1747 serialized data of the wire or such.
1748
1749 The sizes packed in are uint32_t to be the same on all CPU types
1750 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08001751 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001752
1753
Laurence Lundbladeee851742020-01-08 08:37:05 -08001754static inline int
1755MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001756{
1757 // Use of UsefulInputBuf is overkill, but it is convenient.
1758 UsefulInputBuf UIB;
1759
Laurence Lundbladeee851742020-01-08 08:37:05 -08001760 // Just assume the size here. It was checked during SetUp so
1761 // the assumption is safe.
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001762 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem, QCBOR_DECODE_MIN_MEM_POOL_SIZE});
1763 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
1764 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
1765 return UsefulInputBuf_GetError(&UIB);
1766}
1767
1768
Laurence Lundbladeee851742020-01-08 08:37:05 -08001769static inline int
1770MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001771{
1772 // Use of UsefulOutBuf is overkill, but convenient. The
1773 // length check performed here is useful.
1774 UsefulOutBuf UOB;
1775
1776 UsefulOutBuf_Init(&UOB, Pool);
1777 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
1778 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
1779 return UsefulOutBuf_GetError(&UOB);
1780}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001781
1782
1783/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001784 Internal function for an allocation, reallocation free and destuct.
1785
1786 Having only one function rather than one each per mode saves space in
1787 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001788
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001789 Code Reviewers: THIS FUNCTION DOES POINTER MATH
1790 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001791static UsefulBuf
1792MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001793{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001794 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001795
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001796 uint32_t uPoolSize;
1797 uint32_t uFreeOffset;
1798
1799 if(uNewSize > UINT32_MAX) {
1800 // This allocator is only good up to 4GB. This check should
1801 // optimize out if sizeof(size_t) == sizeof(uint32_t)
1802 goto Done;
1803 }
1804 const uint32_t uNewSize32 = (uint32_t)uNewSize;
1805
1806 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
1807 goto Done;
1808 }
1809
1810 if(uNewSize) {
1811 if(pMem) {
1812 // REALLOCATION MODE
1813 // Calculate pointer to the end of the memory pool. It is
1814 // assumed that pPool + uPoolSize won't wrap around by
1815 // assuming the caller won't pass a pool buffer in that is
1816 // not in legitimate memory space.
1817 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
1818
1819 // Check that the pointer for reallocation is in the range of the
1820 // pool. This also makes sure that pointer math further down
1821 // doesn't wrap under or over.
1822 if(pMem >= pPool && pMem < pPoolEnd) {
1823 // Offset to start of chunk for reallocation. This won't
1824 // wrap under because of check that pMem >= pPool. Cast
1825 // is safe because the pool is always less than UINT32_MAX
1826 // because of check in QCBORDecode_SetMemPool().
1827 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
1828
1829 // Check to see if the allocation will fit. uPoolSize -
1830 // uMemOffset will not wrap under because of check that
1831 // pMem is in the range of the uPoolSize by check above.
1832 if(uNewSize <= uPoolSize - uMemOffset) {
1833 ReturnValue.ptr = pMem;
1834 ReturnValue.len = uNewSize;
1835
1836 // Addition won't wrap around over because uNewSize was
1837 // checked to be sure it is less than the pool size.
1838 uFreeOffset = uMemOffset + uNewSize32;
1839 }
1840 }
1841 } else {
1842 // ALLOCATION MODE
1843 // uPoolSize - uFreeOffset will not underflow because this
1844 // pool implementation makes sure uFreeOffset is always
1845 // smaller than uPoolSize through this check here and
1846 // reallocation case.
1847 if(uNewSize <= uPoolSize - uFreeOffset) {
1848 ReturnValue.len = uNewSize;
1849 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001850 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001851 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001852 }
1853 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001854 if(pMem) {
1855 // FREE MODE
1856 // Cast is safe because of limit on pool size in
1857 // QCBORDecode_SetMemPool()
1858 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
1859 } else {
1860 // DESTRUCT MODE
1861 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001862 }
1863 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001864
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001865 UsefulBuf Pool = {pPool, uPoolSize};
1866 MemPool_Pack(Pool, uFreeOffset);
1867
1868Done:
1869 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001870}
1871
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001872
Laurence Lundbladef6531662018-12-04 10:42:22 +09001873/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001874 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09001875 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001876QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
1877 UsefulBuf Pool,
1878 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001879{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001880 // The pool size and free mem offset are packed into the beginning
1881 // of the pool memory. This compile time check make sure the
1882 // constant in the header is correct. This check should optimize
1883 // down to nothing.
1884 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundblade30816f22018-11-10 13:40:22 +07001885 return QCBOR_ERR_BUFFER_TOO_SMALL;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001886 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001887
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001888 // The pool size and free offset packed in to the beginning of pool
1889 // memory are only 32-bits. This check will optimize out on 32-bit
1890 // machines.
1891 if(Pool.len > UINT32_MAX) {
1892 return QCBOR_ERR_BUFFER_TOO_LARGE;
1893 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001894
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001895 // This checks that the pool buffer given is big enough.
1896 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
1897 return QCBOR_ERR_BUFFER_TOO_SMALL;
1898 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001899
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001900 pMe->StringAllocator.pfAllocator = MemPool_Function;
1901 pMe->StringAllocator.pAllocateCxt = Pool.ptr;
1902 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001903
Laurence Lundblade30816f22018-11-10 13:40:22 +07001904 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001905}
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001906
Laurence Lundblade1341c592020-04-11 14:19:05 -07001907#include <stdio.h>
1908void printdecode(QCBORDecodeContext *pMe, const char *szName)
1909{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001910 printf("---%s--%d--%d--\nLevel Count Type Offset SaveCount MapMode\n",
1911 szName,
1912 (uint32_t)pMe->InBuf.cursor,
1913 (uint32_t)pMe->InBuf.UB.len);
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001914 for(int i = 0; i < QCBOR_MAX_ARRAY_NESTING; i++) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001915 if(&(pMe->nesting.pMapsAndArrays[i]) > pMe->nesting.pCurrent) {
1916 break;
1917 }
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001918 printf("%2s %2d %5d %s %6u %2d %d\n",
1919 pMe->nesting.pCurrentMap == &(pMe->nesting.pMapsAndArrays[i]) ? "->": " ",
Laurence Lundblade1341c592020-04-11 14:19:05 -07001920 i,
1921 pMe->nesting.pMapsAndArrays[i].uCount,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001922 pMe->nesting.pMapsAndArrays[i].uMajorType == QCBOR_TYPE_MAP ? " map" :
1923 (pMe->nesting.pMapsAndArrays[i].uMajorType == QCBOR_TYPE_ARRAY ? "array" :
1924 (pMe->nesting.pMapsAndArrays[i].uMajorType == QCBOR_TYPE_NONE ? " none" : "?????")),
Laurence Lundblade1341c592020-04-11 14:19:05 -07001925 pMe->nesting.pMapsAndArrays[i].uOffset,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001926 pMe->nesting.pMapsAndArrays[i].uSaveCount,
1927 pMe->nesting.pMapsAndArrays[i].uMapMode
Laurence Lundblade1341c592020-04-11 14:19:05 -07001928 );
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001929
Laurence Lundblade1341c592020-04-11 14:19:05 -07001930 }
Laurence Lundblade64b607e2020-05-13 13:05:57 -07001931 printf("\n");
Laurence Lundblade1341c592020-04-11 14:19:05 -07001932}
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001933
1934
1935/*
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001936 *
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001937 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001938static inline QCBORError
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001939ConsumeItem(QCBORDecodeContext *pMe,
1940 const QCBORItem *pItemToConsume,
1941 uint_fast8_t *puNextNestLevel)
1942{
Laurence Lundblade1341c592020-04-11 14:19:05 -07001943 QCBORError nReturn;
1944 QCBORItem Item;
1945
1946 printdecode(pMe, "ConsumeItem");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001947
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001948 if(IsMapOrArray(pItemToConsume->uDataType)) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07001949 /* There is only real work to do for maps and arrays */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001950
Laurence Lundblade1341c592020-04-11 14:19:05 -07001951 /* This works for definite and indefinite length
1952 * maps and arrays by using the nesting level
1953 */
1954 do {
1955 nReturn = QCBORDecode_GetNext(pMe, &Item);
1956 if(nReturn != QCBOR_SUCCESS) {
1957 goto Done;
1958 }
1959 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001960
Laurence Lundblade1341c592020-04-11 14:19:05 -07001961 if(puNextNestLevel != NULL) {
1962 *puNextNestLevel = Item.uNextNestLevel;
1963 }
1964 nReturn = QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001965
Laurence Lundblade1341c592020-04-11 14:19:05 -07001966 } else {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07001967 /* item_to_consume is not a map or array */
Laurence Lundblade1341c592020-04-11 14:19:05 -07001968 if(puNextNestLevel != NULL) {
1969 /* Just pass the nesting level through */
1970 *puNextNestLevel = pItemToConsume->uNextNestLevel;
1971 }
1972 nReturn = QCBOR_SUCCESS;
1973 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001974
1975Done:
1976 return nReturn;
1977}
1978
1979
Laurence Lundblade1341c592020-04-11 14:19:05 -07001980/* Return true if the labels in Item1 and Item2 are the same.
1981 Works only for integer and string labels. Returns false
1982 for any other type. */
1983static inline bool
1984MatchLabel(QCBORItem Item1, QCBORItem Item2)
1985{
1986 if(Item1.uLabelType == QCBOR_TYPE_INT64) {
1987 if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
1988 return true;
1989 }
1990 } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07001991 if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07001992 return true;
1993 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07001994 } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07001995 if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
1996 return true;
1997 }
1998 } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
1999 if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
2000 return true;
2001 }
2002 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002003
Laurence Lundblade1341c592020-04-11 14:19:05 -07002004 /* Other label types are never matched */
2005 return false;
2006}
2007
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002008static inline bool
2009MatchType(QCBORItem Item1, QCBORItem Item2)
2010{
2011 if(Item1.uDataType == Item2.uDataType) {
2012 return true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002013 } else if(Item1.uDataType == QCBOR_TYPE_ANY) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002014 return true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002015 } else if(Item2.uDataType == QCBOR_TYPE_ANY) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002016 return true;
2017 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002018 return false;
2019}
2020
2021
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002022/*
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002023 On input pItemArray contains a list of labels and data types
2024 of items to be found.
2025
2026 On output the fully retrieved items are filled in with
2027 values and such. The label was matched, so it never changes.
2028
2029 If an item was not found, its data type is set to none.
2030
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002031 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002032static QCBORError
2033MapSearch(QCBORDecodeContext *pMe, QCBORItem *pItemArray, size_t *puOffset, size_t *puEndOffset)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002034{
Laurence Lundblade1341c592020-04-11 14:19:05 -07002035 QCBORError nReturn;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002036
2037 // 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 -07002038 if(!DecodeNesting_InMapMode(&(pMe->nesting))) {
2039 return QCBOR_ERR_NOT_ENTERED;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002040 }
2041
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002042 QCBORDecodeNesting SaveNesting;
2043 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002044
2045 UsefulInputBuf_Seek(&(pMe->InBuf), pMe->nesting.pCurrent->uOffset);
2046
2047 /* Loop over all the items in the map. They could be
2048 * deeply nested and this should handle both definite
2049 * and indefinite length maps and arrays, so this
2050 * adds some complexity. */
Laurence Lundblade64b607e2020-05-13 13:05:57 -07002051 const uint8_t uMapNestLevel = DecodeNesting_GetMapModeLevel(&(pMe->nesting));
Laurence Lundblade1341c592020-04-11 14:19:05 -07002052
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002053 uint_fast8_t uNextNestLevel;
2054
2055 uint64_t uFound = 0;
2056
2057 do {
2058 /* Remember offset because sometims we have to return it */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002059 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002060
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002061 /* Get the item */
2062 QCBORItem Item;
2063 nReturn = QCBORDecode_GetNext(pMe, &Item);
2064 if(nReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002065 /* Got non-well-formed CBOR */
2066 goto Done;
2067 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002068
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002069 /* See if item has one of the labels that are of interest */
2070 int i;
2071 QCBORItem *pIterator;
2072 for(pIterator = pItemArray, i = 0; pIterator->uLabelType != 0; pIterator++, i++) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002073 if(MatchLabel(Item, *pIterator)) {
2074 // A label match has been found
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002075 if(uFound & (0x01ULL << i)) {
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002076 nReturn = QCBOR_ERR_DUPLICATE_LABEL;
2077 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002078 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002079 if(!MatchType(Item, *pIterator)) {
2080 nReturn = QCBOR_ERR_UNEXPECTED_TYPE;
2081 goto Done;
2082 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002083
2084 /* Successful match. Return the item. */
2085 *pIterator = Item;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002086 uFound |= 0x01ULL << i;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002087 if(puOffset) {
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002088 *puOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002089 }
2090 }
2091 }
2092
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002093 /* Consume the item whether matched or not. This
2094 does th work of traversing maps and array and
2095 everything in them. In this loop only the
2096 items at the current nesting level are examined
2097 to match the labels. */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002098 nReturn = ConsumeItem(pMe, &Item, &uNextNestLevel);
2099 if(nReturn) {
2100 goto Done;
2101 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002102
2103 } while (uNextNestLevel >= uMapNestLevel);
2104
2105
2106 nReturn = QCBOR_SUCCESS;
2107
2108 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
2109 // Cast OK because encoded CBOR is limited to UINT32_MAX
2110 pMe->uMapEndOffset = (uint32_t)uEndOffset;
2111 // TODO: is zero *puOffset OK?
2112 if(puEndOffset) {
2113 *puEndOffset = uEndOffset;
2114 }
2115
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002116 /* For all items not found, set the data type to QCBOR_TYPE_NONE */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002117 int i;
2118 QCBORItem *pIterator;
2119 for(pIterator = pItemArray, i = 0; pIterator->uLabelType != 0; pIterator++, i++) {
2120 if(!(uFound & (0x01ULL << i))) {
2121 pIterator->uDataType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002122 }
2123 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002124
2125Done:
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002126 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002127
Laurence Lundblade1341c592020-04-11 14:19:05 -07002128 return nReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002129}
2130
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002131
Laurence Lundblade34691b92020-05-18 22:25:25 -07002132void QCBORDecode_ExitMapMode(QCBORDecodeContext *pMe, uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002133{
Laurence Lundblade1341c592020-04-11 14:19:05 -07002134 size_t uEndOffset;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002135
Laurence Lundblade34691b92020-05-18 22:25:25 -07002136 (void)uType; // TODO: error check
2137
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002138/*
Laurence Lundblade1341c592020-04-11 14:19:05 -07002139 if(pMe->uMapEndOffset) {
2140 uEndOffset = pMe->uMapEndOffset;
2141 // It is only valid once.
2142 pMe->uMapEndOffset = 0;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002143 } else { */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002144 QCBORItem Dummy;
2145
2146 Dummy.uLabelType = QCBOR_TYPE_NONE;
2147
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002148 QCBORError nReturn = MapSearch(pMe, &Dummy, NULL, &uEndOffset);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002149
2150 (void)nReturn; // TODO:
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002151// }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002152
2153 printdecode(pMe, "start exit");
2154 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
2155
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002156 DecodeNesting_Exit(&(pMe->nesting));
Laurence Lundblade1341c592020-04-11 14:19:05 -07002157 printdecode(pMe, "end exit");
2158
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002159}
2160
2161
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002162void QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
2163 int64_t nLabel,
2164 uint8_t uQcborType,
2165 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002166{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002167 if(pMe->uLastError != QCBOR_SUCCESS) {
2168 return;
2169 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002170
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002171 QCBORItem OneItemSeach[2];
2172 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
2173 OneItemSeach[0].label.int64 = nLabel;
2174 OneItemSeach[0].uDataType = uQcborType;
2175 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07002176
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002177 QCBORError nReturn = MapSearch(pMe, OneItemSeach, NULL, NULL);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002178 if(nReturn) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002179 pMe->uLastError = (uint8_t)nReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002180 }
2181
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002182 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
2183 pMe->uLastError = QCBOR_ERR_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002184 }
2185
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002186 *pItem = OneItemSeach[0];
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002187}
2188
2189
2190QCBORError QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002191 const char *szLabel,
2192 uint8_t uQcborType,
2193 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002194{
Laurence Lundblade1341c592020-04-11 14:19:05 -07002195 QCBORItem One[2];
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002196
Laurence Lundblade1341c592020-04-11 14:19:05 -07002197 One[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2198 One[0].label.string = UsefulBuf_FromSZ(szLabel);
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002199 One[0].uDataType = uQcborType;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002200 One[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
2201
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002202 QCBORError nReturn = MapSearch(pMe, One, NULL, NULL);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002203 if(nReturn) {
2204 return nReturn;
2205 }
2206
2207 if(One[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002208 return QCBOR_ERR_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002209 }
2210
2211 *pItem = One[0];
2212
2213 return QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002214}
2215
2216
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002217static QCBORError CheckTagRequirement(TagSpecification TagSpec, uint8_t uDataType)
2218{
2219 // This gets called a lot, so it needs to be fast, especially for simple cases.
2220 // TODO: this isn't working right yet
2221 if((TagSpec.uTagRequirement == 1 || TagSpec.uTagRequirement == 2) && uDataType == TagSpec.uTaggedType) {
2222 return QCBOR_SUCCESS;
2223 } else {
2224 for(int i = 0; i < 6; i++) {
2225 if(uDataType == TagSpec.uAllowedContentTypes[i]) {
2226 return QCBOR_SUCCESS;
2227 }
2228 }
2229 }
2230
2231 return QCBOR_ERR_UNEXPECTED_TYPE;
2232
2233}
2234
2235void QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
2236 int64_t nLabel,
2237 TagSpecification TagSpec,
2238 QCBORItem *pItem)
2239{
2240 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
2241 if(pMe->uLastError != QCBOR_SUCCESS) {
2242 return;
2243 }
2244
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002245 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem->uDataType);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002246}
2247
2248void QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
2249 const char *szLabel,
2250 TagSpecification TagSpec,
2251 QCBORItem *pItem)
2252{
2253 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
2254 if(pMe->uLastError != QCBOR_SUCCESS) {
2255 return;
2256 }
2257
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002258 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem->uDataType);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002259}
2260
2261void QCBORDecode_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
2262 int64_t nLabel,
2263 TagSpecification TagSpec,
2264 UsefulBufC *pString)
2265{
2266 QCBORItem Item;
2267 QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
2268 if(pMe->uLastError == QCBOR_SUCCESS) {
2269 *pString = Item.val.string;
2270 }
2271}
2272
2273void QCBORDecode_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
2274 const char * szLabel,
2275 TagSpecification TagSpec,
2276 UsefulBufC *pString)
2277{
2278 QCBORItem Item;
2279 QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
2280 if(pMe->uLastError == QCBOR_SUCCESS) {
2281 *pString = Item.val.string;
2282 }
2283}
Laurence Lundblade1341c592020-04-11 14:19:05 -07002284
Laurence Lundblade1341c592020-04-11 14:19:05 -07002285
Laurence Lundblade34691b92020-05-18 22:25:25 -07002286static void SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07002287{
Laurence Lundblade34691b92020-05-18 22:25:25 -07002288 if(pMe->uLastError != QCBOR_SUCCESS) {
2289 // Already in error state; do nothing.
2290 return;
2291 }
2292
2293 size_t uOffset;
Laurence Lundblade986017c2020-05-23 19:25:02 -07002294 pMe->uLastError = (uint8_t)MapSearch(pMe, pSearch, &uOffset, NULL);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002295 if(pMe->uLastError != QCBOR_SUCCESS) {
2296 return;
2297 }
2298
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002299 /* Need to get the current pre-order nesting level and cursor to be
2300 at the first item in the map/array just entered.
2301
2302 Also need to current map nesting level and start cursor to
2303 be at the right place.
2304
2305 The UsefulInBuf offset could be anywhere, so no assumption is
2306 made about it.
2307
2308 No assumption is made about the pre-order nesting level either.
2309
2310 However the map mode nesting level is assumed to be one above
2311 the map level that is being entered.
2312 */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002313 /* Seek to the data item that is the map or array */
2314 UsefulInputBuf_Seek(&(pMe->InBuf), uOffset);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002315 pMe->nesting.pCurrent = pMe->nesting.pCurrentMap; // TODO: part of DecodeNesting
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002316
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002317 // TODO: check error?
Laurence Lundblade34691b92020-05-18 22:25:25 -07002318 QCBORDecode_EnterMapMode(pMe, pSearch->uDataType);
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002319
Laurence Lundblade34691b92020-05-18 22:25:25 -07002320 printdecode(pMe, "FinishEnter");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002321}
2322
2323
Laurence Lundblade34691b92020-05-18 22:25:25 -07002324void QCBORDecode_EnterMapInMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002325{
Laurence Lundblade1341c592020-04-11 14:19:05 -07002326 QCBORItem One[2];
Laurence Lundblade1341c592020-04-11 14:19:05 -07002327 One[0].uLabelType = QCBOR_TYPE_INT64;
2328 One[0].label.int64 = nLabel;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002329 One[0].uDataType = QCBOR_TYPE_MAP;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002330 One[1].uLabelType = QCBOR_TYPE_NONE;
2331
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002332 /* The map to enter was found, now finish of entering it. */
Laurence Lundblade34691b92020-05-18 22:25:25 -07002333 SearchAndEnter(pMe, One);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002334}
2335
2336
Laurence Lundblade34691b92020-05-18 22:25:25 -07002337void QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002338{
2339 QCBORItem One[2];
Laurence Lundblade1341c592020-04-11 14:19:05 -07002340 One[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2341 One[0].label.string = UsefulBuf_FromSZ(szLabel);
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002342 One[0].uDataType = QCBOR_TYPE_MAP;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002343 One[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002344
Laurence Lundblade34691b92020-05-18 22:25:25 -07002345 SearchAndEnter(pMe, One);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002346}
2347
2348
Laurence Lundblade34691b92020-05-18 22:25:25 -07002349void QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07002350{
2351 QCBORItem One[2];
Laurence Lundblade34691b92020-05-18 22:25:25 -07002352 One[0].uLabelType = QCBOR_TYPE_INT64;
2353 One[0].label.int64 = nLabel;
2354 One[0].uDataType = QCBOR_TYPE_ARRAY;
2355 One[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002356
Laurence Lundblade34691b92020-05-18 22:25:25 -07002357 SearchAndEnter(pMe, One);
2358}
2359
2360
2361void QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
2362{
2363 QCBORItem One[2];
Laurence Lundblade1341c592020-04-11 14:19:05 -07002364 One[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2365 One[0].label.string = UsefulBuf_FromSZ(szLabel);
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002366 One[0].uDataType = QCBOR_TYPE_ARRAY;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002367 One[1].uLabelType = QCBOR_TYPE_NONE;
2368
Laurence Lundblade34691b92020-05-18 22:25:25 -07002369 SearchAndEnter(pMe, One);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002370}
2371
2372
2373
2374
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002375
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002376/* Next item must be map or this generates an error */
Laurence Lundblade34691b92020-05-18 22:25:25 -07002377void QCBORDecode_EnterMapMode(QCBORDecodeContext *pMe, uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002378{
Laurence Lundblade34691b92020-05-18 22:25:25 -07002379 if(pMe->uLastError != QCBOR_SUCCESS) {
2380 // Already in error state; do nothing.
2381 return;
2382 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002383
2384 /* Get the data item that is the map that is being searched */
Laurence Lundblade34691b92020-05-18 22:25:25 -07002385 QCBORItem Item;
Laurence Lundblade986017c2020-05-23 19:25:02 -07002386 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002387 if(pMe->uLastError != QCBOR_SUCCESS) {
2388 return;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002389 }
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002390 if(Item.uDataType != uType) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07002391 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
2392 return;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002393 }
2394
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002395 DecodeNesting_EnterMapMode(&(pMe->nesting), UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002396
Laurence Lundblade34691b92020-05-18 22:25:25 -07002397 printdecode(pMe, "EnterMapModeDone");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002398}
2399
2400
2401
2402QCBORError QCBORDecode_GetItemsInMap(QCBORDecodeContext *pCtx, QCBORItem *pItemList)
2403{
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002404 return MapSearch(pCtx, pItemList, NULL, NULL);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002405}
2406
2407
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002408
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002409
2410
Laurence Lundblade1341c592020-04-11 14:19:05 -07002411void QCBORDecode_RewindMap(QCBORDecodeContext *pMe)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002412{
Laurence Lundblade1341c592020-04-11 14:19:05 -07002413 // TODO: check for map mode
2414 pMe->nesting.pCurrent->uCount = pMe->nesting.pCurrent->uSaveCount;
2415 UsefulInputBuf_Seek(&(pMe->InBuf), pMe->nesting.pCurrent->uOffset);
2416}
2417
2418
Laurence Lundblade1341c592020-04-11 14:19:05 -07002419
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002420
Laurence Lundbladee6430642020-03-14 21:15:44 -07002421
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002422
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002423
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002424
Laurence Lundblade11a064e2020-05-07 13:13:42 -07002425
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002426
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002427static QCBORError InterpretBool(const QCBORItem *pItem, bool *pBool)
2428{
2429 switch(pItem->uDataType) {
2430 case QCBOR_TYPE_TRUE:
2431 *pBool = true;
2432 return QCBOR_SUCCESS;
2433 break;
2434
2435 case QCBOR_TYPE_FALSE:
2436 *pBool = false;
2437 return QCBOR_SUCCESS;
2438 break;
2439
2440 default:
2441 return QCBOR_ERR_UNEXPECTED_TYPE;
2442 break;
2443 }
2444}
Laurence Lundbladee6430642020-03-14 21:15:44 -07002445
Laurence Lundbladec4537442020-04-14 18:53:22 -07002446void QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002447{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002448 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002449 // Already in error state, do nothing
Laurence Lundbladee6430642020-03-14 21:15:44 -07002450 return;
2451 }
2452
Laurence Lundbladec4537442020-04-14 18:53:22 -07002453 QCBORError nError;
2454 QCBORItem Item;
2455
2456 nError = QCBORDecode_GetNext(pMe, &Item);
2457 if(nError != QCBOR_SUCCESS) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002458 pMe->uLastError = (uint8_t)nError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002459 return;
2460 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002461 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002462}
2463
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002464void QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe, int64_t nLabel, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002465{
2466 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002467 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002468
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002469 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002470}
2471
2472
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002473void QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, bool *pValue)
2474{
2475 QCBORItem Item;
2476 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
2477
2478 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
2479}
2480
2481
2482
2483void QCBORDecode_GetTaggedStringInternal(QCBORDecodeContext *pMe, TagSpecification TagSpec, UsefulBufC *pBstr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002484{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002485 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002486 // Already in error state, do nothing
2487 return;
2488 }
2489
2490 QCBORError nError;
2491 QCBORItem Item;
2492
2493 nError = QCBORDecode_GetNext(pMe, &Item);
2494 if(nError != QCBOR_SUCCESS) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002495 pMe->uLastError = (uint8_t)nError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002496 return;
2497 }
2498
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002499 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, Item.uDataType);
2500
2501 if(pMe->uLastError == QCBOR_SUCCESS) {
2502 *pBstr = Item.val.string;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002503 }
2504}
2505
Laurence Lundbladec4537442020-04-14 18:53:22 -07002506
2507
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002508
2509static QCBORError ConvertBigNum(const QCBORItem *pItem, UsefulBufC *pValue, bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002510{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002511 *pbIsNegative = false;
2512
2513 bool bMustBeTagged = true; // TODO: fix this
2514
2515 switch(pItem->uDataType) {
2516 case QCBOR_TYPE_BYTE_STRING:
2517 // TODO: check that there is no tag here?
2518 if(bMustBeTagged) {
2519 return QCBOR_ERR_UNEXPECTED_TYPE;
2520 } else {
2521 *pValue = pItem->val.string;
2522 return QCBOR_SUCCESS;
2523 }
2524 break;
2525
2526 case QCBOR_TYPE_POSBIGNUM:
2527 *pValue = pItem->val.string;
2528 return QCBOR_SUCCESS;
2529 break;
2530
2531 case QCBOR_TYPE_NEGBIGNUM:
2532 *pbIsNegative = true;
2533 *pValue = pItem->val.string;
2534 return QCBOR_SUCCESS;
2535 break;
2536
2537 default:
2538 return QCBOR_ERR_UNEXPECTED_TYPE;
2539 break;
2540 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002541}
2542
2543
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002544/**
2545 @param[in] bMustBeTagged If \c true, then the data item must be tagged as either
2546 a positive or negative bignum. If \c false, then it only must be a byte string and bIsNegative
2547 will always be false on the asumption that it is positive, but it can be interpretted as
2548 negative if the the sign is know from other context.
2549 @param[out] pValue The bytes that make up the big num
2550 @param[out] pbIsNegative \c true if tagged as a negative big num. \c false otherwise.
2551
2552 if bMustBeTagged is false, then this will succeed if the data item is a plain byte string,
2553 a positive big num or a negative big num.
2554
2555 */
2556void QCBORDecode_GetBignum(QCBORDecodeContext *pMe, bool bMustBeTagged, UsefulBufC *pValue, bool *pbIsNegative)
2557{
2558 if(pMe->uLastError != QCBOR_SUCCESS) {
2559 // Already in error state, do nothing
2560 return;
2561 }
2562
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002563 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002564 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
2565 if(uError != QCBOR_SUCCESS) {
2566 pMe->uLastError = (uint8_t)uError;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002567 return;
2568 }
2569
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002570 pMe->uLastError = (uint8_t)ConvertBigNum(&Item, pValue, pbIsNegative);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002571}
2572
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002573void QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe, int64_t nLabel, bool bMustBeTagged, UsefulBufC *pValue, bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002574{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002575 QCBORItem Item;
2576 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002577
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002578 pMe->uLastError = (uint8_t)ConvertBigNum(&Item, pValue, pbIsNegative);
Laurence Lundbladec4537442020-04-14 18:53:22 -07002579}
2580
Laurence Lundbladec4537442020-04-14 18:53:22 -07002581
2582
2583
Laurence Lundbladee6430642020-03-14 21:15:44 -07002584
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002585typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002586
2587
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002588// The main exponentiator that works on only positive numbers
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002589static QCBORError Exponentitate10(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002590{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002591 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002592
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002593 if(uResult != 0) {
2594 /* This loop will run a maximum of 19 times because
2595 * UINT64_MAX < 10 ^^ 19. More than that will cause
2596 * exit with the overflow error
2597 */
2598 for(; nExponent > 0; nExponent--) {
2599 if(uResult > UINT64_MAX / 10) {
2600 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Error overflow
2601 }
2602 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002603 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002604
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002605 for(; nExponent < 0; nExponent++) {
2606 uResult = uResult / 10;
2607 if(uResult == 0) {
2608 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Underflow error
2609 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002610 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002611 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002612 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07002613
2614 *puResult = uResult;
2615
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002616 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002617}
2618
2619
Laurence Lundbladee6430642020-03-14 21:15:44 -07002620/* Convert a decimal fraction to an int64_t without using
2621 floating point or math libraries. Most decimal fractions
2622 will not fit in an int64_t and this will error out with
2623 under or overflow
2624 */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002625static QCBORError Exponentitate2(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002626{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002627 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002628
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002629 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002630
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002631 /* This loop will run a maximum of 64 times because
Laurence Lundbladee6430642020-03-14 21:15:44 -07002632 * INT64_MAX < 2^31. More than that will cause
2633 * exist with the overflow error
2634 */
2635 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002636 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002637 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Error overflow
Laurence Lundbladee6430642020-03-14 21:15:44 -07002638 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002639 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002640 nExponent--;
2641 }
2642
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002643 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002644 if(uResult == 0) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002645 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Underflow error
2646 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002647 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002648 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002649 }
2650
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002651 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002652
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002653 return QCBOR_SUCCESS;
2654}
2655
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002656/*
2657 Compute value with signed mantissa and signed result. Works with exponent of 2 or 10 based on exponentiator.
2658 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002659static inline QCBORError ExponentiateNN(int64_t nMantissa, int64_t nExponent, int64_t *pnResult, fExponentiator pfExp)
2660{
2661 uint64_t uResult;
2662
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002663 // Take the absolute value of the mantissa and convert to unsigned.
2664 // TODO: this should be possible in one intruction
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002665 uint64_t uMantissa = nMantissa > 0 ? (uint64_t)nMantissa : (uint64_t)-nMantissa;
2666
2667 // Do the exponentiation of the positive mantissa
2668 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
2669 if(uReturn) {
2670 return uReturn;
2671 }
2672
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002673
Laurence Lundblade983500d2020-05-14 11:49:34 -07002674 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
2675 of INT64_MIN. This assumes two's compliment representation where
2676 INT64_MIN is one increment farther from 0 than INT64_MAX.
2677 Trying to write -INT64_MIN doesn't work to get this because the
2678 compiler tries to work with an int64_t which can't represent
2679 -INT64_MIN.
2680 */
2681 uint64_t uMax = nMantissa > 0 ? INT64_MAX : (uint64_t)INT64_MAX+1;
2682
2683 // Error out if too large
2684 if(uResult > uMax) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002685 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
2686 }
2687
2688 // Casts are safe because of checks above
2689 *pnResult = nMantissa > 0 ? (int64_t)uResult : -(int64_t)uResult;
2690
2691 return QCBOR_SUCCESS;
2692}
2693
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002694/*
2695 Compute value with signed mantissa and unsigned result. Works with exponent of 2 or 10 based on exponentiator.
2696 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002697static inline QCBORError ExponentitateNU(int64_t nMantissa, int64_t nExponent, uint64_t *puResult, fExponentiator pfExp)
2698{
2699 if(nMantissa < 0) {
2700 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
2701 }
2702
2703 // Cast to unsigned is OK because of check for negative
2704 // Cast to unsigned is OK because UINT64_MAX > INT64_MAX
2705 // Exponentiation is straight forward
2706 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
2707}
2708
2709
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002710#include <math.h>
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002711
2712
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002713static QCBORError ConvertBigNumToUnsigned(const UsefulBufC BigNum, uint64_t uMax, uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002714{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002715 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002716
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002717 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002718 const uint8_t *pByte = BigNum.ptr;
2719 size_t uLen = BigNum.len;
2720 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07002721 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002722 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002723 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07002724 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002725 }
2726
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002727 *pResult = uResult;
2728 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002729}
2730
Laurence Lundblade887add82020-05-17 05:50:34 -07002731static inline QCBORError ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum, uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002732{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002733 return ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002734}
2735
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002736static inline QCBORError ConvertPositiveBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002737{
2738 uint64_t uResult;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002739 QCBORError uError = ConvertBigNumToUnsigned(BigNum, INT64_MAX, &uResult);
2740 if(uError) {
2741 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002742 }
2743 /* Cast is safe because ConvertBigNum is told to limit to INT64_MAX */
2744 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002745 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002746}
2747
2748
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002749static inline QCBORError ConvertNegativeBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002750{
2751 uint64_t uResult;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002752 QCBORError uError = ConvertBigNumToUnsigned(BigNum, INT64_MAX-1, &uResult);
2753 if(uError) {
2754 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002755 }
2756 /* Cast is safe because ConvertBigNum is told to limit to INT64_MAX */
Laurence Lundblade887add82020-05-17 05:50:34 -07002757 // TODO: this code is incorrect. See RFC 7049
Laurence Lundbladee6430642020-03-14 21:15:44 -07002758 *pResult = -(int64_t)uResult;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002759 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002760}
2761
Laurence Lundbladef6c86662020-05-12 02:08:00 -07002762#include "fenv.h"
Laurence Lundbladec4537442020-04-14 18:53:22 -07002763
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002764
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002765/*
2766Convert a integers and floats to an int64_t.
2767
2768\param[in] uOptions Bit mask list of conversion options.
2769
2770\retval QCBOR_ERR_CONVERSION_NOT_REQUESTED Conversion, possible, but not requested in uOptions.
2771
2772\retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
2773
2774\retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large or too small.
2775
2776*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002777static QCBORError ConvertInt64(const QCBORItem *pItem, uint32_t uOptions, int64_t *pnValue)
2778{
2779 switch(pItem->uDataType) {
2780 // TODO: float when ifdefs are set
2781 case QCBOR_TYPE_DOUBLE:
2782 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
2783 // TODO: what about under/overflow here?
2784 // Invokes the floating-point HW and/or compiler-added libraries
2785 feclearexcept(FE_ALL_EXCEPT);
2786 *pnValue = llround(pItem->val.dfnum);
2787 if(fetestexcept(FE_INVALID)) {
2788 // TODO: better error code
2789 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
2790 }
2791 } else {
2792 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
2793 }
2794 break;
2795
2796 case QCBOR_TYPE_INT64:
2797 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
2798 *pnValue = pItem->val.int64;
2799 } else {
2800 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
2801 }
2802 break;
2803
2804 case QCBOR_TYPE_UINT64:
2805 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
2806 if(pItem->val.uint64 < INT64_MAX) {
2807 *pnValue = pItem->val.int64;
2808 } else {
2809 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
2810 }
2811 } else {
2812 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
2813 }
2814 break;
2815
2816 default:
2817 return QCBOR_ERR_UNEXPECTED_TYPE;
2818 }
2819 return QCBOR_SUCCESS;
2820}
2821
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002822
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002823void QCBORDecode_GetInt64ConvertInternal(QCBORDecodeContext *pMe,
2824 uint32_t uOptions,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002825 int64_t *pnValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002826 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002827{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002828 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002829 return;
2830 }
2831
Laurence Lundbladee6430642020-03-14 21:15:44 -07002832 QCBORItem Item;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002833 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
2834 if(uError) {
2835 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002836 return;
2837 }
2838
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002839 if(pItem) {
2840 *pItem = Item;
2841 }
2842
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002843 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002844}
2845
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002846
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002847void QCBORDecode_GetInt64ConvertInternalInMapN(QCBORDecodeContext *pMe,
2848 int64_t nLabel,
2849 uint32_t uOptions,
2850 int64_t *pnValue,
2851 QCBORItem *pItem)
2852{
2853 QCBORItem Item;
2854 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
2855
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002856 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002857}
2858
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002859
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002860void QCBORDecode_GetInt64ConvertInternalInMapSZ(QCBORDecodeContext *pMe,
2861 const char * szLabel,
2862 uint32_t uOptions,
2863 int64_t *pnValue,
2864 QCBORItem *pItem)
2865{
2866 if(pMe->uLastError != QCBOR_SUCCESS) {
2867 return;
2868 }
2869
2870 QCBORItem Item;
2871 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
2872
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002873 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002874}
2875
2876
2877
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002878/*
2879 Convert a large variety of integer types to an int64_t.
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002880
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002881 \param[in] uOptions Bit mask list of conversion options.
2882
2883 \retval QCBOR_ERR_CONVERSION_NOT_REQUESTED Conversion, possible, but not requested in uOptions.
2884
2885 \retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
2886
2887 \retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large or too small.
2888
2889 */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002890static QCBORError Int64ConvertAll(const QCBORItem *pItem, uint32_t uOptions, int64_t *pnValue)
2891{
2892 QCBORError uErr;
2893
2894 switch(pItem->uDataType) {
2895
2896 case QCBOR_TYPE_POSBIGNUM:
2897 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
2898 return ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002899 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002900 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002901 }
2902 break;
2903
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002904 case QCBOR_TYPE_NEGBIGNUM:
2905 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
2906 return ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002907 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002908 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002909 }
2910 break;
2911
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002912#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
2913 case QCBOR_TYPE_DECIMAL_FRACTION:
2914 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
2915 return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
2916 pItem->val.expAndMantissa.nExponent,
2917 pnValue,
2918 &Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002919 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002920 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
2921 }
2922 break;
2923
2924 case QCBOR_TYPE_BIGFLOAT:
2925 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
2926 return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
2927 pItem->val.expAndMantissa.nExponent,
2928 pnValue,
2929 Exponentitate2);
2930 } else {
2931 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
2932 }
2933 break;
2934
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002935 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
2936 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
2937 int64_t nMantissa;
2938 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
2939 if(uErr) {
2940 return uErr;
2941 }
2942 return ExponentiateNN(nMantissa,
2943 pItem->val.expAndMantissa.nExponent,
2944 pnValue,
2945 Exponentitate10);
2946 } else {
2947 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
2948 }
2949 break;
2950
2951 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
2952 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
2953 int64_t nMantissa;
2954 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
2955 if(uErr) {
2956 return uErr;
2957 }
2958 return ExponentiateNN(nMantissa,
2959 pItem->val.expAndMantissa.nExponent,
2960 pnValue,
2961 Exponentitate10);
2962 } else {
2963 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
2964 }
2965 break;
2966
2967 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
2968 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
2969 int64_t nMantissa;
2970 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
2971 if(uErr) {
2972 return uErr;
2973 }
2974 return ExponentiateNN(nMantissa,
2975 pItem->val.expAndMantissa.nExponent,
2976 pnValue,
2977 Exponentitate2);
2978 } else {
2979 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
2980 }
2981 break;
2982
2983 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
2984 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
2985 int64_t nMantissa;
2986 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
2987 if(uErr) {
2988 return uErr;
2989 }
2990 return ExponentiateNN(nMantissa,
2991 pItem->val.expAndMantissa.nExponent,
2992 pnValue,
2993 Exponentitate2);
2994 } else {
2995 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002996 }
2997 break;
2998
Laurence Lundbladec4537442020-04-14 18:53:22 -07002999 default:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003000 return QCBOR_ERR_UNEXPECTED_TYPE;
3001#endif
Laurence Lundbladec4537442020-04-14 18:53:22 -07003002 }
3003}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003004
3005
Laurence Lundbladec4537442020-04-14 18:53:22 -07003006/*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003007 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003008 */
3009void QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003010{
3011 QCBORItem Item;
3012
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003013 QCBORDecode_GetInt64ConvertInternal(pMe, uOptions, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003014
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003015 if(pMe->uLastError == QCBOR_SUCCESS) {
3016 // The above conversion succeeded
3017 return;
3018 }
3019
Laurence Lundbladef6c86662020-05-12 02:08:00 -07003020 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003021 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07003022 return;
3023 }
3024
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003025 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003026}
3027
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003028
3029/*
3030Public function, see header qcbor/qcbor_decode.h file
3031*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003032void QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, int64_t *pnValue)
3033{
3034 QCBORItem Item;
3035
3036 QCBORDecode_GetInt64ConvertInternalInMapN(pMe, nLabel, uOptions, pnValue, &Item);
3037
3038 if(pMe->uLastError == QCBOR_SUCCESS) {
3039 // The above conversion succeeded
3040 return;
3041 }
3042
3043 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3044 // The above conversion failed in a way that code below can't correct
3045 return;
3046 }
3047
3048 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
3049}
3050
3051
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003052/*
3053Public function, see header qcbor/qcbor_decode.h file
3054*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003055void QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, int64_t *pnValue)
3056{
3057 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003058 QCBORDecode_GetInt64ConvertInternalInMapSZ(pMe, szLabel, uOptions, pnValue, &Item);
3059
3060 if(pMe->uLastError == QCBOR_SUCCESS) {
3061 // The above conversion succeeded
3062 return;
3063 }
3064
3065 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3066 // The above conversion failed in a way that code below can't correct
3067 return;
3068 }
3069
3070 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
3071}
3072
3073
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003074static QCBORError ConvertUint64(const QCBORItem *pItem, uint32_t uOptions, uint64_t *puValue)
3075{
3076 switch(pItem->uDataType) {
3077 // TODO: type flaot
3078 case QCBOR_TYPE_DOUBLE:
3079 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3080 feclearexcept(FE_ALL_EXCEPT);
3081 double dRounded = round(pItem->val.dfnum);
3082 // TODO: over/underflow
3083 if(fetestexcept(FE_INVALID)) {
3084 // TODO: better error code
3085 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3086 } else if(isnan(dRounded)) {
3087 // TODO: better error code
3088 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3089 } else if(dRounded >= 0) {
3090 *puValue = (uint64_t)dRounded;
3091 } else {
3092 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3093 }
3094 } else {
3095 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3096 }
3097 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003098
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003099 case QCBOR_TYPE_INT64:
3100 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
3101 if(pItem->val.int64 >= 0) {
3102 *puValue = (uint64_t)pItem->val.int64;
3103 } else {
3104 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3105 }
3106 } else {
3107 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3108 }
3109 break;
3110
3111 case QCBOR_TYPE_UINT64:
3112 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
3113 *puValue = pItem->val.uint64;
3114 } else {
3115 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3116 }
3117 break;
3118
3119 default:
3120 return QCBOR_ERR_UNEXPECTED_TYPE;
3121 }
3122 return QCBOR_SUCCESS;
3123}
Laurence Lundbladec4537442020-04-14 18:53:22 -07003124
3125
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003126void QCBORDecode_GetUInt64ConvertInternal(QCBORDecodeContext *pMe,
3127 uint32_t uOptions,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003128 uint64_t *puValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003129 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003130{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003131 if(pMe->uLastError != QCBOR_SUCCESS) {
3132 return;
3133 }
3134
Laurence Lundbladec4537442020-04-14 18:53:22 -07003135 QCBORItem Item;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003136
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003137 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
3138 if(uError) {
3139 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003140 return;
3141 }
3142
Laurence Lundbladea826c502020-05-10 21:07:00 -07003143 if(pItem) {
3144 *pItem = Item;
3145 }
3146
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003147 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003148}
3149
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003150
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003151void QCBORDecode_GetUint64ConvertInternalInMapN(QCBORDecodeContext *pMe,
3152 int64_t nLabel,
3153 uint32_t uOptions,
3154 uint64_t *puValue,
3155 QCBORItem *pItem)
3156{
3157 QCBORItem Item;
3158 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
3159
3160 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
3161}
3162
3163
3164void QCBORDecode_GetUint64ConvertInternalInMapSZ(QCBORDecodeContext *pMe,
3165 const char * szLabel,
3166 uint32_t uOptions,
3167 uint64_t *puValue,
3168 QCBORItem *pItem)
3169{
3170 if(pMe->uLastError != QCBOR_SUCCESS) {
3171 return;
3172 }
3173
3174 QCBORItem Item;
3175 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3176
3177 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
3178}
3179
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003180/*
3181 Public function, see header qcbor/qcbor_decode.h file
3182*/
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003183static QCBORError Uint64ConvertAll(const QCBORItem *pItem, uint32_t uOptions, uint64_t *puValue)
3184{
3185 QCBORError uErr;
3186
3187 switch(pItem->uDataType) {
3188
3189 case QCBOR_TYPE_POSBIGNUM:
3190 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3191 return ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
3192 } else {
3193 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3194 }
3195 break;
3196
3197 case QCBOR_TYPE_NEGBIGNUM:
3198 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3199 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3200 } else {
3201 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3202 }
3203 break;
3204
3205#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
3206
3207 case QCBOR_TYPE_DECIMAL_FRACTION:
3208 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3209 return ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
3210 pItem->val.expAndMantissa.nExponent,
3211 puValue,
3212 Exponentitate10);
3213 } else {
3214 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3215 }
3216 break;
3217
3218 case QCBOR_TYPE_BIGFLOAT:
3219 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3220 return ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
3221 pItem->val.expAndMantissa.nExponent,
3222 puValue,
3223 Exponentitate2);
3224 } else {
3225 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3226 }
3227 break;
3228
3229 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
3230 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3231 // TODO: Would be better to convert to unsigned
3232 int64_t nMantissa;
3233 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3234 if(uErr != QCBOR_SUCCESS) {
3235 return uErr;
3236 }
3237 return ExponentitateNU(nMantissa,
3238 pItem->val.expAndMantissa.nExponent,
3239 puValue,
3240 Exponentitate10);
3241 } else {
3242 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3243 }
3244 break;
3245
3246 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
3247 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3248 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3249 } else {
3250 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3251 }
3252 break;
3253
3254 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
3255 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3256 // TODO: Would be better to convert to unsigned
3257 int64_t nMantissa;
3258 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3259 if(uErr != QCBOR_SUCCESS) {
3260 return uErr;
3261 }
3262 return ExponentitateNU(nMantissa,
3263 pItem->val.expAndMantissa.nExponent,
3264 puValue,
3265 Exponentitate2);
3266 } else {
3267 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3268 }
3269 break;
3270
3271 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
3272 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3273 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3274 } else {
3275 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3276 }
3277 break;
3278#endif
3279 default:
3280 return QCBOR_ERR_UNEXPECTED_TYPE;
3281 }
3282}
3283
3284
3285void QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003286{
3287 QCBORItem Item;
3288
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003289 QCBORDecode_GetUInt64ConvertInternal(pMe, uOptions, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003290
Laurence Lundbladef6c86662020-05-12 02:08:00 -07003291 if(pMe->uLastError == QCBOR_SUCCESS) {
3292 // The above conversion succeeded
3293 return;
3294 }
3295
3296 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3297 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07003298 return;
3299 }
3300
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003301 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003302}
3303
Laurence Lundbladec4537442020-04-14 18:53:22 -07003304
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003305/*
3306Public function, see header qcbor/qcbor_decode.h file
3307*/
3308void QCBORDecode_GetUint64ConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, uint64_t *puValue)
3309{
3310 QCBORItem Item;
3311
3312 QCBORDecode_GetUint64ConvertInternalInMapN(pMe, nLabel, uOptions, puValue, &Item);
3313
3314 if(pMe->uLastError == QCBOR_SUCCESS) {
3315 // The above conversion succeeded
3316 return;
3317 }
3318
3319 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3320 // The above conversion failed in a way that code below can't correct
3321 return;
3322 }
3323
3324 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
3325}
3326
3327
3328/*
3329Public function, see header qcbor/qcbor_decode.h file
3330*/
3331void QCBORDecode_GetUint64ConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, uint64_t *puValue)
3332{
3333 QCBORItem Item;
3334 QCBORDecode_GetUint64ConvertInternalInMapSZ(pMe, szLabel, uOptions, puValue, &Item);
3335
3336 if(pMe->uLastError == QCBOR_SUCCESS) {
3337 // The above conversion succeeded
3338 return;
3339 }
3340
3341 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3342 // The above conversion failed in a way that code below can't correct
3343 return;
3344 }
3345
3346 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
3347}
3348
3349
3350static QCBORError ConvertDouble(const QCBORItem *pItem, uint32_t uOptions, double *pdValue)
3351{
3352 switch(pItem->uDataType) {
3353 // TODO: float when ifdefs are set
3354 case QCBOR_TYPE_DOUBLE:
3355 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3356 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3357 *pdValue = pItem->val.dfnum;
3358 } else {
3359 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3360 }
3361 }
3362 break;
3363
3364 case QCBOR_TYPE_INT64:
3365 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
3366 // TODO: how does this work?
3367 *pdValue = (double)pItem->val.int64;
3368
3369 } else {
3370 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3371 }
3372 break;
3373
3374 case QCBOR_TYPE_UINT64:
3375 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
3376 *pdValue = (double)pItem->val.uint64;
3377 } else {
3378 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3379 }
3380 break;
3381
3382 default:
3383 return QCBOR_ERR_UNEXPECTED_TYPE;
3384 }
3385
3386 return QCBOR_SUCCESS;
3387}
3388
3389
3390
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003391void QCBORDecode_GetDoubleConvertInternal(QCBORDecodeContext *pMe,
3392 uint32_t uOptions,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003393 double *pdValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003394 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003395{
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003396 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003397 return;
3398 }
3399
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003400 QCBORItem Item;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003401
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003402 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003403 if(uError) {
3404 pMe->uLastError = (uint8_t)uError;
3405 return;
3406 }
3407
3408 if(pItem) {
3409 *pItem = Item;
3410 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07003411
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003412 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003413}
Laurence Lundbladec4537442020-04-14 18:53:22 -07003414
Laurence Lundbladec4537442020-04-14 18:53:22 -07003415
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003416void QCBORDecode_GetDoubleConvertInternalInMapN(QCBORDecodeContext *pMe,
3417 int64_t nLabel,
3418 uint32_t uOptions,
3419 double *pdValue,
3420 QCBORItem *pItem)
3421{
3422 QCBORItem Item;
3423 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
3424
3425 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
3426}
3427
3428void QCBORDecode_GetDoubleConvertInternalInMapSZ(QCBORDecodeContext *pMe,
3429 const char * szLabel,
3430 uint32_t uOptions,
3431 double *pdValue,
3432 QCBORItem *pItem)
3433{
3434 if(pMe->uLastError != QCBOR_SUCCESS) {
3435 return;
3436 }
3437
3438 QCBORItem Item;
3439 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3440
3441 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
3442}
3443
3444
3445
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003446static double ConvertBigNumToDouble(const UsefulBufC BigNum)
3447{
3448 double dResult;
3449
3450 dResult = 0.0;
3451 const uint8_t *pByte = BigNum.ptr;
3452 size_t uLen = BigNum.len;
3453 /* This will overflow and become the float value INFINITY if the number
3454 is too large to fit. No error will be logged.
3455 TODO: should an error be logged? */
3456 while(uLen--) {
3457 dResult = (dResult * 256.0) + (double)*pByte++;
3458 }
3459
3460 return dResult;
3461}
3462
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003463static QCBORError DoubleConvertAll(const QCBORItem *pItem, uint32_t uOptions, double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003464{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003465 /*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003466 https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
3467
3468 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003469 switch(pItem->uDataType) {
3470 // TODO: type float
3471 case QCBOR_TYPE_DECIMAL_FRACTION:
3472 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3473 // TODO: rounding and overflow errors
3474 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
3475 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
3476 } else {
3477 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3478 }
3479 break;
3480
3481 case QCBOR_TYPE_BIGFLOAT:
3482 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
3483 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
3484 exp2((double)pItem->val.expAndMantissa.nExponent);
3485 } else {
3486 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3487 }
3488 break;
3489
3490 case QCBOR_TYPE_POSBIGNUM:
3491 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3492 *pdValue = ConvertBigNumToDouble(pItem->val.bigNum);
3493 } else {
3494 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3495 }
3496 break;
3497
3498 case QCBOR_TYPE_NEGBIGNUM:
3499 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3500 *pdValue = -ConvertBigNumToDouble(pItem->val.bigNum);
3501 } else {
3502 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3503 }
3504 break;
3505
3506 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
3507 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3508 double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
3509 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
3510 } else {
3511 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3512 }
3513 break;
3514
3515 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
3516 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3517 double dMantissa = -ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
3518 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
3519 } else {
3520 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3521 }
3522 break;
3523
3524 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
3525 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3526 double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
3527 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
3528 } else {
3529 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3530 }
3531 break;
3532
3533 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
3534 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3535 double dMantissa = -ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
3536 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
3537 } else {
3538 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3539 }
3540 break;
3541
3542 default:
3543 return QCBOR_ERR_UNEXPECTED_TYPE;
3544 }
3545
3546 return QCBOR_SUCCESS;
3547}
3548
3549
3550/*
3551 Public function, see header qcbor/qcbor_decode.h file
3552*/
3553void QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, double *pdValue)
3554{
3555
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003556 QCBORItem Item;
3557
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003558 QCBORDecode_GetDoubleConvertInternal(pMe, uOptions, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003559
3560 if(pMe->uLastError == QCBOR_SUCCESS) {
3561 // The above conversion succeeded
3562 return;
3563 }
3564
3565 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3566 // The above conversion failed in a way that code below can't correct
3567 return;
3568 }
3569
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003570 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003571}
3572
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003573
3574/*
3575Public function, see header qcbor/qcbor_decode.h file
3576*/
3577void QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, double *pdValue)
3578{
3579 QCBORItem Item;
3580
3581 QCBORDecode_GetDoubleConvertInternalInMapN(pMe, nLabel, uOptions, pdValue, &Item);
3582
3583 if(pMe->uLastError == QCBOR_SUCCESS) {
3584 // The above conversion succeeded
3585 return;
3586 }
3587
3588 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3589 // The above conversion failed in a way that code below can't correct
3590 return;
3591 }
3592
3593 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
3594}
3595
3596
3597/*
3598Public function, see header qcbor/qcbor_decode.h file
3599*/
3600void QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, double *pdValue)
3601{
3602 QCBORItem Item;
3603 QCBORDecode_GetDoubleConvertInternalInMapSZ(pMe, szLabel, uOptions, pdValue, &Item);
3604
3605 if(pMe->uLastError == QCBOR_SUCCESS) {
3606 // The above conversion succeeded
3607 return;
3608 }
3609
3610 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3611 // The above conversion failed in a way that code below can't correct
3612 return;
3613 }
3614
3615 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
3616}