blob: a3edc6a1c6ec125774cadfaa680ab44dc836bcd3 [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 Lundblade67257dc2020-07-27 03:33:37 -070035#include "qcbor/qcbor_spiffy_decode.h"
Laurence Lundbladec7114722020-08-13 05:11:40 -070036#include "ieee754.h" // Does not use math.h
37
38#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade323f8a92020-09-06 19:43:09 -070039#include <math.h> // For isnan(), llround(), llroudf(), round(), roundf(),
40 // pow(), exp2()
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -070041#include <fenv.h> // feclearexcept(), fetestexcept()
Laurence Lundbladec7114722020-08-13 05:11:40 -070042#endif
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070043
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070044
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +053045/*
46 This casts away the const-ness of a pointer, usually so it can be
47 freed or realloced.
48 */
49#define UNCONST_POINTER(ptr) ((void *)(ptr))
50
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070051
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070052
Laurence Lundblade02625d42020-06-25 14:41:41 -070053inline static bool
54// TODO: add more tests for QCBOR_TYPE_MAP_AS_ARRAY mode in qcbor_decode_tests.c
55QCBORItem_IsMapOrArray(const QCBORItem *pMe)
56{
57 const uint8_t uDataType = pMe->uDataType;
58 return uDataType == QCBOR_TYPE_MAP ||
59 uDataType == QCBOR_TYPE_ARRAY ||
60 uDataType == QCBOR_TYPE_MAP_AS_ARRAY;
61}
62
63inline static bool
64QCBORItem_IsEmptyDefiniteLengthMapOrArray(const QCBORItem *pMe)
65{
66 if(!QCBORItem_IsMapOrArray(pMe)){
67 return false;
68 }
69
70 if(pMe->val.uCount != 0) {
71 return false;
72 }
73 return true;
74}
75
76inline static bool
77QCBORItem_IsIndefiniteLengthMapOrArray(const QCBORItem *pMe)
78{
79 if(!QCBORItem_IsMapOrArray(pMe)){
80 return false;
81 }
82
83 if(pMe->val.uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
84 return false;
85 }
86 return true;
87}
88
89
Laurence Lundbladeee851742020-01-08 08:37:05 -080090/*===========================================================================
Laurence Lundbladea8edadb2020-06-27 22:35:37 -070091 DecodeNesting -- Tracking array/map/sequence/bstr-wrapped nesting
Laurence Lundbladeee851742020-01-08 08:37:05 -080092 ===========================================================================*/
93
Laurence Lundblade9c905e82020-04-25 11:31:38 -070094/*
Laurence Lundbladea8edadb2020-06-27 22:35:37 -070095 See commecnts about and typedef of QCBORDecodeNesting in qcbor_private.h, the data structure
96 all these functions work on.
Laurence Lundblade9c905e82020-04-25 11:31:38 -070097
Laurence Lundblade9c905e82020-04-25 11:31:38 -070098
Laurence Lundblade9c905e82020-04-25 11:31:38 -070099
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700100 */
101
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700102
103inline static uint8_t
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700104DecodeNesting_GetCurrentLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700105{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700106 const ptrdiff_t nLevel = pNesting->pCurrent - &(pNesting->pLevels[0]);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700107 /*
108 Limit in DecodeNesting_Descend against more than
109 QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
110 */
Laurence Lundblade5e87da62020-06-07 03:24:28 -0700111 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700112}
113
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700114
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700115inline static uint8_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700116DecodeNesting_GetBoundedModeLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700117{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700118 const ptrdiff_t nLevel = pNesting->pCurrentBounded - &(pNesting->pLevels[0]);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700119 /*
120 Limit in DecodeNesting_Descend against more than
121 QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
122 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700123 return (uint8_t)nLevel;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700124}
125
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700126
Laurence Lundblade5f4e8712020-07-25 11:44:43 -0700127static inline uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700128DecodeNesting_GetMapOrArrayStart(const QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700129{
130 return pNesting->pCurrentBounded->u.ma.uStartOffset;
131}
132
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700133
Laurence Lundblade085d7952020-07-24 10:26:30 -0700134static inline bool
135DecodeNesting_IsBoundedEmpty(const QCBORDecodeNesting *pNesting)
136{
137 if(pNesting->pCurrentBounded->u.ma.uCountCursor == QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
138 return true;
139 } else {
140 return false;
141 }
142}
143
144
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700145inline static bool
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700146DecodeNesting_IsCurrentAtTop(const QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700147{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700148 if(pNesting->pCurrent == &(pNesting->pLevels[0])) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700149 return true;
150 } else {
151 return false;
152 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700153}
154
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700155
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700156inline static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700157DecodeNesting_IsCurrentDefiniteLength(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700158{
159 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700160 // Not a map or array
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700161 return false;
162 }
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700163 if(pNesting->pCurrent->u.ma.uCountTotal == QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700164 // Is indefinite
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700165 return false;
166 }
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700167 // All checks passed; is a definte length map or array
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700168 return true;
169}
170
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700171
Laurence Lundblade642282a2020-06-23 12:00:33 -0700172inline static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700173DecodeNesting_IsCurrentBstrWrapped(const QCBORDecodeNesting *pNesting)
Laurence Lundblade642282a2020-06-23 12:00:33 -0700174{
175 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700176 // is a byte string
Laurence Lundblade642282a2020-06-23 12:00:33 -0700177 return true;
178 }
179 return false;
180}
181
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700182
Laurence Lundblade6c8a4442020-06-22 22:16:11 -0700183inline static bool DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700184{
185 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
186 return true;
187 }
Laurence Lundblade02625d42020-06-25 14:41:41 -0700188 if(pNesting->pCurrent->u.ma.uStartOffset != QCBOR_NON_BOUNDED_OFFSET) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700189 return true;
190 }
191 return false;
192}
193
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700194
Laurence Lundblade085d7952020-07-24 10:26:30 -0700195inline static void DecodeNesting_SetMapOrArrayBoundedMode(QCBORDecodeNesting *pNesting, bool bIsEmpty, size_t uStart)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700196{
197 // Should be only called on maps and arrays
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700198 /*
199 DecodeNesting_EnterBoundedMode() checks to be sure uStart is not
200 larger than DecodeNesting_EnterBoundedMode which keeps it less than
201 uin32_t so the cast is safe.
202 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700203 pNesting->pCurrent->u.ma.uStartOffset = (uint32_t)uStart;
Laurence Lundblade085d7952020-07-24 10:26:30 -0700204
205 if(bIsEmpty) {
206 pNesting->pCurrent->u.ma.uCountCursor = QCBOR_COUNT_INDICATES_ZERO_LENGTH;
207 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700208}
209
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700210
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700211inline static void DecodeNesting_ClearBoundedMode(QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700212{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700213 pNesting->pCurrent->u.ma.uStartOffset = QCBOR_NON_BOUNDED_OFFSET;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700214}
215
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700216
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700217inline static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700218DecodeNesting_IsAtEndOfBoundedLevel(const QCBORDecodeNesting *pNesting)
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700219{
220 if(pNesting->pCurrentBounded == NULL) {
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700221 // No bounded map or array or... set up
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700222 return false;
223 }
224 if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700225 // Not a map or array; end of those is by byte count */
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700226 return false;
227 }
228 if(!DecodeNesting_IsCurrentBounded(pNesting)) { // TODO: pCurrent vs pCurrentBounded
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700229 // Not at a bounded level
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700230 return false;
231 }
Laurence Lundbladed0304932020-06-27 10:59:38 -0700232 // Works for both definite and indefinite length maps/arrays
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700233 if(pNesting->pCurrentBounded->u.ma.uCountCursor != 0) {
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700234 // Count is not zero, still unconsumed item
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700235 return false;
236 }
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700237 // All checks passed, got to the end of a map/array
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700238 return true;
239}
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700240
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700241
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700242inline static bool
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700243DecodeNesting_IsEndOfDefiniteLengthMapOrArray(const QCBORDecodeNesting *pNesting)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700244{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700245 // Must only be called on map / array
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700246 if(pNesting->pCurrent->u.ma.uCountCursor == 0) {
247 return true;
Laurence Lundblade9c905e82020-04-25 11:31:38 -0700248 } else {
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700249 return false;
250 }
Laurence Lundblade3f9ef042020-04-14 13:15:51 -0700251}
252
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700253
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700254inline static bool
255DecodeNesting_IsCurrentTypeMap(const QCBORDecodeNesting *pNesting)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700256{
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700257 if(pNesting->pCurrent->uLevelType == CBOR_MAJOR_TYPE_MAP) {
258 return true;
259 } else {
260 return false;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700261 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700262}
263
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700264
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700265inline static bool
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700266DecodeNesting_IsBoundedType(const QCBORDecodeNesting *pNesting, uint8_t uType)
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700267{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700268 if(pNesting->pCurrentBounded == NULL) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700269 return false;
270 }
Laurence Lundblade02625d42020-06-25 14:41:41 -0700271
272 if(pNesting->pCurrentBounded->uLevelType != uType) {
273 return false;
274 }
275
276 return true;
Laurence Lundblade2b843b52020-06-16 20:51:03 -0700277}
278
Laurence Lundblade02625d42020-06-25 14:41:41 -0700279
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700280inline static void
Laurence Lundblade6c8a4442020-06-22 22:16:11 -0700281DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700282{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700283 // Only call on a defnite length array / map
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700284 pNesting->pCurrent->u.ma.uCountCursor--;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -0700285}
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700286
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700287
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700288inline static void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700289DecodeNesting_ReverseDecrement(QCBORDecodeNesting *pNesting)
290{
291 // Only call on a defnite length array / map
292 pNesting->pCurrent->u.ma.uCountCursor++;
293}
294
295
296inline static void
Laurence Lundblade0a042a92020-06-12 14:09:50 -0700297DecodeNesting_Ascend(QCBORDecodeNesting *pNesting)
298{
299 pNesting->pCurrent--;
300}
301
Laurence Lundblade02625d42020-06-25 14:41:41 -0700302
303static QCBORError
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700304DecodeNesting_Descend(QCBORDecodeNesting *pNesting, uint8_t uType)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700305{
306 // Error out if nesting is too deep
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700307 if(pNesting->pCurrent >= &(pNesting->pLevels[QCBOR_MAX_ARRAY_NESTING])) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700308 return QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
309 }
310
311 // The actual descend
312 pNesting->pCurrent++;
313
314 pNesting->pCurrent->uLevelType = uType;
315
316 return QCBOR_SUCCESS;
317}
318
319
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700320inline static QCBORError
Laurence Lundblade085d7952020-07-24 10:26:30 -0700321DecodeNesting_EnterBoundedMapOrArray(QCBORDecodeNesting *pNesting, bool bIsEmpty, size_t uOffset)
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700322{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700323 /*
324 Should only be called on map/array.
325
326 Have descended into this before this is called. The job here is
327 just to mark it in bounded mode.
328 */
Laurence Lundblade287b25c2020-08-06 13:48:42 -0700329 if(uOffset >= QCBOR_NON_BOUNDED_OFFSET) {
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700330 return QCBOR_ERR_BUFFER_TOO_LARGE;
331 }
332
Laurence Lundblade0750fc42020-06-20 21:02:34 -0700333 pNesting->pCurrentBounded = pNesting->pCurrent;
Laurence Lundblade085d7952020-07-24 10:26:30 -0700334
335 DecodeNesting_SetMapOrArrayBoundedMode(pNesting, bIsEmpty, uOffset);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -0700336
337 return QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -0700338}
339
Laurence Lundblade64b607e2020-05-13 13:05:57 -0700340
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700341inline static QCBORError
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700342DecodeNesting_DescendMapOrArray(QCBORDecodeNesting *pNesting,
Laurence Lundblade02625d42020-06-25 14:41:41 -0700343 uint8_t uQCBORType,
344 uint64_t uCount)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700345{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700346 QCBORError uError = QCBOR_SUCCESS;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700347
348 if(uCount == 0) {
349 // Nothing to do for empty definite lenth arrays. They are just are
350 // effectively the same as an item that is not a map or array
351 goto Done;
352 // Empty indefinite length maps and arrays are handled elsewhere
353 }
354
355 // Error out if arrays is too long to handle
Laurence Lundblade02625d42020-06-25 14:41:41 -0700356 if(uCount != QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH &&
357 uCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
358 uError = QCBOR_ERR_ARRAY_TOO_LONG;
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700359 goto Done;
360 }
361
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700362 uError = DecodeNesting_Descend(pNesting, uQCBORType);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700363 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700364 goto Done;
365 }
366
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700367 // Fill in the new map/array level. Check above makes casts OK.
Laurence Lundblade6c8a4442020-06-22 22:16:11 -0700368 pNesting->pCurrent->u.ma.uCountCursor = (uint16_t)uCount;
369 pNesting->pCurrent->u.ma.uCountTotal = (uint16_t)uCount;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700370
371 DecodeNesting_ClearBoundedMode(pNesting);
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700372
373Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700374 return uError;;
375}
376
377
378static inline void
379DecodeNesting_LevelUpCurrent(QCBORDecodeNesting *pNesting)
380{
381 pNesting->pCurrent = pNesting->pCurrentBounded - 1;
382}
383
384
385static inline void
386DecodeNesting_LevelUpBounded(QCBORDecodeNesting *pNesting)
387{
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700388 while(pNesting->pCurrentBounded != &(pNesting->pLevels[0])) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700389 pNesting->pCurrentBounded--;
390 if(DecodeNesting_IsCurrentBounded(pNesting)) {
391 break;
392 }
393 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700394}
395
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700396static inline void
397DecodeNesting_SetCurrentToBoundedLevel(QCBORDecodeNesting *pNesting)
398{
399 pNesting->pCurrent = pNesting->pCurrentBounded;
400}
401
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700402
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700403inline static QCBORError
Laurence Lundblade02625d42020-06-25 14:41:41 -0700404DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting,
Laurence Lundbladef76a2622020-08-06 19:51:03 -0700405 uint32_t uEndOffset,
406 uint32_t uEndOfBstr)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700407{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700408 QCBORError uError = QCBOR_SUCCESS;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700409
Laurence Lundbladee6f15112020-07-23 18:44:16 -0700410 uError = DecodeNesting_Descend(pNesting, QCBOR_TYPE_BYTE_STRING);
Laurence Lundblade02625d42020-06-25 14:41:41 -0700411 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700412 goto Done;
413 }
414
Laurence Lundblade02625d42020-06-25 14:41:41 -0700415 // Fill in the new byte string level
Laurence Lundbladef76a2622020-08-06 19:51:03 -0700416 pNesting->pCurrent->u.bs.uPreviousEndOffset = uEndOffset;
417 pNesting->pCurrent->u.bs.uEndOfBstr = uEndOfBstr;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700418
Laurence Lundblade02625d42020-06-25 14:41:41 -0700419 // Bstr wrapped levels are always bounded
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700420 pNesting->pCurrentBounded = pNesting->pCurrent;
421
422Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -0700423 return uError;;
424}
425
Laurence Lundbladed0304932020-06-27 10:59:38 -0700426
427static inline void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700428DecodeNesting_ZeroMapOrArrayCount(QCBORDecodeNesting *pNesting)
Laurence Lundblade02625d42020-06-25 14:41:41 -0700429{
430 pNesting->pCurrent->u.ma.uCountCursor = 0;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700431}
432
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700433
Laurence Lundbladeee851742020-01-08 08:37:05 -0800434inline static void
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700435DecodeNesting_Init(QCBORDecodeNesting *pNesting)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700436{
Laurence Lundblade02625d42020-06-25 14:41:41 -0700437 /* Assumes that *pNesting has been zero'd before this call. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700438 pNesting->pLevels[0].uLevelType = QCBOR_TYPE_BYTE_STRING;
439 pNesting->pCurrent = &(pNesting->pLevels[0]);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700440}
441
442
Laurence Lundblade410c7e02020-06-25 23:35:29 -0700443inline static void
Laurence Lundblade02625d42020-06-25 14:41:41 -0700444DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting, QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700445{
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -0700446 *pSave = *pNesting;
Laurence Lundblade0750fc42020-06-20 21:02:34 -0700447 pNesting->pCurrent = pNesting->pCurrentBounded;
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700448 pNesting->pCurrent->u.ma.uCountCursor = pNesting->pCurrent->u.ma.uCountTotal;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700449}
450
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700451
Laurence Lundblade02625d42020-06-25 14:41:41 -0700452static inline void
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700453DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting, const QCBORDecodeNesting *pSave)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700454{
455 *pNesting = *pSave;
456}
457
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700458
Laurence Lundblade02625d42020-06-25 14:41:41 -0700459static inline uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700460DecodeNesting_GetEndOfBstr(const QCBORDecodeNesting *pMe)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700461{
462 return pMe->pCurrentBounded->u.bs.uEndOfBstr;
463}
464
465
Laurence Lundblade02625d42020-06-25 14:41:41 -0700466static inline uint32_t
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700467DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe)
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700468{
469 return pMe->pCurrentBounded->u.bs.uPreviousEndOffset;
470}
471
472
Laurence Lundblade02625d42020-06-25 14:41:41 -0700473#include <stdio.h>
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700474
475const char *TypeStr(uint8_t type)
476{
477 switch(type) {
478 case QCBOR_TYPE_MAP: return " map";
479 case QCBOR_TYPE_ARRAY: return "array";
480 case QCBOR_TYPE_BYTE_STRING: return " bstr";
481 default: return " --- ";
482 }
483}
484
485static char buf[20]; // Not thread safe, but that is OK
486const char *CountString(uint16_t uCount, uint16_t uTotal)
487{
488 if(uTotal == QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
489 strcpy(buf, "indefinite");
490 } else {
491 sprintf(buf, "%d/%d", uCount, uTotal);
492 }
493 return buf;
494}
495
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700496
Laurence Lundblade02625d42020-06-25 14:41:41 -0700497void DecodeNesting_Print(QCBORDecodeNesting *pNesting, UsefulInputBuf *pBuf, const char *szName)
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700498{
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -0700499#if 0
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700500 printf("---%s--%d/%d--\narrow is current bounded level\n",
Laurence Lundblade02625d42020-06-25 14:41:41 -0700501 szName,
502 (uint32_t)pBuf->cursor,
503 (uint32_t)pBuf->UB.len);
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700504
505 printf("Level Type Count Offsets \n");
Laurence Lundblade02625d42020-06-25 14:41:41 -0700506 for(int i = 0; i < QCBOR_MAX_ARRAY_NESTING; i++) {
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700507 if(&(pNesting->pLevels[i]) > pNesting->pCurrent) {
Laurence Lundblade02625d42020-06-25 14:41:41 -0700508 break;
509 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700510
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700511 printf("%2s %2d %s ",
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700512 pNesting->pCurrentBounded == &(pNesting->pLevels[i]) ? "->": " ",
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700513 i,
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700514 TypeStr(pNesting->pLevels[i].uLevelType));
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700515
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700516 if(pNesting->pLevels[i].uLevelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700517 printf(" %5d %5d",
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700518 pNesting->pLevels[i].u.bs.uEndOfBstr,
519 pNesting->pLevels[i].u.bs.uPreviousEndOffset);
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700520
521 } else {
522 printf("%10.10s ",
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700523 CountString(pNesting->pLevels[i].u.ma.uCountCursor,
524 pNesting->pLevels[i].u.ma.uCountTotal));
525 if(pNesting->pLevels[i].u.ma.uStartOffset != UINT32_MAX) {
526 printf("Bounded start: %u",pNesting->pLevels[i].u.ma.uStartOffset);
Laurence Lundblade2c1faf92020-06-26 22:43:56 -0700527 }
528 }
529
530 printf("\n");
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700531 }
Laurence Lundblade02625d42020-06-25 14:41:41 -0700532 printf("\n");
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -0700533#endif
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700534}
535
Laurence Lundbladeb340ba72020-05-14 11:41:10 -0700536
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700537
Laurence Lundbladeee851742020-01-08 08:37:05 -0800538/*===========================================================================
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800539 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
540
541 The following four functions are pretty wrappers for invocation of
542 the string allocator supplied by the caller.
543
Laurence Lundbladeee851742020-01-08 08:37:05 -0800544 ===========================================================================*/
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800545
Laurence Lundbladeee851742020-01-08 08:37:05 -0800546static inline void
547StringAllocator_Free(const QCORInternalAllocator *pMe, void *pMem)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800548{
549 (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, 0);
550}
551
Laurence Lundbladeee851742020-01-08 08:37:05 -0800552// StringAllocator_Reallocate called with pMem NULL is
553// equal to StringAllocator_Allocate()
554static inline UsefulBuf
555StringAllocator_Reallocate(const QCORInternalAllocator *pMe,
556 void *pMem,
557 size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800558{
559 return (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, uSize);
560}
561
Laurence Lundbladeee851742020-01-08 08:37:05 -0800562static inline UsefulBuf
563StringAllocator_Allocate(const QCORInternalAllocator *pMe, size_t uSize)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800564{
565 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
566}
567
Laurence Lundbladeee851742020-01-08 08:37:05 -0800568static inline void
569StringAllocator_Destruct(const QCORInternalAllocator *pMe)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800570{
571 if(pMe->pfAllocator) {
572 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
573 }
574}
575
576
577
Laurence Lundbladeee851742020-01-08 08:37:05 -0800578/*===========================================================================
579 QCBORDecode -- The main implementation of CBOR decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700580
Laurence Lundblade844bb5c2020-03-01 17:27:25 -0800581 See qcbor/qcbor_decode.h for definition of the object
582 used here: QCBORDecodeContext
Laurence Lundbladeee851742020-01-08 08:37:05 -0800583 ===========================================================================*/
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700584/*
585 Public function, see header file
586 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800587void QCBORDecode_Init(QCBORDecodeContext *me,
588 UsefulBufC EncodedCBOR,
589 QCBORDecodeMode nDecodeMode)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700590{
591 memset(me, 0, sizeof(QCBORDecodeContext));
592 UsefulInputBuf_Init(&(me->InBuf), EncodedCBOR);
Laurence Lundbladeee851742020-01-08 08:37:05 -0800593 // Don't bother with error check on decode mode. If a bad value is
594 // passed it will just act as if the default normal mode of 0 was set.
Laurence Lundbladee6bcef12020-04-01 10:56:27 -0700595 me->uDecodeMode = (uint8_t)nDecodeMode;
Laurence Lundblade1d85d522020-06-22 13:24:59 -0700596 DecodeNesting_Init(&(me->nesting));
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700597 for(int i = 0; i < QCBOR_NUM_MAPPED_TAGS; i++) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -0700598 me->auMappedTags[i] = CBOR_TAG_INVALID16;
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700599 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700600}
601
602
603/*
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700604 Public function, see header file
605 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800606void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
607 QCBORStringAllocate pfAllocateFunction,
608 void *pAllocateContext,
609 bool bAllStrings)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700610{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800611 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
612 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
613 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700614}
615
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800616
617/*
618 Public function, see header file
619 */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700620void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *pMe,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800621 const QCBORTagListIn *pTagList)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700622{
Laurence Lundblade830fbf92020-05-31 17:22:33 -0700623 // This does nothing now. It is retained for backwards compatibility
Laurence Lundbladea8edadb2020-06-27 22:35:37 -0700624 (void)pMe;
625 (void)pTagList;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700626}
627
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700628
629/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800630 This decodes the fundamental part of a CBOR data item, the type and
631 number
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800632
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700633 This is the Counterpart to InsertEncodedTypeAndNumber().
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800634
Laurence Lundbladeee851742020-01-08 08:37:05 -0800635 This does the network->host byte order conversion. The conversion
636 here also results in the conversion for floats in addition to that
637 for lengths, tags and integer values.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800638
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700639 This returns:
640 pnMajorType -- the major type for the item
Laurence Lundbladeee851742020-01-08 08:37:05 -0800641
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800642 puArgument -- the "number" which is used a the value for integers,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800643 tags and floats and length for strings and arrays
644
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800645 pnAdditionalInfo -- Pass this along to know what kind of float or
Laurence Lundbladeee851742020-01-08 08:37:05 -0800646 if length is indefinite
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800647
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800648 The int type is preferred to uint8_t for some variables as this
649 avoids integer promotions, can reduce code size and makes
650 static analyzers happier.
Laurence Lundblade9b334962020-08-27 10:55:53 -0700651
652 @retval QCBOR_ERR_UNSUPPORTED
653
654 @retval QCBOR_ERR_HIT_END
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700655 */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800656inline static QCBORError DecodeTypeAndNumber(UsefulInputBuf *pUInBuf,
657 int *pnMajorType,
658 uint64_t *puArgument,
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800659 int *pnAdditionalInfo)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700660{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700661 QCBORError nReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800662
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700663 // Get the initial byte that every CBOR data item has
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800664 const int nInitialByte = (int)UsefulInputBuf_GetByte(pUInBuf);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800665
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700666 // Break down the initial byte
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800667 const int nTmpMajorType = nInitialByte >> 5;
668 const int nAdditionalInfo = nInitialByte & 0x1f;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800669
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800670 // Where the number or argument accumulates
671 uint64_t uArgument;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800672
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800673 if(nAdditionalInfo >= LEN_IS_ONE_BYTE && nAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -0700674 // Need to get 1,2,4 or 8 additional argument bytes. Map
675 // LEN_IS_ONE_BYTE..LEN_IS_EIGHT_BYTES to actual length
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800676 static const uint8_t aIterate[] = {1,2,4,8};
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800677
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800678 // Loop getting all the bytes in the argument
679 uArgument = 0;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800680 for(int i = aIterate[nAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800681 // This shift and add gives the endian conversion
682 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
683 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800684 } else if(nAdditionalInfo >= ADDINFO_RESERVED1 && nAdditionalInfo <= ADDINFO_RESERVED3) {
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800685 // The reserved and thus-far unused additional info values
686 nReturn = QCBOR_ERR_UNSUPPORTED;
687 goto Done;
688 } else {
689 // Less than 24, additional info is argument or 31, an indefinite length
690 // No more bytes to get
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800691 uArgument = (uint64_t)nAdditionalInfo;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700692 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800693
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700694 if(UsefulInputBuf_GetError(pUInBuf)) {
695 nReturn = QCBOR_ERR_HIT_END;
696 goto Done;
697 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800698
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700699 // All successful if we got here.
700 nReturn = QCBOR_SUCCESS;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800701 *pnMajorType = nTmpMajorType;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800702 *puArgument = uArgument;
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800703 *pnAdditionalInfo = nAdditionalInfo;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800704
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700705Done:
706 return nReturn;
707}
708
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800709
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700710/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800711 CBOR doesn't explicitly specify two's compliment for integers but all
712 CPUs use it these days and the test vectors in the RFC are so. All
713 integers in the CBOR structure are positive and the major type
714 indicates positive or negative. CBOR can express positive integers
715 up to 2^x - 1 where x is the number of bits and negative integers
716 down to 2^x. Note that negative numbers can be one more away from
717 zero than positive. Stdint, as far as I can tell, uses two's
718 compliment to represent negative integers.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800719
Laurence Lundblade9b334962020-08-27 10:55:53 -0700720 See http://www.unix.org/whitepapers/64bit.html for reasons int is
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800721 used carefully here, and in particular why it isn't used in the interface.
722 Also see
723 https://stackoverflow.com/questions/17489857/why-is-int-typically-32-bit-on-64-bit-compilers
724
725 Int is used for values that need less than 16-bits and would be subject
726 to integer promotion and complaining by static analyzers.
Laurence Lundblade9b334962020-08-27 10:55:53 -0700727
728 @retval QCBOR_ERR_INT_OVERFLOW
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700729 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800730inline static QCBORError
731DecodeInteger(int nMajorType, uint64_t uNumber, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700732{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700733 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800734
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700735 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
736 if (uNumber <= INT64_MAX) {
737 pDecodedItem->val.int64 = (int64_t)uNumber;
738 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800739
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700740 } else {
741 pDecodedItem->val.uint64 = uNumber;
742 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800743
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700744 }
745 } else {
746 if(uNumber <= INT64_MAX) {
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800747 // CBOR's representation of negative numbers lines up with the
748 // two-compliment representation. A negative integer has one
749 // more in range than a positive integer. INT64_MIN is
750 // equal to (-INT64_MAX) - 1.
751 pDecodedItem->val.int64 = (-(int64_t)uNumber) - 1;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700752 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800753
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700754 } else {
755 // C can't represent a negative integer in this range
Laurence Lundblade21d1d812019-09-28 22:47:49 -1000756 // so it is an error.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700757 nReturn = QCBOR_ERR_INT_OVERFLOW;
758 }
759 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800760
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700761 return nReturn;
762}
763
764// Make sure #define value line up as DecodeSimple counts on this.
765#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
766#error QCBOR_TYPE_FALSE macro value wrong
767#endif
768
769#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
770#error QCBOR_TYPE_TRUE macro value wrong
771#endif
772
773#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
774#error QCBOR_TYPE_NULL macro value wrong
775#endif
776
777#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
778#error QCBOR_TYPE_UNDEF macro value wrong
779#endif
780
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700781#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
782#error QCBOR_TYPE_BREAK macro value wrong
783#endif
784
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700785#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
786#error QCBOR_TYPE_DOUBLE macro value wrong
787#endif
788
789#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
790#error QCBOR_TYPE_FLOAT macro value wrong
791#endif
792
793/*
794 Decode true, false, floats, break...
Laurence Lundblade9b334962020-08-27 10:55:53 -0700795
796 @retval QCBOR_ERR_HALF_PRECISION_DISABLED
797
798 @retval QCBOR_ERR_BAD_TYPE_7
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700799 */
Laurence Lundbladeee851742020-01-08 08:37:05 -0800800inline static QCBORError
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800801DecodeSimple(int nAdditionalInfo, uint64_t uNumber, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700802{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700803 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800804
Laurence Lundbladeee851742020-01-08 08:37:05 -0800805 // uAdditionalInfo is 5 bits from the initial byte compile time checks
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800806 // above make sure uAdditionalInfo values line up with uDataType values.
807 // DecodeTypeAndNumber never returns a major type > 1f so cast is safe
808 pDecodedItem->uDataType = (uint8_t)nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800809
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800810 switch(nAdditionalInfo) {
Laurence Lundbladeee851742020-01-08 08:37:05 -0800811 // No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as they are
812 // caught before this is called.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800813
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700814 case HALF_PREC_FLOAT:
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -0700815#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700816 // Half-precision is returned as a double.
Laurence Lundblade3ed0bca2020-07-14 22:50:10 -0700817 // The cast to uint16_t is safe because the encoded value
Laurence Lundblade9682a532020-06-06 18:33:04 -0700818 // was 16 bits. It was widened to 64 bits to be passed in here.
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700819 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uNumber);
820 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade9682a532020-06-06 18:33:04 -0700821#else
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700822 nReturn = QCBOR_ERR_HALF_PRECISION_DISABLED;
Laurence Lundblade9682a532020-06-06 18:33:04 -0700823#endif
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700824 break;
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700825 case SINGLE_PREC_FLOAT:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700826 // Single precision is normally returned as a double
827 // since double is widely supported, there is no loss of
828 // precision, it makes it easy for the caller in
829 // most cases and it can be converted back to single
830 // with no loss of precision
831 //
Laurence Lundblade3ed0bca2020-07-14 22:50:10 -0700832 // The cast to uint32_t is safe because the encoded value
Laurence Lundblade8fa7d5d2020-07-11 16:30:47 -0700833 // was 32 bits. It was widened to 64 bits to be passed in here.
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700834 {
835 const float f = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uNumber);
836#ifndef QCBOR_DISABLE_FLOAT_HW_USE
837 // In the normal case, use HW to convert float to double.
838 pDecodedItem->val.dfnum = (double)f;
839 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade9682a532020-06-06 18:33:04 -0700840#else
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700841 // Use of float HW is disabled, return as a float.
842 pDecodedItem->val.fnum = f;
843 pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
844
845 // IEEE754_FloatToDouble() could be used here to return
846 // as a double, but it adds object code and most likely
847 // anyone disabling FLOAT HW use doesn't care about
848 // floats and wants to save object code.
Laurence Lundblade9682a532020-06-06 18:33:04 -0700849#endif
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700850 }
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700851 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700852
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700853 case DOUBLE_PREC_FLOAT:
854 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uNumber);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700855 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700856 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800857
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700858 case CBOR_SIMPLEV_FALSE: // 20
859 case CBOR_SIMPLEV_TRUE: // 21
860 case CBOR_SIMPLEV_NULL: // 22
861 case CBOR_SIMPLEV_UNDEF: // 23
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700862 case CBOR_SIMPLE_BREAK: // 31
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700863 break; // nothing to do
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800864
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700865 case CBOR_SIMPLEV_ONEBYTE: // 24
866 if(uNumber <= CBOR_SIMPLE_BREAK) {
867 // This takes out f8 00 ... f8 1f which should be encoded as e0 … f7
Laurence Lundblade077475f2019-04-26 09:06:33 -0700868 nReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700869 goto Done;
870 }
Laurence Lundblade5e390822019-01-06 12:35:01 -0800871 /* FALLTHROUGH */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700872 // fall through intentionally
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800873
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700874 default: // 0-19
875 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
Laurence Lundbladeee851742020-01-08 08:37:05 -0800876 /*
877 DecodeTypeAndNumber will make uNumber equal to
878 uAdditionalInfo when uAdditionalInfo is < 24 This cast is
879 safe because the 2, 4 and 8 byte lengths of uNumber are in
880 the double/float cases above
881 */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700882 pDecodedItem->val.uSimple = (uint8_t)uNumber;
883 break;
884 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800885
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700886Done:
887 return nReturn;
888}
889
890
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700891/*
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530892 Decode text and byte strings. Call the string allocator if asked to.
Laurence Lundblade9b334962020-08-27 10:55:53 -0700893
894 @retval QCBOR_ERR_HIT_END
895
896 @retval QCBOR_ERR_STRING_ALLOCATE
897
898 @retval QCBOR_ERR_STRING_TOO_LONG
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700899 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800900inline static QCBORError DecodeBytes(const QCORInternalAllocator *pAllocator,
901 int nMajorType,
902 uint64_t uStrLen,
903 UsefulInputBuf *pUInBuf,
904 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700905{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700906 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800907
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800908 // CBOR lengths can be 64 bits, but size_t is not 64 bits on all CPUs.
909 // This check makes the casts to size_t below safe.
910
911 // 4 bytes less than the largest sizeof() so this can be tested by
912 // putting a SIZE_MAX length in the CBOR test input (no one will
913 // care the limit on strings is 4 bytes shorter).
914 if(uStrLen > SIZE_MAX-4) {
915 nReturn = QCBOR_ERR_STRING_TOO_LONG;
916 goto Done;
917 }
918
919 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, (size_t)uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530920 if(UsefulBuf_IsNULLC(Bytes)) {
921 // Failed to get the bytes for this string item
922 nReturn = QCBOR_ERR_HIT_END;
923 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700924 }
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530925
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800926 if(pAllocator) {
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530927 // We are asked to use string allocator to make a copy
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800928 UsefulBuf NewMem = StringAllocator_Allocate(pAllocator, (size_t)uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530929 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade30816f22018-11-10 13:40:22 +0700930 nReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530931 goto Done;
932 }
933 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800934 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530935 } else {
936 // Normal case with no string allocator
937 pDecodedItem->val.string = Bytes;
938 }
Laurence Lundbladeee851742020-01-08 08:37:05 -0800939 const bool bIsBstr = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING);
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800940 // Cast because ternary operator causes promotion to integer
941 pDecodedItem->uDataType = (uint8_t)(bIsBstr ? QCBOR_TYPE_BYTE_STRING
942 : QCBOR_TYPE_TEXT_STRING);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800943
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530944Done:
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700945 return nReturn;
946}
947
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700948
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800949
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700950
951
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700952
953
Laurence Lundbladeee851742020-01-08 08:37:05 -0800954// Make sure the constants align as this is assumed by
955// the GetAnItem() implementation
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700956#if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
957#error QCBOR_TYPE_ARRAY value not lined up with major type
958#endif
959#if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
960#error QCBOR_TYPE_MAP value not lined up with major type
961#endif
962
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700963/*
Laurence Lundbladeee851742020-01-08 08:37:05 -0800964 This gets a single data item and decodes it including preceding
965 optional tagging. This does not deal with arrays and maps and nesting
966 except to decode the data item introducing them. Arrays and maps are
967 handled at the next level up in GetNext().
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800968
Laurence Lundbladeee851742020-01-08 08:37:05 -0800969 Errors detected here include: an array that is too long to decode,
970 hit end of buffer unexpectedly, a few forms of invalid encoded CBOR
Laurence Lundblade9b334962020-08-27 10:55:53 -0700971
972 @retval QCBOR_ERR_UNSUPPORTED
973
974 @retval QCBOR_ERR_HIT_END
975
976 @retval QCBOR_ERR_INT_OVERFLOW
977
978 @retval QCBOR_ERR_STRING_ALLOCATE
979
980 @retval QCBOR_ERR_STRING_TOO_LONG
981
982 @retval QCBOR_ERR_HALF_PRECISION_DISABLED
983
984 @retval QCBOR_ERR_BAD_TYPE_7
985
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700986 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800987static QCBORError GetNext_Item(UsefulInputBuf *pUInBuf,
988 QCBORItem *pDecodedItem,
989 const QCORInternalAllocator *pAllocator)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700990{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700991 QCBORError nReturn;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800992
Laurence Lundbladeee851742020-01-08 08:37:05 -0800993 /*
994 Get the major type and the number. Number could be length of more
995 bytes or the value depending on the major type nAdditionalInfo is
996 an encoding of the length of the uNumber and is needed to decode
997 floats and doubles
998 */
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800999 int nMajorType;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001000 uint64_t uNumber;
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001001 int nAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001002
Laurence Lundblade4b09f632019-10-09 14:34:59 -07001003 memset(pDecodedItem, 0, sizeof(QCBORItem));
1004
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001005 nReturn = DecodeTypeAndNumber(pUInBuf, &nMajorType, &uNumber, &nAdditionalInfo);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001006
Laurence Lundbladeee851742020-01-08 08:37:05 -08001007 // Error out here if we got into trouble on the type and number. The
1008 // code after this will not work if the type and number is not good.
Laurence Lundblade3a6042e2019-06-28 19:58:04 -07001009 if(nReturn) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001010 goto Done;
Laurence Lundblade3a6042e2019-06-28 19:58:04 -07001011 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001012
Laurence Lundbladeee851742020-01-08 08:37:05 -08001013 // At this point the major type and the value are valid. We've got
1014 // the type and the number that starts every CBOR data item.
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001015 switch (nMajorType) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001016 case CBOR_MAJOR_TYPE_POSITIVE_INT: // Major type 0
1017 case CBOR_MAJOR_TYPE_NEGATIVE_INT: // Major type 1
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001018 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundblade3a6042e2019-06-28 19:58:04 -07001019 nReturn = QCBOR_ERR_BAD_INT;
1020 } else {
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001021 nReturn = DecodeInteger(nMajorType, uNumber, pDecodedItem);
Laurence Lundblade3a6042e2019-06-28 19:58:04 -07001022 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001023 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001024
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001025 case CBOR_MAJOR_TYPE_BYTE_STRING: // Major type 2
1026 case CBOR_MAJOR_TYPE_TEXT_STRING: // Major type 3
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001027 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
1028 const bool bIsBstr = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING);
1029 pDecodedItem->uDataType = (uint8_t)(bIsBstr ? QCBOR_TYPE_BYTE_STRING
1030 : QCBOR_TYPE_TEXT_STRING);
Laurence Lundbladea44d5062018-10-17 18:45:12 +05301031 pDecodedItem->val.string = (UsefulBufC){NULL, SIZE_MAX};
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001032 } else {
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001033 nReturn = DecodeBytes(pAllocator, nMajorType, uNumber, pUInBuf, pDecodedItem);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001034 }
1035 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001036
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001037 case CBOR_MAJOR_TYPE_ARRAY: // Major type 4
1038 case CBOR_MAJOR_TYPE_MAP: // Major type 5
1039 // Record the number of items in the array or map
1040 if(uNumber > QCBOR_MAX_ITEMS_IN_ARRAY) {
1041 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
1042 goto Done;
1043 }
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001044 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07001045 pDecodedItem->val.uCount = QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001046 } else {
Laurence Lundbladeee851742020-01-08 08:37:05 -08001047 // type conversion OK because of check above
1048 pDecodedItem->val.uCount = (uint16_t)uNumber;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001049 }
Laurence Lundbladeee851742020-01-08 08:37:05 -08001050 // C preproc #if above makes sure constants for major types align
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001051 // DecodeTypeAndNumber never returns a major type > 7 so cast is safe
1052 pDecodedItem->uDataType = (uint8_t)nMajorType;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001053 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001054
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001055 case CBOR_MAJOR_TYPE_OPTIONAL: // Major type 6, optional prepended tags
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001056 if(nAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001057 nReturn = QCBOR_ERR_BAD_INT;
1058 } else {
1059 pDecodedItem->val.uTagV = uNumber;
Laurence Lundblade9b334962020-08-27 10:55:53 -07001060 pDecodedItem->uDataType = QCBOR_TYPE_TAG;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001061 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001062 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001063
Laurence Lundbladeee851742020-01-08 08:37:05 -08001064 case CBOR_MAJOR_TYPE_SIMPLE:
1065 // Major type 7, float, double, true, false, null...
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001066 nReturn = DecodeSimple(nAdditionalInfo, uNumber, pDecodedItem);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001067 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001068
Laurence Lundbladeee851742020-01-08 08:37:05 -08001069 default:
1070 // Never happens because DecodeTypeAndNumber() should never return > 7
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001071 nReturn = QCBOR_ERR_UNSUPPORTED;
1072 break;
1073 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001074
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001075Done:
1076 return nReturn;
1077}
1078
1079
1080
1081/*
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001082 This layer deals with indefinite length strings. It pulls all the
Laurence Lundbladeee851742020-01-08 08:37:05 -08001083 individual chunk items together into one QCBORItem using the string
1084 allocator.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001085
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301086 Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade9b334962020-08-27 10:55:53 -07001087
1088 @retval QCBOR_ERR_UNSUPPORTED
1089
1090 @retval QCBOR_ERR_HIT_END
1091
1092 @retval QCBOR_ERR_INT_OVERFLOW
1093
1094 @retval QCBOR_ERR_STRING_ALLOCATE
1095
1096 @retval QCBOR_ERR_STRING_TOO_LONG
1097
1098 @retval QCBOR_ERR_HALF_PRECISION_DISABLED
1099
1100 @retval QCBOR_ERR_BAD_TYPE_7
1101
1102 @retval QCBOR_ERR_NO_STRING_ALLOCATOR
1103
1104 @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001105 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001106static inline QCBORError
1107GetNext_FullItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001108{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001109 // Stack usage; int/ptr 2 UsefulBuf 2 QCBORItem -- 96
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001110
1111 // Get pointer to string allocator. First use is to pass it to
1112 // GetNext_Item() when option is set to allocate for *every* string.
1113 // Second use here is to allocate space to coallese indefinite
1114 // length string items into one.
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001115 const QCORInternalAllocator *pAllocator = me->StringAllocator.pfAllocator ?
1116 &(me->StringAllocator) :
1117 NULL;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001118
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001119 QCBORError nReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001120 nReturn = GetNext_Item(&(me->InBuf),
1121 pDecodedItem,
1122 me->bStringAllocateAll ? pAllocator: NULL);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001123 if(nReturn) {
1124 goto Done;
1125 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001126
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001127 // To reduce code size by removing support for indefinite length strings, the
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301128 // code in this function from here down can be eliminated. Run tests, except
1129 // indefinite length string tests, to be sure all is OK if this is removed.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001130
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001131 // Only do indefinite length processing on strings
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001132 const uint8_t uStringType = pDecodedItem->uDataType;
1133 if(uStringType!= QCBOR_TYPE_BYTE_STRING && uStringType != QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001134 goto Done; // no need to do any work here on non-string types
1135 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001136
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001137 // Is this a string with an indefinite length?
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301138 if(pDecodedItem->val.string.len != SIZE_MAX) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001139 goto Done; // length is not indefinite, so no work to do here
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001140 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001141
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301142 // Can't do indefinite length strings without a string allocator
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001143 if(pAllocator == NULL) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001144 nReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
1145 goto Done;
1146 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001147
Laurence Lundblade4b270642020-08-14 12:53:07 -07001148 // Loop getting chunks of the indefinite length string
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001149 UsefulBufC FullString = NULLUsefulBufC;
1150
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001151 for(;;) {
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001152 // Get item for next chunk
1153 QCBORItem StringChunkItem;
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001154 // NULL string allocator passed here. Do not need to allocate
1155 // chunks even if bStringAllocateAll is set.
Laurence Lundbladefae26bf2019-02-18 11:15:43 -08001156 nReturn = GetNext_Item(&(me->InBuf), &StringChunkItem, NULL);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001157 if(nReturn) {
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001158 break; // Error getting the next chunk
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001159 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001160
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301161 // See if it is a marker at end of indefinite length string
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001162 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001163 // String is complete
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001164 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301165 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001166 break;
1167 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001168
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001169 // Match data type of chunk to type at beginning.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301170 // Also catches error of other non-string types that don't belong.
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001171 // Also catches indefinite length strings inside indefinite length strings
Laurence Lundbladec5fef682020-01-25 11:38:45 -08001172 if(StringChunkItem.uDataType != uStringType ||
1173 StringChunkItem.val.string.len == SIZE_MAX) {
Laurence Lundblade30816f22018-11-10 13:40:22 +07001174 nReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001175 break;
1176 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001177
Laurence Lundblade471a3fd2018-10-18 21:27:45 +05301178 // Alloc new buffer or expand previously allocated buffer so it can fit
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001179 // The first time throurgh FullString.ptr is NULL and this is
1180 // equivalent to StringAllocator_Allocate()
1181 UsefulBuf NewMem = StringAllocator_Reallocate(pAllocator,
1182 UNCONST_POINTER(FullString.ptr),
1183 FullString.len + StringChunkItem.val.string.len);
1184
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001185 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301186 // Allocation of memory for the string failed
Laurence Lundblade30816f22018-11-10 13:40:22 +07001187 nReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001188 break;
1189 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001190
Laurence Lundblade2a6850e2018-10-28 20:13:44 +07001191 // Copy new string chunk at the end of string so far.
1192 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001193 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001194
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001195 if(nReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
1196 // Getting the item failed, clean up the allocated memory
1197 StringAllocator_Free(pAllocator, UNCONST_POINTER(FullString.ptr));
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001198 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001199
Laurence Lundbladed6dfe6d2020-04-09 10:21:36 -07001200Done:
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001201 return nReturn;
1202}
1203
Laurence Lundblade9b334962020-08-27 10:55:53 -07001204static uint64_t ConvertTag(const QCBORDecodeContext *me, uint16_t uTagVal) {
Laurence Lundblade410c7e02020-06-25 23:35:29 -07001205 if(uTagVal <= QCBOR_LAST_UNMAPPED_TAG) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001206 return uTagVal;
Laurence Lundblade9b334962020-08-27 10:55:53 -07001207 } else if(uTagVal == CBOR_TAG_INVALID16) {
1208 return CBOR_TAG_INVALID64;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001209 } else {
Laurence Lundblade9b334962020-08-27 10:55:53 -07001210 const int x = uTagVal - (QCBOR_LAST_UNMAPPED_TAG + 1);
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001211 return me->auMappedTags[x];
1212 }
1213}
1214
Laurence Lundblade9b334962020-08-27 10:55:53 -07001215
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001216/*
Laurence Lundblade59289e52019-12-30 13:44:37 -08001217 Gets all optional tag data items preceding a data item that is not an
1218 optional tag and records them as bits in the tag map.
Laurence Lundblade9b334962020-08-27 10:55:53 -07001219
1220 @retval QCBOR_ERR_UNSUPPORTED
1221
1222 @retval QCBOR_ERR_HIT_END
1223
1224 @retval QCBOR_ERR_INT_OVERFLOW
1225
1226 @retval QCBOR_ERR_STRING_ALLOCATE
1227
1228 @retval QCBOR_ERR_STRING_TOO_LONG
1229
1230 @retval QCBOR_ERR_HALF_PRECISION_DISABLED
1231
1232 @retval QCBOR_ERR_BAD_TYPE_7
1233
1234 @retval QCBOR_ERR_NO_STRING_ALLOCATOR
1235
1236 @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK
1237
1238 @retval QCBOR_ERR_TOO_MANY_TAGS
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001239 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001240static QCBORError
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001241GetNext_TaggedItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001242{
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001243 uint16_t auTags[QCBOR_MAX_TAGS_PER_ITEM] = {CBOR_TAG_INVALID16,
1244 CBOR_TAG_INVALID16,
1245 CBOR_TAG_INVALID16,
1246 CBOR_TAG_INVALID16};
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001247
Laurence Lundblade9b334962020-08-27 10:55:53 -07001248 QCBORError uReturn = QCBOR_SUCCESS;
1249
Laurence Lundblade59289e52019-12-30 13:44:37 -08001250 // Loop fetching items until the item fetched is not a tag
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001251 for(;;) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07001252 QCBORError uErr = GetNext_FullItem(me, pDecodedItem);
1253 if(uErr != QCBOR_SUCCESS) {
1254 uReturn = uErr;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001255 goto Done; // Error out of the loop
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001256 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001257
Laurence Lundblade9b334962020-08-27 10:55:53 -07001258 if(pDecodedItem->uDataType != QCBOR_TYPE_TAG) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001259 // Successful exit from loop; maybe got some tags, maybe not
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001260 memcpy(pDecodedItem->uTags, auTags, sizeof(auTags));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001261 break;
1262 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001263
Laurence Lundblade9b334962020-08-27 10:55:53 -07001264 if(auTags[QCBOR_MAX_TAGS_PER_ITEM - 1] != CBOR_TAG_INVALID16) {
1265 // No room in the tag list
1266 uReturn = QCBOR_ERR_TOO_MANY_TAGS;
1267 // Continue on to get all tags on this item even though
1268 // it is erroring out in the end. This is a resource limit
1269 // error, not an problem with being well-formed CBOR.
1270 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001271 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001272 // Slide tags over one in the array to make room at index 0
1273 for(size_t uTagIndex = QCBOR_MAX_TAGS_PER_ITEM - 1; uTagIndex > 0; uTagIndex--) {
1274 auTags[uTagIndex] = auTags[uTagIndex-1];
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001275 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001276
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001277 // Is the tag > 16 bits?
Laurence Lundblade410c7e02020-06-25 23:35:29 -07001278 if(pDecodedItem->val.uTagV > QCBOR_LAST_UNMAPPED_TAG) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001279 size_t uTagMapIndex;
Laurence Lundblade410c7e02020-06-25 23:35:29 -07001280 // Is there room in the tag map, or is it in it already?
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001281 for(uTagMapIndex = 0; uTagMapIndex < QCBOR_NUM_MAPPED_TAGS; uTagMapIndex++) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07001282 if(me->auMappedTags[uTagMapIndex] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001283 break;
1284 }
1285 if(me->auMappedTags[uTagMapIndex] == pDecodedItem->val.uTagV) {
1286 break;
1287 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001288 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001289 if(uTagMapIndex >= QCBOR_NUM_MAPPED_TAGS) {
1290 // No room for the tag
Laurence Lundblade9b334962020-08-27 10:55:53 -07001291 uReturn = QCBOR_ERR_TOO_MANY_TAGS;
1292 // Continue on to get all tags on this item even though
1293 // it is erroring out in the end. This is a resource limit
1294 // error, not an problem with being well-formed CBOR.
1295 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001296 }
1297
Laurence Lundblade410c7e02020-06-25 23:35:29 -07001298 // Covers the cases where tag is new and were it is already in the map
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001299 me->auMappedTags[uTagMapIndex] = pDecodedItem->val.uTagV;
Laurence Lundblade9b334962020-08-27 10:55:53 -07001300 auTags[0] = (uint16_t)(uTagMapIndex + QCBOR_LAST_UNMAPPED_TAG + 1);
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001301
1302 } else {
Laurence Lundblade9b334962020-08-27 10:55:53 -07001303 auTags[0] = (uint16_t)pDecodedItem->val.uTagV;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001304 }
1305 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001306
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001307Done:
Laurence Lundblade9b334962020-08-27 10:55:53 -07001308 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001309}
1310
1311
1312/*
Laurence Lundbladeee851742020-01-08 08:37:05 -08001313 This layer takes care of map entries. It combines the label and data
1314 items into one QCBORItem.
Laurence Lundblade9b334962020-08-27 10:55:53 -07001315
1316 @retval QCBOR_ERR_UNSUPPORTED
1317
1318 @retval QCBOR_ERR_HIT_END
1319
1320 @retval QCBOR_ERR_INT_OVERFLOW
1321
1322 @retval QCBOR_ERR_STRING_ALLOCATE
1323
1324 @retval QCBOR_ERR_STRING_TOO_LONG
1325
1326 @retval QCBOR_ERR_HALF_PRECISION_DISABLED
1327
1328 @retval QCBOR_ERR_BAD_TYPE_7
1329
1330 @retval QCBOR_ERR_NO_STRING_ALLOCATOR
1331
1332 @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK
1333
1334 @retval QCBOR_ERR_TOO_MANY_TAGS
1335
1336 @retval QCBOR_ERR_MAP_LABEL_TYPE
1337
1338 @retval QCBOR_ERR_ARRAY_TOO_LONG
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001339 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001340static inline QCBORError
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001341GetNext_MapEntry(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001342{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001343 // Stack use: int/ptr 1, QCBORItem -- 56
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001344 QCBORError nReturn = GetNext_TaggedItem(me, pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001345 if(nReturn)
1346 goto Done;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001347
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001348 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001349 // Break can't be a map entry
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001350 goto Done;
1351 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001352
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001353 if(me->uDecodeMode != QCBOR_DECODE_MODE_MAP_AS_ARRAY) {
1354 // In a map and caller wants maps decoded, not treated as arrays
1355
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001356 if(DecodeNesting_IsCurrentTypeMap(&(me->nesting))) {
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001357 // If in a map and the right decoding mode, get the label
1358
Laurence Lundbladeee851742020-01-08 08:37:05 -08001359 // Save label in pDecodedItem and get the next which will
1360 // be the real data
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001361 QCBORItem LabelItem = *pDecodedItem;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001362 nReturn = GetNext_TaggedItem(me, pDecodedItem);
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001363 if(nReturn)
1364 goto Done;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001365
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301366 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001367
1368 if(LabelItem.uDataType == QCBOR_TYPE_TEXT_STRING) {
1369 // strings are always good labels
1370 pDecodedItem->label.string = LabelItem.val.string;
1371 pDecodedItem->uLabelType = QCBOR_TYPE_TEXT_STRING;
1372 } else if (QCBOR_DECODE_MODE_MAP_STRINGS_ONLY == me->uDecodeMode) {
Laurence Lundbladeee851742020-01-08 08:37:05 -08001373 // It's not a string and we only want strings
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001374 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
1375 goto Done;
1376 } else if(LabelItem.uDataType == QCBOR_TYPE_INT64) {
1377 pDecodedItem->label.int64 = LabelItem.val.int64;
1378 pDecodedItem->uLabelType = QCBOR_TYPE_INT64;
1379 } else if(LabelItem.uDataType == QCBOR_TYPE_UINT64) {
1380 pDecodedItem->label.uint64 = LabelItem.val.uint64;
1381 pDecodedItem->uLabelType = QCBOR_TYPE_UINT64;
1382 } else if(LabelItem.uDataType == QCBOR_TYPE_BYTE_STRING) {
1383 pDecodedItem->label.string = LabelItem.val.string;
1384 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
1385 pDecodedItem->uLabelType = QCBOR_TYPE_BYTE_STRING;
1386 } else {
1387 // label is not an int or a string. It is an arrray
1388 // or a float or such and this implementation doesn't handle that.
1389 // Also, tags on labels are ignored.
1390 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
1391 goto Done;
1392 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001393 }
1394 } else {
1395 if(pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001396 if(pDecodedItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY/2) {
1397 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
1398 goto Done;
1399 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001400 // Decoding a map as an array
1401 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
Laurence Lundbladee6bcef12020-04-01 10:56:27 -07001402 // Cast is safe because of check against QCBOR_MAX_ITEMS_IN_ARRAY/2
1403 // Cast is needed because of integer promotion
1404 pDecodedItem->val.uCount = (uint16_t)(pDecodedItem->val.uCount * 2);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001405 }
1406 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001407
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001408Done:
1409 return nReturn;
1410}
1411
1412
Laurence Lundblade02625d42020-06-25 14:41:41 -07001413/*
1414 See if next item is a CBOR break. If it is, it is consumed,
1415 if not it is not consumed.
1416*/
Laurence Lundblade642282a2020-06-23 12:00:33 -07001417static inline QCBORError
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001418NextIsBreak(UsefulInputBuf *pUIB, bool *pbNextIsBreak)
1419{
1420 *pbNextIsBreak = false;
1421 if(UsefulInputBuf_BytesUnconsumed(pUIB) != 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001422 QCBORItem Peek;
1423 size_t uPeek = UsefulInputBuf_Tell(pUIB);
1424 QCBORError uReturn = GetNext_Item(pUIB, &Peek, NULL);
1425 if(uReturn != QCBOR_SUCCESS) {
1426 return uReturn;
1427 }
1428 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07001429 // It is not a break, rewind so it can be processed normally.
1430 UsefulInputBuf_Seek(pUIB, uPeek);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001431 } else {
1432 *pbNextIsBreak = true;
1433 }
1434 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001435
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001436 return QCBOR_SUCCESS;
1437}
1438
1439
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001440/*
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001441 An item was just consumed, now figure out if it was the
1442 end of an array or map that can be closed out. That
1443 may in turn close out another map or array.
Laurence Lundblade642282a2020-06-23 12:00:33 -07001444*/
Laurence Lundbladed0304932020-06-27 10:59:38 -07001445static QCBORError NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001446{
1447 QCBORError uReturn;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001448
Laurence Lundblade642282a2020-06-23 12:00:33 -07001449 /* This loops ascending nesting levels as long as there is ascending to do */
1450 while(!DecodeNesting_IsCurrentAtTop(&(pMe->nesting))) {
1451
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07001452 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07001453 /* Decrement count for definite length maps / arrays */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001454 DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(&(pMe->nesting));
1455 if(!DecodeNesting_IsEndOfDefiniteLengthMapOrArray(&(pMe->nesting))) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07001456 /* Didn't close out map or array, so all work here is done */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001457 break;
1458 }
Laurence Lundblade02625d42020-06-25 14:41:41 -07001459 /* All of a definite length array was consumed; fall through to ascend */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001460
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001461 } else {
Laurence Lundblade02625d42020-06-25 14:41:41 -07001462 /* If not definite length, have to check for a CBOR break */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001463 bool bIsBreak = false;
1464 uReturn = NextIsBreak(&(pMe->InBuf), &bIsBreak);
1465 if(uReturn != QCBOR_SUCCESS) {
1466 goto Done;
1467 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001468
1469 if(!bIsBreak) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07001470 /* It's not a break so nothing closes out and all work is done */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001471 break;
1472 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001473
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07001474 if(DecodeNesting_IsCurrentBstrWrapped(&(pMe->nesting))) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07001475 /*
1476 Break occurred inside a bstr-wrapped CBOR or
1477 in the top level sequence. This is always an
1478 error because neither are an indefinte length
1479 map/array.
1480 */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001481 uReturn = QCBOR_ERR_BAD_BREAK;
1482 goto Done;
1483 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001484
Laurence Lundblade02625d42020-06-25 14:41:41 -07001485 /* It was a break in an indefinite length map / array */
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001486 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001487
Laurence Lundblade02625d42020-06-25 14:41:41 -07001488 /* All items in the map/array level have been consumed. */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001489
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001490 /* But ascent in bounded mode is only by explicit call to QCBORDecode_ExitBoundedMode() */
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07001491 if(DecodeNesting_IsCurrentBounded(&(pMe->nesting))) {
Laurence Lundblade642282a2020-06-23 12:00:33 -07001492 /* Set the count to zero for definite length arrays to indicate cursor is at end of bounded map / array */
Laurence Lundbladed0304932020-06-27 10:59:38 -07001493 if(bMarkEnd) {
1494 // Used for definite and indefinite to signal end
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07001495 DecodeNesting_ZeroMapOrArrayCount(&(pMe->nesting));
Laurence Lundbladed0304932020-06-27 10:59:38 -07001496
Laurence Lundblade2c1faf92020-06-26 22:43:56 -07001497 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001498 break;
1499 }
1500
1501 /* Finally, actually ascend one level. */
1502 DecodeNesting_Ascend(&(pMe->nesting));
1503 }
Laurence Lundblade642282a2020-06-23 12:00:33 -07001504
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001505 uReturn = QCBOR_SUCCESS;
1506
1507Done:
1508 return uReturn;
1509}
1510
1511
1512/*
Laurence Lundbladee6f15112020-07-23 18:44:16 -07001513 This handles the traversal descending into and asecnding out of maps,
Laurence Lundblade642282a2020-06-23 12:00:33 -07001514 arrays and bstr-wrapped CBOR. It figures out the ends of definite and
1515 indefinte length maps and arrays by looking at the item count or
1516 finding CBOR breaks. It detects the ends of the top-level sequence
1517 and of bstr-wrapped CBOR by byte count.
Laurence Lundblade9b334962020-08-27 10:55:53 -07001518
1519 @retval QCBOR_ERR_UNSUPPORTED X
1520
1521 @retval QCBOR_ERR_HIT_END
1522
1523 @retval QCBOR_ERR_INT_OVERFLOW X
1524
1525 @retval QCBOR_ERR_STRING_ALLOCATE
1526
1527 @retval QCBOR_ERR_STRING_TOO_LONG
1528
1529 @retval QCBOR_ERR_HALF_PRECISION_DISABLED X
1530
1531 @retval QCBOR_ERR_BAD_TYPE_7 X
1532
1533 @retval QCBOR_ERR_NO_STRING_ALLOCATOR
1534
1535 @retval QCBOR_ERR_INDEFINITE_STRING_CHUNK
1536
1537 @retval QCBOR_ERR_TOO_MANY_TAGS
1538
1539 @retval QCBOR_ERR_MAP_LABEL_TYPE X
1540
1541 @retval QCBOR_ERR_ARRAY_TOO_LONG
1542
1543 @retval QCBOR_ERR_NO_MORE_ITEMS
1544
1545 @retval QCBOR_ERR_BAD_BREAK
1546
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001547 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001548static QCBORError
1549QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001550{
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001551 QCBORError uReturn;
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07001552 /* ==== First: figure out if at the end of a traversal ==== */
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001553
Laurence Lundblade642282a2020-06-23 12:00:33 -07001554 /*
1555 If out of bytes to consume, it is either the end of the top-level
1556 sequence of some bstr-wrapped CBOR that was entered.
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001557
Laurence Lundblade642282a2020-06-23 12:00:33 -07001558 In the case of bstr-wrapped CBOR, the length of the UsefulInputBuf
1559 was set to that of the bstr-wrapped CBOR. When the bstr-wrapped
1560 CBOR is exited, the length is set back to the top-level's length
1561 or to the next highest bstr-wrapped CBOR.
Laurence Lundblade642282a2020-06-23 12:00:33 -07001562 */
Laurence Lundbladee6f15112020-07-23 18:44:16 -07001563 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf)) == 0) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001564 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001565 goto Done;
1566 }
Laurence Lundblade937ea812020-05-08 11:38:23 -07001567
Laurence Lundblade642282a2020-06-23 12:00:33 -07001568 /*
1569 Check to see if at the end of a bounded definite length map or
Laurence Lundblade02625d42020-06-25 14:41:41 -07001570 array. The check for the end of an indefinite length array is
1571 later.
Laurence Lundblade24d509a2020-06-06 18:43:15 -07001572 */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07001573 if(DecodeNesting_IsAtEndOfBoundedLevel(&(me->nesting))) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001574 uReturn = QCBOR_ERR_NO_MORE_ITEMS;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07001575 goto Done;
1576 }
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001577
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07001578 /* ==== Next: not at the end so get another item ==== */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001579 uReturn = GetNext_MapEntry(me, pDecodedItem);
1580 if(uReturn) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001581 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001582 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301583
Laurence Lundblade642282a2020-06-23 12:00:33 -07001584 /*
1585 Breaks ending arrays/maps are always processed at the end of this
1586 function. They should never show up here.
1587 */
Laurence Lundblade6de37062018-10-15 12:22:42 +05301588 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001589 uReturn = QCBOR_ERR_BAD_BREAK;
Laurence Lundblade6de37062018-10-15 12:22:42 +05301590 goto Done;
Laurence Lundblade5b8c5852018-10-14 21:11:42 +05301591 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001592
Laurence Lundblade642282a2020-06-23 12:00:33 -07001593 /*
1594 Record the nesting level for this data item before processing any
1595 of decrementing and descending.
1596 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001597 pDecodedItem->uNestingLevel = DecodeNesting_GetCurrentLevel(&(me->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001598
Laurence Lundblade642282a2020-06-23 12:00:33 -07001599
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07001600 /* ==== Next: Process the item for descent, ascent, decrement... ==== */
Laurence Lundblade02625d42020-06-25 14:41:41 -07001601 if(QCBORItem_IsMapOrArray(pDecodedItem)) {
Laurence Lundblade642282a2020-06-23 12:00:33 -07001602 /*
Laurence Lundbladee6f15112020-07-23 18:44:16 -07001603 If the new item is a map or array, descend.
Laurence Lundblade642282a2020-06-23 12:00:33 -07001604
Laurence Lundbladee6f15112020-07-23 18:44:16 -07001605 Empty indefinite length maps and arrays are descended into, but then ascended out
Laurence Lundblade02625d42020-06-25 14:41:41 -07001606 of in the next chunk of code.
1607
1608 Maps and arrays do count as items in the map/array that
Laurence Lundblade642282a2020-06-23 12:00:33 -07001609 encloses them so a decrement needs to be done for them too, but
1610 that is done only when all the items in them have been
1611 processed, not when they are opened with the exception of an
1612 empty map or array.
1613 */
1614 uReturn = DecodeNesting_DescendMapOrArray(&(me->nesting),
1615 pDecodedItem->uDataType,
1616 pDecodedItem->val.uCount);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001617 if(uReturn != QCBOR_SUCCESS) {
1618 goto Done;
1619 }
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001620 }
1621
Laurence Lundblade02625d42020-06-25 14:41:41 -07001622 if(!QCBORItem_IsMapOrArray(pDecodedItem) ||
1623 QCBORItem_IsEmptyDefiniteLengthMapOrArray(pDecodedItem) ||
1624 QCBORItem_IsIndefiniteLengthMapOrArray(pDecodedItem)) {
Laurence Lundblade642282a2020-06-23 12:00:33 -07001625 /*
1626 The following cases are handled here:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001627 - A non-aggregate like an integer or string
1628 - An empty definite length map or array
1629 - An indefinite length map or array that might be empty or might not.
Laurence Lundblade642282a2020-06-23 12:00:33 -07001630
Laurence Lundbladee6f15112020-07-23 18:44:16 -07001631 NestLevelAscender() does the work of decrementing the count for an
Laurence Lundblade02625d42020-06-25 14:41:41 -07001632 definite length map/array and break detection for an indefinite
1633 length map/array. If the end of the map/array was reached, then
1634 it ascends nesting levels, possibly all the way to the top level.
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001635 */
Laurence Lundbladed0304932020-06-27 10:59:38 -07001636 uReturn = NestLevelAscender(me, true);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07001637 if(uReturn) {
1638 goto Done;
Laurence Lundblade5e87da62020-06-07 03:24:28 -07001639 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05301640 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001641
Laurence Lundbladeeaa75a52020-07-09 18:13:23 -07001642 /* ==== Last: tell the caller the nest level of the next item ==== */
Laurence Lundblade642282a2020-06-23 12:00:33 -07001643 /*
Laurence Lundblade02625d42020-06-25 14:41:41 -07001644 Tell the caller what level is next. This tells them what
1645 maps/arrays were closed out and makes it possible for them to
1646 reconstruct the tree with just the information returned in
1647 a QCBORItem.
Laurence Lundblade642282a2020-06-23 12:00:33 -07001648 */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07001649 if(DecodeNesting_IsAtEndOfBoundedLevel(&(me->nesting))) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07001650 /* At end of a bounded map/array; uNextNestLevel 0 to indicate this */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001651 pDecodedItem->uNextNestLevel = 0;
1652 } else {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07001653 pDecodedItem->uNextNestLevel = DecodeNesting_GetCurrentLevel(&(me->nesting));
Laurence Lundblade9c905e82020-04-25 11:31:38 -07001654 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001655
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001656Done:
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001657 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade642282a2020-06-23 12:00:33 -07001658 /* This sets uDataType and uLabelType to QCBOR_TYPE_NONE */
Laurence Lundbladee9482dd2019-10-11 12:58:46 -07001659 memset(pDecodedItem, 0, sizeof(QCBORItem));
1660 }
Laurence Lundblade0a042a92020-06-12 14:09:50 -07001661 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001662}
1663
Laurence Lundblade9b334962020-08-27 10:55:53 -07001664static void ShiftTags(QCBORItem *pDecodedItem)
1665{
1666 pDecodedItem->uTags[0] = pDecodedItem->uTags[1];
1667 pDecodedItem->uTags[1] = pDecodedItem->uTags[2];
1668 pDecodedItem->uTags[2] = pDecodedItem->uTags[3];
1669 pDecodedItem->uTags[2] = CBOR_TAG_INVALID16;
1670}
1671
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001672
Laurence Lundblade59289e52019-12-30 13:44:37 -08001673/*
1674 Mostly just assign the right data type for the date string.
1675 */
1676inline static QCBORError DecodeDateString(QCBORItem *pDecodedItem)
1677{
Laurence Lundblade59289e52019-12-30 13:44:37 -08001678 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1679 return QCBOR_ERR_BAD_OPT_TAG;
1680 }
1681
1682 const UsefulBufC Temp = pDecodedItem->val.string;
1683 pDecodedItem->val.dateString = Temp;
1684 pDecodedItem->uDataType = QCBOR_TYPE_DATE_STRING;
Laurence Lundblade9b334962020-08-27 10:55:53 -07001685 ShiftTags(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001686 return QCBOR_SUCCESS;
1687}
1688
1689
Laurence Lundblade9b334962020-08-27 10:55:53 -07001690
Laurence Lundblade59289e52019-12-30 13:44:37 -08001691/*
Laurence Lundbladeee851742020-01-08 08:37:05 -08001692 The epoch formatted date. Turns lots of different forms of encoding
1693 date into uniform one
Laurence Lundblade59289e52019-12-30 13:44:37 -08001694 */
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001695static QCBORError DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08001696{
Laurence Lundbladec7114722020-08-13 05:11:40 -07001697 QCBORError uReturn = QCBOR_SUCCESS;
Laurence Lundblade59289e52019-12-30 13:44:37 -08001698
1699 pDecodedItem->val.epochDate.fSecondsFraction = 0;
1700
1701 switch (pDecodedItem->uDataType) {
1702
1703 case QCBOR_TYPE_INT64:
1704 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
1705 break;
1706
1707 case QCBOR_TYPE_UINT64:
Laurence Lundbladec7114722020-08-13 05:11:40 -07001708 // This only happens for CBOR type 0 > INT64_MAX so it is
1709 // always an overflow.
1710 uReturn = QCBOR_ERR_DATE_OVERFLOW;
1711 goto Done;
Laurence Lundblade59289e52019-12-30 13:44:37 -08001712 break;
1713
1714 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade9682a532020-06-06 18:33:04 -07001715 case QCBOR_TYPE_FLOAT:
1716#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade59289e52019-12-30 13:44:37 -08001717 {
1718 // This comparison needs to be done as a float before
Laurence Lundblade7b5a3b62020-07-22 10:17:16 -07001719 // conversion to an int64_t to be able to detect doubles that
1720 // are too large to fit into an int64_t. A double has 52
1721 // bits of preceision. An int64_t has 63. Casting INT64_MAX
1722 // to a double actually causes a round up which is bad and
1723 // wrong for the comparison because it will allow conversion
1724 // of doubles that can't fit into a uint64_t. To remedy this
1725 // INT64_MAX - 0x7ff is used as the cutoff point because if
1726 // that value rounds up in conversion to double it will still
1727 // be less than INT64_MAX. 0x7ff is picked because it has 11
1728 // bits set.
Laurence Lundblade59289e52019-12-30 13:44:37 -08001729 //
Laurence Lundblade7b5a3b62020-07-22 10:17:16 -07001730 // INT64_MAX seconds is on the order of 10 billion years, and
1731 // the earth is less than 5 billion years old, so for most
1732 // uses this conversion error won't occur even though doubles
1733 // can go much larger.
Laurence Lundblade59289e52019-12-30 13:44:37 -08001734 //
1735 // Without the 0x7ff there is a ~30 minute range of time
1736 // values 10 billion years in the past and in the future
Laurence Lundbladec7114722020-08-13 05:11:40 -07001737 // where this code would go wrong. Some compilers
1738 // will generate warnings or errors without the 0x7ff
1739 // because of the precision issue.
Laurence Lundblade3ed0bca2020-07-14 22:50:10 -07001740 const double d = pDecodedItem->uDataType == QCBOR_TYPE_DOUBLE ?
1741 pDecodedItem->val.dfnum :
1742 (double)pDecodedItem->val.fnum;
Laurence Lundbladec7114722020-08-13 05:11:40 -07001743 if(isnan(d) ||
1744 d > (double)(INT64_MAX - 0x7ff) ||
1745 d < (double)(INT64_MIN + 0x7ff)) {
1746 uReturn = QCBOR_ERR_DATE_OVERFLOW;
Laurence Lundblade59289e52019-12-30 13:44:37 -08001747 goto Done;
1748 }
1749 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
Laurence Lundblade2feb1e12020-07-15 03:50:45 -07001750 pDecodedItem->val.epochDate.fSecondsFraction =
1751 d - (double)pDecodedItem->val.epochDate.nSeconds;
Laurence Lundblade59289e52019-12-30 13:44:37 -08001752 }
Laurence Lundblade9682a532020-06-06 18:33:04 -07001753#else
Laurence Lundblade4b270642020-08-14 12:53:07 -07001754
Laurence Lundbladec7114722020-08-13 05:11:40 -07001755 uReturn = QCBOR_ERR_FLOAT_DATE_DISABLED;
Laurence Lundblade4b270642020-08-14 12:53:07 -07001756 goto Done;
1757
Laurence Lundblade9682a532020-06-06 18:33:04 -07001758#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade59289e52019-12-30 13:44:37 -08001759 break;
1760
1761 default:
Laurence Lundbladec7114722020-08-13 05:11:40 -07001762 uReturn = QCBOR_ERR_BAD_OPT_TAG;
Laurence Lundblade59289e52019-12-30 13:44:37 -08001763 goto Done;
1764 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001765
Laurence Lundblade59289e52019-12-30 13:44:37 -08001766 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
1767
1768Done:
Laurence Lundbladec7114722020-08-13 05:11:40 -07001769 return uReturn;
Laurence Lundblade59289e52019-12-30 13:44:37 -08001770}
1771
1772
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001773/*
1774 Mostly just assign the right data type for the bignum.
1775 */
1776inline static QCBORError DecodeBigNum(QCBORItem *pDecodedItem)
1777{
1778 // Stack Use: UsefulBuf 1 -- 16
1779 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1780 return QCBOR_ERR_BAD_OPT_TAG;
1781 }
1782 const UsefulBufC Temp = pDecodedItem->val.string;
1783 pDecodedItem->val.bigNum = Temp;
1784 const bool bIsPosBigNum = (bool)(pDecodedItem->uTags[0] == CBOR_TAG_POS_BIGNUM);
1785 pDecodedItem->uDataType = (uint8_t)(bIsPosBigNum ? QCBOR_TYPE_POSBIGNUM
1786 : QCBOR_TYPE_NEGBIGNUM);
1787 return QCBOR_SUCCESS;
1788}
1789
1790
Laurence Lundblade59289e52019-12-30 13:44:37 -08001791#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
1792/*
1793 Decode decimal fractions and big floats.
1794
1795 When called pDecodedItem must be the array that is tagged as a big
1796 float or decimal fraction, the array that has the two members, the
1797 exponent and mantissa.
1798
1799 This will fetch and decode the exponent and mantissa and put the
1800 result back into pDecodedItem.
1801 */
1802inline static QCBORError
1803QCBORDecode_MantissaAndExponent(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
1804{
1805 QCBORError nReturn;
1806
1807 // --- Make sure it is an array; track nesting level of members ---
1808 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
1809 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1810 goto Done;
1811 }
1812
1813 // A check for pDecodedItem->val.uCount == 2 would work for
Laurence Lundbladeee851742020-01-08 08:37:05 -08001814 // definite length arrays, but not for indefnite. Instead remember
1815 // the nesting level the two integers must be at, which is one
1816 // deeper than that of the array.
Laurence Lundblade59289e52019-12-30 13:44:37 -08001817 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
1818
1819 // --- Is it a decimal fraction or a bigfloat? ---
1820 const bool bIsTaggedDecimalFraction = QCBORDecode_IsTagged(me, pDecodedItem, CBOR_TAG_DECIMAL_FRACTION);
1821 pDecodedItem->uDataType = bIsTaggedDecimalFraction ? QCBOR_TYPE_DECIMAL_FRACTION : QCBOR_TYPE_BIGFLOAT;
1822
1823 // --- Get the exponent ---
1824 QCBORItem exponentItem;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001825 nReturn = QCBORDecode_GetNextMapOrArray(me, &exponentItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001826 if(nReturn != QCBOR_SUCCESS) {
1827 goto Done;
1828 }
1829 if(exponentItem.uNestingLevel != nNestLevel) {
1830 // Array is empty or a map/array encountered when expecting an int
1831 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1832 goto Done;
1833 }
1834 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
1835 // Data arriving as an unsigned int < INT64_MAX has been converted
1836 // to QCBOR_TYPE_INT64 and thus handled here. This is also means
1837 // that the only data arriving here of type QCBOR_TYPE_UINT64 data
1838 // will be too large for this to handle and thus an error that will
1839 // get handled in the next else.
1840 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
1841 } else {
1842 // Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX
1843 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1844 goto Done;
1845 }
1846
1847 // --- Get the mantissa ---
1848 QCBORItem mantissaItem;
1849 nReturn = QCBORDecode_GetNextWithTags(me, &mantissaItem, NULL);
1850 if(nReturn != QCBOR_SUCCESS) {
1851 goto Done;
1852 }
1853 if(mantissaItem.uNestingLevel != nNestLevel) {
1854 // Mantissa missing or map/array encountered when expecting number
1855 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1856 goto Done;
1857 }
1858 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
1859 // Data arriving as an unsigned int < INT64_MAX has been converted
1860 // to QCBOR_TYPE_INT64 and thus handled here. This is also means
1861 // that the only data arriving here of type QCBOR_TYPE_UINT64 data
1862 // will be too large for this to handle and thus an error that
1863 // will get handled in an else below.
1864 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
1865 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM || mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
1866 // Got a good big num mantissa
1867 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
1868 // Depends on numbering of QCBOR_TYPE_XXX
Laurence Lundblade06350ea2020-01-27 19:32:40 -08001869 pDecodedItem->uDataType = (uint8_t)(pDecodedItem->uDataType +
1870 mantissaItem.uDataType - QCBOR_TYPE_POSBIGNUM +
1871 1);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001872 } else {
1873 // Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX
1874 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1875 goto Done;
1876 }
1877
1878 // --- Check that array only has the two numbers ---
1879 if(mantissaItem.uNextNestLevel == nNestLevel) {
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07001880 // Extra items in the decimal fraction / big float
Laurence Lundblade59289e52019-12-30 13:44:37 -08001881 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1882 goto Done;
1883 }
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07001884 pDecodedItem->uNextNestLevel = mantissaItem.uNextNestLevel;
Laurence Lundblade59289e52019-12-30 13:44:37 -08001885
1886Done:
Laurence Lundblade59289e52019-12-30 13:44:37 -08001887 return nReturn;
1888}
1889#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
1890
1891
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001892inline static QCBORError DecodeURI(QCBORItem *pDecodedItem)
1893{
1894 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1895 return QCBOR_ERR_BAD_OPT_TAG;
1896 }
1897 pDecodedItem->uDataType = QCBOR_TYPE_URI;
1898 return QCBOR_SUCCESS;
1899}
1900
1901
1902inline static QCBORError DecodeB64URL(QCBORItem *pDecodedItem)
1903{
1904 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1905 return QCBOR_ERR_BAD_OPT_TAG;
1906 }
1907 pDecodedItem->uDataType = QCBOR_TYPE_BASE64URL;
Laurence Lundblade9b334962020-08-27 10:55:53 -07001908
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001909 return QCBOR_SUCCESS;
1910}
1911
1912
1913inline static QCBORError DecodeB64(QCBORItem *pDecodedItem)
1914{
1915 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1916 return QCBOR_ERR_BAD_OPT_TAG;
1917 }
1918 pDecodedItem->uDataType = QCBOR_TYPE_BASE64;
Laurence Lundblade9b334962020-08-27 10:55:53 -07001919
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001920 return QCBOR_SUCCESS;
1921}
1922
1923
1924inline static QCBORError DecodeRegex(QCBORItem *pDecodedItem)
1925{
1926 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1927 return QCBOR_ERR_BAD_OPT_TAG;
1928 }
1929 pDecodedItem->uDataType = QCBOR_TYPE_REGEX;
Laurence Lundblade9b334962020-08-27 10:55:53 -07001930
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001931 return QCBOR_SUCCESS;
1932}
1933
Laurence Lundblade4a21be12020-08-05 12:48:33 -07001934
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07001935inline static QCBORError DecodeWrappedCBOR(QCBORItem *pDecodedItem)
1936{
1937 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1938 return QCBOR_ERR_BAD_OPT_TAG;
1939 }
1940 pDecodedItem->uDataType = QBCOR_TYPE_WRAPPED_CBOR;
Laurence Lundblade9b334962020-08-27 10:55:53 -07001941
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07001942 return QCBOR_SUCCESS;
1943}
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001944
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07001945
1946inline static QCBORError DecodeWrappedCBORSequence(QCBORItem *pDecodedItem)
1947{
1948 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1949 return QCBOR_ERR_BAD_OPT_TAG;
1950 }
1951 pDecodedItem->uDataType = QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE;
Laurence Lundblade9b334962020-08-27 10:55:53 -07001952
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07001953 return QCBOR_SUCCESS;
1954}
1955
Laurence Lundblade4a21be12020-08-05 12:48:33 -07001956
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001957inline static QCBORError DecodeMIME(QCBORItem *pDecodedItem)
1958{
1959 if(pDecodedItem->uDataType == QCBOR_TYPE_TEXT_STRING) {
1960 pDecodedItem->uDataType = QCBOR_TYPE_MIME;
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07001961 } else if(pDecodedItem->uDataType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001962 pDecodedItem->uDataType = QCBOR_TYPE_BINARY_MIME;
1963 } else {
1964 return QCBOR_ERR_BAD_OPT_TAG;
Laurence Lundblade9b334962020-08-27 10:55:53 -07001965
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001966 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07001967
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001968 return QCBOR_SUCCESS;
1969}
1970
1971
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001972inline static QCBORError DecodeUUID(QCBORItem *pDecodedItem)
1973{
1974 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1975 return QCBOR_ERR_BAD_OPT_TAG;
1976 }
1977 pDecodedItem->uDataType = QCBOR_TYPE_UUID;
Laurence Lundblade9b334962020-08-27 10:55:53 -07001978
Laurence Lundblade91853ae2020-06-15 19:35:58 -07001979 return QCBOR_SUCCESS;
1980}
1981
1982
Laurence Lundblade59289e52019-12-30 13:44:37 -08001983/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08001984 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08001985 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08001986QCBORError
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001987QCBORDecode_GetNext(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade59289e52019-12-30 13:44:37 -08001988{
1989 QCBORError nReturn;
1990
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001991 nReturn = QCBORDecode_GetNextMapOrArray(me, pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08001992 if(nReturn != QCBOR_SUCCESS) {
1993 goto Done;
1994 }
1995
Laurence Lundblade830fbf92020-05-31 17:22:33 -07001996 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM; i++) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07001997 switch(pDecodedItem->uTags[i]) {
Laurence Lundblade59289e52019-12-30 13:44:37 -08001998
Laurence Lundblade4a21be12020-08-05 12:48:33 -07001999 // Many of the functions here only just map a CBOR tag to
2000 // a QCBOR_TYPE for a string and could probably be
2001 // implemented with less object code. This implementation
2002 // of string types takes about 120 bytes of object code
2003 // (that is always linked and not removed by dead stripping).
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002004 case CBOR_TAG_DATE_STRING:
Laurence Lundblade59289e52019-12-30 13:44:37 -08002005 nReturn = DecodeDateString(pDecodedItem);
2006 break;
2007
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002008 case CBOR_TAG_DATE_EPOCH:
Laurence Lundblade59289e52019-12-30 13:44:37 -08002009 nReturn = DecodeDateEpoch(pDecodedItem);
2010 break;
2011
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002012 case CBOR_TAG_POS_BIGNUM:
2013 case CBOR_TAG_NEG_BIGNUM:
Laurence Lundblade59289e52019-12-30 13:44:37 -08002014 nReturn = DecodeBigNum(pDecodedItem);
2015 break;
2016
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002017 #ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
2018 case CBOR_TAG_DECIMAL_FRACTION:
2019 case CBOR_TAG_BIGFLOAT:
Laurence Lundblade59289e52019-12-30 13:44:37 -08002020 // For aggregate tagged types, what goes into pTags is only collected
2021 // from the surrounding data item, not the contents, so pTags is not
2022 // passed on here.
2023
2024 nReturn = QCBORDecode_MantissaAndExponent(me, pDecodedItem);
2025 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002026 #endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade59289e52019-12-30 13:44:37 -08002027
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07002028 case CBOR_TAG_CBOR:
2029 nReturn = DecodeWrappedCBOR(pDecodedItem);
2030 break;
2031
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07002032 case CBOR_TAG_CBOR_SEQUENCE:
2033 nReturn = DecodeWrappedCBORSequence(pDecodedItem);
2034 break;
2035
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002036 case CBOR_TAG_URI:
2037 nReturn = DecodeURI(pDecodedItem);
2038 break;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002039
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002040 case CBOR_TAG_B64URL:
2041 nReturn = DecodeB64URL(pDecodedItem);
2042 break;
Laurence Lundblade9b334962020-08-27 10:55:53 -07002043
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002044 case CBOR_TAG_B64:
2045 nReturn = DecodeB64(pDecodedItem);
2046 break;
2047
2048 case CBOR_TAG_MIME:
2049 case CBOR_TAG_BINARY_MIME:
2050 nReturn = DecodeMIME(pDecodedItem);
2051 break;
2052
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002053 case CBOR_TAG_REGEX:
2054 nReturn = DecodeRegex(pDecodedItem);
2055 break;
2056
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002057 case CBOR_TAG_BIN_UUID:
2058 nReturn = DecodeUUID(pDecodedItem);
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002059 break;
Laurence Lundblade9b334962020-08-27 10:55:53 -07002060
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002061 case CBOR_TAG_INVALID16:
Laurence Lundblade91853ae2020-06-15 19:35:58 -07002062 // The end of the tag list or no tags
2063 // Successful exit from the loop.
2064 goto Done;
Laurence Lundblade9b334962020-08-27 10:55:53 -07002065
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002066 default:
2067 // A tag that is not understood
2068 // A successful exit from the loop
2069 goto Done;
2070
2071 }
2072 if(nReturn != QCBOR_SUCCESS) {
2073 goto Done;
2074 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002075 // A tag was successfully processed, shift it
2076 // out of the list of tags returned.
2077 ShiftTags(pDecodedItem);
Laurence Lundblade59289e52019-12-30 13:44:37 -08002078 }
2079
2080Done:
2081 if(nReturn != QCBOR_SUCCESS) {
2082 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
2083 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
2084 }
2085 return nReturn;
2086}
2087
2088
2089/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08002090 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade59289e52019-12-30 13:44:37 -08002091 */
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002092void QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
2093{
2094 if(pMe->uLastError != QCBOR_SUCCESS) {
2095 return;
2096 }
2097
2098 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, pDecodedItem);
2099}
2100
2101
2102/*
2103 Public function, see header qcbor/qcbor_decode.h file
2104 */
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002105QCBORError
2106QCBORDecode_GetNextWithTags(QCBORDecodeContext *me,
2107 QCBORItem *pDecodedItem,
2108 QCBORTagListOut *pTags)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002109{
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002110 QCBORError nReturn;
2111
2112 nReturn = QCBORDecode_GetNext(me, pDecodedItem);
2113 if(nReturn != QCBOR_SUCCESS) {
2114 return nReturn;
2115 }
2116
2117 if(pTags != NULL) {
2118 pTags->uNumUsed = 0;
Laurence Lundblade9b334962020-08-27 10:55:53 -07002119 // Reverse the order because pTags is reverse of
2120 // QCBORItem.uTags.
2121 for(int i = QCBOR_MAX_TAGS_PER_ITEM-1; i >=0 ; i--) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002122 if(pDecodedItem->uTags[i] == CBOR_TAG_INVALID16) {
Laurence Lundblade9b334962020-08-27 10:55:53 -07002123 continue;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002124 }
2125 if(pTags->uNumUsed >= pTags->uNumAllocated) {
2126 return QCBOR_ERR_TOO_MANY_TAGS;
2127 }
2128 pTags->puTags[pTags->uNumUsed] = ConvertTag(me, pDecodedItem->uTags[i]);
2129 pTags->uNumUsed++;
2130 }
2131 }
2132
2133 return QCBOR_SUCCESS;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002134}
2135
2136
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002137/*
Laurence Lundblade6de37062018-10-15 12:22:42 +05302138 Decoding items is done in 5 layered functions, one calling the
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05302139 next one down. If a layer has no work to do for a particular item
2140 it returns quickly.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002141
Laurence Lundblade59289e52019-12-30 13:44:37 -08002142 - QCBORDecode_GetNext, GetNextWithTags -- The top layer processes
2143 tagged data items, turning them into the local C representation.
2144 For the most simple it is just associating a QCBOR_TYPE with the data. For
2145 the complex ones that an aggregate of data items, there is some further
2146 decoding and a little bit of recursion.
2147
2148 - QCBORDecode_GetNextMapOrArray - This manages the beginnings and
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05302149 ends of maps and arrays. It tracks descending into and ascending
Laurence Lundblade6de37062018-10-15 12:22:42 +05302150 out of maps/arrays. It processes all breaks that terminate
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002151 indefinite length maps and arrays.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002152
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05302153 - GetNext_MapEntry -- This handles the combining of two
2154 items, the label and the data, that make up a map entry.
2155 It only does work on maps. It combines the label and data
2156 items into one labeled item.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002157
Laurence Lundblade59289e52019-12-30 13:44:37 -08002158 - GetNext_TaggedItem -- This decodes type 6 tagging. It turns the
2159 tags into bit flags associated with the data item. No actual decoding
2160 of the contents of the tagged item is performed here.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002161
Laurence Lundblade59289e52019-12-30 13:44:37 -08002162 - GetNext_FullItem -- This assembles the sub-items that make up
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05302163 an indefinte length string into one string item. It uses the
Laurence Lundblade6de37062018-10-15 12:22:42 +05302164 string allocater to create contiguous space for the item. It
2165 processes all breaks that are part of indefinite length strings.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002166
Laurence Lundblade59289e52019-12-30 13:44:37 -08002167 - GetNext_Item -- This decodes the atomic data items in CBOR. Each
2168 atomic data item has a "major type", an integer "argument" and optionally
2169 some content. For text and byte strings, the content is the bytes
2170 that make up the string. These are the smallest data items that are
2171 considered to be well-formed. The content may also be other data items in
2172 the case of aggregate types. They are not handled in this layer.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002173
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002174 Roughly this takes 300 bytes of stack for vars. Need to
2175 evaluate this more carefully and correctly.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002176
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05302177 */
2178
2179
2180/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08002181 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002182 */
Laurence Lundbladef71e1622020-08-06 18:52:13 -07002183bool QCBORDecode_IsTagged(QCBORDecodeContext *me,
Laurence Lundblade9b334962020-08-27 10:55:53 -07002184 const QCBORItem *pItem,
2185 uint64_t uTag)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002186{
Laurence Lundblade9b334962020-08-27 10:55:53 -07002187 for(int i = 0; i < QCBOR_MAX_TAGS_PER_ITEM; i++) {
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002188 if(pItem->uTags[i] == CBOR_TAG_INVALID16) {
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002189 break;
2190 }
2191 if(ConvertTag(me, pItem->uTags[i]) == uTag) {
Laurence Lundbladef71e1622020-08-06 18:52:13 -07002192 return true;
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002193 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002194 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002195
Laurence Lundbladef71e1622020-08-06 18:52:13 -07002196 return false;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002197}
2198
2199
2200/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08002201 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07002202 */
Laurence Lundblade30816f22018-11-10 13:40:22 +07002203QCBORError QCBORDecode_Finish(QCBORDecodeContext *me)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002204{
Laurence Lundblade085d7952020-07-24 10:26:30 -07002205 QCBORError uReturn = me->uLastError;
2206
2207 if(uReturn != QCBOR_SUCCESS) {
2208 goto Done;
2209 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002210
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002211 // Error out if all the maps/arrays are not closed out
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002212 if(!DecodeNesting_IsCurrentAtTop(&(me->nesting))) {
Laurence Lundblade085d7952020-07-24 10:26:30 -07002213 uReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002214 goto Done;
2215 }
2216
2217 // Error out if not all the bytes are consumed
2218 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) {
Laurence Lundblade085d7952020-07-24 10:26:30 -07002219 uReturn = QCBOR_ERR_EXTRA_BYTES;
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002220 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002221
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002222Done:
Laurence Lundblade6de37062018-10-15 12:22:42 +05302223 // Call the destructor for the string allocator if there is one.
Laurence Lundblade20b533d2018-10-08 20:44:53 +08002224 // Always called, even if there are errors; always have to clean up
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002225 StringAllocator_Destruct(&(me->StringAllocator));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002226
Laurence Lundblade085d7952020-07-24 10:26:30 -07002227 return uReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002228}
2229
2230
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002231/*
Laurence Lundblade9b334962020-08-27 10:55:53 -07002232 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002233*/
Laurence Lundblade9b334962020-08-27 10:55:53 -07002234// Improvement: make these inline?
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002235uint64_t QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
2236 const QCBORItem *pItem,
Laurence Lundblade9b334962020-08-27 10:55:53 -07002237 uint32_t uIndex)
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002238{
Laurence Lundblade9b334962020-08-27 10:55:53 -07002239 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2240 return CBOR_TAG_INVALID64;
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002241 } else {
Laurence Lundblade410c7e02020-06-25 23:35:29 -07002242 return ConvertTag(pMe, pItem->uTags[uIndex]);
Laurence Lundbladec75e68b2020-06-15 20:34:46 -07002243 }
2244}
2245
Laurence Lundblade9b334962020-08-27 10:55:53 -07002246/*
2247 Public function, see header qcbor/qcbor_decode.h file
2248*/
2249uint64_t QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe,
2250 uint32_t uIndex)
2251{
2252 if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
2253 return CBOR_TAG_INVALID64;
2254 } else {
2255 return ConvertTag(pMe, pMe->uLastTags[uIndex]);
2256 }
2257}
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002258
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002259/*
2260
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002261Decoder errors handled in this file
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002262
Laurence Lundbladeee851742020-01-08 08:37:05 -08002263 - Hit end of input before it was expected while decoding type and
2264 number QCBOR_ERR_HIT_END
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002265
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002266 - negative integer that is too large for C QCBOR_ERR_INT_OVERFLOW
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002267
Laurence Lundbladeee851742020-01-08 08:37:05 -08002268 - Hit end of input while decoding a text or byte string
2269 QCBOR_ERR_HIT_END
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002270
Laurence Lundbladeee851742020-01-08 08:37:05 -08002271 - Encountered conflicting tags -- e.g., an item is tagged both a date
2272 string and an epoch date QCBOR_ERR_UNSUPPORTED
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002273
Laurence Lundbladeee851742020-01-08 08:37:05 -08002274 - Encontered an array or mapp that has too many items
2275 QCBOR_ERR_ARRAY_TOO_LONG
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002276
Laurence Lundbladeee851742020-01-08 08:37:05 -08002277 - Encountered array/map nesting that is too deep
2278 QCBOR_ERR_ARRAY_NESTING_TOO_DEEP
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002279
Laurence Lundbladeee851742020-01-08 08:37:05 -08002280 - An epoch date > INT64_MAX or < INT64_MIN was encountered
2281 QCBOR_ERR_DATE_OVERFLOW
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002282
Laurence Lundbladeee851742020-01-08 08:37:05 -08002283 - The type of a map label is not a string or int
2284 QCBOR_ERR_MAP_LABEL_TYPE
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002285
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002286 - Hit end with arrays or maps still open -- QCBOR_ERR_EXTRA_BYTES
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002287
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07002288 */
2289
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002290
2291
Laurence Lundbladef6531662018-12-04 10:42:22 +09002292
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002293/* ===========================================================================
2294 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002295
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002296 This implements a simple sting allocator for indefinite length
2297 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
2298 implements the function type QCBORStringAllocate and allows easy
2299 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09002300
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002301 This particular allocator is built-in for convenience. The caller
2302 can implement their own. All of this following code will get
2303 dead-stripped if QCBORDecode_SetMemPool() is not called.
2304
2305 This is a very primitive memory allocator. It does not track
2306 individual allocations, only a high-water mark. A free or
2307 reallocation must be of the last chunk allocated.
2308
2309 The size of the pool and offset to free memory are packed into the
2310 first 8 bytes of the memory pool so we don't have to keep them in
2311 the decode context. Since the address of the pool may not be
2312 aligned, they have to be packed and unpacked as if they were
2313 serialized data of the wire or such.
2314
2315 The sizes packed in are uint32_t to be the same on all CPU types
2316 and simplify the code.
Laurence Lundbladeee851742020-01-08 08:37:05 -08002317 ========================================================================== */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002318
2319
Laurence Lundbladeee851742020-01-08 08:37:05 -08002320static inline int
2321MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002322{
2323 // Use of UsefulInputBuf is overkill, but it is convenient.
2324 UsefulInputBuf UIB;
2325
Laurence Lundbladeee851742020-01-08 08:37:05 -08002326 // Just assume the size here. It was checked during SetUp so
2327 // the assumption is safe.
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002328 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem, QCBOR_DECODE_MIN_MEM_POOL_SIZE});
2329 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
2330 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
2331 return UsefulInputBuf_GetError(&UIB);
2332}
2333
2334
Laurence Lundbladeee851742020-01-08 08:37:05 -08002335static inline int
2336MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002337{
2338 // Use of UsefulOutBuf is overkill, but convenient. The
2339 // length check performed here is useful.
2340 UsefulOutBuf UOB;
2341
2342 UsefulOutBuf_Init(&UOB, Pool);
2343 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
2344 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
2345 return UsefulOutBuf_GetError(&UOB);
2346}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002347
2348
2349/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002350 Internal function for an allocation, reallocation free and destuct.
2351
2352 Having only one function rather than one each per mode saves space in
2353 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002354
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002355 Code Reviewers: THIS FUNCTION DOES POINTER MATH
2356 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08002357static UsefulBuf
2358MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002359{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002360 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002361
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002362 uint32_t uPoolSize;
2363 uint32_t uFreeOffset;
2364
2365 if(uNewSize > UINT32_MAX) {
2366 // This allocator is only good up to 4GB. This check should
2367 // optimize out if sizeof(size_t) == sizeof(uint32_t)
2368 goto Done;
2369 }
2370 const uint32_t uNewSize32 = (uint32_t)uNewSize;
2371
2372 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
2373 goto Done;
2374 }
2375
2376 if(uNewSize) {
2377 if(pMem) {
2378 // REALLOCATION MODE
2379 // Calculate pointer to the end of the memory pool. It is
2380 // assumed that pPool + uPoolSize won't wrap around by
2381 // assuming the caller won't pass a pool buffer in that is
2382 // not in legitimate memory space.
2383 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
2384
2385 // Check that the pointer for reallocation is in the range of the
2386 // pool. This also makes sure that pointer math further down
2387 // doesn't wrap under or over.
2388 if(pMem >= pPool && pMem < pPoolEnd) {
2389 // Offset to start of chunk for reallocation. This won't
2390 // wrap under because of check that pMem >= pPool. Cast
2391 // is safe because the pool is always less than UINT32_MAX
2392 // because of check in QCBORDecode_SetMemPool().
2393 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
2394
2395 // Check to see if the allocation will fit. uPoolSize -
2396 // uMemOffset will not wrap under because of check that
2397 // pMem is in the range of the uPoolSize by check above.
2398 if(uNewSize <= uPoolSize - uMemOffset) {
2399 ReturnValue.ptr = pMem;
2400 ReturnValue.len = uNewSize;
2401
2402 // Addition won't wrap around over because uNewSize was
2403 // checked to be sure it is less than the pool size.
2404 uFreeOffset = uMemOffset + uNewSize32;
2405 }
2406 }
2407 } else {
2408 // ALLOCATION MODE
2409 // uPoolSize - uFreeOffset will not underflow because this
2410 // pool implementation makes sure uFreeOffset is always
2411 // smaller than uPoolSize through this check here and
2412 // reallocation case.
2413 if(uNewSize <= uPoolSize - uFreeOffset) {
2414 ReturnValue.len = uNewSize;
2415 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
Laurence Lundblade06350ea2020-01-27 19:32:40 -08002416 uFreeOffset += (uint32_t)uNewSize;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002417 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002418 }
2419 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002420 if(pMem) {
2421 // FREE MODE
2422 // Cast is safe because of limit on pool size in
2423 // QCBORDecode_SetMemPool()
2424 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
2425 } else {
2426 // DESTRUCT MODE
2427 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002428 }
2429 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002430
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002431 UsefulBuf Pool = {pPool, uPoolSize};
2432 MemPool_Pack(Pool, uFreeOffset);
2433
2434Done:
2435 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002436}
2437
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002438
Laurence Lundbladef6531662018-12-04 10:42:22 +09002439/*
Laurence Lundblade844bb5c2020-03-01 17:27:25 -08002440 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundbladef6531662018-12-04 10:42:22 +09002441 */
Laurence Lundbladeee851742020-01-08 08:37:05 -08002442QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pMe,
2443 UsefulBuf Pool,
2444 bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002445{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002446 // The pool size and free mem offset are packed into the beginning
2447 // of the pool memory. This compile time check make sure the
2448 // constant in the header is correct. This check should optimize
2449 // down to nothing.
2450 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundblade30816f22018-11-10 13:40:22 +07002451 return QCBOR_ERR_BUFFER_TOO_SMALL;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002452 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002453
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002454 // The pool size and free offset packed in to the beginning of pool
2455 // memory are only 32-bits. This check will optimize out on 32-bit
2456 // machines.
2457 if(Pool.len > UINT32_MAX) {
2458 return QCBOR_ERR_BUFFER_TOO_LARGE;
2459 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002460
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002461 // This checks that the pool buffer given is big enough.
2462 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
2463 return QCBOR_ERR_BUFFER_TOO_SMALL;
2464 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002465
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08002466 pMe->StringAllocator.pfAllocator = MemPool_Function;
2467 pMe->StringAllocator.pAllocateCxt = Pool.ptr;
2468 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08002469
Laurence Lundblade30816f22018-11-10 13:40:22 +07002470 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07002471}
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002472
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002473
2474
Laurence Lundblade9b334962020-08-27 10:55:53 -07002475static inline void CopyTags(QCBORDecodeContext *pMe, const QCBORItem *pItem)
2476{
2477 memcpy(pMe->uLastTags, pItem->uTags, sizeof(pItem->uTags));
2478}
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002479
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002480
2481/*
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002482 Consume an entire map or array (and do next to
2483 nothing for non-aggregate types).
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002484 */
Laurence Lundblade9c905e82020-04-25 11:31:38 -07002485static inline QCBORError
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002486ConsumeItem(QCBORDecodeContext *pMe,
2487 const QCBORItem *pItemToConsume,
2488 uint_fast8_t *puNextNestLevel)
2489{
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002490 QCBORError uReturn;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002491 QCBORItem Item;
Laurence Lundblade9b334962020-08-27 10:55:53 -07002492
Laurence Lundblade02625d42020-06-25 14:41:41 -07002493 DecodeNesting_Print(&(pMe->nesting), &(pMe->InBuf), "ConsumeItem");
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002494
Laurence Lundbladed40951e2020-08-28 11:11:14 -07002495 // If it is a map or array, this will tell if it is empty.
2496 const bool bIsEmpty = (pItemToConsume->uNextNestLevel <= pItemToConsume->uNestingLevel);
2497
2498 if(QCBORItem_IsMapOrArray(pItemToConsume) && !bIsEmpty) {
2499 /* There is only real work to do for non-empty maps and arrays */
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002500
Laurence Lundblade1341c592020-04-11 14:19:05 -07002501 /* This works for definite and indefinite length
2502 * maps and arrays by using the nesting level
2503 */
2504 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002505 uReturn = QCBORDecode_GetNext(pMe, &Item);
Laurence Lundblade323f8a92020-09-06 19:43:09 -07002506 if(QCBORDecode_IsNotWellFormed(uReturn)) {
Laurence Lundblade4b270642020-08-14 12:53:07 -07002507 // TODO: also resource limit errors
Laurence Lundblade1341c592020-04-11 14:19:05 -07002508 goto Done;
2509 }
2510 } while(Item.uNextNestLevel >= pItemToConsume->uNextNestLevel);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002511
Laurence Lundblade1341c592020-04-11 14:19:05 -07002512 if(puNextNestLevel != NULL) {
2513 *puNextNestLevel = Item.uNextNestLevel;
2514 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002515 uReturn = QCBOR_SUCCESS;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002516
Laurence Lundblade1341c592020-04-11 14:19:05 -07002517 } else {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002518 /* item_to_consume is not a map or array */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002519 if(puNextNestLevel != NULL) {
2520 /* Just pass the nesting level through */
2521 *puNextNestLevel = pItemToConsume->uNextNestLevel;
2522 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002523 uReturn = QCBOR_SUCCESS;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002524 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002525
2526Done:
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002527 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002528}
2529
2530
Laurence Lundblade1341c592020-04-11 14:19:05 -07002531/* Return true if the labels in Item1 and Item2 are the same.
2532 Works only for integer and string labels. Returns false
2533 for any other type. */
2534static inline bool
2535MatchLabel(QCBORItem Item1, QCBORItem Item2)
2536{
2537 if(Item1.uLabelType == QCBOR_TYPE_INT64) {
2538 if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
2539 return true;
2540 }
2541 } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002542 if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002543 return true;
2544 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002545 } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002546 if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
2547 return true;
2548 }
2549 } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
2550 if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
2551 return true;
2552 }
2553 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002554
Laurence Lundblade1341c592020-04-11 14:19:05 -07002555 /* Other label types are never matched */
2556 return false;
2557}
2558
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002559
2560/*
2561 Returns true if Item1 and Item2 are the same type
2562 or if either are of QCBOR_TYPE_ANY.
2563 */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002564static inline bool
2565MatchType(QCBORItem Item1, QCBORItem Item2)
2566{
2567 if(Item1.uDataType == Item2.uDataType) {
2568 return true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002569 } else if(Item1.uDataType == QCBOR_TYPE_ANY) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002570 return true;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002571 } else if(Item2.uDataType == QCBOR_TYPE_ANY) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002572 return true;
2573 }
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002574 return false;
2575}
2576
2577
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002578/**
Laurence Lundblade5f53f832020-09-03 12:00:14 -07002579 @brief Search a map for a set of items.
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002580
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07002581 @param[in] pMe The decode context to search.
2582 @param[in,out] pItemArray The items to search for and the items found.
2583 @param[out] puOffset Byte offset of last item matched.
2584 @param[in] pCBContext Context for the not-found item call back.
2585 @param[in] pfCallback Function to call on items not matched in pItemArray.
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002586
2587 @retval QCBOR_ERR_NOT_ENTERED Trying to search without having entered a map
2588
Laurence Lundblade9b334962020-08-27 10:55:53 -07002589 @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label) were found
2590 for one of the labels being search for. This duplicate detection is only performed for items in pItemArray,
2591 not every item in the map.
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002592
2593 @retval QCBOR_ERR_UNEXPECTED_TYPE The label was matched, but not the type.
2594
2595 @retval Also errors returned by QCBORDecode_GetNext().
2596
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002597 On input pItemArray contains a list of labels and data types
2598 of items to be found.
Laurence Lundblade9b334962020-08-27 10:55:53 -07002599
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002600 On output the fully retrieved items are filled in with
2601 values and such. The label was matched, so it never changes.
Laurence Lundblade9b334962020-08-27 10:55:53 -07002602
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07002603 If an item was not found, its data type is set to QCBOR_TYPE_NONE.
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002604 */
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002605static QCBORError
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002606MapSearch(QCBORDecodeContext *pMe,
2607 QCBORItem *pItemArray,
2608 size_t *puOffset,
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002609 void *pCBContext,
2610 QCBORItemCallback pfCallback)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002611{
Laurence Lundbladee6f15112020-07-23 18:44:16 -07002612 QCBORError uReturn;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07002613 uint64_t uFoundItemBitMap = 0;
Laurence Lundbladefb492ea2020-05-02 11:14:07 -07002614
Laurence Lundbladec45b5672020-07-25 23:16:36 -07002615 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07002616 uReturn = pMe->uLastError;
2617 goto Done2;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07002618 }
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07002619
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07002620 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) &&
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07002621 pItemArray->uLabelType != QCBOR_TYPE_NONE) {
2622 /* QCBOR_TYPE_NONE as first item indicates just looking
2623 for the end of an array, so don't give error. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07002624 uReturn = QCBOR_ERR_MAP_NOT_ENTERED;
2625 goto Done2;
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07002626 }
2627
Laurence Lundblade085d7952020-07-24 10:26:30 -07002628 if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) {
2629 // It is an empty bounded array or map
2630 if(pItemArray->uLabelType == QCBOR_TYPE_NONE) {
2631 // Just trying to find the end of the map or array
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07002632 pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting));
Laurence Lundblade085d7952020-07-24 10:26:30 -07002633 uReturn = QCBOR_SUCCESS;
Laurence Lundblade085d7952020-07-24 10:26:30 -07002634 } else {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07002635 // Nothing is ever found in an empty array or map. All items
2636 // are marked as not found below.
Laurence Lundblade085d7952020-07-24 10:26:30 -07002637 uReturn = QCBOR_SUCCESS;
2638 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07002639 goto Done2;
Laurence Lundblade085d7952020-07-24 10:26:30 -07002640 }
2641
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07002642 QCBORDecodeNesting SaveNesting;
Laurence Lundblade085d7952020-07-24 10:26:30 -07002643 DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
2644
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002645 /* Reposition to search from the start of the map / array */
Laurence Lundblade02625d42020-06-25 14:41:41 -07002646 UsefulInputBuf_Seek(&(pMe->InBuf),
2647 DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
Laurence Lundblade1341c592020-04-11 14:19:05 -07002648
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002649 /*
2650 Loop over all the items in the map. They could be
2651 deeply nested and this should handle both definite
2652 and indefinite length maps and arrays, so this
2653 adds some complexity.
2654 */
Laurence Lundblade0a042a92020-06-12 14:09:50 -07002655 const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07002656 uint_fast8_t uNextNestLevel;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002657 do {
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002658 /* Remember offset of the item because sometimes it has to be returned */
Laurence Lundblade1341c592020-04-11 14:19:05 -07002659 const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002660
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002661 /* Get the item */
2662 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002663 uReturn = QCBORDecode_GetNext(pMe, &Item);
Laurence Lundbladec7114722020-08-13 05:11:40 -07002664 if(QCBORDecode_IsNotWellFormed(uReturn)) {
2665 /* Got non-well-formed CBOR so map can't even be decoded. */
Laurence Lundblade4b270642020-08-14 12:53:07 -07002666 // TODO: also bail out on implementation limits like array too big
Laurence Lundblade1341c592020-04-11 14:19:05 -07002667 goto Done;
2668 }
Laurence Lundbladed40951e2020-08-28 11:11:14 -07002669 if(uReturn == QCBOR_ERR_NO_MORE_ITEMS) {
2670 // Unexpected end of map or array.
2671 goto Done;
2672 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002673
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002674 /* See if item has one of the labels that are of interest */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07002675 bool bMatched = false;
2676 for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) {
Laurence Lundblade4b270642020-08-14 12:53:07 -07002677 // TODO: have label filled in on invalid CBOR so error reporting
Laurence Lundblade9b334962020-08-27 10:55:53 -07002678 // can work a lot better.
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07002679 if(MatchLabel(Item, pItemArray[nIndex])) {
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002680 /* A label match has been found */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002681 if(uFoundItemBitMap & (0x01ULL << nIndex)) {
2682 uReturn = QCBOR_ERR_DUPLICATE_LABEL;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002683 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002684 }
Laurence Lundblade830fbf92020-05-31 17:22:33 -07002685 /* Also try to match its type */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07002686 if(!MatchType(Item, pItemArray[nIndex])) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002687 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002688 goto Done;
2689 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07002690
Laurence Lundblade1341c592020-04-11 14:19:05 -07002691 /* Successful match. Return the item. */
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07002692 pItemArray[nIndex] = Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002693 uFoundItemBitMap |= 0x01ULL << nIndex;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002694 if(puOffset) {
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002695 *puOffset = uOffset;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002696 }
Laurence Lundbladec45b5672020-07-25 23:16:36 -07002697 bMatched = true;
2698 }
2699 }
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07002700
2701
Laurence Lundbladec45b5672020-07-25 23:16:36 -07002702 if(!bMatched && pfCallback != NULL) {
2703 /*
2704 Call the callback on unmatched labels.
2705 (It is tempting to do duplicate detection here, but that would
2706 require dynamic memory allocation because the number of labels
2707 that might be encountered is unbounded.)
2708 */
2709 uReturn = (*pfCallback)(pCBContext, &Item);
2710 if(uReturn != QCBOR_SUCCESS) {
2711 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002712 }
2713 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002714
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002715 /*
2716 Consume the item whether matched or not. This
2717 does the work of traversing maps and array and
2718 everything in them. In this loop only the
2719 items at the current nesting level are examined
2720 to match the labels.
2721 */
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002722 uReturn = ConsumeItem(pMe, &Item, &uNextNestLevel);
Laurence Lundbladec7114722020-08-13 05:11:40 -07002723 if(uReturn != QCBOR_SUCCESS) {
Laurence Lundblade1341c592020-04-11 14:19:05 -07002724 goto Done;
2725 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07002726
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002727 } while (uNextNestLevel >= uMapNestLevel);
Laurence Lundblade9b334962020-08-27 10:55:53 -07002728
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002729 uReturn = QCBOR_SUCCESS;
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002730
2731 const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundblade1d85d522020-06-22 13:24:59 -07002732 /* Cast OK because encoded CBOR is limited to UINT32_MAX */
2733 pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07002734
Laurence Lundbladec45b5672020-07-25 23:16:36 -07002735 Done:
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07002736 DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
2737
2738 Done2:
Laurence Lundbladec7114722020-08-13 05:11:40 -07002739 /* For all items not found, set the data type to QCBOR_TYPE_NONE */
2740 for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002741 if(!(uFoundItemBitMap & (0x01ULL << i))) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07002742 pItemArray[i].uDataType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002743 }
2744 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002745
Laurence Lundblade24d509a2020-06-06 18:43:15 -07002746 return uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002747}
2748
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002749
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002750/*
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07002751 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002752*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002753void QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
2754 int64_t nLabel,
2755 uint8_t uQcborType,
2756 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002757{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002758 if(pMe->uLastError != QCBOR_SUCCESS) {
2759 return;
2760 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002761
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002762 QCBORItem OneItemSeach[2];
2763 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
2764 OneItemSeach[0].label.int64 = nLabel;
2765 OneItemSeach[0].uDataType = uQcborType;
2766 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07002767
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07002768 QCBORError uReturn = MapSearch(pMe, OneItemSeach, NULL, NULL, NULL);
2769 if(uReturn != QCBOR_SUCCESS) {
2770 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002771 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002772 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07002773 uReturn = QCBOR_ERR_NOT_FOUND;
2774 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002775 }
2776
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002777 *pItem = OneItemSeach[0];
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07002778
2779 Done:
2780 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002781}
2782
2783
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002784/*
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07002785 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002786*/
Laurence Lundbladeda095972020-06-06 18:35:33 -07002787void QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
2788 const char *szLabel,
Laurence Lundblade323f8a92020-09-06 19:43:09 -07002789 uint8_t uQcborType,
2790 QCBORItem *pItem)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002791{
Laurence Lundbladeda095972020-06-06 18:35:33 -07002792 if(pMe->uLastError != QCBOR_SUCCESS) {
2793 return;
2794 }
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002795
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002796 QCBORItem OneItemSeach[2];
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002797 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
2798 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
2799 OneItemSeach[0].uDataType = uQcborType;
2800 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
Laurence Lundblade1341c592020-04-11 14:19:05 -07002801
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07002802 QCBORError uReturn = MapSearch(pMe, OneItemSeach, NULL, NULL, NULL);
2803 if(uReturn != QCBOR_SUCCESS) {
2804 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002805 }
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002806 if(OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07002807 uReturn = QCBOR_ERR_NOT_FOUND;
2808 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07002809 }
2810
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07002811 *pItem = OneItemSeach[0];
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07002812
2813Done:
2814 pMe->uLastError = (uint8_t)uReturn;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002815}
2816
2817
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07002818
Laurence Lundblade9b334962020-08-27 10:55:53 -07002819static QCBORError CheckTypeList(int uDataType, const uint8_t puTypeList[QCBOR_TAGSPEC_NUM_TYPES])
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07002820{
2821 for(size_t i = 0; i < QCBOR_TAGSPEC_NUM_TYPES; i++) {
2822 if(uDataType == puTypeList[i]) {
2823 return QCBOR_SUCCESS;
2824 }
2825 }
2826 return QCBOR_ERR_UNEXPECTED_TYPE;
2827}
2828
Laurence Lundblade67257dc2020-07-27 03:33:37 -07002829
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002830/**
2831 @param[in] TagSpec Specification for matching tags.
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002832 @param[in] pItem The item to check.
Laurence Lundblade9b334962020-08-27 10:55:53 -07002833
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002834 @retval QCBOR_SUCCESS \c uDataType is allowed by @c TagSpec
2835 @retval QCBOR_ERR_UNEXPECTED_TYPE \c uDataType is not allowed by @c TagSpec
Laurence Lundblade9b334962020-08-27 10:55:53 -07002836
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002837 The data type must be one of the QCBOR_TYPEs, not the IETF CBOR Registered tag value.
2838 */
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002839static QCBORError CheckTagRequirement(const TagSpecification TagSpec, const QCBORItem *pItem)
Laurence Lundblade9b334962020-08-27 10:55:53 -07002840{
2841 if(!(TagSpec.uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS) &&
2842 pItem->uTags[0] != CBOR_TAG_INVALID16) {
2843 /* There are tags that QCBOR couldn't process on this item and
2844 the caller has told us there should not be. */
2845 return QCBOR_ERR_UNEXPECTED_TYPE;
2846 }
2847
2848 const int nTagReq = TagSpec.uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
2849 const int nItemType = pItem->uDataType;
2850
2851 if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
2852 // Must match the tag and only the tag
2853 return CheckTypeList(nItemType, TagSpec.uTaggedTypes);
2854 }
2855
2856 QCBORError uReturn = CheckTypeList(nItemType, TagSpec.uAllowedContentTypes);
2857 if(uReturn == QCBOR_SUCCESS) {
2858 return QCBOR_SUCCESS;
2859 }
2860
2861 if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
2862 /* Must match the content type and only the content type.
2863 There was no match just above so it is a fail. */
2864 return QCBOR_ERR_UNEXPECTED_TYPE;
2865 }
2866
2867 /* If here it can match either the tag or the content
2868 and it hasn't matched the content, so the end
2869 result is whether it matches the tag. This is
2870 also the case that the CBOR standard discourages. */
2871
2872 return CheckTypeList(nItemType, TagSpec.uTaggedTypes);
2873}
2874
Laurence Lundblade9b334962020-08-27 10:55:53 -07002875
Laurence Lundblade9b334962020-08-27 10:55:53 -07002876
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07002877// This could be semi-private if need be
2878static inline
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002879void QCBORDecode_GetTaggedItemInMapN(QCBORDecodeContext *pMe,
2880 int64_t nLabel,
2881 TagSpecification TagSpec,
2882 QCBORItem *pItem)
2883{
2884 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
2885 if(pMe->uLastError != QCBOR_SUCCESS) {
2886 return;
2887 }
2888
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002889 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002890}
2891
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07002892
2893// This could be semi-private if need be
2894static inline
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002895void QCBORDecode_GetTaggedItemInMapSZ(QCBORDecodeContext *pMe,
2896 const char *szLabel,
2897 TagSpecification TagSpec,
2898 QCBORItem *pItem)
2899{
2900 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
2901 if(pMe->uLastError != QCBOR_SUCCESS) {
2902 return;
2903 }
2904
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07002905 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002906}
2907
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002908// Semi-private
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002909void QCBORDecode_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
2910 int64_t nLabel,
2911 TagSpecification TagSpec,
2912 UsefulBufC *pString)
2913{
2914 QCBORItem Item;
2915 QCBORDecode_GetTaggedItemInMapN(pMe, nLabel, TagSpec, &Item);
2916 if(pMe->uLastError == QCBOR_SUCCESS) {
2917 *pString = Item.val.string;
2918 }
2919}
2920
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002921// Semi-private
Laurence Lundblade843a10c2020-05-23 13:57:00 -07002922void QCBORDecode_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
2923 const char * szLabel,
2924 TagSpecification TagSpec,
2925 UsefulBufC *pString)
2926{
2927 QCBORItem Item;
2928 QCBORDecode_GetTaggedItemInMapSZ(pMe, szLabel, TagSpec, &Item);
2929 if(pMe->uLastError == QCBOR_SUCCESS) {
2930 *pString = Item.val.string;
2931 }
2932}
Laurence Lundblade1341c592020-04-11 14:19:05 -07002933
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002934/*
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07002935 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002936*/
Laurence Lundblade5f53f832020-09-03 12:00:14 -07002937void QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002938{
Laurence Lundblade5f53f832020-09-03 12:00:14 -07002939 QCBORError uErr = MapSearch(pMe, pItemList, NULL, NULL, NULL);
2940 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002941}
2942
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002943/*
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07002944 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade4e2da002020-06-13 23:08:31 -07002945*/
Laurence Lundblade5f53f832020-09-03 12:00:14 -07002946void QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe,
2947 QCBORItem *pItemList,
2948 void *pCallbackCtx,
2949 QCBORItemCallback pfCB)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002950{
Laurence Lundblade5f53f832020-09-03 12:00:14 -07002951 QCBORError uErr = MapSearch(pMe, pItemList, NULL, pCallbackCtx, pfCB);
2952 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07002953}
2954
2955
Laurence Lundblade34691b92020-05-18 22:25:25 -07002956static void SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
Laurence Lundblade1341c592020-04-11 14:19:05 -07002957{
Laurence Lundblade323f8a92020-09-06 19:43:09 -07002958 // The first item in pSearch is the one that is to be
2959 // entered. It should be the only one filled in. Any other
2960 // will be ignored unless it causes an error.
Laurence Lundblade34691b92020-05-18 22:25:25 -07002961 if(pMe->uLastError != QCBOR_SUCCESS) {
2962 // Already in error state; do nothing.
2963 return;
2964 }
2965
2966 size_t uOffset;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07002967 pMe->uLastError = (uint8_t)MapSearch(pMe, pSearch, &uOffset, NULL, NULL);
Laurence Lundblade34691b92020-05-18 22:25:25 -07002968 if(pMe->uLastError != QCBOR_SUCCESS) {
2969 return;
2970 }
2971
Laurence Lundblade9b334962020-08-27 10:55:53 -07002972 if(pSearch->uDataType == QCBOR_TYPE_NONE) {
2973 pMe->uLastError = QCBOR_ERR_NOT_FOUND;
2974 return;
2975 }
2976
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002977 /* Need to get the current pre-order nesting level and cursor to be
Laurence Lundblade2c1faf92020-06-26 22:43:56 -07002978 at the map/array about to be entered.
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002979
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07002980 Also need the current map nesting level and start cursor to
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002981 be at the right place.
2982
2983 The UsefulInBuf offset could be anywhere, so no assumption is
2984 made about it.
2985
2986 No assumption is made about the pre-order nesting level either.
2987
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07002988 However the bounded mode nesting level is assumed to be one above
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07002989 the map level that is being entered.
2990 */
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002991 /* Seek to the data item that is the map or array */
2992 UsefulInputBuf_Seek(&(pMe->InBuf), uOffset);
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07002993
2994 DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07002995
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07002996 QCBORDecode_EnterBoundedMapOrArray(pMe, pSearch->uDataType);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07002997}
2998
2999
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003000/*
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07003001 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003002*/
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003003void QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003004{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003005 QCBORItem OneItemSeach[2];
3006 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3007 OneItemSeach[0].label.int64 = nLabel;
3008 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
3009 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003010
Laurence Lundblade9b334962020-08-27 10:55:53 -07003011 /* The map to enter was found, now finish off entering it. */
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003012 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003013}
3014
3015
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003016/*
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07003017 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003018*/
Laurence Lundblade34691b92020-05-18 22:25:25 -07003019void QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003020{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003021 QCBORItem OneItemSeach[2];
3022 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3023 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3024 OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
3025 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade9b334962020-08-27 10:55:53 -07003026
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003027 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003028}
3029
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003030/*
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07003031 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003032*/
Laurence Lundblade34691b92020-05-18 22:25:25 -07003033void QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
Laurence Lundblade1341c592020-04-11 14:19:05 -07003034{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003035 QCBORItem OneItemSeach[2];
3036 OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
3037 OneItemSeach[0].label.int64 = nLabel;
3038 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
3039 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003040
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003041 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade34691b92020-05-18 22:25:25 -07003042}
3043
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003044/*
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07003045 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003046*/
Laurence Lundblade34691b92020-05-18 22:25:25 -07003047void QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
3048{
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003049 QCBORItem OneItemSeach[2];
3050 OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
3051 OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
3052 OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
3053 OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003054
Laurence Lundbladeb90f5362020-05-25 12:17:40 -07003055 SearchAndEnter(pMe, OneItemSeach);
Laurence Lundblade1341c592020-04-11 14:19:05 -07003056}
3057
3058
Laurence Lundblade02625d42020-06-25 14:41:41 -07003059// Semi-private function
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003060void QCBORDecode_EnterBoundedMapOrArray(QCBORDecodeContext *pMe, uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003061{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003062 QCBORError uErr;
3063
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07003064 /* Must only be called on maps and arrays. */
Laurence Lundblade34691b92020-05-18 22:25:25 -07003065 if(pMe->uLastError != QCBOR_SUCCESS) {
3066 // Already in error state; do nothing.
3067 return;
3068 }
Laurence Lundblade1341c592020-04-11 14:19:05 -07003069
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003070 /* Get the data item that is the map or array being entered. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07003071 QCBORItem Item;
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003072 uErr = QCBORDecode_GetNext(pMe, &Item);
3073 if(uErr != QCBOR_SUCCESS) {
3074 goto Done;
Laurence Lundblade3f9ef042020-04-14 13:15:51 -07003075 }
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07003076 if(Item.uDataType != uType) {
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003077 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
3078 goto Done;
Laurence Lundblade1341c592020-04-11 14:19:05 -07003079 }
3080
Laurence Lundbladed40951e2020-08-28 11:11:14 -07003081 CopyTags(pMe, &Item);
3082
3083
Laurence Lundbladef0499502020-08-01 11:55:57 -07003084 const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
Laurence Lundblade085d7952020-07-24 10:26:30 -07003085 if(bIsEmpty) {
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003086 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
3087 // Undo decrement done by QCBORDecode_GetNext() so the the
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003088 // the decrement when exiting the map/array works correctly
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003089 pMe->nesting.pCurrent->u.ma.uCountCursor++;
3090 }
Laurence Lundbladee6f15112020-07-23 18:44:16 -07003091 // Special case to increment nesting level for zero-length maps and arrays entered in bounded mode.
3092 DecodeNesting_Descend(&(pMe->nesting), uType);
3093 }
3094
Laurence Lundblade02625d42020-06-25 14:41:41 -07003095 pMe->uMapEndOffsetCache = MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003096
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003097 uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty,
3098 UsefulInputBuf_Tell(&(pMe->InBuf)));
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003099
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003100Done:
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003101 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003102}
3103
Laurence Lundblade02625d42020-06-25 14:41:41 -07003104
3105/*
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003106 This is the common work for exiting a level that is a bounded map, array or bstr
3107 wrapped CBOR.
Laurence Lundblade02625d42020-06-25 14:41:41 -07003108
3109 One chunk of work is to set up the pre-order traversal so it is at
3110 the item just after the bounded map, array or bstr that is being
3111 exited. This is somewhat complex.
3112
3113 The other work is to level-up the bounded mode to next higest bounded
3114 mode or the top level if there isn't one.
3115 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003116static QCBORError
Laurence Lundblade02625d42020-06-25 14:41:41 -07003117ExitBoundedLevel(QCBORDecodeContext *pMe, uint32_t uEndOffset)
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003118{
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003119 QCBORError uErr;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003120
Laurence Lundblade02625d42020-06-25 14:41:41 -07003121 /*
3122 First the pre-order-traversal byte offset is positioned to the
3123 item just after the bounded mode item that was just consumed.
3124 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003125 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
3126
Laurence Lundblade02625d42020-06-25 14:41:41 -07003127 /*
3128 Next, set the current nesting level to one above the bounded level
3129 that was just exited.
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003130
Laurence Lundblade02625d42020-06-25 14:41:41 -07003131 DecodeNesting_CheckBoundedType() is always called before this and
3132 makes sure pCurrentBounded is valid.
3133 */
3134 DecodeNesting_LevelUpCurrent(&(pMe->nesting));
3135
3136 /*
3137 This does the complex work of leveling up the pre-order traversal
3138 when the end of a map or array or another bounded level is
3139 reached. It may do nothing, or ascend all the way to the top
3140 level.
3141 */
Laurence Lundbladed0304932020-06-27 10:59:38 -07003142 uErr = NestLevelAscender(pMe, false);
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003143 if(uErr != QCBOR_SUCCESS) {
3144 goto Done;
3145 }
3146
Laurence Lundblade02625d42020-06-25 14:41:41 -07003147 /*
3148 This makes the next highest bounded level the current bounded
3149 level. If there is no next highest level, then no bounded mode is
3150 in effect.
3151 */
3152 DecodeNesting_LevelUpBounded(&(pMe->nesting));
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003153
Laurence Lundblade02625d42020-06-25 14:41:41 -07003154 pMe->uMapEndOffsetCache = MAP_OFFSET_CACHE_INVALID;
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003155
3156Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -07003157 DecodeNesting_Print(&(pMe->nesting), &(pMe->InBuf), "ExitBoundedLevel");
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003158 return uErr;
3159}
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003160
Laurence Lundblade02625d42020-06-25 14:41:41 -07003161
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003162// Semi-private function
Laurence Lundblade02625d42020-06-25 14:41:41 -07003163void QCBORDecode_ExitBoundedMapOrArray(QCBORDecodeContext *pMe, uint8_t uType)
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003164{
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003165 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07003166 /* Already in error state; do nothing. */
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003167 return;
3168 }
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003169
Laurence Lundblade02625d42020-06-25 14:41:41 -07003170 QCBORError uErr;
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003171
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003172 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003173 uErr = QCBOR_ERR_CLOSE_MISMATCH;
3174 goto Done;
3175 }
3176
Laurence Lundblade02625d42020-06-25 14:41:41 -07003177 /*
3178 Have to set the offset to the end of the map/array
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003179 that is being exited. If there is no cached value,
Laurence Lundblade02625d42020-06-25 14:41:41 -07003180 from previous map search, then do a dummy search.
3181 */
3182 if(pMe->uMapEndOffsetCache == MAP_OFFSET_CACHE_INVALID) {
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003183 QCBORItem Dummy;
3184 Dummy.uLabelType = QCBOR_TYPE_NONE;
3185 uErr = MapSearch(pMe, &Dummy, NULL, NULL, NULL);
3186 if(uErr != QCBOR_SUCCESS) {
3187 goto Done;
3188 }
3189 }
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003190
Laurence Lundblade02625d42020-06-25 14:41:41 -07003191 uErr = ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003192
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003193Done:
Laurence Lundblade2b843b52020-06-16 20:51:03 -07003194 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladebb87be22020-04-09 19:15:32 -07003195}
3196
3197
Laurence Lundblade1341c592020-04-11 14:19:05 -07003198
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003199static QCBORError InternalEnterBstrWrapped(QCBORDecodeContext *pMe,
Laurence Lundblade02625d42020-06-25 14:41:41 -07003200 const QCBORItem *pItem,
3201 uint8_t uTagRequirement,
3202 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07003203{
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003204 if(pBstr) {
3205 *pBstr = NULLUsefulBufC;
3206 }
3207
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07003208 if(pMe->uLastError != QCBOR_SUCCESS) {
3209 // Already in error state; do nothing.
3210 return pMe->uLastError;
3211 }
3212
3213 QCBORError uError = QCBOR_SUCCESS;
3214
3215 if(pItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
3216 uError = QCBOR_ERR_UNEXPECTED_TYPE;
3217 goto Done;;
3218 }
3219
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07003220 const TagSpecification TagSpec =
3221 {
3222 uTagRequirement,
3223 {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE},
3224 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
3225 };
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07003226
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07003227 uError = CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07003228 if(uError != QCBOR_SUCCESS) {
3229 goto Done;
3230 }
3231
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07003232 if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07003233 /* Reverse the decrement done by GetNext() for the bstr as
Laurence Lundblade410c7e02020-06-25 23:35:29 -07003234 so the increment in NestLevelAscender called by ExitBoundedLevel()
3235 will work right. */
Laurence Lundbladea8edadb2020-06-27 22:35:37 -07003236 DecodeNesting_ReverseDecrement(&(pMe->nesting));
Laurence Lundblade6c8a4442020-06-22 22:16:11 -07003237 }
Laurence Lundblade0750fc42020-06-20 21:02:34 -07003238
3239 if(pBstr) {
3240 *pBstr = pItem->val.string;
3241 }
3242
3243 const size_t uPreviousLength = UsefulInputBuf_GetLength(&(pMe->InBuf));
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07003244
3245 // Need to move UIB input cursor to the right place
Laurence Lundbladef76a2622020-08-06 19:51:03 -07003246 // Most of these calls are simple inline accessors so this doesn't
3247 // amount to much code. There is a range check in the seek.
Laurence Lundblade0750fc42020-06-20 21:02:34 -07003248 const size_t uEndOfBstr = UsefulInputBuf_Tell(&(pMe->InBuf));
Laurence Lundbladef76a2622020-08-06 19:51:03 -07003249 if(uEndOfBstr >= UINT32_MAX || uPreviousLength >= UINT32_MAX) {
3250 // TODO: test this error condition
3251 uError = QCBOR_ERR_BUFFER_TOO_LARGE;
3252 goto Done;
3253 }
Laurence Lundblade0750fc42020-06-20 21:02:34 -07003254 UsefulInputBuf_Seek(&(pMe->InBuf), uEndOfBstr - pItem->val.string.len);
Laurence Lundblade0750fc42020-06-20 21:02:34 -07003255 UsefulInputBuf_SetBufferLen(&(pMe->InBuf), uEndOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07003256
Laurence Lundbladef76a2622020-08-06 19:51:03 -07003257 // Casts are OK because of the checks above.
Laurence Lundblade02625d42020-06-25 14:41:41 -07003258 uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
Laurence Lundbladef76a2622020-08-06 19:51:03 -07003259 (uint32_t)uPreviousLength,
3260 (uint32_t)uEndOfBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07003261Done:
Laurence Lundblade02625d42020-06-25 14:41:41 -07003262 DecodeNesting_Print(&(pMe->nesting), &(pMe->InBuf), "Entered Bstr");
Laurence Lundblade0750fc42020-06-20 21:02:34 -07003263
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07003264 return uError;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07003265}
3266
3267
Laurence Lundblade02625d42020-06-25 14:41:41 -07003268/*
3269 Public function, see header qcbor/qcbor_decode.h file
3270 */
3271void QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe,
Laurence Lundbladec45b5672020-07-25 23:16:36 -07003272 uint8_t uTagRequirement,
3273 UsefulBufC *pBstr)
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003274{
3275 if(pMe->uLastError != QCBOR_SUCCESS) {
3276 // Already in error state; do nothing.
3277 return;
3278 }
3279
3280 /* Get the data item that is the map that is being searched */
Laurence Lundblade0750fc42020-06-20 21:02:34 -07003281 QCBORItem Item;
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003282 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
3283 if(pMe->uLastError != QCBOR_SUCCESS) {
3284 return;
3285 }
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003286
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003287 pMe->uLastError = (uint8_t)InternalEnterBstrWrapped(pMe,
Laurence Lundblade02625d42020-06-25 14:41:41 -07003288 &Item,
3289 uTagRequirement,
3290 pBstr);
Laurence Lundblade24d509a2020-06-06 18:43:15 -07003291}
3292
3293
Laurence Lundblade02625d42020-06-25 14:41:41 -07003294/*
3295 Public function, see header qcbor/qcbor_decode.h file
3296 */
3297void QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe,
Laurence Lundblade02625d42020-06-25 14:41:41 -07003298 int64_t nLabel,
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07003299 uint8_t uTagRequirement,
Laurence Lundblade02625d42020-06-25 14:41:41 -07003300 UsefulBufC *pBstr)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003301{
3302 QCBORItem Item;
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07003303 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003304
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003305 pMe->uLastError = (uint8_t)InternalEnterBstrWrapped(pMe, &Item, uTagRequirement, pBstr);
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003306}
3307
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003308
Laurence Lundblade02625d42020-06-25 14:41:41 -07003309/*
3310 Public function, see header qcbor/qcbor_decode.h file
3311 */
3312void QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe,
Laurence Lundblade02625d42020-06-25 14:41:41 -07003313 const char *szLabel,
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07003314 uint8_t uTagRequirement,
Laurence Lundblade02625d42020-06-25 14:41:41 -07003315 UsefulBufC *pBstr)
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07003316{
3317 QCBORItem Item;
3318 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3319
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07003320 pMe->uLastError = (uint8_t)InternalEnterBstrWrapped(pMe, &Item, uTagRequirement, pBstr);
Laurence Lundbladeaa965d72020-06-17 22:29:22 -07003321}
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003322
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003323
Laurence Lundblade02625d42020-06-25 14:41:41 -07003324/*
3325 Public function, see header qcbor/qcbor_decode.h file
3326 */
Laurence Lundblade0750fc42020-06-20 21:02:34 -07003327void QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003328{
Laurence Lundblade02625d42020-06-25 14:41:41 -07003329 if(pMe->uLastError != QCBOR_SUCCESS) {
3330 // Already in error state; do nothing.
3331 return;
3332 }
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003333
Laurence Lundblade2cd4b0d2020-07-31 08:29:07 -07003334 if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
Laurence Lundblade02625d42020-06-25 14:41:41 -07003335 pMe->uLastError = QCBOR_ERR_CLOSE_MISMATCH;
3336 return;
3337 }
3338
3339 /*
3340 Reset the length of the UsefulInputBuf to what it was before
3341 the bstr wrapped CBOR was entered.
Laurence Lundblade0750fc42020-06-20 21:02:34 -07003342 */
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003343 UsefulInputBuf_SetBufferLen(&(pMe->InBuf),
3344 DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
Laurence Lundblade0750fc42020-06-20 21:02:34 -07003345
3346
Laurence Lundblade02625d42020-06-25 14:41:41 -07003347 QCBORError uErr = ExitBoundedLevel(pMe, DecodeNesting_GetEndOfBstr(&(pMe->nesting)));
Laurence Lundblade1d85d522020-06-22 13:24:59 -07003348 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed8c82c52020-06-12 22:15:52 -07003349}
3350
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07003351
Laurence Lundbladee6430642020-03-14 21:15:44 -07003352
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003353
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003354
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003355
Laurence Lundblade11a064e2020-05-07 13:13:42 -07003356
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003357
Laurence Lundblade9b334962020-08-27 10:55:53 -07003358static QCBORError InterpretBool(QCBORDecodeContext *pMe, const QCBORItem *pItem, bool *pBool)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003359{
3360 switch(pItem->uDataType) {
3361 case QCBOR_TYPE_TRUE:
3362 *pBool = true;
3363 return QCBOR_SUCCESS;
3364 break;
3365
3366 case QCBOR_TYPE_FALSE:
3367 *pBool = false;
3368 return QCBOR_SUCCESS;
3369 break;
3370
3371 default:
3372 return QCBOR_ERR_UNEXPECTED_TYPE;
3373 break;
3374 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003375 CopyTags(pMe, pItem);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003376}
Laurence Lundbladee6430642020-03-14 21:15:44 -07003377
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07003378
Laurence Lundblade9b334962020-08-27 10:55:53 -07003379
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003380/*
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07003381 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003382*/
Laurence Lundbladec4537442020-04-14 18:53:22 -07003383void QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003384{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07003385 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003386 // Already in error state, do nothing
Laurence Lundbladee6430642020-03-14 21:15:44 -07003387 return;
3388 }
3389
Laurence Lundbladec4537442020-04-14 18:53:22 -07003390 QCBORError nError;
3391 QCBORItem Item;
3392
3393 nError = QCBORDecode_GetNext(pMe, &Item);
3394 if(nError != QCBOR_SUCCESS) {
Laurence Lundblade82c2a8f2020-04-29 12:40:19 -07003395 pMe->uLastError = (uint8_t)nError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003396 return;
3397 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003398 pMe->uLastError = (uint8_t)InterpretBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003399}
3400
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07003401
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003402/*
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07003403 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003404*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003405void QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe, int64_t nLabel, bool *pValue)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003406{
3407 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003408 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003409
Laurence Lundblade9b334962020-08-27 10:55:53 -07003410 pMe->uLastError = (uint8_t)InterpretBool(pMe, &Item, pValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003411}
3412
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07003413
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003414/*
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07003415 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003416*/
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003417void QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, bool *pValue)
3418{
3419 QCBORItem Item;
3420 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3421
Laurence Lundblade9b334962020-08-27 10:55:53 -07003422 pMe->uLastError = (uint8_t)InterpretBool(pMe, &Item, pValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003423}
3424
3425
3426
Laurence Lundblade9b334962020-08-27 10:55:53 -07003427/*
3428 A number of methods decode CBOR that is associated with a
3429 specific tag or tags.
Laurence Lundbladec7114722020-08-13 05:11:40 -07003430
Laurence Lundblade9b334962020-08-27 10:55:53 -07003431 The API of the method returns the
3432 data in a way specific to the
3433
3434 No tags at all.
3435
3436
3437 Require tag for the particular type for the method and no other.
3438
3439
3440 Either no tags at all or the particular type for the method and no other.
3441
3442 No tag for particular type; pass other tags along.
3443
3444 Require the tag for the particular type; pass other tags along
3445
3446 Any tagging is OK; consume the tag for the particular type if present,
3447 pass other tags along.
3448
3449
3450 1) REQUIRED
3451- 1 XXXX -- works
3452- T 1 XXX -- works, T is returned
3453
3454 if(tag is of interest) {
3455 process content
3456 return T if present
3457 }
3458
3459
3460 2) FORBIDDEN
3461 - XXX -- works
3462 - T XXX -- ???
3463
3464 if(tag is of interest) {
3465 error out since tag is forbidden
3466 } else {
3467 process contents
3468 return T
3469 }
3470
3471 3) OPTIONAL
3472 - XXX works
3473 - 1 XXX works
3474 - T XXX
3475 - T 1 XXX works, T is returned
3476
3477if (inner tag is of interest) {
3478 process content
3479 return tag T if present
3480 } else if (there is no tag) {
3481 process content
3482 } else {
3483 process content if possible
3484 return T
3485 }
3486
3487A field is type X
3488 - tag for type X is REQUIRED
3489 - tag for type X is FORBIDDEN
3490 - tag for type X is optional
3491 - Other tags are FORBIDDEN
3492 - Other tags are ALLOWED
3493
3494
3495
3496 */
Laurence Lundbladec7114722020-08-13 05:11:40 -07003497
3498static void ProcessEpochDate(QCBORDecodeContext *pMe,
3499 QCBORItem *pItem,
3500 uint8_t uTagRequirement,
3501 int64_t *pnTime)
3502{
3503 if(pMe->uLastError != QCBOR_SUCCESS) {
3504 // Already in error state, do nothing
3505 return;
3506 }
3507
3508 QCBORError uErr;
3509
3510 const TagSpecification TagSpec =
3511 {
3512 uTagRequirement,
3513 {QCBOR_TYPE_DATE_EPOCH, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
3514 {QCBOR_TYPE_INT64, QCBOR_TYPE_DOUBLE, QCBOR_TYPE_FLOAT}
3515 };
3516
Laurence Lundblade4b270642020-08-14 12:53:07 -07003517 // TODO: this will give an unexpected type error instead of
Laurence Lundbladec7114722020-08-13 05:11:40 -07003518 // overflow error for QCBOR_TYPE_UINT64 because TagSpec
3519 // only has three target types.
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07003520 uErr = CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladec7114722020-08-13 05:11:40 -07003521 if(uErr != QCBOR_SUCCESS) {
3522 goto Done;
3523 }
3524
3525 if(pItem->uDataType != QCBOR_TYPE_DATE_EPOCH) {
3526 uErr = DecodeDateEpoch(pItem);
3527 if(uErr != QCBOR_SUCCESS) {
3528 goto Done;
3529 }
3530 }
3531
Laurence Lundblade9b334962020-08-27 10:55:53 -07003532 // Save the tags in the last item's tags in the decode context
3533 // for QCBORDecode_GetNthTagOfLast()
3534 CopyTags(pMe, pItem);
3535
Laurence Lundbladec7114722020-08-13 05:11:40 -07003536 *pnTime = pItem->val.epochDate.nSeconds;
3537
3538Done:
3539 pMe->uLastError = (uint8_t)uErr;
3540}
3541
3542
3543void QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
3544 uint8_t uTagRequirement,
3545 int64_t *pnTime)
3546{
3547 if(pMe->uLastError != QCBOR_SUCCESS) {
3548 // Already in error state, do nothing
3549 return;
3550 }
3551
3552 QCBORItem Item;
3553 pMe->uLastError = (uint8_t)QCBORDecode_GetNext(pMe, &Item);
3554
3555 ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
3556}
3557
3558
3559void
3560QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
3561 int64_t nLabel,
3562 uint8_t uTagRequirement,
3563 int64_t *pnTime)
3564{
3565 QCBORItem Item;
3566 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
3567 ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
3568}
3569
3570
3571void
3572QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
3573 const char *szLabel,
3574 uint8_t uTagRequirement,
3575 int64_t *pnTime)
3576{
3577 QCBORItem Item;
3578 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
3579 ProcessEpochDate(pMe, &Item, uTagRequirement, pnTime);
3580}
3581
3582
3583
3584
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07003585void QCBORDecode_GetTaggedStringInternal(QCBORDecodeContext *pMe,
3586 TagSpecification TagSpec,
3587 UsefulBufC *pBstr)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003588{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07003589 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003590 // Already in error state, do nothing
3591 return;
3592 }
3593
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003594 QCBORError uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003595 QCBORItem Item;
3596
Laurence Lundblade5f4e8712020-07-25 11:44:43 -07003597 uError = QCBORDecode_GetNext(pMe, &Item);
3598 if(uError != QCBOR_SUCCESS) {
3599 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003600 return;
3601 }
3602
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07003603 pMe->uLastError = (uint8_t)CheckTagRequirement(TagSpec, &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003604
3605 if(pMe->uLastError == QCBOR_SUCCESS) {
3606 *pBstr = Item.val.string;
Laurence Lundbladeab40c6f2020-08-28 11:24:58 -07003607 } else {
3608 *pBstr = NULLUsefulBufC;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003609 }
3610}
3611
Laurence Lundbladec4537442020-04-14 18:53:22 -07003612
3613
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003614
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07003615static QCBORError ProcessBigNum(uint8_t uTagRequirement,
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003616 const QCBORItem *pItem,
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07003617 UsefulBufC *pValue,
3618 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003619{
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07003620 const TagSpecification TagSpec =
3621 {
3622 uTagRequirement,
3623 {QCBOR_TYPE_POSBIGNUM, QCBOR_TYPE_NEGBIGNUM, QCBOR_TYPE_NONE},
3624 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
3625 };
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003626
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07003627 QCBORError uErr = CheckTagRequirement(TagSpec, pItem);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003628 if(uErr != QCBOR_SUCCESS) {
3629 return uErr;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003630 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003631
3632 *pValue = pItem->val.string;
3633
3634 if(pItem->uDataType == QCBOR_TYPE_POSBIGNUM) {
3635 *pbIsNegative = false;
3636 } else if(pItem->uDataType == QCBOR_TYPE_NEGBIGNUM) {
3637 *pbIsNegative = true;
3638 }
3639
3640 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003641}
3642
3643
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07003644/*
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003645 Public function, see header qcbor/qcbor_decode.h
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003646 */
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07003647void QCBORDecode_GetBignum(QCBORDecodeContext *pMe,
3648 uint8_t uTagRequirement,
3649 UsefulBufC *pValue,
3650 bool *pbIsNegative)
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003651{
3652 if(pMe->uLastError != QCBOR_SUCCESS) {
3653 // Already in error state, do nothing
3654 return;
3655 }
3656
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003657 QCBORItem Item;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003658 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
3659 if(uError != QCBOR_SUCCESS) {
3660 pMe->uLastError = (uint8_t)uError;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003661 return;
3662 }
3663
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07003664 pMe->uLastError = (uint8_t)ProcessBigNum(uTagRequirement, &Item, pValue, pbIsNegative);
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003665}
3666
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07003667
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003668/*
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07003669 Public function, see header qcbor/qcbor_decode.h
Laurence Lundblade4e2da002020-06-13 23:08:31 -07003670*/
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07003671void QCBORDecode_GetBignumInMapN(QCBORDecodeContext *pMe,
3672 int64_t nLabel,
3673 uint8_t uTagRequirement,
3674 UsefulBufC *pValue,
3675 bool *pbIsNegative)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003676{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003677 QCBORItem Item;
3678 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07003679 if(pMe->uLastError != QCBOR_SUCCESS) {
3680 return;
3681 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003682
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07003683 pMe->uLastError = (uint8_t)ProcessBigNum(uTagRequirement, &Item, pValue, pbIsNegative);
Laurence Lundbladec4537442020-04-14 18:53:22 -07003684}
3685
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07003686
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003687/*
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07003688 Public function, see header qcbor/qcbor_decode.h
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003689*/
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07003690void QCBORDecode_GetBignumInMapSZ(QCBORDecodeContext *pMe,
3691 const char *szLabel,
3692 uint8_t uTagRequirement,
3693 UsefulBufC *pValue,
3694 bool *pbIsNegative)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003695{
3696 QCBORItem Item;
3697 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07003698 if(pMe->uLastError != QCBOR_SUCCESS) {
3699 return;
3700 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003701
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07003702 pMe->uLastError = (uint8_t)ProcessBigNum(uTagRequirement, &Item, pValue, pbIsNegative);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003703}
3704
3705
3706
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07003707
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003708// Semi private
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07003709QCBORError QCBORDecode_GetMIMEInternal(uint8_t uTagRequirement,
3710 const QCBORItem *pItem,
3711 UsefulBufC *pMessage,
3712 bool *pbIsNot7Bit)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003713{
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07003714 const TagSpecification TagSpecText =
3715 {
3716 uTagRequirement,
3717 {QCBOR_TYPE_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
3718 {QCBOR_TYPE_TEXT_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
3719 };
3720 const TagSpecification TagSpecBinary =
3721 {
3722 uTagRequirement,
3723 {QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE},
3724 {QCBOR_TYPE_BYTE_STRING, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
3725 };
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07003726
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003727 QCBORError uReturn;
Laurence Lundblade9b334962020-08-27 10:55:53 -07003728
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07003729 if(CheckTagRequirement(TagSpecText, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003730 *pMessage = pItem->val.string;
3731 if(pbIsNot7Bit != NULL) {
3732 *pbIsNot7Bit = false;
3733 }
3734 uReturn = QCBOR_SUCCESS;
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07003735 } else if(CheckTagRequirement(TagSpecBinary, pItem) == QCBOR_SUCCESS) {
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003736 *pMessage = pItem->val.string;
3737 if(pbIsNot7Bit != NULL) {
3738 *pbIsNot7Bit = true;
3739 }
3740 uReturn = QCBOR_SUCCESS;
3741
3742 } else {
3743 uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
3744 }
Laurence Lundblade9b334962020-08-27 10:55:53 -07003745
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003746 return uReturn;
3747}
3748
Laurence Lundblade9bb039a2020-08-05 12:25:15 -07003749// Improvement: add methods for wrapped CBOR, a simple alternate to EnterBstrWrapped
3750
Laurence Lundblade91853ae2020-06-15 19:35:58 -07003751
3752
3753
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07003754#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
Laurence Lundbladee6430642020-03-14 21:15:44 -07003755
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003756typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003757
3758
Laurence Lundblade784b54b2020-08-10 01:24:52 -07003759// The exponentiator that works on only positive numbers
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003760static QCBORError Exponentitate10(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult)
Laurence Lundbladec4537442020-04-14 18:53:22 -07003761{
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003762 uint64_t uResult = uMantissa;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003763
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003764 if(uResult != 0) {
3765 /* This loop will run a maximum of 19 times because
3766 * UINT64_MAX < 10 ^^ 19. More than that will cause
3767 * exit with the overflow error
3768 */
3769 for(; nExponent > 0; nExponent--) {
3770 if(uResult > UINT64_MAX / 10) {
3771 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Error overflow
3772 }
3773 uResult = uResult * 10;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003774 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07003775
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003776 for(; nExponent < 0; nExponent++) {
3777 uResult = uResult / 10;
3778 if(uResult == 0) {
3779 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Underflow error
3780 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07003781 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07003782 }
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003783 /* else, mantissa is zero so this returns zero */
Laurence Lundbladec4537442020-04-14 18:53:22 -07003784
3785 *puResult = uResult;
3786
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003787 return QCBOR_SUCCESS;
Laurence Lundbladec4537442020-04-14 18:53:22 -07003788}
3789
3790
Laurence Lundblade784b54b2020-08-10 01:24:52 -07003791// The exponentiator that works on only positive numbers
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003792static QCBORError Exponentitate2(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003793{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003794 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003795
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003796 uResult = uMantissa;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003797
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003798 /* This loop will run a maximum of 64 times because
Laurence Lundbladee6430642020-03-14 21:15:44 -07003799 * INT64_MAX < 2^31. More than that will cause
Laurence Lundblade784b54b2020-08-10 01:24:52 -07003800 * exit with the overflow error
Laurence Lundbladee6430642020-03-14 21:15:44 -07003801 */
3802 while(nExponent > 0) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003803 if(uResult > UINT64_MAX >> 1) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003804 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Error overflow
Laurence Lundbladee6430642020-03-14 21:15:44 -07003805 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003806 uResult = uResult << 1;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003807 nExponent--;
3808 }
3809
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003810 while(nExponent < 0 ) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003811 if(uResult == 0) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003812 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW; // Underflow error
3813 }
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003814 uResult = uResult >> 1;
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003815 nExponent++;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003816 }
3817
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003818 *puResult = uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003819
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003820 return QCBOR_SUCCESS;
3821}
3822
Laurence Lundblade784b54b2020-08-10 01:24:52 -07003823
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003824/*
3825 Compute value with signed mantissa and signed result. Works with exponent of 2 or 10 based on exponentiator.
3826 */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07003827static inline QCBORError ExponentiateNN(int64_t nMantissa,
3828 int64_t nExponent,
3829 int64_t *pnResult,
3830 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003831{
3832 uint64_t uResult;
3833
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003834 // Take the absolute value of the mantissa and convert to unsigned.
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07003835 // Improvement: this should be possible in one instruction
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003836 uint64_t uMantissa = nMantissa > 0 ? (uint64_t)nMantissa : (uint64_t)-nMantissa;
3837
3838 // Do the exponentiation of the positive mantissa
3839 QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
3840 if(uReturn) {
3841 return uReturn;
3842 }
3843
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003844
Laurence Lundblade983500d2020-05-14 11:49:34 -07003845 /* (uint64_t)INT64_MAX+1 is used to represent the absolute value
3846 of INT64_MIN. This assumes two's compliment representation where
3847 INT64_MIN is one increment farther from 0 than INT64_MAX.
3848 Trying to write -INT64_MIN doesn't work to get this because the
3849 compiler tries to work with an int64_t which can't represent
3850 -INT64_MIN.
3851 */
3852 uint64_t uMax = nMantissa > 0 ? INT64_MAX : (uint64_t)INT64_MAX+1;
3853
3854 // Error out if too large
3855 if(uResult > uMax) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003856 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
3857 }
3858
3859 // Casts are safe because of checks above
3860 *pnResult = nMantissa > 0 ? (int64_t)uResult : -(int64_t)uResult;
3861
3862 return QCBOR_SUCCESS;
3863}
3864
Laurence Lundblade784b54b2020-08-10 01:24:52 -07003865
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003866/*
3867 Compute value with signed mantissa and unsigned result. Works with exponent of 2 or 10 based on exponentiator.
3868 */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07003869static inline QCBORError ExponentitateNU(int64_t nMantissa,
3870 int64_t nExponent,
3871 uint64_t *puResult,
3872 fExponentiator pfExp)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003873{
3874 if(nMantissa < 0) {
3875 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
3876 }
3877
3878 // Cast to unsigned is OK because of check for negative
3879 // Cast to unsigned is OK because UINT64_MAX > INT64_MAX
3880 // Exponentiation is straight forward
3881 return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
3882}
Laurence Lundblade784b54b2020-08-10 01:24:52 -07003883
3884
3885/*
3886 Compute value with signed mantissa and unsigned result. Works with exponent of 2 or 10 based on exponentiator.
3887 */
3888static inline QCBORError ExponentitateUU(uint64_t uMantissa,
3889 int64_t nExponent,
3890 uint64_t *puResult,
3891 fExponentiator pfExp)
3892{
3893 return (*pfExp)(uMantissa, nExponent, puResult);
3894}
3895
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07003896#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
3897
3898
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003899
3900
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003901
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07003902static QCBORError ConvertBigNumToUnsigned(const UsefulBufC BigNum, uint64_t uMax, uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003903{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003904 uint64_t uResult;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003905
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003906 uResult = 0;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003907 const uint8_t *pByte = BigNum.ptr;
3908 size_t uLen = BigNum.len;
3909 while(uLen--) {
Laurence Lundblade313b2862020-05-16 01:23:06 -07003910 if(uResult > (uMax >> 8)) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07003911 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003912 }
Laurence Lundblade313b2862020-05-16 01:23:06 -07003913 uResult = (uResult << 8) + *pByte++;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003914 }
3915
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003916 *pResult = uResult;
3917 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003918}
3919
Laurence Lundblade784b54b2020-08-10 01:24:52 -07003920
Laurence Lundblade887add82020-05-17 05:50:34 -07003921static inline QCBORError ConvertPositiveBigNumToUnsigned(const UsefulBufC BigNum, uint64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003922{
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003923 return ConvertBigNumToUnsigned(BigNum, UINT64_MAX, pResult);
Laurence Lundbladee6430642020-03-14 21:15:44 -07003924}
3925
Laurence Lundblade784b54b2020-08-10 01:24:52 -07003926
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003927static inline QCBORError ConvertPositiveBigNumToSigned(const UsefulBufC BigNum, int64_t *pResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003928{
3929 uint64_t uResult;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003930 QCBORError uError = ConvertBigNumToUnsigned(BigNum, INT64_MAX, &uResult);
3931 if(uError) {
3932 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003933 }
3934 /* Cast is safe because ConvertBigNum is told to limit to INT64_MAX */
3935 *pResult = (int64_t)uResult;
Laurence Lundblade9c905e82020-04-25 11:31:38 -07003936 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003937}
3938
3939
Laurence Lundblade784b54b2020-08-10 01:24:52 -07003940static inline QCBORError ConvertNegativeBigNumToSigned(const UsefulBufC BigNum, int64_t *pnResult)
Laurence Lundbladee6430642020-03-14 21:15:44 -07003941{
3942 uint64_t uResult;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07003943 /* The negative integer furthest from zero for a C int64_t is
3944 INT64_MIN which is expressed as -INT64_MAX - 1. The value of a
3945 negative number in CBOR is computed as -n - 1 where n is the
3946 encoded integer, where n is what is in the variable BigNum. When
3947 converting BigNum to a uint64_t, the maximum value is thus
3948 INT64_MAX, so that when it -n - 1 is applied to it the result will
3949 never be further from 0 than INT64_MIN.
Laurence Lundbladeda095972020-06-06 18:35:33 -07003950
Laurence Lundblade784b54b2020-08-10 01:24:52 -07003951 -n - 1 <= INT64_MIN.
3952 -n - 1 <= -INT64_MAX - 1
3953 n <= INT64_MAX.
3954 */
Laurence Lundbladeda095972020-06-06 18:35:33 -07003955 QCBORError uError = ConvertBigNumToUnsigned(BigNum, INT64_MAX, &uResult);
Laurence Lundblade784b54b2020-08-10 01:24:52 -07003956 if(uError != QCBOR_SUCCESS) {
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003957 return uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003958 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07003959
3960 /// Now apply -n - 1. The cast is safe because
3961 // ConvertBigNumToUnsigned() is limited to INT64_MAX which does fit
3962 // is the largest positive integer that an int64_t can
3963 // represent. */
3964 *pnResult = -(int64_t)uResult - 1;
3965
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003966 return QCBOR_SUCCESS;
Laurence Lundbladee6430642020-03-14 21:15:44 -07003967}
3968
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07003969
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07003970
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07003971
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07003972
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003973/*
3974Convert a integers and floats to an int64_t.
3975
Laurence Lundblade78f7b932020-07-28 20:02:25 -07003976\param[in] uConvertTypes Bit mask list of conversion options.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003977
Laurence Lundblade78f7b932020-07-28 20:02:25 -07003978\retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested in uConvertTypes.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07003979
3980\retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
3981
3982\retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large or too small.
3983
3984*/
Laurence Lundblade78f7b932020-07-28 20:02:25 -07003985static QCBORError ConvertInt64(const QCBORItem *pItem, uint32_t uConvertTypes, int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003986{
3987 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07003988 case QCBOR_TYPE_FLOAT:
Laurence Lundblade843a10c2020-05-23 13:57:00 -07003989 case QCBOR_TYPE_DOUBLE:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07003990#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07003991 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07003992 /* https://pubs.opengroup.org/onlinepubs/009695399/functions/llround.html
3993 http://www.cplusplus.com/reference/cmath/llround/
3994 */
3995 // Not interested in FE_INEXACT
3996 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07003997 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
3998 *pnValue = llround(pItem->val.dfnum);
3999 } else {
4000 *pnValue = lroundf(pItem->val.fnum);
4001 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07004002 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
4003 // llround() shouldn't result in divide by zero, but catch
4004 // it here in case it unexpectedly does. Don't try to
4005 // distinguish between the various exceptions because it seems
4006 // they vary by CPU, compiler and OS.
4007 return QCBOR_ERR_FLOAT_EXCEPTION;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004008 }
4009 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004010 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004011 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07004012#else
4013 return QCBOR_ERR_HW_FLOAT_DISABLED;
4014#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004015 break;
4016
4017 case QCBOR_TYPE_INT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004018 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004019 *pnValue = pItem->val.int64;
4020 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004021 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004022 }
4023 break;
4024
4025 case QCBOR_TYPE_UINT64:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004026 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004027 if(pItem->val.uint64 < INT64_MAX) {
4028 *pnValue = pItem->val.int64;
4029 } else {
4030 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
4031 }
4032 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004033 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004034 }
4035 break;
4036
4037 default:
4038 return QCBOR_ERR_UNEXPECTED_TYPE;
4039 }
4040 return QCBOR_SUCCESS;
4041}
4042
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004043
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004044void QCBORDecode_GetInt64ConvertInternal(QCBORDecodeContext *pMe,
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004045 uint32_t uConvertTypes,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004046 int64_t *pnValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004047 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004048{
Laurence Lundbladebf3c42d2020-04-14 19:08:51 -07004049 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07004050 return;
4051 }
4052
Laurence Lundbladee6430642020-03-14 21:15:44 -07004053 QCBORItem Item;
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004054 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
4055 if(uError) {
4056 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladee6430642020-03-14 21:15:44 -07004057 return;
4058 }
4059
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004060 if(pItem) {
4061 *pItem = Item;
4062 }
4063
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004064 pMe->uLastError = (uint8_t)ConvertInt64(&Item, uConvertTypes, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004065}
4066
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004067
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004068void QCBORDecode_GetInt64ConvertInternalInMapN(QCBORDecodeContext *pMe,
4069 int64_t nLabel,
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004070 uint32_t uConvertTypes,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004071 int64_t *pnValue,
4072 QCBORItem *pItem)
4073{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004074 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004075 if(pMe->uLastError != QCBOR_SUCCESS) {
4076 return;
4077 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004078
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004079 pMe->uLastError = (uint8_t)ConvertInt64(pItem, uConvertTypes, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004080}
4081
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004082
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004083void QCBORDecode_GetInt64ConvertInternalInMapSZ(QCBORDecodeContext *pMe,
4084 const char * szLabel,
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004085 uint32_t uConvertTypes,
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004086 int64_t *pnValue,
4087 QCBORItem *pItem)
4088{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004089 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004090 if(pMe->uLastError != QCBOR_SUCCESS) {
4091 return;
4092 }
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004093
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004094 pMe->uLastError = (uint8_t)ConvertInt64(pItem, uConvertTypes, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004095}
4096
4097
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004098/*
4099 Convert a large variety of integer types to an int64_t.
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004100
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004101 \param[in] uConvertTypes Bit mask list of conversion options.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004102
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004103 \retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested in uConvertTypes.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004104
4105 \retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
4106
4107 \retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large or too small.
4108
4109 */
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004110static QCBORError Int64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004111{
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004112 switch(pItem->uDataType) {
4113
4114 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004115 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004116 return ConvertPositiveBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004117 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004118 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07004119 }
4120 break;
4121
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004122 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004123 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004124 return ConvertNegativeBigNumToSigned(pItem->val.bigNum, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004125 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004126 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07004127 }
4128 break;
4129
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004130#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
4131 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004132 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004133 return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004134 pItem->val.expAndMantissa.nExponent,
4135 pnValue,
4136 &Exponentitate10);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004137 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004138 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004139 }
4140 break;
4141
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004142 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004143 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004144 return ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004145 pItem->val.expAndMantissa.nExponent,
4146 pnValue,
4147 Exponentitate2);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004148 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004149 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004150 }
4151 break;
4152
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004153 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004154 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07004155 int64_t nMantissa;
4156 QCBORError uErr;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004157 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
4158 if(uErr) {
4159 return uErr;
4160 }
4161 return ExponentiateNN(nMantissa,
4162 pItem->val.expAndMantissa.nExponent,
4163 pnValue,
4164 Exponentitate10);
4165 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004166 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004167 }
4168 break;
4169
4170 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004171 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07004172 int64_t nMantissa;
4173 QCBORError uErr;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004174 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
4175 if(uErr) {
4176 return uErr;
4177 }
4178 return ExponentiateNN(nMantissa,
4179 pItem->val.expAndMantissa.nExponent,
4180 pnValue,
4181 Exponentitate10);
4182 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004183 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004184 }
4185 break;
4186
4187 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004188 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07004189 int64_t nMantissa;
4190 QCBORError uErr;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004191 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
4192 if(uErr) {
4193 return uErr;
4194 }
4195 return ExponentiateNN(nMantissa,
4196 pItem->val.expAndMantissa.nExponent,
4197 pnValue,
4198 Exponentitate2);
4199 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004200 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004201 }
4202 break;
4203
4204 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004205 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07004206 int64_t nMantissa;
4207 QCBORError uErr;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004208 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
4209 if(uErr) {
4210 return uErr;
4211 }
4212 return ExponentiateNN(nMantissa,
4213 pItem->val.expAndMantissa.nExponent,
4214 pnValue,
4215 Exponentitate2);
4216 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004217 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladee6430642020-03-14 21:15:44 -07004218 }
4219 break;
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07004220#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
4221
Laurence Lundbladee6430642020-03-14 21:15:44 -07004222
Laurence Lundbladec4537442020-04-14 18:53:22 -07004223 default:
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07004224 return QCBOR_ERR_UNEXPECTED_TYPE; }
Laurence Lundbladec4537442020-04-14 18:53:22 -07004225}
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004226
4227
Laurence Lundbladec4537442020-04-14 18:53:22 -07004228/*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004229 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004230 */
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004231void QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uConvertTypes, int64_t *pnValue)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004232{
4233 QCBORItem Item;
4234
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004235 QCBORDecode_GetInt64ConvertInternal(pMe, uConvertTypes, pnValue, &Item);
Laurence Lundbladec4537442020-04-14 18:53:22 -07004236
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004237 if(pMe->uLastError == QCBOR_SUCCESS) {
4238 // The above conversion succeeded
4239 return;
4240 }
4241
Laurence Lundbladef6c86662020-05-12 02:08:00 -07004242 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004243 // The above conversion failed in a way that code below can't correct
Laurence Lundbladec4537442020-04-14 18:53:22 -07004244 return;
4245 }
4246
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004247 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uConvertTypes, pnValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004248}
4249
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004250
4251/*
4252Public function, see header qcbor/qcbor_decode.h file
4253*/
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004254void QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
4255 int64_t nLabel,
4256 uint32_t uConvertTypes,
4257 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004258{
4259 QCBORItem Item;
4260
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004261 QCBORDecode_GetInt64ConvertInternalInMapN(pMe, nLabel, uConvertTypes, pnValue, &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004262
4263 if(pMe->uLastError == QCBOR_SUCCESS) {
4264 // The above conversion succeeded
4265 return;
4266 }
4267
4268 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
4269 // The above conversion failed in a way that code below can't correct
4270 return;
4271 }
4272
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004273 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uConvertTypes, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004274}
4275
4276
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004277/*
4278Public function, see header qcbor/qcbor_decode.h file
4279*/
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004280void QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
4281 const char *szLabel,
4282 uint32_t uConvertTypes,
4283 int64_t *pnValue)
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004284{
4285 QCBORItem Item;
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004286 QCBORDecode_GetInt64ConvertInternalInMapSZ(pMe, szLabel, uConvertTypes, pnValue, &Item);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004287
4288 if(pMe->uLastError == QCBOR_SUCCESS) {
4289 // The above conversion succeeded
4290 return;
4291 }
4292
4293 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
4294 // The above conversion failed in a way that code below can't correct
4295 return;
4296 }
4297
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004298 pMe->uLastError = (uint8_t)Int64ConvertAll(&Item, uConvertTypes, pnValue);
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004299}
4300
4301
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004302static QCBORError ConvertUint64(const QCBORItem *pItem, uint32_t uConvertTypes, uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004303{
4304 switch(pItem->uDataType) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004305 case QCBOR_TYPE_DOUBLE:
4306 case QCBOR_TYPE_FLOAT:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07004307#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004308 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07004309 // Can't use llround here because it will not convert values
4310 // greater than INT64_MAX and less than UINT64_MAX that
4311 // need to be converted so it is more complicated.
4312 feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
4313 if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
4314 if(isnan(pItem->val.dfnum)) {
4315 return QCBOR_ERR_FLOAT_EXCEPTION;
4316 } else if(pItem->val.dfnum < 0) {
4317 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
4318 } else {
4319 double dRounded = round(pItem->val.dfnum);
4320 // See discussion in DecodeDateEpoch() for
4321 // explanation of - 0x7ff
4322 if(dRounded > (double)(UINT64_MAX- 0x7ff)) {
4323 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
4324 }
4325 *puValue = (uint64_t)dRounded;
4326 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004327 } else {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07004328 if(isnan(pItem->val.fnum)) {
4329 return QCBOR_ERR_FLOAT_EXCEPTION;
4330 } else if(pItem->val.fnum < 0) {
4331 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
4332 } else {
4333 float fRounded = roundf(pItem->val.fnum);
4334 // See discussion in DecodeDateEpoch() for
4335 // explanation of - 0x7ff
4336 if(fRounded > (float)(UINT64_MAX- 0x7ff)) {
4337 return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
4338 }
4339 *puValue = (uint64_t)fRounded;
4340 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004341 }
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07004342 if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
4343 // round() and roundf() shouldn't result in exceptions here, but
4344 // catch them to be robust and thorough. Don't try to
4345 // distinguish between the various exceptions because it seems
4346 // they vary by CPU, compiler and OS.
4347 return QCBOR_ERR_FLOAT_EXCEPTION;
4348 }
4349
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004350 } else {
4351 return QCBOR_ERR_UNEXPECTED_TYPE;
4352 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07004353#else
4354 return QCBOR_ERR_HW_FLOAT_DISABLED;
4355#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004356 break;
Laurence Lundblade843a10c2020-05-23 13:57:00 -07004357
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004358 case QCBOR_TYPE_INT64:
4359 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
4360 if(pItem->val.int64 >= 0) {
4361 *puValue = (uint64_t)pItem->val.int64;
4362 } else {
4363 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
4364 }
4365 } else {
4366 return QCBOR_ERR_UNEXPECTED_TYPE;
4367 }
4368 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004369
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004370 case QCBOR_TYPE_UINT64:
4371 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
4372 *puValue = pItem->val.uint64;
4373 } else {
4374 return QCBOR_ERR_UNEXPECTED_TYPE;
4375 }
4376 break;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004377
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004378 default:
4379 return QCBOR_ERR_UNEXPECTED_TYPE;
4380 }
4381
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004382 return QCBOR_SUCCESS;
4383}
Laurence Lundbladec4537442020-04-14 18:53:22 -07004384
4385
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004386void QCBORDecode_GetUInt64ConvertInternal(QCBORDecodeContext *pMe,
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004387 uint32_t uConvertTypes,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004388 uint64_t *puValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004389 QCBORItem *pItem)
Laurence Lundbladec4537442020-04-14 18:53:22 -07004390{
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004391 if(pMe->uLastError != QCBOR_SUCCESS) {
4392 return;
4393 }
4394
Laurence Lundbladec4537442020-04-14 18:53:22 -07004395 QCBORItem Item;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004396
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004397 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
4398 if(uError) {
4399 pMe->uLastError = (uint8_t)uError;
Laurence Lundbladec4537442020-04-14 18:53:22 -07004400 return;
4401 }
4402
Laurence Lundbladea826c502020-05-10 21:07:00 -07004403 if(pItem) {
4404 *pItem = Item;
4405 }
4406
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004407 pMe->uLastError = (uint8_t)ConvertUint64(&Item, uConvertTypes, puValue);
Laurence Lundbladec4537442020-04-14 18:53:22 -07004408}
4409
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004410
Laurence Lundblade95b64bb2020-08-30 00:17:38 -07004411void QCBORDecode_GetUInt64ConvertInternalInMapN(QCBORDecodeContext *pMe,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004412 int64_t nLabel,
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004413 uint32_t uConvertTypes,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004414 uint64_t *puValue,
4415 QCBORItem *pItem)
4416{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004417 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004418 if(pMe->uLastError != QCBOR_SUCCESS) {
4419 return;
4420 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004421
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004422 pMe->uLastError = (uint8_t)ConvertUint64(pItem, uConvertTypes, puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004423}
4424
4425
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07004426void QCBORDecode_GetUInt64ConvertInternalInMapSZ(QCBORDecodeContext *pMe,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004427 const char * szLabel,
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004428 uint32_t uConvertTypes,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004429 uint64_t *puValue,
4430 QCBORItem *pItem)
4431{
4432 if(pMe->uLastError != QCBOR_SUCCESS) {
4433 return;
4434 }
4435
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004436 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004437 if(pMe->uLastError != QCBOR_SUCCESS) {
4438 return;
4439 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004440
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004441 pMe->uLastError = (uint8_t)ConvertUint64(pItem, uConvertTypes, puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004442}
4443
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004444
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004445/*
4446 Public function, see header qcbor/qcbor_decode.h file
4447*/
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004448static QCBORError Uint64ConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004449{
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004450 switch(pItem->uDataType) {
4451
4452 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004453 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004454 return ConvertPositiveBigNumToUnsigned(pItem->val.bigNum, puValue);
4455 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004456 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004457 }
4458 break;
4459
4460 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004461 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004462 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
4463 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004464 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004465 }
4466 break;
4467
4468#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
4469
4470 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004471 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004472 return ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004473 pItem->val.expAndMantissa.nExponent,
4474 puValue,
4475 Exponentitate10);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004476 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004477 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004478 }
4479 break;
4480
4481 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004482 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004483 return ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
4484 pItem->val.expAndMantissa.nExponent,
4485 puValue,
4486 Exponentitate2);
4487 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004488 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004489 }
4490 break;
4491
4492 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004493 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004494 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07004495 QCBORError uErr;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004496 uErr = ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004497 if(uErr != QCBOR_SUCCESS) {
4498 return uErr;
4499 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004500 return ExponentitateUU(uMantissa,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004501 pItem->val.expAndMantissa.nExponent,
4502 puValue,
4503 Exponentitate10);
4504 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004505 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004506 }
4507 break;
4508
4509 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004510 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004511 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
4512 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004513 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004514 }
4515 break;
4516
4517 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004518 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004519 uint64_t uMantissa;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07004520 QCBORError uErr;
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004521 uErr = ConvertPositiveBigNumToUnsigned(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004522 if(uErr != QCBOR_SUCCESS) {
4523 return uErr;
4524 }
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004525 return ExponentitateUU(uMantissa,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004526 pItem->val.expAndMantissa.nExponent,
4527 puValue,
4528 Exponentitate2);
4529 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004530 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004531 }
4532 break;
4533
4534 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004535 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004536 return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
4537 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004538 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004539 }
4540 break;
4541#endif
4542 default:
4543 return QCBOR_ERR_UNEXPECTED_TYPE;
4544 }
4545}
4546
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004547
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004548/*
4549 Public function, see header qcbor/qcbor_decode.h file
4550*/
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004551void QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe, uint32_t uConvertTypes, uint64_t *puValue)
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004552{
4553 QCBORItem Item;
4554
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004555 QCBORDecode_GetUInt64ConvertInternal(pMe, uConvertTypes, puValue, &Item);
Laurence Lundblade9c905e82020-04-25 11:31:38 -07004556
Laurence Lundbladef6c86662020-05-12 02:08:00 -07004557 if(pMe->uLastError == QCBOR_SUCCESS) {
4558 // The above conversion succeeded
4559 return;
4560 }
4561
4562 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
4563 // The above conversion failed in a way that code below can't correct
Laurence Lundbladee6430642020-03-14 21:15:44 -07004564 return;
4565 }
4566
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004567 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uConvertTypes, puValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004568}
4569
Laurence Lundbladec4537442020-04-14 18:53:22 -07004570
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004571/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004572 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004573*/
Laurence Lundblade95b64bb2020-08-30 00:17:38 -07004574void QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
Laurence Lundblade9b334962020-08-27 10:55:53 -07004575 int64_t nLabel,
4576 uint32_t uConvertTypes,
4577 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004578{
4579 QCBORItem Item;
4580
Laurence Lundblade95b64bb2020-08-30 00:17:38 -07004581 QCBORDecode_GetUInt64ConvertInternalInMapN(pMe, nLabel, uConvertTypes, puValue, &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004582
4583 if(pMe->uLastError == QCBOR_SUCCESS) {
4584 // The above conversion succeeded
4585 return;
4586 }
4587
4588 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
4589 // The above conversion failed in a way that code below can't correct
4590 return;
4591 }
4592
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004593 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uConvertTypes, puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004594}
4595
4596
4597/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004598 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004599*/
Laurence Lundblade95b64bb2020-08-30 00:17:38 -07004600void QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
Laurence Lundblade9b334962020-08-27 10:55:53 -07004601 const char *szLabel,
4602 uint32_t uConvertTypes,
4603 uint64_t *puValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004604{
4605 QCBORItem Item;
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004606 QCBORDecode_GetUInt64ConvertInternalInMapSZ(pMe, szLabel, uConvertTypes, puValue, &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004607
4608 if(pMe->uLastError == QCBOR_SUCCESS) {
4609 // The above conversion succeeded
4610 return;
4611 }
4612
4613 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
4614 // The above conversion failed in a way that code below can't correct
4615 return;
4616 }
4617
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004618 pMe->uLastError = (uint8_t)Uint64ConvertAll(&Item, uConvertTypes, puValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004619}
4620
4621
Laurence Lundblade9b334962020-08-27 10:55:53 -07004622static QCBORError ConvertDouble(const QCBORItem *pItem,
4623 uint32_t uConvertTypes,
4624 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004625{
4626 switch(pItem->uDataType) {
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07004627 case QCBOR_TYPE_FLOAT:
4628#ifndef QCBOR_DISABLE_FLOAT_HW_USE
4629 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
4630 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07004631 // Simple cast does the job.
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07004632 *pdValue = (double)pItem->val.fnum;
4633 } else {
4634 return QCBOR_ERR_UNEXPECTED_TYPE;
4635 }
4636 }
4637#else
4638 return QCBOR_ERR_HW_FLOAT_DISABLED;
4639#endif
4640 break;
4641
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004642 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004643 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
4644 if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004645 *pdValue = pItem->val.dfnum;
4646 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004647 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004648 }
4649 }
4650 break;
4651
4652 case QCBOR_TYPE_INT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07004653#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004654 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07004655 // A simple cast seems to do the job with no worry of exceptions.
4656 // There will be precision loss for some values.
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004657 *pdValue = (double)pItem->val.int64;
4658
4659 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004660 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004661 }
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07004662#else
4663 return QCBOR_ERR_HW_FLOAT_DISABLED;
4664#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004665 break;
4666
4667 case QCBOR_TYPE_UINT64:
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07004668#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004669 if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
Laurence Lundbladedfd49fc2020-09-01 14:17:16 -07004670 // A simple cast seems to do the job with no worry of exceptions.
4671 // There will be precision loss for some values.
4672 *pdValue = (double)pItem->val.uint64;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004673 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004674 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004675 }
4676 break;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07004677#else
4678 return QCBOR_ERR_HW_FLOAT_DISABLED;
4679#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004680
4681 default:
4682 return QCBOR_ERR_UNEXPECTED_TYPE;
4683 }
4684
4685 return QCBOR_SUCCESS;
4686}
4687
4688
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004689void QCBORDecode_GetDoubleConvertInternal(QCBORDecodeContext *pMe,
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004690 uint32_t uConvertTypes,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004691 double *pdValue,
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004692 QCBORItem *pItem)
Laurence Lundbladee6430642020-03-14 21:15:44 -07004693{
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004694 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundbladec4537442020-04-14 18:53:22 -07004695 return;
4696 }
4697
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004698 QCBORItem Item;
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004699
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004700 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004701 if(uError) {
4702 pMe->uLastError = (uint8_t)uError;
4703 return;
4704 }
4705
4706 if(pItem) {
4707 *pItem = Item;
4708 }
Laurence Lundbladec4537442020-04-14 18:53:22 -07004709
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004710 pMe->uLastError = (uint8_t)ConvertDouble(&Item, uConvertTypes, pdValue);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004711}
Laurence Lundbladec4537442020-04-14 18:53:22 -07004712
Laurence Lundbladec4537442020-04-14 18:53:22 -07004713
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004714void QCBORDecode_GetDoubleConvertInternalInMapN(QCBORDecodeContext *pMe,
4715 int64_t nLabel,
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004716 uint32_t uConvertTypes,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004717 double *pdValue,
4718 QCBORItem *pItem)
4719{
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004720 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004721 if(pMe->uLastError != QCBOR_SUCCESS) {
4722 return;
4723 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004724
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004725 pMe->uLastError = (uint8_t)ConvertDouble(pItem, uConvertTypes, pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004726}
4727
Laurence Lundblade784b54b2020-08-10 01:24:52 -07004728
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004729void QCBORDecode_GetDoubleConvertInternalInMapSZ(QCBORDecodeContext *pMe,
4730 const char * szLabel,
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004731 uint32_t uConvertTypes,
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004732 double *pdValue,
4733 QCBORItem *pItem)
4734{
4735 if(pMe->uLastError != QCBOR_SUCCESS) {
4736 return;
4737 }
4738
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07004739 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
Laurence Lundbladeabf5c572020-06-29 21:21:29 -07004740 if(pMe->uLastError != QCBOR_SUCCESS) {
4741 return;
4742 }
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004743
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004744 pMe->uLastError = (uint8_t)ConvertDouble(pItem, uConvertTypes, pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004745}
4746
4747
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07004748#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07004749static double ConvertBigNumToDouble(const UsefulBufC BigNum)
4750{
4751 double dResult;
4752
4753 dResult = 0.0;
4754 const uint8_t *pByte = BigNum.ptr;
4755 size_t uLen = BigNum.len;
4756 /* This will overflow and become the float value INFINITY if the number
Laurence Lundblade11fd78b2020-09-01 22:13:27 -07004757 is too large to fit. */
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07004758 while(uLen--) {
4759 dResult = (dResult * 256.0) + (double)*pByte++;
4760 }
4761
4762 return dResult;
4763}
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07004764#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
4765
Laurence Lundblade9ab5abb2020-05-20 12:10:45 -07004766
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004767static QCBORError DoubleConvertAll(const QCBORItem *pItem, uint32_t uConvertTypes, double *pdValue)
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004768{
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07004769#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004770 /*
Laurence Lundblade54cd99c2020-05-15 02:25:32 -07004771 https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
4772
4773 */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004774 switch(pItem->uDataType) {
Laurence Lundblade410c7e02020-06-25 23:35:29 -07004775
4776#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004777 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004778 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07004779 // Underflow gives 0, overflow gives infinity
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004780 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
4781 pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
4782 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004783 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004784 }
4785 break;
4786
4787 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004788 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
Laurence Lundblade51722fd2020-09-02 13:01:33 -07004789 // Underflow gives 0, overflow gives infinity
4790 *pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
4791 exp2((double)pItem->val.expAndMantissa.nExponent);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004792 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004793 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004794 }
4795 break;
Laurence Lundblade410c7e02020-06-25 23:35:29 -07004796#endif /* ndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004797
4798 case QCBOR_TYPE_POSBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004799 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004800 *pdValue = ConvertBigNumToDouble(pItem->val.bigNum);
4801 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004802 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004803 }
4804 break;
4805
4806 case QCBOR_TYPE_NEGBIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004807 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07004808 *pdValue = -1-ConvertBigNumToDouble(pItem->val.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004809 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004810 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004811 }
4812 break;
4813
Laurence Lundblade410c7e02020-06-25 23:35:29 -07004814#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004815 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004816 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004817 double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
4818 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
4819 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004820 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004821 }
4822 break;
4823
4824 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004825 if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004826 double dMantissa = -ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
4827 *pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
4828 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004829 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004830 }
4831 break;
4832
4833 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004834 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004835 double dMantissa = ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
4836 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
4837 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004838 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004839 }
4840 break;
4841
4842 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004843 if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
Laurence Lundbladeda095972020-06-06 18:35:33 -07004844 double dMantissa = -1-ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004845 *pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
4846 } else {
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004847 return QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004848 }
4849 break;
Laurence Lundblade410c7e02020-06-25 23:35:29 -07004850#endif /* ndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
4851
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004852 default:
4853 return QCBOR_ERR_UNEXPECTED_TYPE;
4854 }
4855
4856 return QCBOR_SUCCESS;
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07004857
4858#else
4859 (void)pItem;
4860 (void)uConvertTypes;
4861 (void)pdValue;
4862 return QCBOR_ERR_HW_FLOAT_DISABLED;
4863#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
4864
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004865}
4866
4867
4868/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004869 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004870*/
Laurence Lundblade9b334962020-08-27 10:55:53 -07004871void QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe,
4872 uint32_t uConvertTypes,
4873 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004874{
4875
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004876 QCBORItem Item;
4877
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004878 QCBORDecode_GetDoubleConvertInternal(pMe, uConvertTypes, pdValue, &Item);
Laurence Lundbladeb340ba72020-05-14 11:41:10 -07004879
4880 if(pMe->uLastError == QCBOR_SUCCESS) {
4881 // The above conversion succeeded
4882 return;
4883 }
4884
4885 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
4886 // The above conversion failed in a way that code below can't correct
4887 return;
4888 }
4889
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004890 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uConvertTypes, pdValue);
Laurence Lundbladee6430642020-03-14 21:15:44 -07004891}
4892
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004893
4894/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004895 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004896*/
Laurence Lundblade9b334962020-08-27 10:55:53 -07004897void QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe,
4898 int64_t nLabel,
4899 uint32_t uConvertTypes,
4900 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004901{
4902 QCBORItem Item;
4903
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004904 QCBORDecode_GetDoubleConvertInternalInMapN(pMe, nLabel, uConvertTypes, pdValue, &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004905
4906 if(pMe->uLastError == QCBOR_SUCCESS) {
4907 // The above conversion succeeded
4908 return;
4909 }
4910
4911 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
4912 // The above conversion failed in a way that code below can't correct
4913 return;
4914 }
4915
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004916 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uConvertTypes, pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004917}
4918
4919
4920/*
Laurence Lundblade4e2da002020-06-13 23:08:31 -07004921 Public function, see header qcbor/qcbor_decode.h file
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004922*/
Laurence Lundblade9b334962020-08-27 10:55:53 -07004923void QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe,
4924 const char *szLabel,
4925 uint32_t uConvertTypes,
4926 double *pdValue)
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004927{
4928 QCBORItem Item;
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004929 QCBORDecode_GetDoubleConvertInternalInMapSZ(pMe, szLabel, uConvertTypes, pdValue, &Item);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004930
4931 if(pMe->uLastError == QCBOR_SUCCESS) {
4932 // The above conversion succeeded
4933 return;
4934 }
4935
4936 if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
4937 // The above conversion failed in a way that code below can't correct
4938 return;
4939 }
4940
Laurence Lundblade78f7b932020-07-28 20:02:25 -07004941 pMe->uLastError = (uint8_t)DoubleConvertAll(&Item, uConvertTypes, pdValue);
Laurence Lundblade7e5be1d2020-05-24 21:17:28 -07004942}
Laurence Lundblade91853ae2020-06-15 19:35:58 -07004943
4944
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07004945
4946
Laurence Lundblade410c7e02020-06-25 23:35:29 -07004947#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07004948static inline UsefulBufC ConvertIntToBigNum(uint64_t uInt, UsefulBuf Buffer)
4949{
4950 while((uInt & 0xff00000000000000UL) == 0) {
4951 uInt = uInt << 8;
4952 };
4953
4954 UsefulOutBuf UOB;
4955
4956 UsefulOutBuf_Init(&UOB, Buffer);
4957
4958 while(uInt) {
4959 const uint64_t xx = uInt & 0xff00000000000000UL;
4960 UsefulOutBuf_AppendByte(&UOB, (uint8_t)((uInt & 0xff00000000000000UL) >> 56));
4961 uInt = uInt << 8;
4962 (void)xx;
4963 }
4964
4965 return UsefulOutBuf_OutUBuf(&UOB);
4966}
4967
4968
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07004969static QCBORError MantissaAndExponentTypeHandler(QCBORDecodeContext *pMe,
4970 TagSpecification TagSpec,
4971 QCBORItem *pItem)
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07004972{
4973 QCBORError uErr;
4974 // Loops runs at most 1.5 times. Making it a loop saves object code.
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07004975 while(1) {
Laurence Lundblade6f3f78e2020-08-31 13:09:14 -07004976 uErr = CheckTagRequirement(TagSpec, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07004977 if(uErr != QCBOR_SUCCESS) {
4978 goto Done;
4979 }
4980
4981 if(pItem->uDataType != QCBOR_TYPE_ARRAY) {
4982 break; // Successful exit. Moving on to finish decoding.
4983 }
4984
4985 // The item is an array, which means an undecoded
4986 // mantissa and exponent, so decode it. It will then
4987 // have a different type and exit the loop if.
4988 uErr = QCBORDecode_MantissaAndExponent(pMe, pItem);
4989 if(uErr != QCBOR_SUCCESS) {
4990 goto Done;
4991 }
4992
4993 // Second time around, the type must match.
Laurence Lundblade9b334962020-08-27 10:55:53 -07004994 TagSpec.uTagRequirement = QCBOR_TAG_REQUIREMENT_TAG;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07004995 }
4996Done:
4997 return uErr;
4998}
4999
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005000
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005001static void ProcessMantissaAndExponent(QCBORDecodeContext *pMe,
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005002 TagSpecification TagSpec,
5003 QCBORItem *pItem,
5004 int64_t *pnMantissa,
5005 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005006{
5007 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07005008
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005009 uErr = MantissaAndExponentTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005010 if(uErr != QCBOR_SUCCESS) {
5011 goto Done;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005012 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005013
Laurence Lundblade9b334962020-08-27 10:55:53 -07005014 switch (pItem->uDataType) {
5015
5016 case QCBOR_TYPE_DECIMAL_FRACTION:
5017 case QCBOR_TYPE_BIGFLOAT:
5018 *pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
5019 *pnExponent = pItem->val.expAndMantissa.nExponent;
5020 break;
5021
5022 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
5023 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
5024 *pnExponent = pItem->val.expAndMantissa.nExponent;
5025 uErr = ConvertPositiveBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
5026 break;
5027
5028 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
5029 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
5030 *pnExponent = pItem->val.expAndMantissa.nExponent;
5031 uErr = ConvertNegativeBigNumToSigned(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
5032 break;
5033
5034 default:
5035 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
5036 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005037
5038 Done:
5039 pMe->uLastError = (uint8_t)uErr;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005040}
5041
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07005042
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005043static void ProcessMantissaAndExponentBig(QCBORDecodeContext *pMe,
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005044 TagSpecification TagSpec,
5045 QCBORItem *pItem,
5046 UsefulBuf BufferForMantissa,
5047 UsefulBufC *pMantissa,
5048 bool *pbIsNegative,
5049 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07005050{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005051 QCBORError uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07005052
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005053 uErr = MantissaAndExponentTypeHandler(pMe, TagSpec, pItem);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07005054 if(uErr != QCBOR_SUCCESS) {
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005055 goto Done;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07005056 }
5057
5058 uint64_t uMantissa;
5059
5060 switch (pItem->uDataType) {
5061
5062 case QCBOR_TYPE_DECIMAL_FRACTION:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005063 case QCBOR_TYPE_BIGFLOAT:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07005064 if(pItem->val.expAndMantissa.Mantissa.nInt >= 0) {
5065 uMantissa = (uint64_t)pItem->val.expAndMantissa.Mantissa.nInt;
5066 *pbIsNegative = false;
5067 } else {
5068 uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt;
5069 *pbIsNegative = true;
5070 }
5071 *pMantissa = ConvertIntToBigNum(uMantissa, BufferForMantissa);
5072 *pnExponent = pItem->val.expAndMantissa.nExponent;
5073 break;
5074
5075 case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005076 case QCBOR_TYPE_BIGFLOAT_POS_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07005077 *pnExponent = pItem->val.expAndMantissa.nExponent;
5078 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
5079 *pbIsNegative = false;
5080 break;
5081
5082 case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005083 case QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM:
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07005084 *pnExponent = pItem->val.expAndMantissa.nExponent;
5085 *pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
5086 *pbIsNegative = true;
5087 break;
5088
5089 default:
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005090 uErr = QCBOR_ERR_UNEXPECTED_TYPE;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07005091 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005092
5093Done:
5094 pMe->uLastError = (uint8_t)uErr;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07005095}
5096
5097
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005098/*
5099 Public function, see header qcbor/qcbor_decode.h file
5100*/
5101void QCBORDecode_GetDecimalFraction(QCBORDecodeContext *pMe,
5102 uint8_t uTagRequirement,
5103 int64_t *pnMantissa,
5104 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07005105{
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07005106 if(pMe->uLastError != QCBOR_SUCCESS) {
5107 return;
5108 }
5109
5110 QCBORItem Item;
5111 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
5112 if(uError) {
5113 pMe->uLastError = (uint8_t)uError;
5114 return;
5115 }
5116
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005117 const TagSpecification TagSpec =
5118 {
5119 uTagRequirement,
5120 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM},
5121 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
5122 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005123
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005124 ProcessMantissaAndExponent(pMe, TagSpec, &Item, pnMantissa, pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07005125}
5126
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005127
5128/*
5129 Public function, see header qcbor/qcbor_decode.h file
5130*/
5131void QCBORDecode_GetDecimalFractionInMapN(QCBORDecodeContext *pMe,
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005132 int64_t nLabel,
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005133 uint8_t uTagRequirement,
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005134 int64_t *pnMantissa,
5135 int64_t *pnExponent)
5136{
5137 if(pMe->uLastError != QCBOR_SUCCESS) {
5138 return;
5139 }
5140
5141 QCBORItem Item;
5142 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
5143
5144 const TagSpecification TagSpec =
5145 {
5146 uTagRequirement,
5147 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM},
5148 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
5149 };
5150
5151 ProcessMantissaAndExponent(pMe, TagSpec, &Item, pnMantissa, pnExponent);
5152}
5153
5154
5155/*
5156 Public function, see header qcbor/qcbor_decode.h file
5157*/
5158void QCBORDecode_GetDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005159 const char *szLabel,
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005160 uint8_t uTagRequirement,
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005161 int64_t *pnMantissa,
5162 int64_t *pnExponent)
5163{
5164 if(pMe->uLastError != QCBOR_SUCCESS) {
5165 return;
5166 }
5167
5168 QCBORItem Item;
5169 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
5170
5171 const TagSpecification TagSpec =
5172 {
5173 uTagRequirement,
5174 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM},
5175 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
5176 };
Laurence Lundblade9b334962020-08-27 10:55:53 -07005177
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005178 ProcessMantissaAndExponent(pMe, TagSpec, &Item, pnMantissa, pnExponent);
5179}
5180
5181
5182/*
5183 Public function, see header qcbor/qcbor_decode.h file
5184*/
5185void QCBORDecode_GetDecimalFractionBig(QCBORDecodeContext *pMe,
5186 uint8_t uTagRequirement,
5187 UsefulBuf MantissaBuffer,
5188 UsefulBufC *pMantissa,
5189 bool *pbMantissaIsNegative,
5190 int64_t *pnExponent)
5191{
5192 if(pMe->uLastError != QCBOR_SUCCESS) {
5193 return;
5194 }
5195
5196 QCBORItem Item;
5197 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
5198 if(uError) {
5199 pMe->uLastError = (uint8_t)uError;
5200 return;
5201 }
5202
5203 const TagSpecification TagSpec =
5204 {
5205 uTagRequirement,
5206 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM},
5207 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
5208 };
5209
5210 ProcessMantissaAndExponentBig(pMe, TagSpec, &Item, MantissaBuffer, pMantissa, pbMantissaIsNegative, pnExponent);
5211}
5212
5213
5214/*
5215 Public function, see header qcbor/qcbor_decode.h file
5216*/
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07005217void QCBORDecode_GetDecimalFractionBigInMapN(QCBORDecodeContext *pMe,
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07005218 int64_t nLabel,
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005219 uint8_t uTagRequirement,
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07005220 UsefulBuf BufferForMantissa,
5221 UsefulBufC *pMantissa,
5222 bool *pbIsNegative,
5223 int64_t *pnExponent)
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005224{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005225 if(pMe->uLastError != QCBOR_SUCCESS) {
5226 return;
5227 }
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005228
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005229 QCBORItem Item;
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005230 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005231 if(pMe->uLastError != QCBOR_SUCCESS) {
5232 return;
5233 }
5234
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005235 const TagSpecification TagSpec =
5236 {
5237 uTagRequirement,
5238 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM},
5239 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
5240 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005241
5242 ProcessMantissaAndExponentBig(pMe, TagSpec, &Item, BufferForMantissa, pMantissa, pbIsNegative, pnExponent);
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07005243}
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005244
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07005245
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005246/*
5247 Public function, see header qcbor/qcbor_decode.h file
5248*/
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07005249void QCBORDecode_GetDecimalFractionBigInMapSZ(QCBORDecodeContext *pMe,
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005250 const char *szLabel,
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005251 uint8_t uTagRequirement,
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005252 UsefulBuf BufferForMantissa,
5253 UsefulBufC *pMantissa,
5254 bool *pbIsNegative,
5255 int64_t *pnExponent)
5256{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005257 if(pMe->uLastError != QCBOR_SUCCESS) {
5258 return;
5259 }
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005260
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005261 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005262 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
5263 if(pMe->uLastError != QCBOR_SUCCESS) {
5264 return;
5265 }
5266
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005267 const TagSpecification TagSpec =
5268 {
5269 uTagRequirement,
5270 {QCBOR_TYPE_DECIMAL_FRACTION, QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM},
5271 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
5272 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005273
5274 ProcessMantissaAndExponentBig(pMe, TagSpec, &Item, BufferForMantissa, pMantissa, pbIsNegative, pnExponent);
5275}
5276
5277
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005278/*
5279 Public function, see header qcbor/qcbor_decode.h file
5280*/
5281void QCBORDecode_GetBigFloat(QCBORDecodeContext *pMe,
5282 uint8_t uTagRequirement,
5283 int64_t *pnMantissa,
5284 int64_t *pnExponent)
5285{
5286 if(pMe->uLastError != QCBOR_SUCCESS) {
5287 return;
5288 }
5289
5290 QCBORItem Item;
5291 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
5292 if(uError) {
5293 pMe->uLastError = (uint8_t)uError;
5294 return;
5295 }
5296 const TagSpecification TagSpec =
5297 {
5298 uTagRequirement,
5299 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM},
5300 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
5301 };
5302
5303 ProcessMantissaAndExponent(pMe, TagSpec, &Item, pnMantissa, pnExponent);
5304}
5305
5306
5307/*
5308 Public function, see header qcbor/qcbor_decode.h file
5309*/
5310void QCBORDecode_GetBigFloatInMapN(QCBORDecodeContext *pMe,
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005311 int64_t nLabel,
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005312 uint8_t uTagRequirement,
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005313 int64_t *pnMantissa,
5314 int64_t *pnExponent)
5315{
5316 if(pMe->uLastError != QCBOR_SUCCESS) {
5317 return;
5318 }
5319
5320 QCBORItem Item;
5321 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
5322 if(pMe->uLastError != QCBOR_SUCCESS) {
5323 return;
5324 }
5325
5326 const TagSpecification TagSpec =
5327 {
5328 uTagRequirement,
5329 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM},
5330 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
5331 };
5332
5333 ProcessMantissaAndExponent(pMe, TagSpec, &Item, pnMantissa, pnExponent);
5334}
5335
5336
5337/*
5338 Public function, see header qcbor/qcbor_decode.h file
5339*/
5340void QCBORDecode_GetBigFloatInMapSZ(QCBORDecodeContext *pMe,
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005341 const char *szLabel,
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005342 uint8_t uTagRequirement,
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005343 int64_t *pnMantissa,
5344 int64_t *pnExponent)
5345{
5346 if(pMe->uLastError != QCBOR_SUCCESS) {
5347 return;
5348 }
5349
5350 QCBORItem Item;
5351 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
5352 if(pMe->uLastError != QCBOR_SUCCESS) {
5353 return;
5354 }
5355
5356 const TagSpecification TagSpec =
5357 {
5358 uTagRequirement,
5359 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM},
5360 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
5361 };
5362
5363 ProcessMantissaAndExponent(pMe, TagSpec, &Item, pnMantissa, pnExponent);
5364}
5365
5366
5367/*
5368 Public function, see header qcbor/qcbor_decode.h file
5369*/
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005370void QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pMe,
5371 uint8_t uTagRequirement,
5372 UsefulBuf MantissaBuffer,
5373 UsefulBufC *pMantissa,
5374 bool *pbMantissaIsNegative,
5375 int64_t *pnExponent)
5376{
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005377 if(pMe->uLastError != QCBOR_SUCCESS) {
5378 return;
5379 }
5380
5381 QCBORItem Item;
5382 QCBORError uError = QCBORDecode_GetNext(pMe, &Item);
5383 if(uError) {
5384 pMe->uLastError = (uint8_t)uError;
5385 return;
5386 }
5387
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005388 const TagSpecification TagSpec =
5389 {
5390 uTagRequirement,
5391 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM},
5392 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
5393 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005394
5395 ProcessMantissaAndExponentBig(pMe, TagSpec, &Item, MantissaBuffer, pMantissa, pbMantissaIsNegative, pnExponent);
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005396}
5397
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005398
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005399/*
5400 Public function, see header qcbor/qcbor_decode.h file
5401*/
5402void QCBORDecode_GetBigFloatBigInMapN(QCBORDecodeContext *pMe,
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005403 int64_t nLabel,
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005404 uint8_t uTagRequirement,
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005405 UsefulBuf BufferForMantissa,
5406 UsefulBufC *pMantissa,
5407 bool *pbIsNegative,
5408 int64_t *pnExponent)
5409{
5410 if(pMe->uLastError != QCBOR_SUCCESS) {
5411 return;
5412 }
5413
5414 QCBORItem Item;
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005415 QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
5416 if(pMe->uLastError != QCBOR_SUCCESS) {
5417 return;
5418 }
5419
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005420 const TagSpecification TagSpec =
5421 {
5422 uTagRequirement,
5423 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM},
5424 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
5425 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005426
5427 ProcessMantissaAndExponentBig(pMe, TagSpec, &Item, BufferForMantissa, pMantissa, pbIsNegative, pnExponent);
5428}
5429
5430
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005431/*
5432 Public function, see header qcbor/qcbor_decode.h file
5433*/
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005434void QCBORDecode_GetBigFloatBigInMapSZ(QCBORDecodeContext *pMe,
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005435 const char *szLabel,
Laurence Lundblade2f5e16d2020-08-04 20:35:23 -07005436 uint8_t uTagRequirement,
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005437 UsefulBuf BufferForMantissa,
5438 UsefulBufC *pMantissa,
5439 bool *pbIsNegative,
5440 int64_t *pnExponent)
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07005441{
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005442 if(pMe->uLastError != QCBOR_SUCCESS) {
5443 return;
5444 }
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07005445
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005446 QCBORItem Item;
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07005447 QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
5448 if(pMe->uLastError != QCBOR_SUCCESS) {
Laurence Lundblade3cd26eb2020-06-29 23:33:13 -07005449 return;
5450 }
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005451
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005452 const TagSpecification TagSpec =
5453 {
5454 uTagRequirement,
5455 {QCBOR_TYPE_BIGFLOAT, QCBOR_TYPE_BIGFLOAT_POS_BIGNUM, QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM},
5456 {QCBOR_TYPE_ARRAY, QCBOR_TYPE_NONE, QCBOR_TYPE_NONE}
5457 };
Laurence Lundbladeb3683da2020-08-02 17:44:54 -07005458
5459 ProcessMantissaAndExponentBig(pMe, TagSpec, &Item, BufferForMantissa, pMantissa, pbIsNegative, pnExponent);
Laurence Lundblade91853ae2020-06-15 19:35:58 -07005460}
Laurence Lundbladed4cd7232020-07-03 19:30:48 -07005461
Laurence Lundbladefaec39f2020-08-02 21:53:53 -07005462#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */