blob: 0fd84f13c82919ad9e7e67a5e46b3960c840cf4f [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
Laurence Lundbladeda095972020-06-06 18:35:33 -07002190void QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
2191 const char *szLabel,
2192 uint8_t uQcborType,
2193 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002194{
Laurence Lundbladeda095972020-06-06 18:35:33 -07002195 if(pMe->uLastError != QCBOR_SUCCESS) {
2196 return;
2197 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002198
Laurence Lundbladeda095972020-06-06 18:35:33 -07002199 QCBORItem OneItemSeach[2];
2200 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2201 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
2202 OneItemSeach[0].uDataType = uQcborType;
2203 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07002204
Laurence Lundbladeda095972020-06-06 18:35:33 -07002205 QCBORError nReturn = MapSearch(pMe, OneItemSeach, NULL, NULL);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002206 if(nReturn) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07002207 pMe->uLastError = (uint8_t)nReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002208 }
2209
Laurence Lundbladeda095972020-06-06 18:35:33 -07002210
2211 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
2212 pMe->uLastError = QCBOR_ERR_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002213 }
2214
Laurence Lundbladeda095972020-06-06 18:35:33 -07002215 *pItem = OneItemSeach[0];
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002216}
2217
2218
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002219static QCBORError CheckTagRequirement(TagSpecification TagSpec, uint8_t uDataType)
2220{
2221 // This gets called a lot, so it needs to be fast, especially for simple cases.
2222 // TODO: this isn't working right yet
2223 if((TagSpec.uTagRequirement == 1 || TagSpec.uTagRequirement == 2) && uDataType == TagSpec.uTaggedType) {
2224 return QCBOR_SUCCESS;
2225 } else {
2226 for(int i = 0; i < 6; i++) {
2227 if(uDataType == TagSpec.uAllowedContentTypes[i]) {
2228 return QCBOR_SUCCESS;
2229 }
2230 }
2231 }
2232
2233 return QCBOR_ERR_UNEXPECTED_TYPE;
2234
2235}
2236
2237void QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
2238 int64_t nLabel,
2239 TagSpecification TagSpec,
2240 QCBORItem *pItem)
2241{
2242 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
2243 if(pMe->uLastError != QCBOR_SUCCESS) {
2244 return;
2245 }
2246
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002247 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem->uDataType);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002248}
2249
2250void QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
2251 const char *szLabel,
2252 TagSpecification TagSpec,
2253 QCBORItem *pItem)
2254{
2255 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
2256 if(pMe->uLastError != QCBOR_SUCCESS) {
2257 return;
2258 }
2259
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002260 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem->uDataType);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002261}
2262
2263void QCBORDecode_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
2264 int64_t nLabel,
2265 TagSpecification TagSpec,
2266 UsefulBufC *pString)
2267{
2268 QCBORItem Item;
2269 QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
2270 if(pMe->uLastError == QCBOR_SUCCESS) {
2271 *pString = Item.val.string;
2272 }
2273}
2274
2275void QCBORDecode_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
2276 const char * szLabel,
2277 TagSpecification TagSpec,
2278 UsefulBufC *pString)
2279{
2280 QCBORItem Item;
2281 QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
2282 if(pMe->uLastError == QCBOR_SUCCESS) {
2283 *pString = Item.val.string;
2284 }
2285}
Laurence Lundblade1341c592020-04-11 14:19:05 -07002286
Laurence Lundblade1341c592020-04-11 14:19:05 -07002287
Laurence Lundblade34691b92020-05-18 22:25:25 -07002288static void SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07002289{
Laurence Lundblade34691b92020-05-18 22:25:25 -07002290 if(pMe->uLastError != QCBOR_SUCCESS) {
2291 // Already in error state; do nothing.
2292 return;
2293 }
2294
2295 size_t uOffset;
Laurence Lundblade986017c2020-05-23 19:25:02 -07002296 pMe->uLastError = (uint8_t)MapSearch(pMe, pSearch, &uOffset, NULL);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002297 if(pMe->uLastError != QCBOR_SUCCESS) {
2298 return;
2299 }
2300
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002301 /* Need to get the current pre-order nesting level and cursor to be
2302 at the first item in the map/array just entered.
2303
2304 Also need to current map nesting level and start cursor to
2305 be at the right place.
2306
2307 The UsefulInBuf offset could be anywhere, so no assumption is
2308 made about it.
2309
2310 No assumption is made about the pre-order nesting level either.
2311
2312 However the map mode nesting level is assumed to be one above
2313 the map level that is being entered.
2314 */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002315 /* Seek to the data item that is the map or array */
2316 UsefulInputBuf_Seek(&(pMe->InBuf), uOffset);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002317 pMe->nesting.pCurrent = pMe->nesting.pCurrentMap; // TODO: part of DecodeNesting
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002318
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002319 // TODO: check error?
Laurence Lundblade34691b92020-05-18 22:25:25 -07002320 QCBORDecode_EnterMapMode(pMe, pSearch->uDataType);
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002321
Laurence Lundblade34691b92020-05-18 22:25:25 -07002322 printdecode(pMe, "FinishEnter");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002323}
2324
2325
Laurence Lundblade34691b92020-05-18 22:25:25 -07002326void QCBORDecode_EnterMapInMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002327{
Laurence Lundblade1341c592020-04-11 14:19:05 -07002328 QCBORItem One[2];
Laurence Lundblade1341c592020-04-11 14:19:05 -07002329 One[0].uLabelType = QCBOR_TYPE_INT64;
2330 One[0].label.int64 = nLabel;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002331 One[0].uDataType = QCBOR_TYPE_MAP;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002332 One[1].uLabelType = QCBOR_TYPE_NONE;
2333
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002334 /* The map to enter was found, now finish of entering it. */
Laurence Lundblade34691b92020-05-18 22:25:25 -07002335 SearchAndEnter(pMe, One);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002336}
2337
2338
Laurence Lundblade34691b92020-05-18 22:25:25 -07002339void QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002340{
2341 QCBORItem One[2];
Laurence Lundblade1341c592020-04-11 14:19:05 -07002342 One[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2343 One[0].label.string = UsefulBuf_FromSZ(szLabel);
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002344 One[0].uDataType = QCBOR_TYPE_MAP;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002345 One[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002346
Laurence Lundblade34691b92020-05-18 22:25:25 -07002347 SearchAndEnter(pMe, One);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002348}
2349
2350
Laurence Lundblade34691b92020-05-18 22:25:25 -07002351void QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07002352{
2353 QCBORItem One[2];
Laurence Lundblade34691b92020-05-18 22:25:25 -07002354 One[0].uLabelType = QCBOR_TYPE_INT64;
2355 One[0].label.int64 = nLabel;
2356 One[0].uDataType = QCBOR_TYPE_ARRAY;
2357 One[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002358
Laurence Lundblade34691b92020-05-18 22:25:25 -07002359 SearchAndEnter(pMe, One);
2360}
2361
2362
2363void QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
2364{
2365 QCBORItem One[2];
Laurence Lundblade1341c592020-04-11 14:19:05 -07002366 One[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2367 One[0].label.string = UsefulBuf_FromSZ(szLabel);
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002368 One[0].uDataType = QCBOR_TYPE_ARRAY;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002369 One[1].uLabelType = QCBOR_TYPE_NONE;
2370
Laurence Lundblade34691b92020-05-18 22:25:25 -07002371 SearchAndEnter(pMe, One);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002372}
2373
2374
2375
2376
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002377
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002378/* Next item must be map or this generates an error */
Laurence Lundblade34691b92020-05-18 22:25:25 -07002379void QCBORDecode_EnterMapMode(QCBORDecodeContext *pMe, uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002380{
Laurence Lundblade34691b92020-05-18 22:25:25 -07002381 if(pMe->uLastError != QCBOR_SUCCESS) {
2382 // Already in error state; do nothing.
2383 return;
2384 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002385
2386 /* Get the data item that is the map that is being searched */
Laurence Lundblade34691b92020-05-18 22:25:25 -07002387 QCBORItem Item;
Laurence Lundblade986017c2020-05-23 19:25:02 -07002388 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002389 if(pMe->uLastError != QCBOR_SUCCESS) {
2390 return;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002391 }
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002392 if(Item.uDataType != uType) {
Laurence Lundblade34691b92020-05-18 22:25:25 -07002393 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
2394 return;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002395 }
2396
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002397 DecodeNesting_EnterMapMode(&(pMe->nesting), UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002398
Laurence Lundblade34691b92020-05-18 22:25:25 -07002399 printdecode(pMe, "EnterMapModeDone");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002400}
2401
2402
2403
2404QCBORError QCBORDecode_GetItemsInMap(QCBORDecodeContext *pCtx, QCBORItem *pItemList)
2405{
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002406 return MapSearch(pCtx, pItemList, NULL, NULL);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002407}
2408
2409
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002410
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002411
2412
Laurence Lundblade1341c592020-04-11 14:19:05 -07002413void QCBORDecode_RewindMap(QCBORDecodeContext *pMe)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002414{
Laurence Lundblade1341c592020-04-11 14:19:05 -07002415 // TODO: check for map mode
2416 pMe->nesting.pCurrent->uCount = pMe->nesting.pCurrent->uSaveCount;
2417 UsefulInputBuf_Seek(&(pMe->InBuf), pMe->nesting.pCurrent->uOffset);
2418}
2419
2420
Laurence Lundblade1341c592020-04-11 14:19:05 -07002421
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002422
Laurence Lundbladee6430642020-03-14 21:15:44 -07002423
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002424
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002425
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002426
Laurence Lundblade11a064e2020-05-07 13:13:42 -07002427
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002428
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002429static QCBORError InterpretBool(const QCBORItem *pItem, bool *pBool)
2430{
2431 switch(pItem->uDataType) {
2432 case QCBOR_TYPE_TRUE:
2433 *pBool = true;
2434 return QCBOR_SUCCESS;
2435 break;
2436
2437 case QCBOR_TYPE_FALSE:
2438 *pBool = false;
2439 return QCBOR_SUCCESS;
2440 break;
2441
2442 default:
2443 return QCBOR_ERR_UNEXPECTED_TYPE;
2444 break;
2445 }
2446}
Laurence Lundbladee6430642020-03-14 21:15:44 -07002447
Laurence Lundbladec4537442020-04-14 18:53:22 -07002448void QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002449{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002450 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002451 // Already in error state, do nothing
Laurence Lundbladee6430642020-03-14 21:15:44 -07002452 return;
2453 }
2454
Laurence Lundbladec4537442020-04-14 18:53:22 -07002455 QCBORError nError;
2456 QCBORItem Item;
2457
2458 nError = QCBORDecode_GetNext(pMe, &Item);
2459 if(nError != QCBOR_SUCCESS) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002460 pMe->uLastError = (uint8_t)nError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002461 return;
2462 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002463 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002464}
2465
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002466void QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe, int64_t nLabel, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002467{
2468 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002469 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002470
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002471 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002472}
2473
2474
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002475void QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, bool *pValue)
2476{
2477 QCBORItem Item;
2478 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
2479
2480 pMe->uLastError = (uint8_t)InterpretBool(&Item, pValue);
2481}
2482
2483
2484
2485void QCBORDecode_GetTaggedStringInternal(QCBORDecodeContext *pMe, TagSpecification TagSpec, UsefulBufC *pBstr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002486{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002487 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002488 // Already in error state, do nothing
2489 return;
2490 }
2491
2492 QCBORError nError;
2493 QCBORItem Item;
2494
2495 nError = QCBORDecode_GetNext(pMe, &Item);
2496 if(nError != QCBOR_SUCCESS) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002497 pMe->uLastError = (uint8_t)nError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002498 return;
2499 }
2500
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002501 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, Item.uDataType);
2502
2503 if(pMe->uLastError == QCBOR_SUCCESS) {
2504 *pBstr = Item.val.string;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002505 }
2506}
2507
Laurence Lundbladec4537442020-04-14 18:53:22 -07002508
2509
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002510
2511static QCBORError ConvertBigNum(const QCBORItem *pItem, UsefulBufC *pValue, bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002512{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002513 *pbIsNegative = false;
2514
2515 bool bMustBeTagged = true; // TODO: fix this
2516
2517 switch(pItem->uDataType) {
2518 case QCBOR_TYPE_BYTE_STRING:
2519 // TODO: check that there is no tag here?
2520 if(bMustBeTagged) {
2521 return QCBOR_ERR_UNEXPECTED_TYPE;
2522 } else {
2523 *pValue = pItem->val.string;
2524 return QCBOR_SUCCESS;
2525 }
2526 break;
2527
2528 case QCBOR_TYPE_POSBIGNUM:
2529 *pValue = pItem->val.string;
2530 return QCBOR_SUCCESS;
2531 break;
2532
2533 case QCBOR_TYPE_NEGBIGNUM:
2534 *pbIsNegative = true;
2535 *pValue = pItem->val.string;
2536 return QCBOR_SUCCESS;
2537 break;
2538
2539 default:
2540 return QCBOR_ERR_UNEXPECTED_TYPE;
2541 break;
2542 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002543}
2544
2545
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002546/**
2547 @param[in] bMustBeTagged If \c true, then the data item must be tagged as either
2548 a positive or negative bignum. If \c false, then it only must be a byte string and bIsNegative
2549 will always be false on the asumption that it is positive, but it can be interpretted as
2550 negative if the the sign is know from other context.
2551 @param[out] pValue The bytes that make up the big num
2552 @param[out] pbIsNegative \c true if tagged as a negative big num. \c false otherwise.
2553
2554 if bMustBeTagged is false, then this will succeed if the data item is a plain byte string,
2555 a positive big num or a negative big num.
2556
2557 */
2558void QCBORDecode_GetBignum(QCBORDecodeContext *pMe, bool bMustBeTagged, UsefulBufC *pValue, bool *pbIsNegative)
2559{
2560 if(pMe->uLastError != QCBOR_SUCCESS) {
2561 // Already in error state, do nothing
2562 return;
2563 }
2564
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002565 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002566 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
2567 if(uError != QCBOR_SUCCESS) {
2568 pMe->uLastError = (uint8_t)uError;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002569 return;
2570 }
2571
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002572 pMe->uLastError = (uint8_t)ConvertBigNum(&Item, pValue, pbIsNegative);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002573}
2574
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002575void QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe, int64_t nLabel, bool bMustBeTagged, UsefulBufC *pValue, bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002576{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002577 QCBORItem Item;
2578 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002579
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002580 pMe->uLastError = (uint8_t)ConvertBigNum(&Item, pValue, pbIsNegative);
Laurence Lundbladec4537442020-04-14 18:53:22 -07002581}
2582
Laurence Lundbladec4537442020-04-14 18:53:22 -07002583
2584
2585
Laurence Lundbladee6430642020-03-14 21:15:44 -07002586
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002587typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002588
2589
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002590// The main exponentiator that works on only positive numbers
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002591static QCBORError Exponentitate10(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002592{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002593 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002594
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002595 if(uResult != 0) {
2596 /* This loop will run a maximum of 19 times because
2597 * UINT64_MAX < 10 ^^ 19. More than that will cause
2598 * exit with the overflow error
2599 */
2600 for(; nExponent > 0; nExponent--) {
2601 if(uResult > UINT64_MAX / 10) {
2602 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Error overflow
2603 }
2604 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002605 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002606
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002607 for(; nExponent < 0; nExponent++) {
2608 uResult = uResult / 10;
2609 if(uResult == 0) {
2610 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Underflow error
2611 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002612 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07002613 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002614 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07002615
2616 *puResult = uResult;
2617
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002618 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002619}
2620
2621
Laurence Lundbladee6430642020-03-14 21:15:44 -07002622/* Convert a decimal fraction to an int64_t without using
2623 floating point or math libraries. Most decimal fractions
2624 will not fit in an int64_t and this will error out with
2625 under or overflow
2626 */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002627static QCBORError Exponentitate2(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002628{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002629 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002630
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002631 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002632
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002633 /* This loop will run a maximum of 64 times because
Laurence Lundbladee6430642020-03-14 21:15:44 -07002634 * INT64_MAX < 2^31. More than that will cause
2635 * exist with the overflow error
2636 */
2637 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002638 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002639 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Error overflow
Laurence Lundbladee6430642020-03-14 21:15:44 -07002640 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002641 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002642 nExponent--;
2643 }
2644
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002645 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002646 if(uResult == 0) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002647 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Underflow error
2648 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002649 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002650 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002651 }
2652
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002653 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002654
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002655 return QCBOR_SUCCESS;
2656}
2657
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002658/*
2659 Compute value with signed mantissa and signed result. Works with exponent of 2 or 10 based on exponentiator.
2660 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002661static inline QCBORError ExponentiateNN(int64_t nMantissa, int64_t nExponent, int64_t *pnResult, fExponentiator pfExp)
2662{
2663 uint64_t uResult;
2664
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002665 // Take the absolute value of the mantissa and convert to unsigned.
2666 // TODO: this should be possible in one intruction
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002667 uint64_t uMantissa = nMantissa > 0 ? (uint64_t)nMantissa : (uint64_t)-nMantissa;
2668
2669 // Do the exponentiation of the positive mantissa
2670 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
2671 if(uReturn) {
2672 return uReturn;
2673 }
2674
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002675
Laurence Lundblade983500d2020-05-14 11:49:34 -07002676 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
2677 of INT64_MIN. This assumes two's compliment representation where
2678 INT64_MIN is one increment farther from 0 than INT64_MAX.
2679 Trying to write -INT64_MIN doesn't work to get this because the
2680 compiler tries to work with an int64_t which can't represent
2681 -INT64_MIN.
2682 */
2683 uint64_t uMax = nMantissa > 0 ? INT64_MAX : (uint64_t)INT64_MAX+1;
2684
2685 // Error out if too large
2686 if(uResult > uMax) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002687 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
2688 }
2689
2690 // Casts are safe because of checks above
2691 *pnResult = nMantissa > 0 ? (int64_t)uResult : -(int64_t)uResult;
2692
2693 return QCBOR_SUCCESS;
2694}
2695
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002696/*
2697 Compute value with signed mantissa and unsigned result. Works with exponent of 2 or 10 based on exponentiator.
2698 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002699static inline QCBORError ExponentitateNU(int64_t nMantissa, int64_t nExponent, uint64_t *puResult, fExponentiator pfExp)
2700{
2701 if(nMantissa < 0) {
2702 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
2703 }
2704
2705 // Cast to unsigned is OK because of check for negative
2706 // Cast to unsigned is OK because UINT64_MAX > INT64_MAX
2707 // Exponentiation is straight forward
2708 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
2709}
2710
2711
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002712#include <math.h>
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002713
2714
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07002715static QCBORError ConvertBigNumToUnsigned(const UsefulBufC BigNum, uint64_t uMax, uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002716{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002717 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002718
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002719 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002720 const uint8_t *pByte = BigNum.ptr;
2721 size_t uLen = BigNum.len;
2722 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07002723 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002724 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002725 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07002726 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002727 }
2728
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002729 *pResult = uResult;
2730 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002731}
2732
Laurence Lundblade887add82020-05-17 05:50:34 -07002733static inline QCBORError ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum, uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002734{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002735 return ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002736}
2737
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002738static inline QCBORError ConvertPositiveBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002739{
2740 uint64_t uResult;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002741 QCBORError uError = ConvertBigNumToUnsigned(BigNum, INT64_MAX, &uResult);
2742 if(uError) {
2743 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002744 }
2745 /* Cast is safe because ConvertBigNum is told to limit to INT64_MAX */
2746 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002747 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002748}
2749
2750
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002751static inline QCBORError ConvertNegativeBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002752{
2753 uint64_t uResult;
Laurence Lundbladeda095972020-06-06 18:35:33 -07002754 /* negaative int furthest from zero is INT64_MIN
2755 which is expressed as -INT64_MAX-1. The value of
2756 a negative bignum is -n-1, one further from zero
2757 than the positive bignum */
2758
2759 /* say INT64_MIN is -2; then INT64_MAX is 1.
2760 Then -n-1 <= INT64_MIN.
2761 Then -n -1 <= -INT64_MAX - 1
2762 THen n <= INT64_MAX. */
2763 QCBORError uError = ConvertBigNumToUnsigned(BigNum, INT64_MAX, &uResult);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002764 if(uError) {
2765 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002766 }
2767 /* Cast is safe because ConvertBigNum is told to limit to INT64_MAX */
Laurence Lundblade887add82020-05-17 05:50:34 -07002768 // TODO: this code is incorrect. See RFC 7049
Laurence Lundbladeda095972020-06-06 18:35:33 -07002769 uResult++; // this is the -1 in -n-1
Laurence Lundbladee6430642020-03-14 21:15:44 -07002770 *pResult = -(int64_t)uResult;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002771 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002772}
2773
Laurence Lundbladef6c86662020-05-12 02:08:00 -07002774#include "fenv.h"
Laurence Lundbladec4537442020-04-14 18:53:22 -07002775
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002776
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002777/*
2778Convert a integers and floats to an int64_t.
2779
2780\param[in] uOptions Bit mask list of conversion options.
2781
2782\retval QCBOR_ERR_CONVERSION_NOT_REQUESTED Conversion, possible, but not requested in uOptions.
2783
2784\retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
2785
2786\retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large or too small.
2787
2788*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002789static QCBORError ConvertInt64(const QCBORItem *pItem, uint32_t uOptions, int64_t *pnValue)
2790{
2791 switch(pItem->uDataType) {
2792 // TODO: float when ifdefs are set
2793 case QCBOR_TYPE_DOUBLE:
2794 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
2795 // TODO: what about under/overflow here?
2796 // Invokes the floating-point HW and/or compiler-added libraries
2797 feclearexcept(FE_ALL_EXCEPT);
2798 *pnValue = llround(pItem->val.dfnum);
2799 if(fetestexcept(FE_INVALID)) {
2800 // TODO: better error code
2801 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
2802 }
2803 } else {
2804 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
2805 }
2806 break;
2807
2808 case QCBOR_TYPE_INT64:
2809 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
2810 *pnValue = pItem->val.int64;
2811 } else {
2812 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
2813 }
2814 break;
2815
2816 case QCBOR_TYPE_UINT64:
2817 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
2818 if(pItem->val.uint64 < INT64_MAX) {
2819 *pnValue = pItem->val.int64;
2820 } else {
2821 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
2822 }
2823 } else {
2824 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
2825 }
2826 break;
2827
2828 default:
2829 return QCBOR_ERR_UNEXPECTED_TYPE;
2830 }
2831 return QCBOR_SUCCESS;
2832}
2833
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002834
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002835void QCBORDecode_GetInt64ConvertInternal(QCBORDecodeContext *pMe,
2836 uint32_t uOptions,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002837 int64_t *pnValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002838 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002839{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002840 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002841 return;
2842 }
2843
Laurence Lundbladee6430642020-03-14 21:15:44 -07002844 QCBORItem Item;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07002845 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
2846 if(uError) {
2847 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002848 return;
2849 }
2850
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002851 if(pItem) {
2852 *pItem = Item;
2853 }
2854
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002855 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002856}
2857
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002858
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002859void QCBORDecode_GetInt64ConvertInternalInMapN(QCBORDecodeContext *pMe,
2860 int64_t nLabel,
2861 uint32_t uOptions,
2862 int64_t *pnValue,
2863 QCBORItem *pItem)
2864{
2865 QCBORItem Item;
2866 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
2867
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002868 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002869}
2870
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002871
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002872void QCBORDecode_GetInt64ConvertInternalInMapSZ(QCBORDecodeContext *pMe,
2873 const char * szLabel,
2874 uint32_t uOptions,
2875 int64_t *pnValue,
2876 QCBORItem *pItem)
2877{
2878 if(pMe->uLastError != QCBOR_SUCCESS) {
2879 return;
2880 }
2881
2882 QCBORItem Item;
2883 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
2884
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002885 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uOptions, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002886}
2887
2888
2889
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002890/*
2891 Convert a large variety of integer types to an int64_t.
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002892
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07002893 \param[in] uOptions Bit mask list of conversion options.
2894
2895 \retval QCBOR_ERR_CONVERSION_NOT_REQUESTED Conversion, possible, but not requested in uOptions.
2896
2897 \retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
2898
2899 \retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large or too small.
2900
2901 */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002902static QCBORError Int64ConvertAll(const QCBORItem *pItem, uint32_t uOptions, int64_t *pnValue)
2903{
2904 QCBORError uErr;
2905
2906 switch(pItem->uDataType) {
2907
2908 case QCBOR_TYPE_POSBIGNUM:
2909 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
2910 return ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002911 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002912 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002913 }
2914 break;
2915
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002916 case QCBOR_TYPE_NEGBIGNUM:
2917 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
2918 return ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002919 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002920 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002921 }
2922 break;
2923
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002924#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
2925 case QCBOR_TYPE_DECIMAL_FRACTION:
2926 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
2927 return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
2928 pItem->val.expAndMantissa.nExponent,
2929 pnValue,
2930 &Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002931 } else {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002932 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
2933 }
2934 break;
2935
2936 case QCBOR_TYPE_BIGFLOAT:
2937 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
2938 return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
2939 pItem->val.expAndMantissa.nExponent,
2940 pnValue,
2941 Exponentitate2);
2942 } else {
2943 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
2944 }
2945 break;
2946
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002947 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
2948 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
2949 int64_t nMantissa;
2950 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
2951 if(uErr) {
2952 return uErr;
2953 }
2954 return ExponentiateNN(nMantissa,
2955 pItem->val.expAndMantissa.nExponent,
2956 pnValue,
2957 Exponentitate10);
2958 } else {
2959 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
2960 }
2961 break;
2962
2963 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
2964 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
2965 int64_t nMantissa;
2966 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
2967 if(uErr) {
2968 return uErr;
2969 }
2970 return ExponentiateNN(nMantissa,
2971 pItem->val.expAndMantissa.nExponent,
2972 pnValue,
2973 Exponentitate10);
2974 } else {
2975 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
2976 }
2977 break;
2978
2979 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
2980 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
2981 int64_t nMantissa;
2982 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
2983 if(uErr) {
2984 return uErr;
2985 }
2986 return ExponentiateNN(nMantissa,
2987 pItem->val.expAndMantissa.nExponent,
2988 pnValue,
2989 Exponentitate2);
2990 } else {
2991 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
2992 }
2993 break;
2994
2995 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
2996 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
2997 int64_t nMantissa;
2998 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
2999 if(uErr) {
3000 return uErr;
3001 }
3002 return ExponentiateNN(nMantissa,
3003 pItem->val.expAndMantissa.nExponent,
3004 pnValue,
3005 Exponentitate2);
3006 } else {
3007 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003008 }
3009 break;
3010
Laurence Lundbladec4537442020-04-14 18:53:22 -07003011 default:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003012 return QCBOR_ERR_UNEXPECTED_TYPE;
3013#endif
Laurence Lundbladec4537442020-04-14 18:53:22 -07003014 }
3015}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003016
3017
Laurence Lundbladec4537442020-04-14 18:53:22 -07003018/*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003019 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003020 */
3021void QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003022{
3023 QCBORItem Item;
3024
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003025 QCBORDecode_GetInt64ConvertInternal(pMe, uOptions, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003026
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003027 if(pMe->uLastError == QCBOR_SUCCESS) {
3028 // The above conversion succeeded
3029 return;
3030 }
3031
Laurence Lundbladef6c86662020-05-12 02:08:00 -07003032 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003033 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07003034 return;
3035 }
3036
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003037 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003038}
3039
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003040
3041/*
3042Public function, see header qcbor/qcbor_decode.h file
3043*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003044void QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, int64_t *pnValue)
3045{
3046 QCBORItem Item;
3047
3048 QCBORDecode_GetInt64ConvertInternalInMapN(pMe, nLabel, uOptions, pnValue, &Item);
3049
3050 if(pMe->uLastError == QCBOR_SUCCESS) {
3051 // The above conversion succeeded
3052 return;
3053 }
3054
3055 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3056 // The above conversion failed in a way that code below can't correct
3057 return;
3058 }
3059
3060 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
3061}
3062
3063
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003064/*
3065Public function, see header qcbor/qcbor_decode.h file
3066*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003067void QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, int64_t *pnValue)
3068{
3069 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003070 QCBORDecode_GetInt64ConvertInternalInMapSZ(pMe, szLabel, uOptions, pnValue, &Item);
3071
3072 if(pMe->uLastError == QCBOR_SUCCESS) {
3073 // The above conversion succeeded
3074 return;
3075 }
3076
3077 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3078 // The above conversion failed in a way that code below can't correct
3079 return;
3080 }
3081
3082 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uOptions, pnValue);
3083}
3084
3085
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003086static QCBORError ConvertUint64(const QCBORItem *pItem, uint32_t uOptions, uint64_t *puValue)
3087{
3088 switch(pItem->uDataType) {
3089 // TODO: type flaot
3090 case QCBOR_TYPE_DOUBLE:
3091 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3092 feclearexcept(FE_ALL_EXCEPT);
3093 double dRounded = round(pItem->val.dfnum);
3094 // TODO: over/underflow
3095 if(fetestexcept(FE_INVALID)) {
3096 // TODO: better error code
3097 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3098 } else if(isnan(dRounded)) {
3099 // TODO: better error code
3100 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3101 } else if(dRounded >= 0) {
3102 *puValue = (uint64_t)dRounded;
3103 } else {
3104 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3105 }
3106 } else {
3107 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3108 }
3109 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003110
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003111 case QCBOR_TYPE_INT64:
3112 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
3113 if(pItem->val.int64 >= 0) {
3114 *puValue = (uint64_t)pItem->val.int64;
3115 } else {
3116 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3117 }
3118 } else {
3119 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3120 }
3121 break;
3122
3123 case QCBOR_TYPE_UINT64:
3124 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
3125 *puValue = pItem->val.uint64;
3126 } else {
3127 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3128 }
3129 break;
3130
3131 default:
3132 return QCBOR_ERR_UNEXPECTED_TYPE;
3133 }
3134 return QCBOR_SUCCESS;
3135}
Laurence Lundbladec4537442020-04-14 18:53:22 -07003136
3137
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003138void QCBORDecode_GetUInt64ConvertInternal(QCBORDecodeContext *pMe,
3139 uint32_t uOptions,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003140 uint64_t *puValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003141 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003142{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003143 if(pMe->uLastError != QCBOR_SUCCESS) {
3144 return;
3145 }
3146
Laurence Lundbladec4537442020-04-14 18:53:22 -07003147 QCBORItem Item;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003148
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003149 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
3150 if(uError) {
3151 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003152 return;
3153 }
3154
Laurence Lundbladea826c502020-05-10 21:07:00 -07003155 if(pItem) {
3156 *pItem = Item;
3157 }
3158
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003159 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003160}
3161
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003162
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003163void QCBORDecode_GetUint64ConvertInternalInMapN(QCBORDecodeContext *pMe,
3164 int64_t nLabel,
3165 uint32_t uOptions,
3166 uint64_t *puValue,
3167 QCBORItem *pItem)
3168{
3169 QCBORItem Item;
3170 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
3171
3172 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
3173}
3174
3175
3176void QCBORDecode_GetUint64ConvertInternalInMapSZ(QCBORDecodeContext *pMe,
3177 const char * szLabel,
3178 uint32_t uOptions,
3179 uint64_t *puValue,
3180 QCBORItem *pItem)
3181{
3182 if(pMe->uLastError != QCBOR_SUCCESS) {
3183 return;
3184 }
3185
3186 QCBORItem Item;
3187 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3188
3189 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uOptions, puValue);
3190}
3191
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003192/*
3193 Public function, see header qcbor/qcbor_decode.h file
3194*/
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003195static QCBORError Uint64ConvertAll(const QCBORItem *pItem, uint32_t uOptions, uint64_t *puValue)
3196{
3197 QCBORError uErr;
3198
3199 switch(pItem->uDataType) {
3200
3201 case QCBOR_TYPE_POSBIGNUM:
3202 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3203 return ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
3204 } else {
3205 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3206 }
3207 break;
3208
3209 case QCBOR_TYPE_NEGBIGNUM:
3210 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3211 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3212 } else {
3213 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3214 }
3215 break;
3216
3217#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
3218
3219 case QCBOR_TYPE_DECIMAL_FRACTION:
3220 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3221 return ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
3222 pItem->val.expAndMantissa.nExponent,
3223 puValue,
3224 Exponentitate10);
3225 } else {
3226 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3227 }
3228 break;
3229
3230 case QCBOR_TYPE_BIGFLOAT:
3231 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3232 return ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
3233 pItem->val.expAndMantissa.nExponent,
3234 puValue,
3235 Exponentitate2);
3236 } else {
3237 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3238 }
3239 break;
3240
3241 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
3242 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3243 // TODO: Would be better to convert to unsigned
3244 int64_t nMantissa;
3245 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3246 if(uErr != QCBOR_SUCCESS) {
3247 return uErr;
3248 }
3249 return ExponentitateNU(nMantissa,
3250 pItem->val.expAndMantissa.nExponent,
3251 puValue,
3252 Exponentitate10);
3253 } else {
3254 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3255 }
3256 break;
3257
3258 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
3259 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3260 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3261 } else {
3262 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3263 }
3264 break;
3265
3266 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
3267 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3268 // TODO: Would be better to convert to unsigned
3269 int64_t nMantissa;
3270 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
3271 if(uErr != QCBOR_SUCCESS) {
3272 return uErr;
3273 }
3274 return ExponentitateNU(nMantissa,
3275 pItem->val.expAndMantissa.nExponent,
3276 puValue,
3277 Exponentitate2);
3278 } else {
3279 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3280 }
3281 break;
3282
3283 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
3284 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3285 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3286 } else {
3287 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3288 }
3289 break;
3290#endif
3291 default:
3292 return QCBOR_ERR_UNEXPECTED_TYPE;
3293 }
3294}
3295
3296
3297void QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003298{
3299 QCBORItem Item;
3300
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003301 QCBORDecode_GetUInt64ConvertInternal(pMe, uOptions, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003302
Laurence Lundbladef6c86662020-05-12 02:08:00 -07003303 if(pMe->uLastError == QCBOR_SUCCESS) {
3304 // The above conversion succeeded
3305 return;
3306 }
3307
3308 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3309 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07003310 return;
3311 }
3312
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003313 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003314}
3315
Laurence Lundbladec4537442020-04-14 18:53:22 -07003316
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003317/*
3318Public function, see header qcbor/qcbor_decode.h file
3319*/
3320void QCBORDecode_GetUint64ConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, uint64_t *puValue)
3321{
3322 QCBORItem Item;
3323
3324 QCBORDecode_GetUint64ConvertInternalInMapN(pMe, nLabel, uOptions, puValue, &Item);
3325
3326 if(pMe->uLastError == QCBOR_SUCCESS) {
3327 // The above conversion succeeded
3328 return;
3329 }
3330
3331 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3332 // The above conversion failed in a way that code below can't correct
3333 return;
3334 }
3335
3336 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
3337}
3338
3339
3340/*
3341Public function, see header qcbor/qcbor_decode.h file
3342*/
3343void QCBORDecode_GetUint64ConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, uint64_t *puValue)
3344{
3345 QCBORItem Item;
3346 QCBORDecode_GetUint64ConvertInternalInMapSZ(pMe, szLabel, uOptions, puValue, &Item);
3347
3348 if(pMe->uLastError == QCBOR_SUCCESS) {
3349 // The above conversion succeeded
3350 return;
3351 }
3352
3353 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3354 // The above conversion failed in a way that code below can't correct
3355 return;
3356 }
3357
3358 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uOptions, puValue);
3359}
3360
3361
3362static QCBORError ConvertDouble(const QCBORItem *pItem, uint32_t uOptions, double *pdValue)
3363{
3364 switch(pItem->uDataType) {
3365 // TODO: float when ifdefs are set
3366 case QCBOR_TYPE_DOUBLE:
3367 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3368 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
3369 *pdValue = pItem->val.dfnum;
3370 } else {
3371 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3372 }
3373 }
3374 break;
3375
3376 case QCBOR_TYPE_INT64:
3377 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
3378 // TODO: how does this work?
3379 *pdValue = (double)pItem->val.int64;
3380
3381 } else {
3382 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3383 }
3384 break;
3385
3386 case QCBOR_TYPE_UINT64:
3387 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
3388 *pdValue = (double)pItem->val.uint64;
3389 } else {
3390 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3391 }
3392 break;
3393
3394 default:
3395 return QCBOR_ERR_UNEXPECTED_TYPE;
3396 }
3397
3398 return QCBOR_SUCCESS;
3399}
3400
3401
3402
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003403void QCBORDecode_GetDoubleConvertInternal(QCBORDecodeContext *pMe,
3404 uint32_t uOptions,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003405 double *pdValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003406 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003407{
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003408 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003409 return;
3410 }
3411
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003412 QCBORItem Item;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003413
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003414 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003415 if(uError) {
3416 pMe->uLastError = (uint8_t)uError;
3417 return;
3418 }
3419
3420 if(pItem) {
3421 *pItem = Item;
3422 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07003423
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003424 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003425}
Laurence Lundbladec4537442020-04-14 18:53:22 -07003426
Laurence Lundbladec4537442020-04-14 18:53:22 -07003427
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003428void QCBORDecode_GetDoubleConvertInternalInMapN(QCBORDecodeContext *pMe,
3429 int64_t nLabel,
3430 uint32_t uOptions,
3431 double *pdValue,
3432 QCBORItem *pItem)
3433{
3434 QCBORItem Item;
3435 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
3436
3437 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
3438}
3439
3440void QCBORDecode_GetDoubleConvertInternalInMapSZ(QCBORDecodeContext *pMe,
3441 const char * szLabel,
3442 uint32_t uOptions,
3443 double *pdValue,
3444 QCBORItem *pItem)
3445{
3446 if(pMe->uLastError != QCBOR_SUCCESS) {
3447 return;
3448 }
3449
3450 QCBORItem Item;
3451 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3452
3453 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uOptions, pdValue);
3454}
3455
3456
3457
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003458static double ConvertBigNumToDouble(const UsefulBufC BigNum)
3459{
3460 double dResult;
3461
3462 dResult = 0.0;
3463 const uint8_t *pByte = BigNum.ptr;
3464 size_t uLen = BigNum.len;
3465 /* This will overflow and become the float value INFINITY if the number
3466 is too large to fit. No error will be logged.
3467 TODO: should an error be logged? */
3468 while(uLen--) {
3469 dResult = (dResult * 256.0) + (double)*pByte++;
3470 }
3471
3472 return dResult;
3473}
3474
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003475static QCBORError DoubleConvertAll(const QCBORItem *pItem, uint32_t uOptions, double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003476{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003477 /*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003478 https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
3479
3480 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003481 switch(pItem->uDataType) {
3482 // TODO: type float
3483 case QCBOR_TYPE_DECIMAL_FRACTION:
3484 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3485 // TODO: rounding and overflow errors
3486 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
3487 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
3488 } else {
3489 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3490 }
3491 break;
3492
3493 case QCBOR_TYPE_BIGFLOAT:
3494 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
3495 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
3496 exp2((double)pItem->val.expAndMantissa.nExponent);
3497 } else {
3498 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3499 }
3500 break;
3501
3502 case QCBOR_TYPE_POSBIGNUM:
3503 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3504 *pdValue = ConvertBigNumToDouble(pItem->val.bigNum);
3505 } else {
3506 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3507 }
3508 break;
3509
3510 case QCBOR_TYPE_NEGBIGNUM:
3511 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07003512 *pdValue = -1-ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003513 } else {
3514 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3515 }
3516 break;
3517
3518 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
3519 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3520 double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
3521 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
3522 } else {
3523 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3524 }
3525 break;
3526
3527 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
3528 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3529 double dMantissa = -ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
3530 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
3531 } else {
3532 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3533 }
3534 break;
3535
3536 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
3537 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3538 double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
3539 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
3540 } else {
3541 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3542 }
3543 break;
3544
3545 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
3546 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07003547 double dMantissa = -1-ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003548 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
3549 } else {
3550 return QCBOR_ERR_CONVERSION_NOT_REQUESTED;
3551 }
3552 break;
3553
3554 default:
3555 return QCBOR_ERR_UNEXPECTED_TYPE;
3556 }
3557
3558 return QCBOR_SUCCESS;
3559}
3560
3561
3562/*
3563 Public function, see header qcbor/qcbor_decode.h file
3564*/
3565void QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, double *pdValue)
3566{
3567
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003568 QCBORItem Item;
3569
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003570 QCBORDecode_GetDoubleConvertInternal(pMe, uOptions, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003571
3572 if(pMe->uLastError == QCBOR_SUCCESS) {
3573 // The above conversion succeeded
3574 return;
3575 }
3576
3577 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3578 // The above conversion failed in a way that code below can't correct
3579 return;
3580 }
3581
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003582 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003583}
3584
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003585
3586/*
3587Public function, see header qcbor/qcbor_decode.h file
3588*/
3589void QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe, int64_t nLabel, uint32_t uOptions, double *pdValue)
3590{
3591 QCBORItem Item;
3592
3593 QCBORDecode_GetDoubleConvertInternalInMapN(pMe, nLabel, uOptions, pdValue, &Item);
3594
3595 if(pMe->uLastError == QCBOR_SUCCESS) {
3596 // The above conversion succeeded
3597 return;
3598 }
3599
3600 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3601 // The above conversion failed in a way that code below can't correct
3602 return;
3603 }
3604
3605 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
3606}
3607
3608
3609/*
3610Public function, see header qcbor/qcbor_decode.h file
3611*/
3612void QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint32_t uOptions, double *pdValue)
3613{
3614 QCBORItem Item;
3615 QCBORDecode_GetDoubleConvertInternalInMapSZ(pMe, szLabel, uOptions, pdValue, &Item);
3616
3617 if(pMe->uLastError == QCBOR_SUCCESS) {
3618 // The above conversion succeeded
3619 return;
3620 }
3621
3622 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
3623 // The above conversion failed in a way that code below can't correct
3624 return;
3625 }
3626
3627 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uOptions, pdValue);
3628}