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