blob: 9950ef40b40caf39e43d7277aed43b1dd6886688 [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 Lundblade9c905e82020-04-25 11:31:38 -0700134// Determine if at the end of a map or array, taking into
135// account map mode. If this returns true, it is OK
136// to get another item.
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700137inline static bool
138DecodeNesting_AtEnd(const QCBORDecodeNesting *pNesting)
139{
Laurence Lundbladea826c502020-05-10 21:07:00 -0700140 //if(DecodeNesting_IsAtTop(pNesting)){
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700141 // Always at end if at the top level of nesting
Laurence Lundbladea826c502020-05-10 21:07:00 -0700142 // return true;
143 //}
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700144
145 if(pNesting->pCurrent->uMapMode) {
146 if(pNesting->pCurrent->uCount == 0) {
147 // In map mode and consumed all items, so it is the end
148 return true;
149 } else {
150 // In map mode, all items not consumed, so it is NOT the end
151 return false;
152 }
153 } else {
154 // Not in map mode, and not at top level so it NOT the end.
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700155 return false;
156 }
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700157}
158
159
Laurence Lundbladeee851742020-01-08 08:37:05 -0800160inline static int
161DecodeNesting_IsIndefiniteLength(const QCBORDecodeNesting *pNesting)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700162{
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700163 return pNesting->pCurrent->uCount == UINT16_MAX;
164}
165
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700166inline static int
167DecodeNesting_InMapMode(const QCBORDecodeNesting *pNesting)
168{
169 return (bool)pNesting->pCurrent->uMapMode;
170}
171
Laurence Lundbladeee851742020-01-08 08:37:05 -0800172inline static uint8_t
173DecodeNesting_GetLevel(QCBORDecodeNesting *pNesting)
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800174{
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800175 // Check in DecodeNesting_Descend and never having
Laurence Lundbladebb87be22020-04-09 19:15:32 -0700176 // QCBOR_MAX_ARRAY_NESTING > 255 gaurantees cast is safe
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800177 return (uint8_t)(pNesting->pCurrent - &(pNesting->pMapsAndArrays[0]));
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800178}
179
Laurence Lundbladeee851742020-01-08 08:37:05 -0800180inline static int
181DecodeNesting_TypeIsMap(const QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700182{
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700183 if(DecodeNesting_IsAtTop(pNesting)) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700184 return 0;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700185 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800186
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700187 return CBOR_MAJOR_TYPE_MAP == pNesting->pCurrent->uMajorType;
188}
189
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800190// Process a break. This will either ascend the nesting or error out
Laurence Lundbladeee851742020-01-08 08:37:05 -0800191inline static QCBORError
192DecodeNesting_BreakAscend(QCBORDecodeNesting *pNesting)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700193{
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800194 // breaks must always occur when there is nesting
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700195 if(DecodeNesting_IsAtTop(pNesting)) {
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800196 return QCBOR_ERR_BAD_BREAK;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700197 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800198
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800199 // breaks can only occur when the map/array is indefinite length
200 if(!DecodeNesting_IsIndefiniteLength(pNesting)) {
201 return QCBOR_ERR_BAD_BREAK;
202 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800203
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800204 // if all OK, the break reduces the level of nesting
205 pNesting->pCurrent--;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800206
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800207 return QCBOR_SUCCESS;
208}
209
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700210// Called on every single item except breaks including decode of a map/array
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700211/* Decrements the map/array counter if possible. If decrement
212 closed out a map or array, then level up in nesting and decrement
213 again, until, the top is reached or the end of a map mode is reached
214 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800215inline static void
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700216DecodeNesting_DecrementCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800217{
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700218 while(!DecodeNesting_IsAtTop(pNesting)) {
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700219 // Not at the top level, so there is decrementing to be done.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800220
Laurence Lundblade9e3651c2018-10-10 11:49:55 +0800221 if(!DecodeNesting_IsIndefiniteLength(pNesting)) {
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700222 // Decrement the current nesting level if it is not indefinite.
Laurence Lundblade9e3651c2018-10-10 11:49:55 +0800223 pNesting->pCurrent->uCount--;
224 }
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700225
226 if(pNesting->pCurrent->uCount != 0) {
227 // Did not close out an array or map, so nothing further
228 break;
229 }
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700230
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700231 if(pNesting->pCurrent->uMapMode) {
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700232 // In map mode the level-up must be done explicitly
233 break;
234 }
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700235
236 // Closed out an array or map so level up
237 pNesting->pCurrent--;
238
239 // Continue with loop to see if closing out this doesn't close out more
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700240 }
241}
242
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700243inline static void
244DecodeNesting_EnterMapMode(QCBORDecodeNesting *pNesting, size_t uOffset)
245{
246 pNesting->pCurrent->uMapMode = 1;
247 // Cast to uint32_t is safe because QCBOR onl works on data < UINT32_MAX
248 pNesting->pCurrent->uOffset = (uint32_t)uOffset;
249}
250
251inline static void
252DecodeNesting_Exit(QCBORDecodeNesting *pNesting)
253{
254 pNesting->pCurrent->uMapMode = 0;
255 pNesting->pCurrent--;
256
257 DecodeNesting_DecrementCount(pNesting);
258}
259
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800260// Called on every map/array
Laurence Lundbladeee851742020-01-08 08:37:05 -0800261inline static QCBORError
262DecodeNesting_Descend(QCBORDecodeNesting *pNesting, QCBORItem *pItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700263{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700264 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800265
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800266 if(pItem->val.uCount == 0) {
267 // Nothing to do for empty definite lenth arrays. They are just are
268 // effectively the same as an item that is not a map or array
269 goto Done;
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530270 // Empty indefinite length maps and arrays are handled elsewhere
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800271 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800272
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800273 // Error out if arrays is too long to handle
274 if(pItem->val.uCount != UINT16_MAX && pItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700275 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
276 goto Done;
277 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800278
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800279 // Error out if nesting is too deep
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700280 if(pNesting->pCurrent >= &(pNesting->pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING])) {
281 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
282 goto Done;
283 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800284
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800285 // The actual descend
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700286 pNesting->pCurrent++;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800287
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800288 // Record a few details for this nesting level
289 pNesting->pCurrent->uMajorType = pItem->uDataType;
290 pNesting->pCurrent->uCount = pItem->val.uCount;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700291 pNesting->pCurrent->uSaveCount = pItem->val.uCount;
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700292 pNesting->pCurrent->uMapMode = 0;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800293
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700294Done:
295 return nReturn;;
296}
297
Laurence Lundbladeee851742020-01-08 08:37:05 -0800298inline static void
299DecodeNesting_Init(QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700300{
301 pNesting->pCurrent = &(pNesting->pMapsAndArrays[0]);
302}
303
304
305
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700306/*
307 This list of built-in tags. Only add tags here that are
308 clearly established and useful. Once a tag is added here
309 it can't be taken out as that would break backwards compatibility.
310 There are only 48 slots available forever.
311 */
312static const uint16_t spBuiltInTagMap[] = {
Laurence Lundblade59289e52019-12-30 13:44:37 -0800313 CBOR_TAG_DATE_STRING, // See TAG_MAPPER_FIRST_SIX
314 CBOR_TAG_DATE_EPOCH, // See TAG_MAPPER_FIRST_SIX
315 CBOR_TAG_POS_BIGNUM, // See TAG_MAPPER_FIRST_SIX
316 CBOR_TAG_NEG_BIGNUM, // See TAG_MAPPER_FIRST_SIX
317 CBOR_TAG_DECIMAL_FRACTION, // See TAG_MAPPER_FIRST_SIX
318 CBOR_TAG_BIGFLOAT, // See TAG_MAPPER_FIRST_SIX
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700319 CBOR_TAG_COSE_ENCRYPTO,
320 CBOR_TAG_COSE_MAC0,
321 CBOR_TAG_COSE_SIGN1,
322 CBOR_TAG_ENC_AS_B64URL,
323 CBOR_TAG_ENC_AS_B64,
324 CBOR_TAG_ENC_AS_B16,
325 CBOR_TAG_CBOR,
326 CBOR_TAG_URI,
327 CBOR_TAG_B64URL,
328 CBOR_TAG_B64,
329 CBOR_TAG_REGEX,
330 CBOR_TAG_MIME,
331 CBOR_TAG_BIN_UUID,
332 CBOR_TAG_CWT,
333 CBOR_TAG_ENCRYPT,
334 CBOR_TAG_MAC,
335 CBOR_TAG_SIGN,
336 CBOR_TAG_GEO_COORD,
337 CBOR_TAG_CBOR_MAGIC
338};
339
340// This is used in a bit of cleverness in GetNext_TaggedItem() to
341// keep code size down and switch for the internal processing of
Laurence Lundblade59289e52019-12-30 13:44:37 -0800342// these types. This will break if the first six items in
343// spBuiltInTagMap don't have values 0,1,2,3,4,5. That is the
344// mapping is 0 to 0, 1 to 1, 2 to 2 and 3 to 3....
345#define QCBOR_TAGFLAG_DATE_STRING (0x01LL << CBOR_TAG_DATE_STRING)
346#define QCBOR_TAGFLAG_DATE_EPOCH (0x01LL << CBOR_TAG_DATE_EPOCH)
347#define QCBOR_TAGFLAG_POS_BIGNUM (0x01LL << CBOR_TAG_POS_BIGNUM)
348#define QCBOR_TAGFLAG_NEG_BIGNUM (0x01LL << CBOR_TAG_NEG_BIGNUM)
349#define QCBOR_TAGFLAG_DECIMAL_FRACTION (0x01LL << CBOR_TAG_DECIMAL_FRACTION)
350#define QCBOR_TAGFLAG_BIGFLOAT (0x01LL << CBOR_TAG_BIGFLOAT)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700351
Laurence Lundblade59289e52019-12-30 13:44:37 -0800352#define TAG_MAPPER_FIRST_SIX (QCBOR_TAGFLAG_DATE_STRING |\
353 QCBOR_TAGFLAG_DATE_EPOCH |\
354 QCBOR_TAGFLAG_POS_BIGNUM |\
355 QCBOR_TAGFLAG_NEG_BIGNUM |\
356 QCBOR_TAGFLAG_DECIMAL_FRACTION |\
357 QCBOR_TAGFLAG_BIGFLOAT)
358
359#define TAG_MAPPER_FIRST_FOUR (QCBOR_TAGFLAG_DATE_STRING |\
360 QCBOR_TAGFLAG_DATE_EPOCH |\
361 QCBOR_TAGFLAG_POS_BIGNUM |\
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700362 QCBOR_TAGFLAG_NEG_BIGNUM)
363
364#define TAG_MAPPER_TOTAL_TAG_BITS 64 // Number of bits in a uint64_t
365#define TAG_MAPPER_CUSTOM_TAGS_BASE_INDEX (TAG_MAPPER_TOTAL_TAG_BITS - QCBOR_MAX_CUSTOM_TAGS) // 48
366#define TAG_MAPPER_MAX_SIZE_BUILT_IN_TAGS (TAG_MAPPER_TOTAL_TAG_BITS - QCBOR_MAX_CUSTOM_TAGS ) // 48
367
368static inline int TagMapper_LookupBuiltIn(uint64_t uTag)
369{
370 if(sizeof(spBuiltInTagMap)/sizeof(uint16_t) > TAG_MAPPER_MAX_SIZE_BUILT_IN_TAGS) {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800371 /*
372 This is a cross-check to make sure the above array doesn't
373 accidentally get made too big. In normal conditions the above
374 test should optimize out as all the values are known at compile
375 time.
376 */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700377 return -1;
378 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800379
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700380 if(uTag > UINT16_MAX) {
381 // This tag map works only on 16-bit tags
382 return -1;
383 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800384
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700385 for(int nTagBitIndex = 0; nTagBitIndex < (int)(sizeof(spBuiltInTagMap)/sizeof(uint16_t)); nTagBitIndex++) {
386 if(spBuiltInTagMap[nTagBitIndex] == uTag) {
387 return nTagBitIndex;
388 }
389 }
390 return -1; // Indicates no match
391}
392
393static inline int TagMapper_LookupCallerConfigured(const QCBORTagListIn *pCallerConfiguredTagMap, uint64_t uTag)
394{
395 for(int nTagBitIndex = 0; nTagBitIndex < pCallerConfiguredTagMap->uNumTags; nTagBitIndex++) {
396 if(pCallerConfiguredTagMap->puTags[nTagBitIndex] == uTag) {
397 return nTagBitIndex + TAG_MAPPER_CUSTOM_TAGS_BASE_INDEX;
398 }
399 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800400
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700401 return -1; // Indicates no match
402}
403
404/*
405 Find the tag bit index for a given tag value, or error out
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800406
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700407 This and the above functions could probably be optimized and made
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800408 clearer and neater.
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700409 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800410static QCBORError
411TagMapper_Lookup(const QCBORTagListIn *pCallerConfiguredTagMap,
412 uint64_t uTag,
413 uint8_t *puTagBitIndex)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700414{
415 int nTagBitIndex = TagMapper_LookupBuiltIn(uTag);
416 if(nTagBitIndex >= 0) {
417 // Cast is safe because TagMapper_LookupBuiltIn never returns > 47
418 *puTagBitIndex = (uint8_t)nTagBitIndex;
419 return QCBOR_SUCCESS;
420 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800421
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700422 if(pCallerConfiguredTagMap) {
423 if(pCallerConfiguredTagMap->uNumTags > QCBOR_MAX_CUSTOM_TAGS) {
424 return QCBOR_ERR_TOO_MANY_TAGS;
425 }
426 nTagBitIndex = TagMapper_LookupCallerConfigured(pCallerConfiguredTagMap, uTag);
427 if(nTagBitIndex >= 0) {
428 // Cast is safe because TagMapper_LookupBuiltIn never returns > 63
429
430 *puTagBitIndex = (uint8_t)nTagBitIndex;
431 return QCBOR_SUCCESS;
432 }
433 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800434
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700435 return QCBOR_ERR_BAD_OPT_TAG;
436}
437
438
439
Laurence Lundbladeee851742020-01-08 08:37:05 -0800440/*===========================================================================
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800441 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
442
443 The following four functions are pretty wrappers for invocation of
444 the string allocator supplied by the caller.
445
Laurence Lundbladeee851742020-01-08 08:37:05 -0800446 ===========================================================================*/
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800447
Laurence Lundbladeee851742020-01-08 08:37:05 -0800448static inline void
449StringAllocator_Free(const QCORInternalAllocator *pMe, void *pMem)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800450{
451 (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, 0);
452}
453
Laurence Lundbladeee851742020-01-08 08:37:05 -0800454// StringAllocator_Reallocate called with pMem NULL is
455// equal to StringAllocator_Allocate()
456static inline UsefulBuf
457StringAllocator_Reallocate(const QCORInternalAllocator *pMe,
458 void *pMem,
459 size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800460{
461 return (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, uSize);
462}
463
Laurence Lundbladeee851742020-01-08 08:37:05 -0800464static inline UsefulBuf
465StringAllocator_Allocate(const QCORInternalAllocator *pMe, size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800466{
467 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
468}
469
Laurence Lundbladeee851742020-01-08 08:37:05 -0800470static inline void
471StringAllocator_Destruct(const QCORInternalAllocator *pMe)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800472{
473 if(pMe->pfAllocator) {
474 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
475 }
476}
477
478
479
Laurence Lundbladeee851742020-01-08 08:37:05 -0800480/*===========================================================================
481 QCBORDecode -- The main implementation of CBOR decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700482
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800483 See qcbor/qcbor_decode.h for definition of the object
484 used here: QCBORDecodeContext
Laurence Lundbladeee851742020-01-08 08:37:05 -0800485 ===========================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700486/*
487 Public function, see header file
488 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800489void QCBORDecode_Init(QCBORDecodeContext *me,
490 UsefulBufC EncodedCBOR,
491 QCBORDecodeMode nDecodeMode)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700492{
493 memset(me, 0, sizeof(QCBORDecodeContext));
494 UsefulInputBuf_Init(&(me->InBuf), EncodedCBOR);
Laurence Lundbladeee851742020-01-08 08:37:05 -0800495 // Don't bother with error check on decode mode. If a bad value is
496 // passed it will just act as if the default normal mode of 0 was set.
Laurence Lundbladee6bcef12020-04-01 10:56:27 -0700497 me->uDecodeMode = (uint8_t)nDecodeMode;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700498 DecodeNesting_Init(&(me->nesting));
499}
500
501
502/*
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700503 Public function, see header file
504 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800505void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
506 QCBORStringAllocate pfAllocateFunction,
507 void *pAllocateContext,
508 bool bAllStrings)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700509{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800510 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
511 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
512 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700513}
514
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800515
516/*
517 Public function, see header file
518 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800519void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *me,
520 const QCBORTagListIn *pTagList)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700521{
522 me->pCallerConfiguredTagList = pTagList;
523}
524
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700525
526/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800527 This decodes the fundamental part of a CBOR data item, the type and
528 number
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800529
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700530 This is the Counterpart to InsertEncodedTypeAndNumber().
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800531
Laurence Lundbladeee851742020-01-08 08:37:05 -0800532 This does the network->host byte order conversion. The conversion
533 here also results in the conversion for floats in addition to that
534 for lengths, tags and integer values.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800535
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700536 This returns:
537 pnMajorType -- the major type for the item
Laurence Lundbladeee851742020-01-08 08:37:05 -0800538
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800539 puArgument -- the "number" which is used a the value for integers,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800540 tags and floats and length for strings and arrays
541
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800542 pnAdditionalInfo -- Pass this along to know what kind of float or
Laurence Lundbladeee851742020-01-08 08:37:05 -0800543 if length is indefinite
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800544
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800545 The int type is preferred to uint8_t for some variables as this
546 avoids integer promotions, can reduce code size and makes
547 static analyzers happier.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700548 */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800549inline static QCBORError DecodeTypeAndNumber(UsefulInputBuf *pUInBuf,
550 int *pnMajorType,
551 uint64_t *puArgument,
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800552 int *pnAdditionalInfo)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700553{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700554 QCBORError nReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800555
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700556 // Get the initial byte that every CBOR data item has
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800557 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800558
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700559 // Break down the initial byte
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800560 const int nTmpMajorType = nInitialByte >> 5;
561 const int nAdditionalInfo = nInitialByte & 0x1f;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800562
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800563 // Where the number or argument accumulates
564 uint64_t uArgument;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800565
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800566 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800567 // Need to get 1,2,4 or 8 additional argument bytes Map
568 // LEN_IS_ONE_BYTE.. LEN_IS_EIGHT_BYTES to actual length
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800569 static const uint8_t aIterate[] = {1,2,4,8};
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800570
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800571 // Loop getting all the bytes in the argument
572 uArgument = 0;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800573 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800574 // This shift and add gives the endian conversion
575 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
576 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800577 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800578 // The reserved and thus-far unused additional info values
579 nReturn = QCBOR_ERR_UNSUPPORTED;
580 goto Done;
581 } else {
582 // Less than 24, additional info is argument or 31, an indefinite length
583 // No more bytes to get
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800584 uArgument = (uint64_t)nAdditionalInfo;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700585 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800586
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700587 if(UsefulInputBuf_GetError(pUInBuf)) {
588 nReturn = QCBOR_ERR_HIT_END;
589 goto Done;
590 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800591
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700592 // All successful if we got here.
593 nReturn = QCBOR_SUCCESS;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800594 *pnMajorType = nTmpMajorType;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800595 *puArgument = uArgument;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800596 *pnAdditionalInfo = nAdditionalInfo;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800597
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700598Done:
599 return nReturn;
600}
601
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800602
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700603/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800604 CBOR doesn't explicitly specify two's compliment for integers but all
605 CPUs use it these days and the test vectors in the RFC are so. All
606 integers in the CBOR structure are positive and the major type
607 indicates positive or negative. CBOR can express positive integers
608 up to 2^x - 1 where x is the number of bits and negative integers
609 down to 2^x. Note that negative numbers can be one more away from
610 zero than positive. Stdint, as far as I can tell, uses two's
611 compliment to represent negative integers.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800612
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700613 See http://www.unix.org/whitepapers/64bit.html for reasons int isn't
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800614 used carefully here, and in particular why it isn't used in the interface.
615 Also see
616 https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers
617
618 Int is used for values that need less than 16-bits and would be subject
619 to integer promotion and complaining by static analyzers.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700620 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800621inline static QCBORError
622DecodeInteger(int nMajorType, uint64_t uNumber, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700623{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700624 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800625
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700626 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
627 if (uNumber <= INT64_MAX) {
628 pDecodedItem->val.int64 = (int64_t)uNumber;
629 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800630
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700631 } else {
632 pDecodedItem->val.uint64 = uNumber;
633 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800634
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700635 }
636 } else {
637 if(uNumber <= INT64_MAX) {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800638 // CBOR's representation of negative numbers lines up with the
639 // two-compliment representation. A negative integer has one
640 // more in range than a positive integer. INT64_MIN is
641 // equal to (-INT64_MAX) - 1.
642 pDecodedItem->val.int64 = (-(int64_t)uNumber) - 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700643 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800644
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700645 } else {
646 // C can't represent a negative integer in this range
Laurence Lundblade21d1d812019-09-28 22:47:49 -1000647 // so it is an error.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700648 nReturn = QCBOR_ERR_INT_OVERFLOW;
649 }
650 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800651
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700652 return nReturn;
653}
654
655// Make sure #define value line up as DecodeSimple counts on this.
656#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
657#error QCBOR_TYPE_FALSE macro value wrong
658#endif
659
660#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
661#error QCBOR_TYPE_TRUE macro value wrong
662#endif
663
664#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
665#error QCBOR_TYPE_NULL macro value wrong
666#endif
667
668#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
669#error QCBOR_TYPE_UNDEF macro value wrong
670#endif
671
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700672#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
673#error QCBOR_TYPE_BREAK macro value wrong
674#endif
675
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700676#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
677#error QCBOR_TYPE_DOUBLE macro value wrong
678#endif
679
680#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
681#error QCBOR_TYPE_FLOAT macro value wrong
682#endif
683
684/*
685 Decode true, false, floats, break...
686 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800687inline static QCBORError
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800688DecodeSimple(int nAdditionalInfo, uint64_t uNumber, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700689{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700690 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800691
Laurence Lundbladeee851742020-01-08 08:37:05 -0800692 // uAdditionalInfo is 5 bits from the initial byte compile time checks
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800693 // above make sure uAdditionalInfo values line up with uDataType values.
694 // DecodeTypeAndNumber never returns a major type > 1f so cast is safe
695 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800696
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800697 switch(nAdditionalInfo) {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800698 // No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they are
699 // caught before this is called.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800700
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700701 case HALF_PREC_FLOAT:
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700702 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uNumber);
703 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700704 break;
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700705 case SINGLE_PREC_FLOAT:
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700706 pDecodedItem->val.dfnum = (double)UsefulBufUtil_CopyUint32ToFloat((uint32_t)uNumber);
707 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700708 break;
709 case DOUBLE_PREC_FLOAT:
710 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uNumber);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700711 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700712 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800713
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700714 case CBOR_SIMPLEV_FALSE: // 20
715 case CBOR_SIMPLEV_TRUE: // 21
716 case CBOR_SIMPLEV_NULL: // 22
717 case CBOR_SIMPLEV_UNDEF: // 23
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700718 case CBOR_SIMPLE_BREAK: // 31
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700719 break; // nothing to do
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800720
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700721 case CBOR_SIMPLEV_ONEBYTE: // 24
722 if(uNumber <= CBOR_SIMPLE_BREAK) {
723 // This takes out f8 00 ... f8 1f which should be encoded as e0 … f7
Laurence Lundblade077475f2019-04-26 09:06:33 -0700724 nReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700725 goto Done;
726 }
Laurence Lundblade5e390822019-01-06 12:35:01 -0800727 /* FALLTHROUGH */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700728 // fall through intentionally
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800729
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700730 default: // 0-19
731 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
Laurence Lundbladeee851742020-01-08 08:37:05 -0800732 /*
733 DecodeTypeAndNumber will make uNumber equal to
734 uAdditionalInfo when uAdditionalInfo is < 24 This cast is
735 safe because the 2, 4 and 8 byte lengths of uNumber are in
736 the double/float cases above
737 */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700738 pDecodedItem->val.uSimple = (uint8_t)uNumber;
739 break;
740 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800741
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700742Done:
743 return nReturn;
744}
745
746
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700747/*
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530748 Decode text and byte strings. Call the string allocator if asked to.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700749 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800750inline static QCBORError DecodeBytes(const QCORInternalAllocator *pAllocator,
751 int nMajorType,
752 uint64_t uStrLen,
753 UsefulInputBuf *pUInBuf,
754 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700755{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700756 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800757
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800758 // CBOR lengths can be 64 bits, but size_t is not 64 bits on all CPUs.
759 // This check makes the casts to size_t below safe.
760
761 // 4 bytes less than the largest sizeof() so this can be tested by
762 // putting a SIZE_MAX length in the CBOR test input (no one will
763 // care the limit on strings is 4 bytes shorter).
764 if(uStrLen > SIZE_MAX-4) {
765 nReturn = QCBOR_ERR_STRING_TOO_LONG;
766 goto Done;
767 }
768
769 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, (size_t)uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530770 if(UsefulBuf_IsNULLC(Bytes)) {
771 // Failed to get the bytes for this string item
772 nReturn = QCBOR_ERR_HIT_END;
773 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700774 }
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530775
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800776 if(pAllocator) {
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530777 // We are asked to use string allocator to make a copy
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800778 UsefulBuf NewMem = StringAllocator_Allocate(pAllocator, (size_t)uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530779 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade30816f22018-11-10 13:40:22 +0700780 nReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530781 goto Done;
782 }
783 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800784 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530785 } else {
786 // Normal case with no string allocator
787 pDecodedItem->val.string = Bytes;
788 }
Laurence Lundbladeee851742020-01-08 08:37:05 -0800789 const bool bIsBstr = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING);
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800790 // Cast because ternary operator causes promotion to integer
791 pDecodedItem->uDataType = (uint8_t)(bIsBstr ? QCBOR_TYPE_BYTE_STRING
792 : QCBOR_TYPE_TEXT_STRING);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800793
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530794Done:
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700795 return nReturn;
796}
797
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700798
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800799
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700800
801
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700802
803
Laurence Lundbladeee851742020-01-08 08:37:05 -0800804// Make sure the constants align as this is assumed by
805// the GetAnItem() implementation
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700806#if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
807#error QCBOR_TYPE_ARRAY value not lined up with major type
808#endif
809#if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
810#error QCBOR_TYPE_MAP value not lined up with major type
811#endif
812
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700813/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800814 This gets a single data item and decodes it including preceding
815 optional tagging. This does not deal with arrays and maps and nesting
816 except to decode the data item introducing them. Arrays and maps are
817 handled at the next level up in GetNext().
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800818
Laurence Lundbladeee851742020-01-08 08:37:05 -0800819 Errors detected here include: an array that is too long to decode,
820 hit end of buffer unexpectedly, a few forms of invalid encoded CBOR
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700821 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800822static QCBORError GetNext_Item(UsefulInputBuf *pUInBuf,
823 QCBORItem *pDecodedItem,
824 const QCORInternalAllocator *pAllocator)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700825{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700826 QCBORError nReturn;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800827
Laurence Lundbladeee851742020-01-08 08:37:05 -0800828 /*
829 Get the major type and the number. Number could be length of more
830 bytes or the value depending on the major type nAdditionalInfo is
831 an encoding of the length of the uNumber and is needed to decode
832 floats and doubles
833 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800834 int nMajorType;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700835 uint64_t uNumber;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800836 int nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800837
Laurence Lundblade4b09f632019-10-09 14:34:59 -0700838 memset(pDecodedItem, 0, sizeof(QCBORItem));
839
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800840 nReturn = DecodeTypeAndNumber(pUInBuf, &nMajorType, &uNumber, &nAdditionalInfo);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800841
Laurence Lundbladeee851742020-01-08 08:37:05 -0800842 // Error out here if we got into trouble on the type and number. The
843 // code after this will not work if the type and number is not good.
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700844 if(nReturn) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700845 goto Done;
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700846 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800847
Laurence Lundbladeee851742020-01-08 08:37:05 -0800848 // At this point the major type and the value are valid. We've got
849 // the type and the number that starts every CBOR data item.
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800850 switch (nMajorType) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700851 case CBOR_MAJOR_TYPE_POSITIVE_INT: // Major type 0
852 case CBOR_MAJOR_TYPE_NEGATIVE_INT: // Major type 1
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800853 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700854 nReturn = QCBOR_ERR_BAD_INT;
855 } else {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800856 nReturn = DecodeInteger(nMajorType, uNumber, pDecodedItem);
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700857 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700858 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800859
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700860 case CBOR_MAJOR_TYPE_BYTE_STRING: // Major type 2
861 case CBOR_MAJOR_TYPE_TEXT_STRING: // Major type 3
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800862 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
863 const bool bIsBstr = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING);
864 pDecodedItem->uDataType = (uint8_t)(bIsBstr ? QCBOR_TYPE_BYTE_STRING
865 : QCBOR_TYPE_TEXT_STRING);
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530866 pDecodedItem->val.string = (UsefulBufC){NULL, SIZE_MAX};
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700867 } else {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800868 nReturn = DecodeBytes(pAllocator, nMajorType, uNumber, pUInBuf, pDecodedItem);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700869 }
870 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800871
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700872 case CBOR_MAJOR_TYPE_ARRAY: // Major type 4
873 case CBOR_MAJOR_TYPE_MAP: // Major type 5
874 // Record the number of items in the array or map
875 if(uNumber > QCBOR_MAX_ITEMS_IN_ARRAY) {
876 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
877 goto Done;
878 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800879 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530880 pDecodedItem->val.uCount = UINT16_MAX; // Indicate indefinite length
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700881 } else {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800882 // type conversion OK because of check above
883 pDecodedItem->val.uCount = (uint16_t)uNumber;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700884 }
Laurence Lundbladeee851742020-01-08 08:37:05 -0800885 // C preproc #if above makes sure constants for major types align
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800886 // DecodeTypeAndNumber never returns a major type > 7 so cast is safe
887 pDecodedItem->uDataType = (uint8_t)nMajorType;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700888 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800889
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700890 case CBOR_MAJOR_TYPE_OPTIONAL: // Major type 6, optional prepended tags
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800891 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700892 nReturn = QCBOR_ERR_BAD_INT;
893 } else {
894 pDecodedItem->val.uTagV = uNumber;
895 pDecodedItem->uDataType = QCBOR_TYPE_OPTTAG;
896 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700897 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800898
Laurence Lundbladeee851742020-01-08 08:37:05 -0800899 case CBOR_MAJOR_TYPE_SIMPLE:
900 // Major type 7, float, double, true, false, null...
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800901 nReturn = DecodeSimple(nAdditionalInfo, uNumber, pDecodedItem);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700902 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800903
Laurence Lundbladeee851742020-01-08 08:37:05 -0800904 default:
905 // Never happens because DecodeTypeAndNumber() should never return > 7
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700906 nReturn = QCBOR_ERR_UNSUPPORTED;
907 break;
908 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800909
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700910Done:
911 return nReturn;
912}
913
914
915
916/*
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800917 This layer deals with indefinite length strings. It pulls all the
Laurence Lundbladeee851742020-01-08 08:37:05 -0800918 individual chunk items together into one QCBORItem using the string
919 allocator.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800920
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530921 Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700922 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800923static inline QCBORError
924GetNext_FullItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700925{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700926 // Stack usage; int/ptr 2 UsefulBuf 2 QCBORItem -- 96
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700927
928 // Get pointer to string allocator. First use is to pass it to
929 // GetNext_Item() when option is set to allocate for *every* string.
930 // Second use here is to allocate space to coallese indefinite
931 // length string items into one.
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800932 const QCORInternalAllocator *pAllocator = me->StringAllocator.pfAllocator ?
933 &(me->StringAllocator) :
934 NULL;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800935
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700936 QCBORError nReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800937 nReturn = GetNext_Item(&(me->InBuf),
938 pDecodedItem,
939 me->bStringAllocateAll ? pAllocator: NULL);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700940 if(nReturn) {
941 goto Done;
942 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800943
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700944 // To reduce code size by removing support for indefinite length strings, the
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530945 // code in this function from here down can be eliminated. Run tests, except
946 // indefinite length string tests, to be sure all is OK if this is removed.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800947
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800948 // Only do indefinite length processing on strings
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700949 const uint8_t uStringType = pDecodedItem->uDataType;
950 if(uStringType!= QCBOR_TYPE_BYTE_STRING && uStringType != QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700951 goto Done; // no need to do any work here on non-string types
952 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800953
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800954 // Is this a string with an indefinite length?
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530955 if(pDecodedItem->val.string.len != SIZE_MAX) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800956 goto Done; // length is not indefinite, so no work to do here
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700957 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800958
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530959 // Can't do indefinite length strings without a string allocator
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800960 if(pAllocator == NULL) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700961 nReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
962 goto Done;
963 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800964
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700965 // Loop getting chunk of indefinite string
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700966 UsefulBufC FullString = NULLUsefulBufC;
967
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700968 for(;;) {
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700969 // Get item for next chunk
970 QCBORItem StringChunkItem;
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -0700971 // NULL string allocator passed here. Do not need to allocate
972 // chunks even if bStringAllocateAll is set.
Laurence Lundbladefae26bf2019-02-18 11:15:43 -0800973 nReturn = GetNext_Item(&(me->InBuf), &StringChunkItem, NULL);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700974 if(nReturn) {
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700975 break; // Error getting the next chunk
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700976 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800977
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530978 // See if it is a marker at end of indefinite length string
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700979 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800980 // String is complete
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700981 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +0530982 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700983 break;
984 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800985
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700986 // Match data type of chunk to type at beginning.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530987 // Also catches error of other non-string types that don't belong.
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700988 // Also catches indefinite length strings inside indefinite length strings
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800989 if(StringChunkItem.uDataType != uStringType ||
990 StringChunkItem.val.string.len == SIZE_MAX) {
Laurence Lundblade30816f22018-11-10 13:40:22 +0700991 nReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700992 break;
993 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800994
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530995 // Alloc new buffer or expand previously allocated buffer so it can fit
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800996 // The first time throurgh FullString.ptr is NULL and this is
997 // equivalent to StringAllocator_Allocate()
998 UsefulBuf NewMem = StringAllocator_Reallocate(pAllocator,
999 UNCONST_POINTER(FullString.ptr),
1000 FullString.len + StringChunkItem.val.string.len);
1001
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001002 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301003 // Allocation of memory for the string failed
Laurence Lundblade30816f22018-11-10 13:40:22 +07001004 nReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001005 break;
1006 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001007
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001008 // Copy new string chunk at the end of string so far.
1009 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001010 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001011
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001012 if(nReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
1013 // Getting the item failed, clean up the allocated memory
1014 StringAllocator_Free(pAllocator, UNCONST_POINTER(FullString.ptr));
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001015 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001016
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001017Done:
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001018 return nReturn;
1019}
1020
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001021
1022/*
Laurence Lundblade59289e52019-12-30 13:44:37 -08001023 Gets all optional tag data items preceding a data item that is not an
1024 optional tag and records them as bits in the tag map.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001025 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001026static QCBORError
1027GetNext_TaggedItem(QCBORDecodeContext *me,
1028 QCBORItem *pDecodedItem,
1029 QCBORTagListOut *pTags)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001030{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001031 // Stack usage: int/ptr: 3 -- 24
Laurence Lundblade30816f22018-11-10 13:40:22 +07001032 QCBORError nReturn;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001033 uint64_t uTagBits = 0;
1034 if(pTags) {
1035 pTags->uNumUsed = 0;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001036 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001037
Laurence Lundblade59289e52019-12-30 13:44:37 -08001038 // Loop fetching items until the item fetched is not a tag
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001039 for(;;) {
1040 nReturn = GetNext_FullItem(me, pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001041 if(nReturn) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001042 goto Done; // Error out of the loop
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001043 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001044
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001045 if(pDecodedItem->uDataType != QCBOR_TYPE_OPTTAG) {
1046 // Successful exit from loop; maybe got some tags, maybe not
1047 pDecodedItem->uTagBits = uTagBits;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001048 break;
1049 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001050
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001051 uint8_t uTagBitIndex;
1052 // Tag was mapped, tag was not mapped, error with tag list
1053 switch(TagMapper_Lookup(me->pCallerConfiguredTagList, pDecodedItem->val.uTagV, &uTagBitIndex)) {
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001054
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001055 case QCBOR_SUCCESS:
1056 // Successfully mapped the tag
1057 uTagBits |= 0x01ULL << uTagBitIndex;
1058 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001059
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001060 case QCBOR_ERR_BAD_OPT_TAG:
1061 // Tag is not recognized. Do nothing
1062 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001063
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001064 default:
1065 // Error Condition
1066 goto Done;
1067 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001068
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001069 if(pTags) {
1070 // Caller wants all tags recorded in the provided buffer
1071 if(pTags->uNumUsed >= pTags->uNumAllocated) {
1072 nReturn = QCBOR_ERR_TOO_MANY_TAGS;
1073 goto Done;
1074 }
1075 pTags->puTags[pTags->uNumUsed] = pDecodedItem->val.uTagV;
1076 pTags->uNumUsed++;
1077 }
1078 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001079
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001080Done:
1081 return nReturn;
1082}
1083
1084
1085/*
Laurence Lundbladeee851742020-01-08 08:37:05 -08001086 This layer takes care of map entries. It combines the label and data
1087 items into one QCBORItem.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001088 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001089static inline QCBORError
1090GetNext_MapEntry(QCBORDecodeContext *me,
1091 QCBORItem *pDecodedItem,
1092 QCBORTagListOut *pTags)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001093{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001094 // Stack use: int/ptr 1, QCBORItem -- 56
Laurence Lundblade30816f22018-11-10 13:40:22 +07001095 QCBORError nReturn = GetNext_TaggedItem(me, pDecodedItem, pTags);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001096 if(nReturn)
1097 goto Done;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001098
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001099 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001100 // Break can't be a map entry
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001101 goto Done;
1102 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001103
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001104 if(me->uDecodeMode != QCBOR_DECODE_MODE_MAP_AS_ARRAY) {
1105 // In a map and caller wants maps decoded, not treated as arrays
1106
1107 if(DecodeNesting_TypeIsMap(&(me->nesting))) {
1108 // If in a map and the right decoding mode, get the label
1109
Laurence Lundbladeee851742020-01-08 08:37:05 -08001110 // Save label in pDecodedItem and get the next which will
1111 // be the real data
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001112 QCBORItem LabelItem = *pDecodedItem;
1113 nReturn = GetNext_TaggedItem(me, pDecodedItem, pTags);
1114 if(nReturn)
1115 goto Done;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001116
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301117 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001118
1119 if(LabelItem.uDataType == QCBOR_TYPE_TEXT_STRING) {
1120 // strings are always good labels
1121 pDecodedItem->label.string = LabelItem.val.string;
1122 pDecodedItem->uLabelType = QCBOR_TYPE_TEXT_STRING;
1123 } else if (QCBOR_DECODE_MODE_MAP_STRINGS_ONLY == me->uDecodeMode) {
Laurence Lundbladeee851742020-01-08 08:37:05 -08001124 // It's not a string and we only want strings
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001125 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
1126 goto Done;
1127 } else if(LabelItem.uDataType == QCBOR_TYPE_INT64) {
1128 pDecodedItem->label.int64 = LabelItem.val.int64;
1129 pDecodedItem->uLabelType = QCBOR_TYPE_INT64;
1130 } else if(LabelItem.uDataType == QCBOR_TYPE_UINT64) {
1131 pDecodedItem->label.uint64 = LabelItem.val.uint64;
1132 pDecodedItem->uLabelType = QCBOR_TYPE_UINT64;
1133 } else if(LabelItem.uDataType == QCBOR_TYPE_BYTE_STRING) {
1134 pDecodedItem->label.string = LabelItem.val.string;
1135 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
1136 pDecodedItem->uLabelType = QCBOR_TYPE_BYTE_STRING;
1137 } else {
1138 // label is not an int or a string. It is an arrray
1139 // or a float or such and this implementation doesn't handle that.
1140 // Also, tags on labels are ignored.
1141 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
1142 goto Done;
1143 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001144 }
1145 } else {
1146 if(pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001147 if(pDecodedItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
1148 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
1149 goto Done;
1150 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001151 // Decoding a map as an array
1152 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001153 // Cast is safe because of check against QCBOR_MAX_ITEMS_IN_ARRAY/2
1154 // Cast is needed because of integer promotion
1155 pDecodedItem->val.uCount = (uint16_t)(pDecodedItem->val.uCount * 2);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001156 }
1157 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001158
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001159Done:
1160 return nReturn;
1161}
1162
1163
1164/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001165 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001166 TODO: correct this comment
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001167 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001168QCBORError QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *me,
1169 QCBORItem *pDecodedItem,
1170 QCBORTagListOut *pTags)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001171{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001172 // Stack ptr/int: 2, QCBORItem : 64
1173
Laurence Lundblade30816f22018-11-10 13:40:22 +07001174 QCBORError nReturn;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001175
Laurence Lundblade1341c592020-04-11 14:19:05 -07001176 // Check if there are an TODO: incomplete comment
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001177 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf)) == 0 && DecodeNesting_IsAtTop(&(me->nesting))) {
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001178 nReturn = QCBOR_ERR_NO_MORE_ITEMS;
1179 goto Done;
1180 }
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07001181
1182 // This is to handle map and array mode
1183 if(UsefulInputBuf_Tell(&(me->InBuf)) != 0 && DecodeNesting_AtEnd(&(me->nesting))) {
1184 nReturn = QCBOR_ERR_NO_MORE_ITEMS;
1185 goto Done;
1186 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001187
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001188 nReturn = GetNext_MapEntry(me, pDecodedItem, pTags);
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001189 if(nReturn) {
1190 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001191 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301192
1193 // Break ending arrays/maps are always processed at the end of this function.
1194 // They should never show up here.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301195 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade6de37062018-10-15 12:22:42 +05301196 nReturn = QCBOR_ERR_BAD_BREAK;
1197 goto Done;
Laurence Lundblade5b8c5852018-10-14 21:11:42 +05301198 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001199
Laurence Lundblade6de37062018-10-15 12:22:42 +05301200 // Record the nesting level for this data item before processing any of
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301201 // decrementing and descending.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301202 pDecodedItem->uNestingLevel = DecodeNesting_GetLevel(&(me->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001203
Laurence Lundblade6de37062018-10-15 12:22:42 +05301204 // Process the item just received for descent or decrement, and
1205 // ascent if decrements are enough to close out a definite length array/map
Laurence Lundblade3a760b02018-10-08 13:46:03 +08001206 if(IsMapOrArray(pDecodedItem->uDataType)) {
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001207 // If the new item is array or map, the nesting level descends
Laurence Lundblade3a760b02018-10-08 13:46:03 +08001208 nReturn = DecodeNesting_Descend(&(me->nesting), pDecodedItem);
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001209 // Maps and arrays do count in as items in the map/array that encloses
1210 // them so a decrement needs to be done for them too, but that is done
1211 // only when all the items in them have been processed, not when they
Laurence Lundblade9916b1b2019-09-07 22:33:25 -07001212 // are opened with the exception of an empty map or array.
1213 if(pDecodedItem->val.uCount == 0) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07001214 DecodeNesting_DecrementCount(&(me->nesting));
Laurence Lundblade9916b1b2019-09-07 22:33:25 -07001215 }
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001216 } else {
1217 // Decrement the count of items in the enclosing map/array
1218 // If the count in the enclosing map/array goes to zero, that
Laurence Lundblade6de37062018-10-15 12:22:42 +05301219 // triggers a decrement in the map/array above that and
1220 // an ascend in nesting level.
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07001221 DecodeNesting_DecrementCount(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001222 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05301223 if(nReturn) {
1224 goto Done;
1225 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001226
Laurence Lundblade6de37062018-10-15 12:22:42 +05301227 // For indefinite length maps/arrays, looking at any and
1228 // all breaks that might terminate them. The equivalent
1229 // for definite length maps/arrays happens in
1230 // DecodeNesting_DecrementCount().
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001231 if(!DecodeNesting_IsAtTop(&(me->nesting)) && DecodeNesting_IsIndefiniteLength(&(me->nesting))) {
Laurence Lundblade6de37062018-10-15 12:22:42 +05301232 while(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) {
1233 // Peek forward one item to see if it is a break.
1234 QCBORItem Peek;
1235 size_t uPeek = UsefulInputBuf_Tell(&(me->InBuf));
1236 nReturn = GetNext_Item(&(me->InBuf), &Peek, NULL);
1237 if(nReturn) {
1238 goto Done;
1239 }
1240 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
1241 // It is not a break, rewind so it can be processed normally.
1242 UsefulInputBuf_Seek(&(me->InBuf), uPeek);
1243 break;
1244 }
1245 // It is a break. Ascend one nesting level.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301246 // The break is consumed.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301247 nReturn = DecodeNesting_BreakAscend(&(me->nesting));
1248 if(nReturn) {
1249 // break occured outside of an indefinite length array/map
1250 goto Done;
1251 }
1252 }
1253 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001254
Laurence Lundblade6de37062018-10-15 12:22:42 +05301255 // Tell the caller what level is next. This tells them what maps/arrays
1256 // were closed out and makes it possible for them to reconstruct
1257 // the tree with just the information returned by GetNext
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001258 if(me->nesting.pCurrent->uMapMode && me->nesting.pCurrent->uCount == 0) {
1259 // At end of a map / array in map mode, so next nest is 0 to
1260 // indicate this end.
1261 pDecodedItem->uNextNestLevel = 0;
1262 } else {
1263 pDecodedItem->uNextNestLevel = DecodeNesting_GetLevel(&(me->nesting));
1264 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001265
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001266Done:
Laurence Lundbladee9482dd2019-10-11 12:58:46 -07001267 if(nReturn != QCBOR_SUCCESS) {
1268 // Make sure uDataType and uLabelType are QCBOR_TYPE_NONE
1269 memset(pDecodedItem, 0, sizeof(QCBORItem));
1270 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001271 return nReturn;
1272}
1273
1274
Laurence Lundblade59289e52019-12-30 13:44:37 -08001275/*
1276 Mostly just assign the right data type for the date string.
1277 */
1278inline static QCBORError DecodeDateString(QCBORItem *pDecodedItem)
1279{
1280 // Stack Use: UsefulBuf 1 16
1281 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1282 return QCBOR_ERR_BAD_OPT_TAG;
1283 }
1284
1285 const UsefulBufC Temp = pDecodedItem->val.string;
1286 pDecodedItem->val.dateString = Temp;
1287 pDecodedItem->uDataType = QCBOR_TYPE_DATE_STRING;
1288 return QCBOR_SUCCESS;
1289}
1290
1291
1292/*
1293 Mostly just assign the right data type for the bignum.
1294 */
1295inline static QCBORError DecodeBigNum(QCBORItem *pDecodedItem)
1296{
1297 // Stack Use: UsefulBuf 1 -- 16
1298 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1299 return QCBOR_ERR_BAD_OPT_TAG;
1300 }
1301 const UsefulBufC Temp = pDecodedItem->val.string;
1302 pDecodedItem->val.bigNum = Temp;
Laurence Lundbladeee851742020-01-08 08:37:05 -08001303 const bool bIsPosBigNum = (bool)(pDecodedItem->uTagBits & QCBOR_TAGFLAG_POS_BIGNUM);
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001304 pDecodedItem->uDataType = (uint8_t)(bIsPosBigNum ? QCBOR_TYPE_POSBIGNUM
1305 : QCBOR_TYPE_NEGBIGNUM);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001306 return QCBOR_SUCCESS;
1307}
1308
1309
1310/*
Laurence Lundbladeee851742020-01-08 08:37:05 -08001311 The epoch formatted date. Turns lots of different forms of encoding
1312 date into uniform one
Laurence Lundblade59289e52019-12-30 13:44:37 -08001313 */
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001314static QCBORError DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08001315{
1316 // Stack usage: 1
1317 QCBORError nReturn = QCBOR_SUCCESS;
1318
1319 pDecodedItem->val.epochDate.fSecondsFraction = 0;
1320
1321 switch (pDecodedItem->uDataType) {
1322
1323 case QCBOR_TYPE_INT64:
1324 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
1325 break;
1326
1327 case QCBOR_TYPE_UINT64:
1328 if(pDecodedItem->val.uint64 > INT64_MAX) {
1329 nReturn = QCBOR_ERR_DATE_OVERFLOW;
1330 goto Done;
1331 }
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001332 pDecodedItem->val.epochDate.nSeconds = (int64_t)pDecodedItem->val.uint64;
Laurence Lundblade59289e52019-12-30 13:44:37 -08001333 break;
1334
1335 case QCBOR_TYPE_DOUBLE:
1336 {
1337 // This comparison needs to be done as a float before
1338 // conversion to an int64_t to be able to detect doubles
1339 // that are too large to fit into an int64_t. A double
1340 // has 52 bits of preceision. An int64_t has 63. Casting
1341 // INT64_MAX to a double actually causes a round up which
1342 // is bad and wrong for the comparison because it will
1343 // allow conversion of doubles that can't fit into a
1344 // uint64_t. To remedy this INT64_MAX - 0x7ff is used as
1345 // the cutoff point as if that rounds up in conversion to
1346 // double it will still be less than INT64_MAX. 0x7ff is
1347 // picked because it has 11 bits set.
1348 //
1349 // INT64_MAX seconds is on the order of 10 billion years,
1350 // and the earth is less than 5 billion years old, so for
1351 // most uses this conversion error won't occur even though
1352 // doubles can go much larger.
1353 //
1354 // Without the 0x7ff there is a ~30 minute range of time
1355 // values 10 billion years in the past and in the future
1356 // where this this code would go wrong.
1357 const double d = pDecodedItem->val.dfnum;
1358 if(d > (double)(INT64_MAX - 0x7ff)) {
1359 nReturn = QCBOR_ERR_DATE_OVERFLOW;
1360 goto Done;
1361 }
1362 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
1363 pDecodedItem->val.epochDate.fSecondsFraction = d - (double)pDecodedItem->val.epochDate.nSeconds;
1364 }
1365 break;
1366
1367 default:
1368 nReturn = QCBOR_ERR_BAD_OPT_TAG;
1369 goto Done;
1370 }
1371 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
1372
1373Done:
1374 return nReturn;
1375}
1376
1377
1378#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
1379/*
1380 Decode decimal fractions and big floats.
1381
1382 When called pDecodedItem must be the array that is tagged as a big
1383 float or decimal fraction, the array that has the two members, the
1384 exponent and mantissa.
1385
1386 This will fetch and decode the exponent and mantissa and put the
1387 result back into pDecodedItem.
1388 */
1389inline static QCBORError
1390QCBORDecode_MantissaAndExponent(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
1391{
1392 QCBORError nReturn;
1393
1394 // --- Make sure it is an array; track nesting level of members ---
1395 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
1396 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1397 goto Done;
1398 }
1399
1400 // A check for pDecodedItem->val.uCount == 2 would work for
Laurence Lundbladeee851742020-01-08 08:37:05 -08001401 // definite length arrays, but not for indefnite. Instead remember
1402 // the nesting level the two integers must be at, which is one
1403 // deeper than that of the array.
Laurence Lundblade59289e52019-12-30 13:44:37 -08001404 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
1405
1406 // --- Is it a decimal fraction or a bigfloat? ---
1407 const bool bIsTaggedDecimalFraction = QCBORDecode_IsTagged(me, pDecodedItem, CBOR_TAG_DECIMAL_FRACTION);
1408 pDecodedItem->uDataType = bIsTaggedDecimalFraction ? QCBOR_TYPE_DECIMAL_FRACTION : QCBOR_TYPE_BIGFLOAT;
1409
1410 // --- Get the exponent ---
1411 QCBORItem exponentItem;
1412 nReturn = QCBORDecode_GetNextMapOrArray(me, &exponentItem, NULL);
1413 if(nReturn != QCBOR_SUCCESS) {
1414 goto Done;
1415 }
1416 if(exponentItem.uNestingLevel != nNestLevel) {
1417 // Array is empty or a map/array encountered when expecting an int
1418 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1419 goto Done;
1420 }
1421 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
1422 // Data arriving as an unsigned int < INT64_MAX has been converted
1423 // to QCBOR_TYPE_INT64 and thus handled here. This is also means
1424 // that the only data arriving here of type QCBOR_TYPE_UINT64 data
1425 // will be too large for this to handle and thus an error that will
1426 // get handled in the next else.
1427 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
1428 } else {
1429 // Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX
1430 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1431 goto Done;
1432 }
1433
1434 // --- Get the mantissa ---
1435 QCBORItem mantissaItem;
1436 nReturn = QCBORDecode_GetNextWithTags(me, &mantissaItem, NULL);
1437 if(nReturn != QCBOR_SUCCESS) {
1438 goto Done;
1439 }
1440 if(mantissaItem.uNestingLevel != nNestLevel) {
1441 // Mantissa missing or map/array encountered when expecting number
1442 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1443 goto Done;
1444 }
1445 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
1446 // Data arriving as an unsigned int < INT64_MAX has been converted
1447 // to QCBOR_TYPE_INT64 and thus handled here. This is also means
1448 // that the only data arriving here of type QCBOR_TYPE_UINT64 data
1449 // will be too large for this to handle and thus an error that
1450 // will get handled in an else below.
1451 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
1452 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM || mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
1453 // Got a good big num mantissa
1454 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
1455 // Depends on numbering of QCBOR_TYPE_XXX
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001456 pDecodedItem->uDataType = (uint8_t)(pDecodedItem->uDataType +
1457 mantissaItem.uDataType - QCBOR_TYPE_POSBIGNUM +
1458 1);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001459 } else {
1460 // Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX
1461 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1462 goto Done;
1463 }
1464
1465 // --- Check that array only has the two numbers ---
1466 if(mantissaItem.uNextNestLevel == nNestLevel) {
1467 // Extra items in the decimal fraction / big num
1468 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1469 goto Done;
1470 }
1471
1472Done:
1473
1474 return nReturn;
1475}
1476#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
1477
1478
1479/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001480 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08001481 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001482QCBORError
1483QCBORDecode_GetNextWithTags(QCBORDecodeContext *me,
1484 QCBORItem *pDecodedItem,
1485 QCBORTagListOut *pTags)
Laurence Lundblade59289e52019-12-30 13:44:37 -08001486{
1487 QCBORError nReturn;
1488
1489 nReturn = QCBORDecode_GetNextMapOrArray(me, pDecodedItem, pTags);
1490 if(nReturn != QCBOR_SUCCESS) {
1491 goto Done;
1492 }
1493
1494#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
1495#define TAG_MAPPER_FIRST_XXX TAG_MAPPER_FIRST_SIX
1496#else
1497#define TAG_MAPPER_FIRST_XXX TAG_MAPPER_FIRST_FOUR
1498#endif
1499
1500 // Only pay attention to tags this code knows how to decode.
1501 switch(pDecodedItem->uTagBits & TAG_MAPPER_FIRST_XXX) {
1502 case 0:
1503 // No tags at all or none we know about. Nothing to do.
1504 // This is the pass-through path of this function
1505 // that will mostly be taken when decoding any item.
1506 break;
1507
1508 case QCBOR_TAGFLAG_DATE_STRING:
1509 nReturn = DecodeDateString(pDecodedItem);
1510 break;
1511
1512 case QCBOR_TAGFLAG_DATE_EPOCH:
1513 nReturn = DecodeDateEpoch(pDecodedItem);
1514 break;
1515
1516 case QCBOR_TAGFLAG_POS_BIGNUM:
1517 case QCBOR_TAGFLAG_NEG_BIGNUM:
1518 nReturn = DecodeBigNum(pDecodedItem);
1519 break;
1520
1521#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
1522 case QCBOR_TAGFLAG_DECIMAL_FRACTION:
1523 case QCBOR_TAGFLAG_BIGFLOAT:
1524 // For aggregate tagged types, what goes into pTags is only collected
1525 // from the surrounding data item, not the contents, so pTags is not
1526 // passed on here.
1527
1528 nReturn = QCBORDecode_MantissaAndExponent(me, pDecodedItem);
1529 break;
1530#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
1531
1532 default:
1533 // Encountering some mixed-up CBOR like something that
1534 // is tagged as both a string and integer date.
1535 nReturn = QCBOR_ERR_BAD_OPT_TAG;
1536 }
1537
1538Done:
1539 if(nReturn != QCBOR_SUCCESS) {
1540 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
1541 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
1542 }
1543 return nReturn;
1544}
1545
1546
1547/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001548 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08001549 */
Laurence Lundblade30816f22018-11-10 13:40:22 +07001550QCBORError QCBORDecode_GetNext(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001551{
1552 return QCBORDecode_GetNextWithTags(me, pDecodedItem, NULL);
1553}
1554
1555
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001556/*
Laurence Lundblade6de37062018-10-15 12:22:42 +05301557 Decoding items is done in 5 layered functions, one calling the
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301558 next one down. If a layer has no work to do for a particular item
1559 it returns quickly.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001560
Laurence Lundblade59289e52019-12-30 13:44:37 -08001561 - QCBORDecode_GetNext, GetNextWithTags -- The top layer processes
1562 tagged data items, turning them into the local C representation.
1563 For the most simple it is just associating a QCBOR_TYPE with the data. For
1564 the complex ones that an aggregate of data items, there is some further
1565 decoding and a little bit of recursion.
1566
1567 - QCBORDecode_GetNextMapOrArray - This manages the beginnings and
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301568 ends of maps and arrays. It tracks descending into and ascending
Laurence Lundblade6de37062018-10-15 12:22:42 +05301569 out of maps/arrays. It processes all breaks that terminate
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001570 indefinite length maps and arrays.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001571
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301572 - GetNext_MapEntry -- This handles the combining of two
1573 items, the label and the data, that make up a map entry.
1574 It only does work on maps. It combines the label and data
1575 items into one labeled item.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001576
Laurence Lundblade59289e52019-12-30 13:44:37 -08001577 - GetNext_TaggedItem -- This decodes type 6 tagging. It turns the
1578 tags into bit flags associated with the data item. No actual decoding
1579 of the contents of the tagged item is performed here.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001580
Laurence Lundblade59289e52019-12-30 13:44:37 -08001581 - GetNext_FullItem -- This assembles the sub-items that make up
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301582 an indefinte length string into one string item. It uses the
Laurence Lundblade6de37062018-10-15 12:22:42 +05301583 string allocater to create contiguous space for the item. It
1584 processes all breaks that are part of indefinite length strings.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001585
Laurence Lundblade59289e52019-12-30 13:44:37 -08001586 - GetNext_Item -- This decodes the atomic data items in CBOR. Each
1587 atomic data item has a "major type", an integer "argument" and optionally
1588 some content. For text and byte strings, the content is the bytes
1589 that make up the string. These are the smallest data items that are
1590 considered to be well-formed. The content may also be other data items in
1591 the case of aggregate types. They are not handled in this layer.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001592
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001593 Roughly this takes 300 bytes of stack for vars. Need to
1594 evaluate this more carefully and correctly.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001595
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301596 */
1597
1598
1599/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001600 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001601 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001602int QCBORDecode_IsTagged(QCBORDecodeContext *me,
1603 const QCBORItem *pItem,
1604 uint64_t uTag)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001605{
1606 const QCBORTagListIn *pCallerConfiguredTagMap = me->pCallerConfiguredTagList;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001607
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001608 uint8_t uTagBitIndex;
1609 // Do not care about errors in pCallerConfiguredTagMap here. They are
1610 // caught during GetNext() before this is called.
1611 if(TagMapper_Lookup(pCallerConfiguredTagMap, uTag, &uTagBitIndex)) {
1612 return 0;
1613 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001614
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001615 const uint64_t uTagBit = 0x01ULL << uTagBitIndex;
1616 return (uTagBit & pItem->uTagBits) != 0;
1617}
1618
1619
1620/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001621 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001622 */
Laurence Lundblade30816f22018-11-10 13:40:22 +07001623QCBORError QCBORDecode_Finish(QCBORDecodeContext *me)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001624{
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001625 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001626
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001627 // Error out if all the maps/arrays are not closed out
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001628 if(!DecodeNesting_IsAtTop(&(me->nesting))) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001629 nReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
1630 goto Done;
1631 }
1632
1633 // Error out if not all the bytes are consumed
1634 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) {
1635 nReturn = QCBOR_ERR_EXTRA_BYTES;
1636 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001637
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001638Done:
Laurence Lundblade6de37062018-10-15 12:22:42 +05301639 // Call the destructor for the string allocator if there is one.
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001640 // Always called, even if there are errors; always have to clean up
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001641 StringAllocator_Destruct(&(me->StringAllocator));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001642
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001643 return nReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001644}
1645
1646
1647
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001648/*
1649
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001650Decoder errors handled in this file
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001651
Laurence Lundbladeee851742020-01-08 08:37:05 -08001652 - Hit end of input before it was expected while decoding type and
1653 number QCBOR_ERR_HIT_END
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001654
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001655 - negative integer that is too large for C QCBOR_ERR_INT_OVERFLOW
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001656
Laurence Lundbladeee851742020-01-08 08:37:05 -08001657 - Hit end of input while decoding a text or byte string
1658 QCBOR_ERR_HIT_END
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001659
Laurence Lundbladeee851742020-01-08 08:37:05 -08001660 - Encountered conflicting tags -- e.g., an item is tagged both a date
1661 string and an epoch date QCBOR_ERR_UNSUPPORTED
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001662
Laurence Lundbladeee851742020-01-08 08:37:05 -08001663 - Encontered an array or mapp that has too many items
1664 QCBOR_ERR_ARRAY_TOO_LONG
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001665
Laurence Lundbladeee851742020-01-08 08:37:05 -08001666 - Encountered array/map nesting that is too deep
1667 QCBOR_ERR_ARRAY_NESTING_TOO_DEEP
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001668
Laurence Lundbladeee851742020-01-08 08:37:05 -08001669 - An epoch date > INT64_MAX or < INT64_MIN was encountered
1670 QCBOR_ERR_DATE_OVERFLOW
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001671
Laurence Lundbladeee851742020-01-08 08:37:05 -08001672 - The type of a map label is not a string or int
1673 QCBOR_ERR_MAP_LABEL_TYPE
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001674
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001675 - Hit end with arrays or maps still open -- QCBOR_ERR_EXTRA_BYTES
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001676
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001677 */
1678
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001679
1680
Laurence Lundbladef6531662018-12-04 10:42:22 +09001681
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001682/* ===========================================================================
1683 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001684
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001685 This implements a simple sting allocator for indefinite length
1686 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
1687 implements the function type QCBORStringAllocate and allows easy
1688 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09001689
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001690 This particular allocator is built-in for convenience. The caller
1691 can implement their own. All of this following code will get
1692 dead-stripped if QCBORDecode_SetMemPool() is not called.
1693
1694 This is a very primitive memory allocator. It does not track
1695 individual allocations, only a high-water mark. A free or
1696 reallocation must be of the last chunk allocated.
1697
1698 The size of the pool and offset to free memory are packed into the
1699 first 8 bytes of the memory pool so we don't have to keep them in
1700 the decode context. Since the address of the pool may not be
1701 aligned, they have to be packed and unpacked as if they were
1702 serialized data of the wire or such.
1703
1704 The sizes packed in are uint32_t to be the same on all CPU types
1705 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08001706 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001707
1708
Laurence Lundbladeee851742020-01-08 08:37:05 -08001709static inline int
1710MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001711{
1712 // Use of UsefulInputBuf is overkill, but it is convenient.
1713 UsefulInputBuf UIB;
1714
Laurence Lundbladeee851742020-01-08 08:37:05 -08001715 // Just assume the size here. It was checked during SetUp so
1716 // the assumption is safe.
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001717 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem, QCBOR_DECODE_MIN_MEM_POOL_SIZE});
1718 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
1719 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
1720 return UsefulInputBuf_GetError(&UIB);
1721}
1722
1723
Laurence Lundbladeee851742020-01-08 08:37:05 -08001724static inline int
1725MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001726{
1727 // Use of UsefulOutBuf is overkill, but convenient. The
1728 // length check performed here is useful.
1729 UsefulOutBuf UOB;
1730
1731 UsefulOutBuf_Init(&UOB, Pool);
1732 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
1733 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
1734 return UsefulOutBuf_GetError(&UOB);
1735}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001736
1737
1738/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001739 Internal function for an allocation, reallocation free and destuct.
1740
1741 Having only one function rather than one each per mode saves space in
1742 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001743
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001744 Code Reviewers: THIS FUNCTION DOES POINTER MATH
1745 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001746static UsefulBuf
1747MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001748{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001749 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001750
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001751 uint32_t uPoolSize;
1752 uint32_t uFreeOffset;
1753
1754 if(uNewSize > UINT32_MAX) {
1755 // This allocator is only good up to 4GB. This check should
1756 // optimize out if sizeof(size_t) == sizeof(uint32_t)
1757 goto Done;
1758 }
1759 const uint32_t uNewSize32 = (uint32_t)uNewSize;
1760
1761 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
1762 goto Done;
1763 }
1764
1765 if(uNewSize) {
1766 if(pMem) {
1767 // REALLOCATION MODE
1768 // Calculate pointer to the end of the memory pool. It is
1769 // assumed that pPool + uPoolSize won't wrap around by
1770 // assuming the caller won't pass a pool buffer in that is
1771 // not in legitimate memory space.
1772 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
1773
1774 // Check that the pointer for reallocation is in the range of the
1775 // pool. This also makes sure that pointer math further down
1776 // doesn't wrap under or over.
1777 if(pMem >= pPool && pMem < pPoolEnd) {
1778 // Offset to start of chunk for reallocation. This won't
1779 // wrap under because of check that pMem >= pPool. Cast
1780 // is safe because the pool is always less than UINT32_MAX
1781 // because of check in QCBORDecode_SetMemPool().
1782 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
1783
1784 // Check to see if the allocation will fit. uPoolSize -
1785 // uMemOffset will not wrap under because of check that
1786 // pMem is in the range of the uPoolSize by check above.
1787 if(uNewSize <= uPoolSize - uMemOffset) {
1788 ReturnValue.ptr = pMem;
1789 ReturnValue.len = uNewSize;
1790
1791 // Addition won't wrap around over because uNewSize was
1792 // checked to be sure it is less than the pool size.
1793 uFreeOffset = uMemOffset + uNewSize32;
1794 }
1795 }
1796 } else {
1797 // ALLOCATION MODE
1798 // uPoolSize - uFreeOffset will not underflow because this
1799 // pool implementation makes sure uFreeOffset is always
1800 // smaller than uPoolSize through this check here and
1801 // reallocation case.
1802 if(uNewSize <= uPoolSize - uFreeOffset) {
1803 ReturnValue.len = uNewSize;
1804 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001805 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001806 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001807 }
1808 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001809 if(pMem) {
1810 // FREE MODE
1811 // Cast is safe because of limit on pool size in
1812 // QCBORDecode_SetMemPool()
1813 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
1814 } else {
1815 // DESTRUCT MODE
1816 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001817 }
1818 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001819
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001820 UsefulBuf Pool = {pPool, uPoolSize};
1821 MemPool_Pack(Pool, uFreeOffset);
1822
1823Done:
1824 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001825}
1826
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001827
Laurence Lundbladef6531662018-12-04 10:42:22 +09001828/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001829 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09001830 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001831QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
1832 UsefulBuf Pool,
1833 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001834{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001835 // The pool size and free mem offset are packed into the beginning
1836 // of the pool memory. This compile time check make sure the
1837 // constant in the header is correct. This check should optimize
1838 // down to nothing.
1839 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundblade30816f22018-11-10 13:40:22 +07001840 return QCBOR_ERR_BUFFER_TOO_SMALL;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001841 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001842
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001843 // The pool size and free offset packed in to the beginning of pool
1844 // memory are only 32-bits. This check will optimize out on 32-bit
1845 // machines.
1846 if(Pool.len > UINT32_MAX) {
1847 return QCBOR_ERR_BUFFER_TOO_LARGE;
1848 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001849
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001850 // This checks that the pool buffer given is big enough.
1851 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
1852 return QCBOR_ERR_BUFFER_TOO_SMALL;
1853 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001854
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001855 pMe->StringAllocator.pfAllocator = MemPool_Function;
1856 pMe->StringAllocator.pAllocateCxt = Pool.ptr;
1857 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001858
Laurence Lundblade30816f22018-11-10 13:40:22 +07001859 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001860}
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001861
Laurence Lundblade1341c592020-04-11 14:19:05 -07001862#include <stdio.h>
1863void printdecode(QCBORDecodeContext *pMe, const char *szName)
1864{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001865 printf("---%s--%d--%d--\nLevel Count Type Offset SaveCount MapMode\n",
1866 szName,
1867 (uint32_t)pMe->InBuf.cursor,
1868 (uint32_t)pMe->InBuf.UB.len);
1869/* for(int i = 0; i < QCBOR_MAX_ARRAY_NESTING; i++) {
1870 if(&(pMe->nesting.pMapsAndArrays[i]) > pMe->nesting.pCurrent) {
1871 break;
1872 }
1873 printf(" %2d %5d %s %6u %2d %d\n",
Laurence Lundblade1341c592020-04-11 14:19:05 -07001874 i,
1875 pMe->nesting.pMapsAndArrays[i].uCount,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001876 pMe->nesting.pMapsAndArrays[i].uMajorType == QCBOR_TYPE_MAP ? " map" :
1877 (pMe->nesting.pMapsAndArrays[i].uMajorType == QCBOR_TYPE_ARRAY ? "array" :
1878 (pMe->nesting.pMapsAndArrays[i].uMajorType == QCBOR_TYPE_NONE ? " none" : "?????")),
Laurence Lundblade1341c592020-04-11 14:19:05 -07001879 pMe->nesting.pMapsAndArrays[i].uOffset,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001880 pMe->nesting.pMapsAndArrays[i].uSaveCount,
1881 pMe->nesting.pMapsAndArrays[i].uMapMode
Laurence Lundblade1341c592020-04-11 14:19:05 -07001882 );
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001883
Laurence Lundblade1341c592020-04-11 14:19:05 -07001884 }
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001885 printf("\n"); */
Laurence Lundblade1341c592020-04-11 14:19:05 -07001886}
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001887
1888
1889/*
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001890 *
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001891 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001892static inline QCBORError
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001893ConsumeItem(QCBORDecodeContext *pMe,
1894 const QCBORItem *pItemToConsume,
1895 uint_fast8_t *puNextNestLevel)
1896{
Laurence Lundblade1341c592020-04-11 14:19:05 -07001897 QCBORError nReturn;
1898 QCBORItem Item;
1899
1900 printdecode(pMe, "ConsumeItem");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001901
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001902 if(IsMapOrArray(pItemToConsume->uDataType)) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07001903 /* There is only real work to do for maps and arrays */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001904
Laurence Lundblade1341c592020-04-11 14:19:05 -07001905 /* This works for definite and indefinite length
1906 * maps and arrays by using the nesting level
1907 */
1908 do {
1909 nReturn = QCBORDecode_GetNext(pMe, &Item);
1910 if(nReturn != QCBOR_SUCCESS) {
1911 goto Done;
1912 }
1913 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001914
Laurence Lundblade1341c592020-04-11 14:19:05 -07001915 if(puNextNestLevel != NULL) {
1916 *puNextNestLevel = Item.uNextNestLevel;
1917 }
1918 nReturn = QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001919
Laurence Lundblade1341c592020-04-11 14:19:05 -07001920 } else {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07001921 /* item_to_consume is not a map or array */
Laurence Lundblade1341c592020-04-11 14:19:05 -07001922 if(puNextNestLevel != NULL) {
1923 /* Just pass the nesting level through */
1924 *puNextNestLevel = pItemToConsume->uNextNestLevel;
1925 }
1926 nReturn = QCBOR_SUCCESS;
1927 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001928
1929Done:
1930 return nReturn;
1931}
1932
1933
Laurence Lundblade1341c592020-04-11 14:19:05 -07001934/* Return true if the labels in Item1 and Item2 are the same.
1935 Works only for integer and string labels. Returns false
1936 for any other type. */
1937static inline bool
1938MatchLabel(QCBORItem Item1, QCBORItem Item2)
1939{
1940 if(Item1.uLabelType == QCBOR_TYPE_INT64) {
1941 if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
1942 return true;
1943 }
1944 } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07001945 if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07001946 return true;
1947 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07001948 } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07001949 if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
1950 return true;
1951 }
1952 } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
1953 if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
1954 return true;
1955 }
1956 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07001957
Laurence Lundblade1341c592020-04-11 14:19:05 -07001958 /* Other label types are never matched */
1959 return false;
1960}
1961
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07001962static inline bool
1963MatchType(QCBORItem Item1, QCBORItem Item2)
1964{
1965 if(Item1.uDataType == Item2.uDataType) {
1966 return true;
1967 } else if(Item1.uLabelType == QCBOR_TYPE_ANY) {
1968 return true;
1969 } else if(Item2.uLabelType == QCBOR_TYPE_ANY) {
1970 return true;
1971 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07001972 return false;
1973}
1974
1975
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001976/*
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07001977 On input pItemArray contains a list of labels and data types
1978 of items to be found.
1979
1980 On output the fully retrieved items are filled in with
1981 values and such. The label was matched, so it never changes.
1982
1983 If an item was not found, its data type is set to none.
1984
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001985 */
1986QCBORError
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001987GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemArray, size_t *puOffset, size_t *puEndOffset)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07001988{
Laurence Lundblade1341c592020-04-11 14:19:05 -07001989 QCBORError nReturn;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07001990
1991 // 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 -07001992 if(!DecodeNesting_InMapMode(&(pMe->nesting))) {
1993 return QCBOR_ERR_NOT_ENTERED;
Laurence Lundblade1341c592020-04-11 14:19:05 -07001994 }
1995
Laurence Lundblade1341c592020-04-11 14:19:05 -07001996 QCBORDecodeNesting N = pMe->nesting;
1997
1998 if(pMe->nesting.pCurrent->uCount != UINT16_MAX) {
1999 pMe->nesting.pCurrent->uCount = pMe->nesting.pCurrent->uSaveCount;
2000 }
2001
2002 UsefulInputBuf_Seek(&(pMe->InBuf), pMe->nesting.pCurrent->uOffset);
2003
2004 /* Loop over all the items in the map. They could be
2005 * deeply nested and this should handle both definite
2006 * and indefinite length maps and arrays, so this
2007 * adds some complexity. */
2008 const uint8_t uMapNestLevel = DecodeNesting_GetLevel(&(pMe->nesting));
2009
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002010 uint_fast8_t uNextNestLevel;
2011
2012 uint64_t uFound = 0;
2013
2014 do {
2015 /* Remember offset because sometims we have to return it */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002016 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002017
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002018 /* Get the item */
2019 QCBORItem Item;
2020 nReturn = QCBORDecode_GetNext(pMe, &Item);
2021 if(nReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002022 /* Got non-well-formed CBOR */
2023 goto Done;
2024 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002025
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002026 /* See if item has one of the labels that are of interest */
2027 int i;
2028 QCBORItem *pIterator;
2029 for(pIterator = pItemArray, i = 0; pIterator->uLabelType != 0; pIterator++, i++) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002030 if(MatchLabel(Item, *pIterator)) {
2031 // A label match has been found
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002032 if(uFound & (0x01ULL << i)) {
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002033 nReturn = QCBOR_ERR_DUPLICATE_LABEL;
2034 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002035 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002036 if(!MatchType(Item, *pIterator)) {
2037 nReturn = QCBOR_ERR_UNEXPECTED_TYPE;
2038 goto Done;
2039 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002040
2041 /* Successful match. Return the item. */
2042 *pIterator = Item;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002043 uFound |= 0x01ULL << i;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002044 if(puOffset) {
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002045 *puOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002046 }
2047 }
2048 }
2049
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002050 /* Consume the item whether matched or not. This
2051 does th work of traversing maps and array and
2052 everything in them. In this loop only the
2053 items at the current nesting level are examined
2054 to match the labels. */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002055 nReturn = ConsumeItem(pMe, &Item, &uNextNestLevel);
2056 if(nReturn) {
2057 goto Done;
2058 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002059
2060 } while (uNextNestLevel >= uMapNestLevel);
2061
2062
2063 nReturn = QCBOR_SUCCESS;
2064
2065 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
2066 // Cast OK because encoded CBOR is limited to UINT32_MAX
2067 pMe->uMapEndOffset = (uint32_t)uEndOffset;
2068 // TODO: is zero *puOffset OK?
2069 if(puEndOffset) {
2070 *puEndOffset = uEndOffset;
2071 }
2072
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002073 /* For all items not found, set the data type to QCBOR_TYPE_NONE */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002074 int i;
2075 QCBORItem *pIterator;
2076 for(pIterator = pItemArray, i = 0; pIterator->uLabelType != 0; pIterator++, i++) {
2077 if(!(uFound & (0x01ULL << i))) {
2078 pIterator->uDataType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002079 }
2080 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002081
2082Done:
Laurence Lundblade1341c592020-04-11 14:19:05 -07002083 pMe->nesting = N;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002084
Laurence Lundblade1341c592020-04-11 14:19:05 -07002085 return nReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002086}
2087
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002088
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002089void QCBORDecode_ExitMap(QCBORDecodeContext *pMe)
2090{
Laurence Lundblade1341c592020-04-11 14:19:05 -07002091 size_t uEndOffset;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002092
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002093/*
Laurence Lundblade1341c592020-04-11 14:19:05 -07002094 if(pMe->uMapEndOffset) {
2095 uEndOffset = pMe->uMapEndOffset;
2096 // It is only valid once.
2097 pMe->uMapEndOffset = 0;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002098 } else { */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002099 QCBORItem Dummy;
2100
2101 Dummy.uLabelType = QCBOR_TYPE_NONE;
2102
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002103 QCBORError nReturn = GetItemsInMap(pMe, &Dummy, NULL, &uEndOffset);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002104
2105 (void)nReturn; // TODO:
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002106// }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002107
2108 printdecode(pMe, "start exit");
2109 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
2110
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002111 DecodeNesting_Exit(&(pMe->nesting));
Laurence Lundblade1341c592020-04-11 14:19:05 -07002112 printdecode(pMe, "end exit");
2113
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002114}
2115
2116
2117QCBORError QCBORDecode_GetItemInMap(QCBORDecodeContext *pMe,
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002118 int64_t nLabel,
2119 uint8_t uQcborType,
2120 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002121{
Laurence Lundblade1341c592020-04-11 14:19:05 -07002122 QCBORItem One[2];
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002123
Laurence Lundblade1341c592020-04-11 14:19:05 -07002124 One[0].uLabelType = QCBOR_TYPE_INT64;
2125 One[0].label.int64 = nLabel;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002126 One[0].uDataType = uQcborType;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002127 One[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
2128
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002129 QCBORError nReturn = GetItemsInMap(pMe, One, NULL, NULL);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002130 if(nReturn) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002131 return nReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002132 }
2133
2134 if(One[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002135 return QCBOR_ERR_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002136 }
2137
2138 *pItem = One[0];
2139
2140 return QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002141}
2142
2143
2144QCBORError QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002145 const char *szLabel,
2146 uint8_t uQcborType,
2147 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002148{
Laurence Lundblade1341c592020-04-11 14:19:05 -07002149 QCBORItem One[2];
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002150
Laurence Lundblade1341c592020-04-11 14:19:05 -07002151 One[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2152 One[0].label.string = UsefulBuf_FromSZ(szLabel);
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002153 One[0].uDataType = uQcborType;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002154 One[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
2155
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002156 QCBORError nReturn = GetItemsInMap(pMe, One, NULL, NULL);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002157 if(nReturn) {
2158 return nReturn;
2159 }
2160
2161 if(One[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002162 return QCBOR_ERR_NOT_FOUND;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002163 }
2164
2165 *pItem = One[0];
2166
2167 return QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002168}
2169
2170
Laurence Lundblade1341c592020-04-11 14:19:05 -07002171
Laurence Lundblade1341c592020-04-11 14:19:05 -07002172
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002173static int FinishEnter(QCBORDecodeContext *pMe, size_t uOffset)
Laurence Lundblade1341c592020-04-11 14:19:05 -07002174{
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002175 /* Seek to the data item that is the map or array */
2176 UsefulInputBuf_Seek(&(pMe->InBuf), uOffset);
2177
2178 /* Skip the data item that is the map or array */
2179 QCBORItem MapToEnter;
2180 // TODO: check error
2181 QCBORDecode_GetNext(pMe, &MapToEnter);
2182
2183 /* Enter map mode with an offset that is the first item
2184 in the map or array. */
2185 // TODO: what if map or array is empty?
2186 DecodeNesting_EnterMapMode(&(pMe->nesting), UsefulInputBuf_Tell(&(pMe->InBuf)));
2187
2188
2189 printdecode(pMe, "Entered Map in Map");
2190
2191 return 0;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002192}
2193
2194
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002195QCBORError QCBORDecode_EnterMapInMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002196{
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002197 /* Use GetItemsInMap to find the map by label, including the
2198 byte offset of it. */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002199 QCBORItem One[2];
Laurence Lundblade1341c592020-04-11 14:19:05 -07002200 One[0].uLabelType = QCBOR_TYPE_INT64;
2201 One[0].label.int64 = nLabel;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002202 One[0].uDataType = QCBOR_TYPE_MAP;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002203 One[1].uLabelType = QCBOR_TYPE_NONE;
2204
2205 size_t uOffset;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002206 QCBORError nReturn = GetItemsInMap(pMe, One, &uOffset, NULL);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002207 if(nReturn) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002208 return nReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002209 }
2210
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002211 /* The map to enter was found, now finish of entering it. */
2212 FinishEnter(pMe, uOffset);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002213
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002214 // TODO: error code?
Laurence Lundblade1341c592020-04-11 14:19:05 -07002215 return 0;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002216}
2217
2218
2219QCBORError QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
2220{
2221 QCBORItem One[2];
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002222
Laurence Lundblade1341c592020-04-11 14:19:05 -07002223 One[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2224 One[0].label.string = UsefulBuf_FromSZ(szLabel);
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002225 One[0].uDataType = QCBOR_TYPE_MAP;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002226 One[1].uLabelType = QCBOR_TYPE_NONE;
2227
2228 size_t uOffset;
2229
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002230 QCBORError nReturn = GetItemsInMap(pMe, One, &uOffset, NULL);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002231
2232 if(nReturn) {
2233 return nReturn;
2234 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002235
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002236 FinishEnter(pMe, uOffset);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002237
2238 return 0;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002239}
2240
2241
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002242QCBORError QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002243{
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002244 QCBORItem One[2];
2245
2246 One[0].uLabelType = QCBOR_TYPE_INT64;
2247 One[0].label.int64 = nLabel;
2248 One[0].uDataType = QCBOR_TYPE_ARRAY;
2249 One[1].uLabelType = QCBOR_TYPE_NONE;
2250
2251 size_t uOffset;
2252
2253 QCBORError nReturn = GetItemsInMap(pMe, One, &uOffset, NULL);
2254
2255 if(nReturn != QCBOR_SUCCESS) {
2256 return nReturn;
2257 }
2258
2259 FinishEnter(pMe, uOffset);
2260
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002261 return 0;
2262}
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002263
Laurence Lundblade1341c592020-04-11 14:19:05 -07002264
2265QCBORError QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
2266{
2267 QCBORItem One[2];
2268
2269 One[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2270 One[0].label.string = UsefulBuf_FromSZ(szLabel);
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002271 One[0].uDataType = QCBOR_TYPE_ARRAY;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002272 One[1].uLabelType = QCBOR_TYPE_NONE;
2273
2274 size_t uOffset;
2275
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002276 QCBORError nReturn = GetItemsInMap(pMe, One, &uOffset, NULL);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002277
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002278 if(nReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002279 return nReturn;
2280 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002281
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002282 FinishEnter(pMe, uOffset);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002283
2284 return 0;
2285}
2286
2287
2288
2289
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002290
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002291/* Next item must be map or this generates an error */
2292QCBORError QCBORDecode_EnterMap(QCBORDecodeContext *pMe)
2293{
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002294 QCBORItem Item;
2295 QCBORError nReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002296
2297 /* Get the data item that is the map that is being searched */
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002298 nReturn = QCBORDecode_GetNext(pMe, &Item);
2299 if(nReturn != QCBOR_SUCCESS) {
2300 return nReturn;
2301 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002302 if(Item.uDataType != QCBOR_TYPE_MAP) {
2303 return QCBOR_ERR_UNEXPECTED_TYPE;
2304 }
2305
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002306 DecodeNesting_EnterMapMode(&(pMe->nesting), UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002307
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002308 printdecode(pMe, "EnterMapDone");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002309
Laurence Lundblade1341c592020-04-11 14:19:05 -07002310 return QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002311}
2312
2313
2314
2315QCBORError QCBORDecode_GetItemsInMap(QCBORDecodeContext *pCtx, QCBORItem *pItemList)
2316{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002317 return GetItemsInMap(pCtx, pItemList, NULL, NULL);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002318}
2319
2320
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002321
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002322
2323
Laurence Lundblade1341c592020-04-11 14:19:05 -07002324void QCBORDecode_RewindMap(QCBORDecodeContext *pMe)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002325{
Laurence Lundblade1341c592020-04-11 14:19:05 -07002326 // TODO: check for map mode
2327 pMe->nesting.pCurrent->uCount = pMe->nesting.pCurrent->uSaveCount;
2328 UsefulInputBuf_Seek(&(pMe->InBuf), pMe->nesting.pCurrent->uOffset);
2329}
2330
2331
2332QCBORError QCBORDecode_EnterArray(QCBORDecodeContext *pMe)
2333{
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002334 QCBORItem Item;
2335 QCBORError nReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002336
2337 /* Get the data item that is the map that is being searched */
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07002338 nReturn = QCBORDecode_GetNext(pMe, &Item);
2339 if(nReturn != QCBOR_SUCCESS) {
2340 return nReturn;
2341 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07002342 if(Item.uDataType != QCBOR_TYPE_ARRAY) {
2343 return QCBOR_ERR_UNEXPECTED_TYPE;
2344 }
2345
2346 printdecode(pMe, "EnterArray");
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002347
2348 DecodeNesting_EnterMapMode(&(pMe->nesting), UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundblade1341c592020-04-11 14:19:05 -07002349
2350 return QCBOR_SUCCESS;
2351}
2352
2353
2354void QCBORDecode_ExitArray(QCBORDecodeContext *pMe)
2355{
2356 // TODO: make sure we have entered an array
2357 // TODO: combine with code for map? It is the same so far.
2358 size_t uEndOffset;
2359
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002360 /* if(pMe->uMapEndOffset) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002361 uEndOffset = pMe->uMapEndOffset;
2362 // It is only valid once.
2363 pMe->uMapEndOffset = 0;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002364 } else {*/
Laurence Lundblade1341c592020-04-11 14:19:05 -07002365 QCBORItem Dummy;
2366
2367 Dummy.uLabelType = QCBOR_TYPE_NONE;
2368
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002369 QCBORError nReturn = GetItemsInMap(pMe, &Dummy, NULL, &uEndOffset);
Laurence Lundblade1341c592020-04-11 14:19:05 -07002370
2371 (void)nReturn; // TODO:
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002372 //}
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002373
Laurence Lundblade1341c592020-04-11 14:19:05 -07002374 printdecode(pMe, "start exit");
2375 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
2376
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002377 DecodeNesting_Exit(&(pMe->nesting));
Laurence Lundblade1341c592020-04-11 14:19:05 -07002378 printdecode(pMe, "end exit");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002379}
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002380
Laurence Lundbladee6430642020-03-14 21:15:44 -07002381
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002382void QCBORDecode_GetIntInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, int64_t *pInt)
2383{
2384 // TODO: error handling
2385 QCBORItem Item;
2386 QCBORDecode_GetItemInMapSZ(pMe,szLabel, QCBOR_TYPE_INT64, &Item);
2387 *pInt = Item.val.int64;
2388}
2389
2390void QCBORDecode_GetBstrInMapN(QCBORDecodeContext *pMe, int64_t nLabel, UsefulBufC *pBstr)
2391{
2392 // TODO: error handling
2393 QCBORItem Item;
2394 QCBORDecode_GetItemInMap(pMe, nLabel, QCBOR_TYPE_BYTE_STRING, &Item);
2395 *pBstr = Item.val.string;
2396}
2397
2398void QCBORDecode_GetBstrInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, UsefulBufC *pBstr)
2399{
2400 // TODO: error handling
2401 QCBORItem Item;
2402 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_BYTE_STRING, &Item);
2403 *pBstr = Item.val.string;
2404}
2405
2406void QCBORDecode_GetTextInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, UsefulBufC *pBstr)
2407{
2408 // TODO: error handling
2409 QCBORItem Item;
2410 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_TEXT_STRING, &Item);
2411 *pBstr = Item.val.string;
2412}
2413
Laurence Lundbladee6430642020-03-14 21:15:44 -07002414
Laurence Lundbladec4537442020-04-14 18:53:22 -07002415void QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002416{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002417 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002418 // Already in error state, do nothing
Laurence Lundbladee6430642020-03-14 21:15:44 -07002419 return;
2420 }
2421
Laurence Lundbladec4537442020-04-14 18:53:22 -07002422 QCBORError nError;
2423 QCBORItem Item;
2424
2425 nError = QCBORDecode_GetNext(pMe, &Item);
2426 if(nError != QCBOR_SUCCESS) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002427 pMe->uLastError = (uint8_t)nError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002428 return;
2429 }
Laurence Lundbladee6430642020-03-14 21:15:44 -07002430
2431 switch(Item.uDataType) {
2432 case QCBOR_TYPE_TRUE:
2433 *pValue = true;
2434 break;
2435
2436 case QCBOR_TYPE_FALSE:
2437 *pValue = false;
2438 break;
2439
2440 default:
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002441 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002442 break;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002443 }
2444}
2445
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002446#if 0
2447// TODO: fix this
Laurence Lundbladee6430642020-03-14 21:15:44 -07002448/* Types of text strings
2449 * Plain, b64, b64url, URI, regex, MIME Text
2450 * One function for each with options to expect plain?
2451 * One function for all so you can say what you want?
Laurence Lundbladec4537442020-04-14 18:53:22 -07002452 *
2453 * A label is expected if pLabel is not NULL.
Laurence Lundbladee6430642020-03-14 21:15:44 -07002454 */
Laurence Lundbladec4537442020-04-14 18:53:22 -07002455void QCBORDecode_GetTextFoo(QCBORDecodeContext *pMe, QCBORLabel *pLabel, UsefulBufC *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002456{
2457 QCBORItem Item;
2458 QCBORError nError;
2459
2460 nError = QCBORDecode_GetNext(pMe, &Item);
2461 if(nError) {
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002462 pMe->uLastError = nError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002463 return;
2464 }
2465
Laurence Lundbladec4537442020-04-14 18:53:22 -07002466 if(pLabel != NULL) {
2467 if(Item.uLabelType == QCBOR_TYPE_NONE) {
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002468 pMe->uLastError = 9; // TODO: error code
Laurence Lundbladec4537442020-04-14 18:53:22 -07002469 return;
2470 } else {
2471 // TODO: what about label allocation?
2472 pLabel->uLabelType = Item.uLabelType;
2473 pLabel->label.xx = Item.label.int64; // TOOD: figure out assignment
2474 }
2475 }
Laurence Lundbladee6430642020-03-14 21:15:44 -07002476
2477 switch(Item.uDataType) {
2478 case QCBOR_TYPE_TEXT_STRING:
2479 *pValue = Item.val.string;
2480 break;
2481
2482 default:
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002483 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002484 }
2485}
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002486#endif
Laurence Lundbladee6430642020-03-14 21:15:44 -07002487
2488
Laurence Lundbladec4537442020-04-14 18:53:22 -07002489/*
2490 Options for MIME data, CBOR, positive big num, negative big num ??
2491 */
2492void QCBORDecode_GetStringInternal(QCBORDecodeContext *pMe, UsefulBufC *pValue, uint8_t uType)
2493{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002494 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002495 // Already in error state, do nothing
2496 return;
2497 }
2498
2499 QCBORError nError;
2500 QCBORItem Item;
2501
2502 nError = QCBORDecode_GetNext(pMe, &Item);
2503 if(nError != QCBOR_SUCCESS) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002504 pMe->uLastError = (uint8_t)nError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002505 return;
2506 }
2507
2508 if(Item.uDataType == uType) {
2509 *pValue = Item.val.string;
2510 } else {
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002511 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002512 }
2513}
2514
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002515void QCBORDecode_GetBytes(QCBORDecodeContext *pMe, UsefulBufC *pValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002516{
2517 QCBORDecode_GetStringInternal(pMe, pValue, QCBOR_TYPE_BYTE_STRING);
2518}
2519
2520
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002521void QCBORDecode_GetText(QCBORDecodeContext *pMe, UsefulBufC *pValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002522{
2523 QCBORDecode_GetStringInternal(pMe, pValue, QCBOR_TYPE_TEXT_STRING);
2524}
2525
2526
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002527void QCBORDecode_GetPosBignum(QCBORDecodeContext *pMe, UsefulBufC *pValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002528{
2529 // TODO: do these have to be tagged?
2530 // Probably should allow tagged or untagged, but not wrong-tagged
2531 QCBORDecode_GetStringInternal(pMe, pValue, QCBOR_TYPE_POSBIGNUM);
2532}
2533
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002534void QCBORDecode_GetNegBignum(QCBORDecodeContext *pMe, UsefulBufC *pValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002535{
2536 QCBORDecode_GetStringInternal(pMe, pValue, QCBOR_TYPE_NEGBIGNUM);
2537}
2538
2539
2540
Laurence Lundbladee6430642020-03-14 21:15:44 -07002541
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002542typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002543
2544
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002545// The main exponentiator that works on only positive numbers
2546static QCBORError Exponentitate10UU(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07002547{
2548 uint64_t uResult;
2549
2550 uResult = uMantissa;
2551
2552 /* This loop will run a maximum of 19 times because
2553 * UINT64_MAX < 10 ^^ 19. More than that will cause
2554 * exit with the overflow error
2555 */
2556 while(nExponent > 0) {
2557 if(uResult > UINT64_MAX / 10) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002558 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Error overflow
Laurence Lundbladec4537442020-04-14 18:53:22 -07002559 }
2560 uResult = uResult * 10;
2561 nExponent--;
2562 }
2563
2564 while(nExponent < 0 ) {
2565 if(uResult == 0) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002566 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Underflow error
Laurence Lundbladec4537442020-04-14 18:53:22 -07002567 }
2568 uResult = uResult / 10;
2569 nExponent--;
2570 }
2571
2572 *puResult = uResult;
2573
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002574 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002575}
2576
2577
Laurence Lundbladee6430642020-03-14 21:15:44 -07002578/* Convert a decimal fraction to an int64_t without using
2579 floating point or math libraries. Most decimal fractions
2580 will not fit in an int64_t and this will error out with
2581 under or overflow
2582 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002583static QCBORError Exponentitate2UU(uint64_t nMantissa, int64_t nExponent, uint64_t *pnResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002584{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002585 uint64_t nResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002586
2587 nResult = nMantissa;
2588
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002589 /* This loop will run a maximum of 64 times because
Laurence Lundbladee6430642020-03-14 21:15:44 -07002590 * INT64_MAX < 2^31. More than that will cause
2591 * exist with the overflow error
2592 */
2593 while(nExponent > 0) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002594 if(nResult > UINT64_MAX >> 1) {
2595 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Error overflow
Laurence Lundbladee6430642020-03-14 21:15:44 -07002596 }
2597 nResult = nResult << 1;
2598 nExponent--;
2599 }
2600
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002601 while(nExponent < 0 ) {
2602 if(nResult == 0) {
2603 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Underflow error
2604 }
2605 nResult = nResult >> 1;
2606 nExponent--;
2607 }
2608
Laurence Lundbladee6430642020-03-14 21:15:44 -07002609 *pnResult = nResult;
2610
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002611 return QCBOR_SUCCESS;
2612}
2613
2614
2615static inline QCBORError ExponentiateNN(int64_t nMantissa, int64_t nExponent, int64_t *pnResult, fExponentiator pfExp)
2616{
2617 uint64_t uResult;
2618
2619 // Take the absolute value of the mantissa
2620 uint64_t uMantissa = nMantissa > 0 ? (uint64_t)nMantissa : (uint64_t)-nMantissa;
2621
2622 // Do the exponentiation of the positive mantissa
2623 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
2624 if(uReturn) {
2625 return uReturn;
2626 }
2627
2628 // Error out if too large on the plus side for an int64_t
2629 if(uResult > INT64_MAX) {
2630 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
2631 }
2632
2633 // Error out if too large on the negative side for an int64_t
2634 if(uResult < (uint64_t)INT64_MAX+1) {
2635 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
2636 of INT64_MIN. This assumes two's compliment representation where
2637 INT64_MIN is one increment farther from 0 than INT64_MAX.
2638 Trying to write -INT64_MIN doesn't work to get this because the
2639 compiler tries to work with an int64_t which can't represent
2640 -INT64_MIN.
2641 */
2642 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
2643 }
2644
2645 // Casts are safe because of checks above
2646 *pnResult = nMantissa > 0 ? (int64_t)uResult : -(int64_t)uResult;
2647
2648 return QCBOR_SUCCESS;
2649}
2650
2651
2652static inline QCBORError ExponentitateNU(int64_t nMantissa, int64_t nExponent, uint64_t *puResult, fExponentiator pfExp)
2653{
2654 if(nMantissa < 0) {
2655 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
2656 }
2657
2658 // Cast to unsigned is OK because of check for negative
2659 // Cast to unsigned is OK because UINT64_MAX > INT64_MAX
2660 // Exponentiation is straight forward
2661 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
2662}
2663
2664
2665// TODO: use this or get rid of it
2666QCBORError ExponentitateUN(uint64_t uMantissa, int64_t nExponent, int64_t *pnResult, fExponentiator pfExp)
2667{
2668 uint64_t uResult;
2669
2670 QCBORError uR;
2671
2672 uR = (*pfExp)(uMantissa, nExponent, &uResult);
2673 if(uR) {
2674 return uR;
2675 }
2676
2677 if(uResult > INT64_MAX) {
2678 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
2679 }
2680
2681 // Cast is OK because of check above
2682 *pnResult = (int64_t)uResult;
2683
2684 return QCBOR_SUCCESS;
2685}
2686
2687
2688
2689
2690#include <math.h>
2691/*
2692static inline uint8_t Exponentitate10F(uint64_t uMantissa, int64_t nExponent, double *pfResult)
2693{
2694 // TODO: checkout exceptions; what is HUGE_VAL?
2695 *pfResult = pow((double)10, (double)nExponent) * (double)uMantissa;
2696
2697 //if(*pfResult == HUGE_VAL)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002698 return 0;
2699}
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002700*/
2701
2702
2703
2704
2705
Laurence Lundbladee6430642020-03-14 21:15:44 -07002706
2707/*
2708 A) bignum is positive
2709 A1) output is signed INT64_MAX
2710 A2) output is unsigned UINT64_MAX
2711 B) bignum is negative
2712 B1) output is signed INT64_MAX
2713 B2) output is unsigned error
2714 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002715static inline QCBORError ConvertBigNum(const UsefulBufC BigNum, uint64_t uMax, uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002716{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002717 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002718
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002719 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002720 const uint8_t *pByte = BigNum.ptr;
2721 size_t uLen = BigNum.len;
2722 while(uLen--) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002723 if(uResult > uMax >> 8) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002724 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002725 }
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002726 uResult = (uResult << 8) + *pByte;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002727 }
2728
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002729 *pResult = uResult;
2730 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002731}
2732
Laurence Lundbladec4537442020-04-14 18:53:22 -07002733
Laurence Lundbladec4537442020-04-14 18:53:22 -07002734
Laurence Lundbladea826c502020-05-10 21:07:00 -07002735static double ConvertBigNumToDouble(const UsefulBufC BigNum)
2736{
2737 double dResult;
2738
2739 dResult = 0.0;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002740 const uint8_t *pByte = BigNum.ptr;
2741 size_t uLen = BigNum.len;
2742 /* This will overflow and become the float value INFINITY if the number
2743 is too large to fit. No error will be logged.
2744 TODO: should an error be logged? */
2745 while(uLen--) {
Laurence Lundbladea826c502020-05-10 21:07:00 -07002746 dResult = (dResult * 256.0) + *pByte;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002747 }
2748
Laurence Lundbladea826c502020-05-10 21:07:00 -07002749 return dResult;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002750}
Laurence Lundbladea826c502020-05-10 21:07:00 -07002751
2752
Laurence Lundbladec4537442020-04-14 18:53:22 -07002753
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002754static inline QCBORError ConvertPositiveBigNumToUnSigned(const UsefulBufC BigNum, uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002755{
2756 return ConvertBigNum(BigNum, UINT64_MAX, pResult);
2757}
2758
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002759static inline QCBORError ConvertPositiveBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002760{
2761 uint64_t uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002762 QCBORError n = ConvertBigNum(BigNum, INT64_MAX, &uResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002763 if(n) {
2764 return n;
2765 }
2766 /* Cast is safe because ConvertBigNum is told to limit to INT64_MAX */
2767 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002768 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002769}
2770
2771
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002772static inline QCBORError ConvertNegativeBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002773{
2774 uint64_t uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002775 QCBORError n = ConvertBigNum(BigNum, INT64_MAX-1, &uResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002776 if(n) {
2777 return n;
2778 }
2779 /* Cast is safe because ConvertBigNum is told to limit to INT64_MAX */
2780 *pResult = -(int64_t)uResult;
2781 return 0;
2782}
2783
Laurence Lundbladec4537442020-04-14 18:53:22 -07002784// No function to convert a negative bignum to unsigned; it is an error
2785
2786
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002787#if 0
2788static inline int ConvertXYZ(const UsefulBufC Mantissa, int64_t nExponent, int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002789{
2790 int64_t nMantissa;
2791
2792 int xx = ConvertPositiveBigNumToSigned(Mantissa, &nMantissa);
2793 if(xx) {
2794 return xx;
2795 }
2796
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002797 return ExponentiateNN(nMantissa, nExponent, pResult, &Exponentitate10UU);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002798}
2799
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002800#endif
Laurence Lundbladee6430642020-03-14 21:15:44 -07002801
2802
Laurence Lundbladee6430642020-03-14 21:15:44 -07002803
Laurence Lundbladec4537442020-04-14 18:53:22 -07002804
2805/*
2806 Get the next item as an int64_t. The CBOR type can be unsigned, negative, float
2807 a big float, a decimal fraction or a big num. Conversion will be dones as
2808 expected. Some cases will error out with under or over flow.
2809 */
Laurence Lundbladea826c502020-05-10 21:07:00 -07002810static void QCBORDecode_GetInt64ConvertInternal(QCBORDecodeContext *pMe, uint32_t uOptions, int64_t *pValue, QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07002811{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002812 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002813 return;
2814 }
2815
Laurence Lundbladee6430642020-03-14 21:15:44 -07002816 QCBORItem Item;
2817 QCBORError nError;
2818
2819 nError = QCBORDecode_GetNext(pMe, &Item);
2820 if(nError) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002821 pMe->uLastError = (uint8_t)nError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002822 return;
2823 }
2824
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002825 if(pItem) {
2826 *pItem = Item;
2827 }
2828
Laurence Lundbladee6430642020-03-14 21:15:44 -07002829 switch(Item.uDataType) {
2830 case QCBOR_TYPE_FLOAT:
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002831 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07002832 // TODO: what about under/overflow here?
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002833 // Invokes the floating-point HW and/or compiler-added libraries
Laurence Lundbladea826c502020-05-10 21:07:00 -07002834 *pValue = llround(Item.val.dfnum);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002835 } else {
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002836 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002837 }
2838 break;
2839
2840 case QCBOR_TYPE_INT64:
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002841 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
Laurence Lundbladee6430642020-03-14 21:15:44 -07002842 *pValue = Item.val.int64;
2843 } else {
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002844 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002845 }
2846 break;
2847
2848 case QCBOR_TYPE_UINT64:
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002849 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
Laurence Lundbladee6430642020-03-14 21:15:44 -07002850 if(Item.val.uint64 < INT64_MAX) {
2851 *pValue = Item.val.int64;
2852 } else {
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002853 pMe->uLastError = QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002854 }
2855 } else {
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002856 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002857 }
2858 break;
2859
Laurence Lundbladec4537442020-04-14 18:53:22 -07002860 default:
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002861 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladec4537442020-04-14 18:53:22 -07002862 }
2863}
2864
Laurence Lundbladea826c502020-05-10 21:07:00 -07002865/* This works for signed, unsigned and float data items */
Laurence Lundbladec4537442020-04-14 18:53:22 -07002866void QCBORDecode_GetInt64Convert(QCBORDecodeContext *pMe, uint32_t uOptions, int64_t *pValue)
2867{
2868 QCBORItem Item;
2869 QCBORDecode_GetInt64ConvertInternal(pMe, uOptions, pValue, &Item);
2870}
2871
2872
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002873// TODO make this inline
2874void QCBORDecode_GetInt64(QCBORDecodeContext *pMe, uint32_t uOptions, int64_t *pValue)
2875{
2876 QCBORDecode_GetInt64Convert(pMe, QCBOR_TYPE_INT64, pValue);
2877}
2878
2879
Laurence Lundbladec4537442020-04-14 18:53:22 -07002880
2881/*
2882 Get the next item as an int64_t. The CBOR type can be unsigned, negative, float
2883 a big float, a decimal fraction or a big num. Conversion will be dones as
2884 expected. Some cases will error out with under or over flow.
2885 */
2886void QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, int64_t *pValue)
2887{
2888 QCBORItem Item;
2889
2890 QCBORDecode_GetInt64ConvertInternal(pMe, uOptions, pValue, &Item);
2891
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002892 if(pMe->uLastError == QCBOR_SUCCESS) {
2893 // The above conversion succeeded
2894 return;
2895 }
2896
2897 if(pMe->uLastError != QCBOR_SUCCESS && pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
2898 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07002899 return;
2900 }
2901
2902 switch(Item.uDataType) {
Laurence Lundbladee6430642020-03-14 21:15:44 -07002903
2904 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002905 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002906 pMe->uLastError = (uint8_t)ConvertPositiveBigNumToSigned(Item.val.bigNum, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002907 } else {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002908 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002909 }
2910 break;
2911
2912 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002913 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002914 pMe->uLastError = (uint8_t)ConvertNegativeBigNumToSigned(Item.val.bigNum, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002915 } else {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002916 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002917 }
2918 break;
2919
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002920#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
2921 case QCBOR_TYPE_DECIMAL_FRACTION:
2922 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002923 pMe->uLastError = (uint8_t)ExponentiateNN(Item.val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002924 Item.val.expAndMantissa.nExponent,
2925 pValue,
2926 &Exponentitate10UU);
2927 } else {
2928 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
2929 }
2930 break;
2931
2932 case QCBOR_TYPE_BIGFLOAT:
2933 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002934 pMe->uLastError = (uint8_t)ExponentiateNN(Item.val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002935 Item.val.expAndMantissa.nExponent,
2936 pValue,
2937 &Exponentitate2UU);
2938 } else {
2939 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
2940 }
2941 break;
2942
2943
Laurence Lundbladee6430642020-03-14 21:15:44 -07002944 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002945 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladee6430642020-03-14 21:15:44 -07002946 int64_t nMantissa;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002947 pMe->uLastError = (uint8_t)ConvertPositiveBigNumToSigned(Item.val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002948 if(!pMe->uLastError) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002949 pMe->uLastError = (uint8_t)ExponentiateNN(nMantissa,
Laurence Lundbladee6430642020-03-14 21:15:44 -07002950 Item.val.expAndMantissa.nExponent,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002951 pValue,
2952 &Exponentitate10UU);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002953 }
2954 } else {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002955 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002956 }
2957 break;
2958
2959 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002960 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladee6430642020-03-14 21:15:44 -07002961 int64_t nMantissa;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002962 pMe->uLastError = (uint8_t)ConvertNegativeBigNumToSigned(Item.val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002963 if(!pMe->uLastError) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002964 pMe->uLastError = (uint8_t)ExponentiateNN(nMantissa,
Laurence Lundbladee6430642020-03-14 21:15:44 -07002965 Item.val.expAndMantissa.nExponent,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002966 pValue,
2967 Exponentitate10UU);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002968 }
2969 } else {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002970 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002971 }
2972 break;
2973
2974 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002975 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladee6430642020-03-14 21:15:44 -07002976 int64_t nMantissa;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002977 pMe->uLastError = (uint8_t)ConvertPositiveBigNumToSigned(Item.val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002978 if(!pMe->uLastError) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002979 pMe->uLastError = (uint8_t)ExponentiateNN(nMantissa,
Laurence Lundbladee6430642020-03-14 21:15:44 -07002980 Item.val.expAndMantissa.nExponent,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002981 pValue,
2982 Exponentitate2UU);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002983 }
2984 } else {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002985 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07002986 }
2987 break;
2988
2989 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002990 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladee6430642020-03-14 21:15:44 -07002991 int64_t nMantissa;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002992 pMe->uLastError = (uint8_t)ConvertNegativeBigNumToSigned(Item.val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07002993 if(!pMe->uLastError) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002994 pMe->uLastError = (uint8_t)ExponentiateNN(nMantissa,
Laurence Lundbladee6430642020-03-14 21:15:44 -07002995 Item.val.expAndMantissa.nExponent,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002996 pValue,
2997 Exponentitate2UU);
Laurence Lundbladee6430642020-03-14 21:15:44 -07002998 }
2999 } else {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003000 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003001 }
3002 break;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003003
3004 default:
3005 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
3006#endif
Laurence Lundbladee6430642020-03-14 21:15:44 -07003007 }
3008}
3009
Laurence Lundbladec4537442020-04-14 18:53:22 -07003010
3011
3012void QCBORDecode_GetUInt64ConvertInternal(QCBORDecodeContext *pMe, uint32_t uOptions, uint64_t *pValue, QCBORItem *pItem)
3013{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003014 if(pMe->uLastError != QCBOR_SUCCESS) {
3015 return;
3016 }
3017
Laurence Lundbladec4537442020-04-14 18:53:22 -07003018 QCBORItem Item;
3019 QCBORError nError;
3020
3021 nError = QCBORDecode_GetNext(pMe, &Item);
3022 if(nError) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003023 pMe->uLastError = (uint8_t)nError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003024 return;
3025 }
3026
Laurence Lundbladea826c502020-05-10 21:07:00 -07003027 if(pItem) {
3028 *pItem = Item;
3029 }
3030
Laurence Lundbladec4537442020-04-14 18:53:22 -07003031 switch(Item.uDataType) {
3032 case QCBOR_TYPE_FLOAT:
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003033 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003034 if(Item.val.dfnum >= 0) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003035 // TODO: over/underflow
Laurence Lundbladea826c502020-05-10 21:07:00 -07003036 // TODO: find a rounding function
3037 *pValue = (uint64_t)round(Item.val.dfnum);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003038 } else {
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07003039 pMe->uLastError = QCBOR_ERR_NUMBER_SIGN_CONVERSION;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003040 }
3041 } else {
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07003042 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003043 }
3044 break;
3045
3046 case QCBOR_TYPE_INT64:
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003047 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003048 if(Item.val.int64 >= 0) {
3049 *pValue = (uint64_t)Item.val.int64;
3050 } else {
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07003051 pMe->uLastError = QCBOR_ERR_NUMBER_SIGN_CONVERSION;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003052 }
3053 } else {
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07003054 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003055 }
3056 break;
3057
3058 case QCBOR_TYPE_UINT64:
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003059 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003060 *pValue = Item.val.uint64;
3061 } else {
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07003062 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003063 }
3064 break;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003065
3066 default:
3067 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003068 }
3069}
3070
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003071
3072/* This works for signed, unsigned and float */
3073void QCBORDecode_GetUInt64Convert(QCBORDecodeContext *pMe, uint32_t uOptions, uint64_t *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003074{
3075 QCBORItem Item;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003076 QCBORDecode_GetUInt64ConvertInternal(pMe, uOptions, pValue, &Item);
3077}
Laurence Lundbladee6430642020-03-14 21:15:44 -07003078
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003079
3080// TODO make this inline
3081void QCBORDecode_GetUInt64(QCBORDecodeContext *pMe, uint32_t uOptions, uint64_t *pValue)
3082{
3083 QCBORDecode_GetUInt64Convert(pMe, QCBOR_TYPE_UINT64, pValue);
3084}
3085
3086
3087
3088
3089void QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, uint64_t *pValue)
3090{
3091 QCBORItem Item;
3092
3093 QCBORDecode_GetUInt64ConvertInternal(pMe, uOptions, pValue, &Item);
3094
3095 if(pMe->uLastError != QCBOR_SUCCESS && pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundbladee6430642020-03-14 21:15:44 -07003096 return;
3097 }
3098
Laurence Lundbladee6430642020-03-14 21:15:44 -07003099 switch(Item.uDataType) {
Laurence Lundbladee6430642020-03-14 21:15:44 -07003100
3101 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003102 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003103 pMe->uLastError = (uint8_t)ConvertPositiveBigNumToUnSigned(Item.val.bigNum, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003104 } else {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003105 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003106 }
3107 break;
3108
3109 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003110 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003111 pMe->uLastError = (uint8_t)ConvertPositiveBigNumToUnSigned(Item.val.bigNum, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003112 } else {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003113 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003114 }
3115 break;
3116
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003117#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
3118
3119 case QCBOR_TYPE_DECIMAL_FRACTION:
3120 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003121 pMe->uLastError = (uint8_t)ExponentitateNU(Item.val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003122 Item.val.expAndMantissa.nExponent,
3123 pValue,
3124 Exponentitate10UU);
3125 } else {
3126 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED; // TODO: error code
3127 }
3128 break;
3129
3130 case QCBOR_TYPE_BIGFLOAT:
3131 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003132 pMe->uLastError = (uint8_t)ExponentitateNU(Item.val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003133 Item.val.expAndMantissa.nExponent,
3134 pValue,
3135 Exponentitate2UU);
3136 } else {
3137 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED; // TODO: error code
3138 }
3139 break;
3140
3141
3142
Laurence Lundbladee6430642020-03-14 21:15:44 -07003143 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003144 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladee6430642020-03-14 21:15:44 -07003145 int64_t nMantissa;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003146 pMe->uLastError = (uint8_t)ConvertPositiveBigNumToSigned(Item.val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07003147 if(!pMe->uLastError) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003148 pMe->uLastError = (uint8_t)ExponentitateNU(nMantissa,
Laurence Lundbladee6430642020-03-14 21:15:44 -07003149 Item.val.expAndMantissa.nExponent,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003150 pValue,
3151 Exponentitate10UU);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003152 }
3153 } else {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003154 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED; // TODO: error code
Laurence Lundbladee6430642020-03-14 21:15:44 -07003155 }
3156 break;
3157
3158 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003159 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladee6430642020-03-14 21:15:44 -07003160 int64_t nMantissa;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003161 pMe->uLastError = (uint8_t)ConvertNegativeBigNumToSigned(Item.val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07003162 if(!pMe->uLastError) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003163 pMe->uLastError = (uint8_t)ExponentitateNU(nMantissa,
Laurence Lundbladee6430642020-03-14 21:15:44 -07003164 Item.val.expAndMantissa.nExponent,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003165 pValue,
3166 Exponentitate10UU);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003167 }
3168 } else {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003169 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED; // TODO: error code
Laurence Lundbladee6430642020-03-14 21:15:44 -07003170 }
3171 break;
3172
3173 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003174 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladee6430642020-03-14 21:15:44 -07003175 int64_t nMantissa;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003176 pMe->uLastError = (uint8_t)ConvertPositiveBigNumToSigned(Item.val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07003177 if(!pMe->uLastError) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003178 pMe->uLastError = (uint8_t)ExponentitateNU(nMantissa,
Laurence Lundbladee6430642020-03-14 21:15:44 -07003179 Item.val.expAndMantissa.nExponent,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003180 pValue,
3181 Exponentitate2UU);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003182 }
3183 } else {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003184 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED; // TODO: error code
Laurence Lundbladee6430642020-03-14 21:15:44 -07003185 }
3186 break;
3187
3188 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003189 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladee6430642020-03-14 21:15:44 -07003190 int64_t nMantissa;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003191 pMe->uLastError = (uint8_t)ConvertNegativeBigNumToSigned(Item.val.expAndMantissa.Mantissa.bigNum, &nMantissa);
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07003192 if(!pMe->uLastError) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003193 pMe->uLastError = (uint8_t)ExponentitateNU(nMantissa,
Laurence Lundbladee6430642020-03-14 21:15:44 -07003194 Item.val.expAndMantissa.nExponent,
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003195 pValue,
3196 Exponentitate2UU);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003197 }
3198 } else {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003199 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003200 }
3201 break;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003202#endif
3203 default:
3204 pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003205 }
3206}
3207
Laurence Lundbladec4537442020-04-14 18:53:22 -07003208
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003209
Laurence Lundbladec4537442020-04-14 18:53:22 -07003210/*
3211
3212 Convert from bignums,
3213
Laurence Lundbladea826c502020-05-10 21:07:00 -07003214 https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
3215
Laurence Lundbladec4537442020-04-14 18:53:22 -07003216 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003217void QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe, uint32_t uOptions, double *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003218{
3219 /* the same range of conversions */
3220
Laurence Lundbladec4537442020-04-14 18:53:22 -07003221 QCBORItem Item;
3222 QCBORError nError;
3223
3224 nError = QCBORDecode_GetNext(pMe, &Item);
3225 if(nError) {
Laurence Lundbladea826c502020-05-10 21:07:00 -07003226 pMe->uLastError = (uint8_t)nError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003227 return;
3228 }
3229
Laurence Lundbladec4537442020-04-14 18:53:22 -07003230
3231 switch(Item.uDataType) {
3232 case QCBOR_TYPE_FLOAT:
Laurence Lundbladea826c502020-05-10 21:07:00 -07003233 if(uOptions & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003234 *pValue = Item.val.dfnum;
3235 } else {
Laurence Lundbladea826c502020-05-10 21:07:00 -07003236 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003237 }
3238 break;
3239
3240 case QCBOR_TYPE_INT64:
Laurence Lundbladea826c502020-05-10 21:07:00 -07003241 if(uOptions & QCBOR_CONVERT_TYPE_INT64) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003242 // TODO: how does this work?
3243 *pValue = (double)Item.val.int64;
3244 } else {
Laurence Lundbladea826c502020-05-10 21:07:00 -07003245 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003246 }
3247 break;
3248
3249 case QCBOR_TYPE_UINT64:
Laurence Lundbladea826c502020-05-10 21:07:00 -07003250 if(uOptions & QCBOR_CONVERT_TYPE_UINT64) {
3251 // TODO: check more carefully how this cast works.
Laurence Lundbladec4537442020-04-14 18:53:22 -07003252 *pValue = (double)Item.val.uint64;
3253 } else {
Laurence Lundbladea826c502020-05-10 21:07:00 -07003254 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003255 }
Laurence Lundbladea826c502020-05-10 21:07:00 -07003256
Laurence Lundbladec4537442020-04-14 18:53:22 -07003257
3258 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundbladea826c502020-05-10 21:07:00 -07003259 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3260 // TODO: rounding and overflow errors
3261 *pValue = (double)Item.val.expAndMantissa.Mantissa.nInt *
3262 pow(10.0, (double)Item.val.expAndMantissa.nExponent);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003263 } else {
Laurence Lundbladea826c502020-05-10 21:07:00 -07003264 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003265 }
3266 break;
3267
3268 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundbladea826c502020-05-10 21:07:00 -07003269 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
3270 *pValue = (double)Item.val.expAndMantissa.Mantissa.nInt *
3271 exp2((double)Item.val.expAndMantissa.nExponent);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003272 } else {
Laurence Lundbladea826c502020-05-10 21:07:00 -07003273 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003274 }
3275 break;
3276
3277 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundbladea826c502020-05-10 21:07:00 -07003278 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3279 *pValue = ConvertBigNumToDouble(Item.val.bigNum);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003280 } else {
Laurence Lundbladea826c502020-05-10 21:07:00 -07003281 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003282 }
3283 break;
3284
3285 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundbladea826c502020-05-10 21:07:00 -07003286 if(uOptions & QCBOR_CONVERT_TYPE_BIG_NUM) {
3287 *pValue = -ConvertBigNumToDouble(Item.val.bigNum);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003288 } else {
Laurence Lundbladea826c502020-05-10 21:07:00 -07003289 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003290 }
3291 break;
3292
3293 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundbladea826c502020-05-10 21:07:00 -07003294 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3295 double dMantissa = ConvertBigNumToDouble(Item.val.expAndMantissa.Mantissa.bigNum);
3296 *pValue = dMantissa * pow(10, (double)Item.val.expAndMantissa.nExponent);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003297 } else {
Laurence Lundbladea826c502020-05-10 21:07:00 -07003298 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003299 }
3300 break;
3301
3302 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundbladea826c502020-05-10 21:07:00 -07003303 if(uOptions & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
3304 double dMantissa = -ConvertBigNumToDouble(Item.val.expAndMantissa.Mantissa.bigNum);
3305 *pValue = dMantissa * pow(10, (double)Item.val.expAndMantissa.nExponent);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003306 } else {
Laurence Lundbladea826c502020-05-10 21:07:00 -07003307 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003308 }
3309 break;
3310
3311 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundbladea826c502020-05-10 21:07:00 -07003312 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3313 double dMantissa = ConvertBigNumToDouble(Item.val.expAndMantissa.Mantissa.bigNum);
3314 *pValue = dMantissa * exp2((double)Item.val.expAndMantissa.nExponent);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003315 } else {
Laurence Lundbladea826c502020-05-10 21:07:00 -07003316 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003317 }
3318 break;
3319
3320 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundbladea826c502020-05-10 21:07:00 -07003321 if(uOptions & QCBOR_CONVERT_TYPE_BIGFLOAT) {
3322 double dMantissa = -ConvertBigNumToDouble(Item.val.expAndMantissa.Mantissa.bigNum);
3323 *pValue = dMantissa * exp2((double)Item.val.expAndMantissa.nExponent);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003324 } else {
Laurence Lundbladea826c502020-05-10 21:07:00 -07003325 pMe->uLastError = QCBOR_ERR_CONVERSION_NOT_REQUESTED;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003326 }
3327 break;
3328 }
Laurence Lundbladee6430642020-03-14 21:15:44 -07003329}
3330