blob: 36a9d116e4d2a015c0e0b749c9dcb45013930f84 [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 Lundbladef0ea5f32019-01-11 20:10:26 -08003 Copyright (c) 2018-2019, 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 Lundblade624405d2018-09-18 20:10:47 -070031 ==============================================================================*/
32
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070033/*===================================================================================
34 FILE: qcbor_decode.c
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080035
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070036 DESCRIPTION: This file contains the implementation of QCBOR.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080037
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070038 EDIT HISTORY FOR FILE:
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080039
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070040 This section contains comments describing changes made to the module.
41 Notice that changes are listed in reverse chronological order.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080042
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070043 when who what, where, why
44 -------- ---- ---------------------------------------------------
Laurence Lundbladea1ad8782019-11-08 00:12:11 -080045 11/07/19 llundblade Fix long long conversion to double compiler warning
Laurence Lundblade9916b1b2019-09-07 22:33:25 -070046 09/07/19 llundblade Fix bug decoding empty arrays and maps
Laurence Lundbladebb1062e2019-08-12 23:28:54 -070047 07/31/19 llundblade Decode error fixes for some not-well-formed CBOR
48 07/31/19 llundblade New error code for better end of data handling
Laurence Lundblade1d7eb632019-02-17 17:23:38 -080049 02/17/19 llundblade Fixed: QCBORItem.u{Data|Label}Alloc when bAllStrings set
50 02/16/19 llundblade Redesign MemPool to fix memory access alignment bug
Laurence Lundblade4c0cf842019-01-12 03:25:44 -080051 01/10/19 llundblade Clever type and argument decoder is 250 bytes smaller
Laurence Lundblade8b06e2e2018-12-04 12:26:51 +090052 11/9/18 llundblade Error codes are now enums.
53 11/2/18 llundblade Simplify float decoding and align with preferred
54 float encoding
55 10/31/18 llundblade Switch to one license that is almost BSD-3.
56 10/28/18 llundblade Reworked tag decoding
57 10/15/18 llundblade Indefinite length maps and arrays supported
58 10/8/18 llundblade Indefinite length strings supported
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070059 02/04/17 llundbla Work on CPUs that don's require pointer alignment
60 by making use of changes in UsefulBuf
61 03/01/17 llundbla More data types; decoding improvements and fixes
62 11/13/16 llundbla Integrate most TZ changes back into github version.
63 09/30/16 gkanike Porting to TZ.
64 03/15/16 llundbla Initial Version.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080065
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070066 =====================================================================================*/
67
68#include "qcbor.h"
Laurence Lundblade12d32c52018-09-19 11:25:27 -070069#include "ieee754.h"
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070070
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070071
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +053072/*
73 This casts away the const-ness of a pointer, usually so it can be
74 freed or realloced.
75 */
76#define UNCONST_POINTER(ptr) ((void *)(ptr))
77
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070078
79/*
Laurence Lundblade3a760b02018-10-08 13:46:03 +080080 Collection of functions to track the map/array nesting for decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070081 */
82
83inline static int IsMapOrArray(uint8_t uDataType)
84{
85 return uDataType == QCBOR_TYPE_MAP || uDataType == QCBOR_TYPE_ARRAY;
86}
87
88inline static int DecodeNesting_IsNested(const QCBORDecodeNesting *pNesting)
89{
90 return pNesting->pCurrent != &(pNesting->pMapsAndArrays[0]);
91}
92
Laurence Lundblade041ffa52018-10-07 11:43:51 +070093inline static int DecodeNesting_IsIndefiniteLength(const QCBORDecodeNesting *pNesting)
Laurence Lundblade0f99d692018-09-26 14:39:28 -070094{
Laurence Lundblade0f99d692018-09-26 14:39:28 -070095 return pNesting->pCurrent->uCount == UINT16_MAX;
96}
97
Laurence Lundblade3a760b02018-10-08 13:46:03 +080098inline static uint8_t DecodeNesting_GetLevel(QCBORDecodeNesting *pNesting)
99{
100 return pNesting->pCurrent - &(pNesting->pMapsAndArrays[0]);
101}
102
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700103inline static int DecodeNesting_TypeIsMap(const QCBORDecodeNesting *pNesting)
104{
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700105 if(!DecodeNesting_IsNested(pNesting)) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700106 return 0;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700107 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800108
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700109 return CBOR_MAJOR_TYPE_MAP == pNesting->pCurrent->uMajorType;
110}
111
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800112// Process a break. This will either ascend the nesting or error out
Laurence Lundblade30816f22018-11-10 13:40:22 +0700113inline static QCBORError DecodeNesting_BreakAscend(QCBORDecodeNesting *pNesting)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700114{
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800115 // breaks must always occur when there is nesting
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700116 if(!DecodeNesting_IsNested(pNesting)) {
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800117 return QCBOR_ERR_BAD_BREAK;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700118 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800119
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800120 // breaks can only occur when the map/array is indefinite length
121 if(!DecodeNesting_IsIndefiniteLength(pNesting)) {
122 return QCBOR_ERR_BAD_BREAK;
123 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800124
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800125 // if all OK, the break reduces the level of nesting
126 pNesting->pCurrent--;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800127
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800128 return QCBOR_SUCCESS;
129}
130
131// Called on every single item except breaks including the opening of a map/array
132inline static void DecodeNesting_DecrementCount(QCBORDecodeNesting *pNesting)
133{
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700134 while(DecodeNesting_IsNested(pNesting)) {
135 // Not at the top level, so there is decrementing to be done.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800136
Laurence Lundblade9e3651c2018-10-10 11:49:55 +0800137 if(!DecodeNesting_IsIndefiniteLength(pNesting)) {
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700138 // Decrement the current nesting level if it is not indefinite.
Laurence Lundblade9e3651c2018-10-10 11:49:55 +0800139 pNesting->pCurrent->uCount--;
140 }
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700141
142 if(pNesting->pCurrent->uCount != 0) {
143 // Did not close out an array or map, so nothing further
144 break;
145 }
146
147 // Closed out an array or map so level up
148 pNesting->pCurrent--;
149
150 // Continue with loop to see if closing out this doesn't close out more
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700151 }
152}
153
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700154
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800155// Called on every map/array
Laurence Lundblade30816f22018-11-10 13:40:22 +0700156inline static QCBORError DecodeNesting_Descend(QCBORDecodeNesting *pNesting, QCBORItem *pItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700157{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700158 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800159
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800160 if(pItem->val.uCount == 0) {
161 // Nothing to do for empty definite lenth arrays. They are just are
162 // effectively the same as an item that is not a map or array
163 goto Done;
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530164 // Empty indefinite length maps and arrays are handled elsewhere
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800165 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800166
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800167 // Error out if arrays is too long to handle
168 if(pItem->val.uCount != UINT16_MAX && pItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700169 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
170 goto Done;
171 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800172
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800173 // Error out if nesting is too deep
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700174 if(pNesting->pCurrent >= &(pNesting->pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING])) {
175 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
176 goto Done;
177 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800178
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800179 // The actual descend
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700180 pNesting->pCurrent++;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800181
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800182 // Record a few details for this nesting level
183 pNesting->pCurrent->uMajorType = pItem->uDataType;
184 pNesting->pCurrent->uCount = pItem->val.uCount;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800185
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700186Done:
187 return nReturn;;
188}
189
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700190inline static void DecodeNesting_Init(QCBORDecodeNesting *pNesting)
191{
192 pNesting->pCurrent = &(pNesting->pMapsAndArrays[0]);
193}
194
195
196
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700197/*
198 This list of built-in tags. Only add tags here that are
199 clearly established and useful. Once a tag is added here
200 it can't be taken out as that would break backwards compatibility.
201 There are only 48 slots available forever.
202 */
203static const uint16_t spBuiltInTagMap[] = {
204 CBOR_TAG_DATE_STRING, // See TAG_MAPPER_FIRST_FOUR
205 CBOR_TAG_DATE_EPOCH, // See TAG_MAPPER_FIRST_FOUR
206 CBOR_TAG_POS_BIGNUM, // See TAG_MAPPER_FIRST_FOUR
207 CBOR_TAG_NEG_BIGNUM, // See TAG_MAPPER_FIRST_FOUR
208 CBOR_TAG_FRACTION,
209 CBOR_TAG_BIGFLOAT,
210 CBOR_TAG_COSE_ENCRYPTO,
211 CBOR_TAG_COSE_MAC0,
212 CBOR_TAG_COSE_SIGN1,
213 CBOR_TAG_ENC_AS_B64URL,
214 CBOR_TAG_ENC_AS_B64,
215 CBOR_TAG_ENC_AS_B16,
216 CBOR_TAG_CBOR,
217 CBOR_TAG_URI,
218 CBOR_TAG_B64URL,
219 CBOR_TAG_B64,
220 CBOR_TAG_REGEX,
221 CBOR_TAG_MIME,
222 CBOR_TAG_BIN_UUID,
223 CBOR_TAG_CWT,
224 CBOR_TAG_ENCRYPT,
225 CBOR_TAG_MAC,
226 CBOR_TAG_SIGN,
227 CBOR_TAG_GEO_COORD,
228 CBOR_TAG_CBOR_MAGIC
229};
230
231// This is used in a bit of cleverness in GetNext_TaggedItem() to
232// keep code size down and switch for the internal processing of
233// these types. This will break if the first four items in
234// spBuiltInTagMap don't have values 0,1,2,3. That is the
235// mapping is 0 to 0, 1 to 1, 2 to 2 and 3 to 3.
236#define QCBOR_TAGFLAG_DATE_STRING (0x01LL << CBOR_TAG_DATE_STRING)
237#define QCBOR_TAGFLAG_DATE_EPOCH (0x01LL << CBOR_TAG_DATE_EPOCH)
238#define QCBOR_TAGFLAG_POS_BIGNUM (0x01LL << CBOR_TAG_POS_BIGNUM)
239#define QCBOR_TAGFLAG_NEG_BIGNUM (0x01LL << CBOR_TAG_NEG_BIGNUM)
240
241#define TAG_MAPPER_FIRST_FOUR (QCBOR_TAGFLAG_DATE_STRING |\
242 QCBOR_TAGFLAG_DATE_EPOCH |\
243 QCBOR_TAGFLAG_POS_BIGNUM |\
244 QCBOR_TAGFLAG_NEG_BIGNUM)
245
246#define TAG_MAPPER_TOTAL_TAG_BITS 64 // Number of bits in a uint64_t
247#define TAG_MAPPER_CUSTOM_TAGS_BASE_INDEX (TAG_MAPPER_TOTAL_TAG_BITS - QCBOR_MAX_CUSTOM_TAGS) // 48
248#define TAG_MAPPER_MAX_SIZE_BUILT_IN_TAGS (TAG_MAPPER_TOTAL_TAG_BITS - QCBOR_MAX_CUSTOM_TAGS ) // 48
249
250static inline int TagMapper_LookupBuiltIn(uint64_t uTag)
251{
252 if(sizeof(spBuiltInTagMap)/sizeof(uint16_t) > TAG_MAPPER_MAX_SIZE_BUILT_IN_TAGS) {
253 // This is a cross-check to make sure the above array doesn't
254 // accidentally get made too big.
255 // In normal conditions the above test should optimize out
256 // as all the values are known at compile time.
257 return -1;
258 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800259
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700260 if(uTag > UINT16_MAX) {
261 // This tag map works only on 16-bit tags
262 return -1;
263 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800264
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700265 for(int nTagBitIndex = 0; nTagBitIndex < (int)(sizeof(spBuiltInTagMap)/sizeof(uint16_t)); nTagBitIndex++) {
266 if(spBuiltInTagMap[nTagBitIndex] == uTag) {
267 return nTagBitIndex;
268 }
269 }
270 return -1; // Indicates no match
271}
272
273static inline int TagMapper_LookupCallerConfigured(const QCBORTagListIn *pCallerConfiguredTagMap, uint64_t uTag)
274{
275 for(int nTagBitIndex = 0; nTagBitIndex < pCallerConfiguredTagMap->uNumTags; nTagBitIndex++) {
276 if(pCallerConfiguredTagMap->puTags[nTagBitIndex] == uTag) {
277 return nTagBitIndex + TAG_MAPPER_CUSTOM_TAGS_BASE_INDEX;
278 }
279 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800280
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700281 return -1; // Indicates no match
282}
283
284/*
285 Find the tag bit index for a given tag value, or error out
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800286
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700287 This and the above functions could probably be optimized and made
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800288 clearer and neater.
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700289 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700290static QCBORError TagMapper_Lookup(const QCBORTagListIn *pCallerConfiguredTagMap, uint64_t uTag, uint8_t *puTagBitIndex)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700291{
292 int nTagBitIndex = TagMapper_LookupBuiltIn(uTag);
293 if(nTagBitIndex >= 0) {
294 // Cast is safe because TagMapper_LookupBuiltIn never returns > 47
295 *puTagBitIndex = (uint8_t)nTagBitIndex;
296 return QCBOR_SUCCESS;
297 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800298
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700299 if(pCallerConfiguredTagMap) {
300 if(pCallerConfiguredTagMap->uNumTags > QCBOR_MAX_CUSTOM_TAGS) {
301 return QCBOR_ERR_TOO_MANY_TAGS;
302 }
303 nTagBitIndex = TagMapper_LookupCallerConfigured(pCallerConfiguredTagMap, uTag);
304 if(nTagBitIndex >= 0) {
305 // Cast is safe because TagMapper_LookupBuiltIn never returns > 63
306
307 *puTagBitIndex = (uint8_t)nTagBitIndex;
308 return QCBOR_SUCCESS;
309 }
310 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800311
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700312 return QCBOR_ERR_BAD_OPT_TAG;
313}
314
315
316
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800317/* ===========================================================================
318 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
319
320 The following four functions are pretty wrappers for invocation of
321 the string allocator supplied by the caller.
322
323 ==============================================================================*/
324
325static inline void StringAllocator_Free(const QCORInternalAllocator *pMe, void *pMem)
326{
327 (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, 0);
328}
329
330// StringAllocator_Reallocate called with pMem NULL is equal to StringAllocator_Allocate()
331static inline UsefulBuf StringAllocator_Reallocate(const QCORInternalAllocator *pMe, void *pMem, size_t uSize)
332{
333 return (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, uSize);
334}
335
336static inline UsefulBuf StringAllocator_Allocate(const QCORInternalAllocator *pMe, size_t uSize)
337{
338 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
339}
340
341static inline void StringAllocator_Destruct(const QCORInternalAllocator *pMe)
342{
343 if(pMe->pfAllocator) {
344 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
345 }
346}
347
348
349
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700350
351/*
352 Public function, see header file
353 */
Laurence Lundbladed61cbf32018-12-09 11:42:21 -0800354void QCBORDecode_Init(QCBORDecodeContext *me, UsefulBufC EncodedCBOR, QCBORDecodeMode nDecodeMode)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700355{
356 memset(me, 0, sizeof(QCBORDecodeContext));
357 UsefulInputBuf_Init(&(me->InBuf), EncodedCBOR);
358 // Don't bother with error check on decode mode. If a bad value is passed it will just act as
359 // if the default normal mode of 0 was set.
360 me->uDecodeMode = nDecodeMode;
361 DecodeNesting_Init(&(me->nesting));
362}
363
364
365/*
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700366 Public function, see header file
367 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800368void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
369 QCBORStringAllocate pfAllocateFunction,
370 void *pAllocateContext,
371 bool bAllStrings)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700372{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800373 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
374 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
375 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700376}
377
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800378
379/*
380 Public function, see header file
381 */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700382void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *me, const QCBORTagListIn *pTagList)
383{
384 me->pCallerConfiguredTagList = pTagList;
385}
386
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700387
388/*
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700389 This decodes the fundamental part of a CBOR data item, the type and number
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800390
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700391 This is the Counterpart to InsertEncodedTypeAndNumber().
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800392
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700393 This does the network->host byte order conversion. The conversion here
394 also results in the conversion for floats in addition to that for
395 lengths, tags and integer values.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800396
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700397 This returns:
398 pnMajorType -- the major type for the item
399 puNumber -- the "number" which is used a the value for integers, tags and floats and length for strings and arrays
400 puAdditionalInfo -- Pass this along to know what kind of float or if length is indefinite
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800401
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700402 */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800403inline static QCBORError DecodeTypeAndNumber(UsefulInputBuf *pUInBuf,
404 int *pnMajorType,
405 uint64_t *puArgument,
406 uint8_t *puAdditionalInfo)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700407{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700408 QCBORError nReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800409
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700410 // Get the initial byte that every CBOR data item has
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800411 const uint8_t uInitialByte = UsefulInputBuf_GetByte(pUInBuf);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800412
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700413 // Break down the initial byte
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800414 const uint8_t uTmpMajorType = uInitialByte >> 5;
415 const uint8_t uAdditionalInfo = uInitialByte & 0x1f;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800416
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800417 // Where the number or argument accumulates
418 uint64_t uArgument;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800419
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800420 if(uAdditionalInfo >= LEN_IS_ONE_BYTE && uAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
421 // Need to get 1,2,4 or 8 additional argument bytes
422 // Map LEN_IS_ONE_BYTE.. LEN_IS_EIGHT_BYTES to actual length
423 static const uint8_t aIterate[] = {1,2,4,8};
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800424
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800425 // Loop getting all the bytes in the argument
426 uArgument = 0;
427 for(int i = aIterate[uAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
428 // This shift and add gives the endian conversion
429 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
430 }
431 } else if(uAdditionalInfo >= ADDINFO_RESERVED1 && uAdditionalInfo <= ADDINFO_RESERVED3) {
432 // The reserved and thus-far unused additional info values
433 nReturn = QCBOR_ERR_UNSUPPORTED;
434 goto Done;
435 } else {
436 // Less than 24, additional info is argument or 31, an indefinite length
437 // No more bytes to get
438 uArgument = uAdditionalInfo;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700439 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800440
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700441 if(UsefulInputBuf_GetError(pUInBuf)) {
442 nReturn = QCBOR_ERR_HIT_END;
443 goto Done;
444 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800445
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700446 // All successful if we got here.
447 nReturn = QCBOR_SUCCESS;
448 *pnMajorType = uTmpMajorType;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800449 *puArgument = uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700450 *puAdditionalInfo = uAdditionalInfo;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800451
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700452Done:
453 return nReturn;
454}
455
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700456/*
457 CBOR doesn't explicitly specify two's compliment for integers but all CPUs
458 use it these days and the test vectors in the RFC are so. All integers in the CBOR
459 structure are positive and the major type indicates positive or negative.
460 CBOR can express positive integers up to 2^x - 1 where x is the number of bits
461 and negative integers down to 2^x. Note that negative numbers can be one
462 more away from zero than positive.
463 Stdint, as far as I can tell, uses two's compliment to represent
464 negative integers.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800465
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700466 See http://www.unix.org/whitepapers/64bit.html for reasons int isn't
467 used here in any way including in the interface
468 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700469inline static QCBORError DecodeInteger(int nMajorType, uint64_t uNumber, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700470{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700471 // Stack usage: int/ptr 1 -- 8
Laurence Lundblade30816f22018-11-10 13:40:22 +0700472 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800473
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700474 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
475 if (uNumber <= INT64_MAX) {
476 pDecodedItem->val.int64 = (int64_t)uNumber;
477 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800478
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700479 } else {
480 pDecodedItem->val.uint64 = uNumber;
481 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800482
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700483 }
484 } else {
485 if(uNumber <= INT64_MAX) {
486 pDecodedItem->val.int64 = -uNumber-1;
487 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800488
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700489 } else {
490 // C can't represent a negative integer in this range
Laurence Lundblade21d1d812019-09-28 22:47:49 -1000491 // so it is an error.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700492 nReturn = QCBOR_ERR_INT_OVERFLOW;
493 }
494 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800495
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700496 return nReturn;
497}
498
499// Make sure #define value line up as DecodeSimple counts on this.
500#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
501#error QCBOR_TYPE_FALSE macro value wrong
502#endif
503
504#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
505#error QCBOR_TYPE_TRUE macro value wrong
506#endif
507
508#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
509#error QCBOR_TYPE_NULL macro value wrong
510#endif
511
512#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
513#error QCBOR_TYPE_UNDEF macro value wrong
514#endif
515
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700516#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
517#error QCBOR_TYPE_BREAK macro value wrong
518#endif
519
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700520#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
521#error QCBOR_TYPE_DOUBLE macro value wrong
522#endif
523
524#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
525#error QCBOR_TYPE_FLOAT macro value wrong
526#endif
527
528/*
529 Decode true, false, floats, break...
530 */
531
Laurence Lundblade30816f22018-11-10 13:40:22 +0700532inline static QCBORError DecodeSimple(uint8_t uAdditionalInfo, uint64_t uNumber, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700533{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700534 // Stack usage: 0
Laurence Lundblade30816f22018-11-10 13:40:22 +0700535 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800536
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700537 // uAdditionalInfo is 5 bits from the initial byte
538 // compile time checks above make sure uAdditionalInfo values line up with uDataType values
539 pDecodedItem->uDataType = uAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800540
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700541 switch(uAdditionalInfo) {
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700542 // No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as it is caught before this is called.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800543
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700544 case HALF_PREC_FLOAT:
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700545 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uNumber);
546 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700547 break;
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700548 case SINGLE_PREC_FLOAT:
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700549 pDecodedItem->val.dfnum = (double)UsefulBufUtil_CopyUint32ToFloat((uint32_t)uNumber);
550 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700551 break;
552 case DOUBLE_PREC_FLOAT:
553 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uNumber);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700554 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700555 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800556
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700557 case CBOR_SIMPLEV_FALSE: // 20
558 case CBOR_SIMPLEV_TRUE: // 21
559 case CBOR_SIMPLEV_NULL: // 22
560 case CBOR_SIMPLEV_UNDEF: // 23
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700561 case CBOR_SIMPLE_BREAK: // 31
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700562 break; // nothing to do
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800563
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700564 case CBOR_SIMPLEV_ONEBYTE: // 24
565 if(uNumber <= CBOR_SIMPLE_BREAK) {
566 // This takes out f8 00 ... f8 1f which should be encoded as e0 … f7
Laurence Lundblade077475f2019-04-26 09:06:33 -0700567 nReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700568 goto Done;
569 }
Laurence Lundblade5e390822019-01-06 12:35:01 -0800570 /* FALLTHROUGH */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700571 // fall through intentionally
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800572
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700573 default: // 0-19
574 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
575 // DecodeTypeAndNumber will make uNumber equal to uAdditionalInfo when uAdditionalInfo is < 24
576 // This cast is safe because the 2, 4 and 8 byte lengths of uNumber are in the double/float cases above
577 pDecodedItem->val.uSimple = (uint8_t)uNumber;
578 break;
579 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800580
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700581Done:
582 return nReturn;
583}
584
585
586
587/*
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530588 Decode text and byte strings. Call the string allocator if asked to.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700589 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800590inline static QCBORError DecodeBytes(const QCORInternalAllocator *pAllocator,
591 int nMajorType,
592 uint64_t uStrLen,
593 UsefulInputBuf *pUInBuf,
594 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700595{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700596 // Stack usage: UsefulBuf 2, int/ptr 1 40
Laurence Lundblade30816f22018-11-10 13:40:22 +0700597 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800598
Laurence Lundblade25c6c0a2018-12-17 13:21:59 -0800599 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530600 if(UsefulBuf_IsNULLC(Bytes)) {
601 // Failed to get the bytes for this string item
602 nReturn = QCBOR_ERR_HIT_END;
603 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700604 }
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530605
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800606 if(pAllocator) {
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530607 // We are asked to use string allocator to make a copy
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800608 UsefulBuf NewMem = StringAllocator_Allocate(pAllocator, uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530609 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade30816f22018-11-10 13:40:22 +0700610 nReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530611 goto Done;
612 }
613 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800614 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530615 } else {
616 // Normal case with no string allocator
617 pDecodedItem->val.string = Bytes;
618 }
619 pDecodedItem->uDataType = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING) ? QCBOR_TYPE_BYTE_STRING : QCBOR_TYPE_TEXT_STRING;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800620
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530621Done:
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700622 return nReturn;
623}
624
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700625
626/*
627 Mostly just assign the right data type for the date string.
628 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700629inline static QCBORError DecodeDateString(QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700630{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700631 // Stack Use: UsefulBuf 1 16
632 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700633 return QCBOR_ERR_BAD_OPT_TAG;
634 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800635
Laurence Lundblade25c6c0a2018-12-17 13:21:59 -0800636 const UsefulBufC Temp = pDecodedItem->val.string;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700637 pDecodedItem->val.dateString = Temp;
638 pDecodedItem->uDataType = QCBOR_TYPE_DATE_STRING;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700639 return QCBOR_SUCCESS;
640}
641
642
643/*
644 Mostly just assign the right data type for the bignum.
645 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700646inline static QCBORError DecodeBigNum(QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700647{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700648 // Stack Use: UsefulBuf 1 -- 16
649 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700650 return QCBOR_ERR_BAD_OPT_TAG;
651 }
Laurence Lundblade25c6c0a2018-12-17 13:21:59 -0800652 const UsefulBufC Temp = pDecodedItem->val.string;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700653 pDecodedItem->val.bigNum = Temp;
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700654 pDecodedItem->uDataType = pDecodedItem->uTagBits & QCBOR_TAGFLAG_POS_BIGNUM ? QCBOR_TYPE_POSBIGNUM : QCBOR_TYPE_NEGBIGNUM;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700655 return QCBOR_SUCCESS;
656}
657
658
659/*
660 The epoch formatted date. Turns lots of different forms of encoding date into uniform one
661 */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700662static int DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700663{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700664 // Stack usage: 1
Laurence Lundblade30816f22018-11-10 13:40:22 +0700665 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800666
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700667 pDecodedItem->val.epochDate.fSecondsFraction = 0;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800668
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700669 switch (pDecodedItem->uDataType) {
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800670
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700671 case QCBOR_TYPE_INT64:
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700672 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700673 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800674
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700675 case QCBOR_TYPE_UINT64:
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700676 if(pDecodedItem->val.uint64 > INT64_MAX) {
677 nReturn = QCBOR_ERR_DATE_OVERFLOW;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700678 goto Done;
679 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700680 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.uint64;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700681 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800682
Laurence Lundblade9e3651c2018-10-10 11:49:55 +0800683 case QCBOR_TYPE_DOUBLE:
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700684 {
Laurence Lundbladea1ad8782019-11-08 00:12:11 -0800685 // This comparison needs to be done as a float before
686 // conversion to an int64_t to be able to detect doubles
687 // that are too large to fit into an int64_t. A double
688 // has 52 bits of preceision. An int64_t has 63. Casting
689 // INT64_MAX to a double actually causes a round up which
690 // is bad and wrong for the comparison because it will
691 // allow conversion of doubles that can't fit into a
692 // uint64_t. To remedy this INT64_MAX - 0x7ff is used as
693 // the cutoff point as if that rounds up in conversion to
694 // double it will still be less than INT64_MAX. 0x7ff is
695 // picked because it has 11 bits set.
696 //
697 // INT64_MAX seconds is on the order of 10 billion years,
698 // and the earth is less than 5 billion years old, so for
699 // most uses this conversion error won't occur even though
700 // doubles can go much larger.
701 //
702 // Without the 0x7ff there is a ~30 minute range of time
703 // values 10 billion years in the past and in the future
704 // where this this code would go wrong.
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700705 const double d = pDecodedItem->val.dfnum;
Laurence Lundbladea1ad8782019-11-08 00:12:11 -0800706 if(d > (double)(INT64_MAX - 0x7ff)) {
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700707 nReturn = QCBOR_ERR_DATE_OVERFLOW;
708 goto Done;
709 }
Laurence Lundbladea1ad8782019-11-08 00:12:11 -0800710 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
711 pDecodedItem->val.epochDate.fSecondsFraction = d - (double)pDecodedItem->val.epochDate.nSeconds;
Laurence Lundblade9e3651c2018-10-10 11:49:55 +0800712 }
Laurence Lundblade9e3651c2018-10-10 11:49:55 +0800713 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800714
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700715 default:
716 nReturn = QCBOR_ERR_BAD_OPT_TAG;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700717 goto Done;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700718 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700719 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800720
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700721Done:
722 return nReturn;
723}
724
725
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700726
727
728// Make sure the constants align as this is assumed by the GetAnItem() implementation
729#if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
730#error QCBOR_TYPE_ARRAY value not lined up with major type
731#endif
732#if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
733#error QCBOR_TYPE_MAP value not lined up with major type
734#endif
735
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700736/*
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700737 This gets a single data item and decodes it including preceding optional tagging. This does not
738 deal with arrays and maps and nesting except to decode the data item introducing them. Arrays and
739 maps are handled at the next level up in GetNext().
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800740
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700741 Errors detected here include: an array that is too long to decode, hit end of buffer unexpectedly,
742 a few forms of invalid encoded CBOR
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700743 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800744static QCBORError GetNext_Item(UsefulInputBuf *pUInBuf,
745 QCBORItem *pDecodedItem,
746 const QCORInternalAllocator *pAllocator)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700747{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700748 // Stack usage: int/ptr 3 -- 24
Laurence Lundblade30816f22018-11-10 13:40:22 +0700749 QCBORError nReturn;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800750
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700751 // Get the major type and the number. Number could be length of more bytes or the value depending on the major type
752 // nAdditionalInfo is an encoding of the length of the uNumber and is needed to decode floats and doubles
753 int uMajorType;
754 uint64_t uNumber;
755 uint8_t uAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800756
Laurence Lundblade4b09f632019-10-09 14:34:59 -0700757 memset(pDecodedItem, 0, sizeof(QCBORItem));
758
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700759 nReturn = DecodeTypeAndNumber(pUInBuf, &uMajorType, &uNumber, &uAdditionalInfo);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800760
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700761 // Error out here if we got into trouble on the type and number.
762 // The code after this will not work if the type and number is not good.
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700763 if(nReturn) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700764 goto Done;
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700765 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800766
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700767 // At this point the major type and the value are valid. We've got the type and the number that
768 // starts every CBOR data item.
769 switch (uMajorType) {
770 case CBOR_MAJOR_TYPE_POSITIVE_INT: // Major type 0
771 case CBOR_MAJOR_TYPE_NEGATIVE_INT: // Major type 1
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700772 if(uAdditionalInfo == LEN_IS_INDEFINITE) {
773 nReturn = QCBOR_ERR_BAD_INT;
774 } else {
775 nReturn = DecodeInteger(uMajorType, uNumber, pDecodedItem);
776 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700777 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800778
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700779 case CBOR_MAJOR_TYPE_BYTE_STRING: // Major type 2
780 case CBOR_MAJOR_TYPE_TEXT_STRING: // Major type 3
781 if(uAdditionalInfo == LEN_IS_INDEFINITE) {
782 pDecodedItem->uDataType = (uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING) ? QCBOR_TYPE_BYTE_STRING : QCBOR_TYPE_TEXT_STRING;
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530783 pDecodedItem->val.string = (UsefulBufC){NULL, SIZE_MAX};
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700784 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800785 nReturn = DecodeBytes(pAllocator, uMajorType, uNumber, pUInBuf, pDecodedItem);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700786 }
787 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800788
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700789 case CBOR_MAJOR_TYPE_ARRAY: // Major type 4
790 case CBOR_MAJOR_TYPE_MAP: // Major type 5
791 // Record the number of items in the array or map
792 if(uNumber > QCBOR_MAX_ITEMS_IN_ARRAY) {
793 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
794 goto Done;
795 }
796 if(uAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530797 pDecodedItem->val.uCount = UINT16_MAX; // Indicate indefinite length
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700798 } else {
799 pDecodedItem->val.uCount = (uint16_t)uNumber; // type conversion OK because of check above
800 }
801 pDecodedItem->uDataType = uMajorType; // C preproc #if above makes sure constants align
802 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800803
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700804 case CBOR_MAJOR_TYPE_OPTIONAL: // Major type 6, optional prepended tags
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700805 if(uAdditionalInfo == LEN_IS_INDEFINITE) {
806 nReturn = QCBOR_ERR_BAD_INT;
807 } else {
808 pDecodedItem->val.uTagV = uNumber;
809 pDecodedItem->uDataType = QCBOR_TYPE_OPTTAG;
810 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700811 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800812
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700813 case CBOR_MAJOR_TYPE_SIMPLE: // Major type 7, float, double, true, false, null...
814 nReturn = DecodeSimple(uAdditionalInfo, uNumber, pDecodedItem);
815 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800816
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700817 default: // Should never happen because DecodeTypeAndNumber() should never return > 7
818 nReturn = QCBOR_ERR_UNSUPPORTED;
819 break;
820 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800821
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700822Done:
823 return nReturn;
824}
825
826
827
828/*
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800829 This layer deals with indefinite length strings. It pulls all the
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700830 individual chunk items together into one QCBORItem using the
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530831 string allocator.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800832
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530833 Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700834 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700835static inline QCBORError GetNext_FullItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700836{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700837 // Stack usage; int/ptr 2 UsefulBuf 2 QCBORItem -- 96
Laurence Lundblade30816f22018-11-10 13:40:22 +0700838 QCBORError nReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800839 const QCORInternalAllocator *pAllocator = me->StringAllocator.pfAllocator ?
840 &(me->StringAllocator) :
841 NULL;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530842 UsefulBufC FullString = NULLUsefulBufC;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800843
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800844 nReturn = GetNext_Item(&(me->InBuf),
845 pDecodedItem,
846 me->bStringAllocateAll ? pAllocator: NULL);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700847 if(nReturn) {
848 goto Done;
849 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800850
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700851 // To reduce code size by removing support for indefinite length strings, the
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530852 // code in this function from here down can be eliminated. Run tests, except
853 // indefinite length string tests, to be sure all is OK if this is removed.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800854
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800855 // Only do indefinite length processing on strings
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700856 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING && pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
857 goto Done; // no need to do any work here on non-string types
858 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800859
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800860 // Is this a string with an indefinite length?
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530861 if(pDecodedItem->val.string.len != SIZE_MAX) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800862 goto Done; // length is not indefinite, so no work to do here
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700863 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800864
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530865 // Can't do indefinite length strings without a string allocator
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800866 if(pAllocator == NULL) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700867 nReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
868 goto Done;
869 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800870
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700871 // There is an indefinite length string to work on...
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800872 // Track which type of string it is
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700873 const uint8_t uStringType = pDecodedItem->uDataType;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800874
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700875 // Loop getting chunk of indefinite string
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700876 for(;;) {
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700877 // Get item for next chunk
878 QCBORItem StringChunkItem;
879 // NULL passed to never string alloc chunk of indefinite length strings
Laurence Lundbladefae26bf2019-02-18 11:15:43 -0800880 nReturn = GetNext_Item(&(me->InBuf), &StringChunkItem, NULL);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700881 if(nReturn) {
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700882 break; // Error getting the next chunk
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700883 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800884
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530885 // See if it is a marker at end of indefinite length string
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700886 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800887 // String is complete
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700888 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +0530889 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700890 break;
891 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800892
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700893 // Match data type of chunk to type at beginning.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530894 // Also catches error of other non-string types that don't belong.
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700895 // Also catches indefinite length strings inside indefinite length strings
896 if(StringChunkItem.uDataType != uStringType || StringChunkItem.val.string.len == SIZE_MAX) {
Laurence Lundblade30816f22018-11-10 13:40:22 +0700897 nReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700898 break;
899 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800900
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530901 // Alloc new buffer or expand previously allocated buffer so it can fit
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800902 // The first time throurgh FullString.ptr is NULL and this is
903 // equivalent to StringAllocator_Allocate()
904 UsefulBuf NewMem = StringAllocator_Reallocate(pAllocator,
905 UNCONST_POINTER(FullString.ptr),
906 FullString.len + StringChunkItem.val.string.len);
907
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700908 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530909 // Allocation of memory for the string failed
Laurence Lundblade30816f22018-11-10 13:40:22 +0700910 nReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700911 break;
912 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800913
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700914 // Copy new string chunk at the end of string so far.
915 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700916 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800917
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700918Done:
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800919 if(nReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
920 // Getting the item failed, clean up the allocated memory
921 StringAllocator_Free(pAllocator, UNCONST_POINTER(FullString.ptr));
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700922 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800923
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700924 return nReturn;
925}
926
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700927
928/*
929 Returns an error if there was something wrong with the optional item or it couldn't
930 be handled.
931 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700932static QCBORError GetNext_TaggedItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem, QCBORTagListOut *pTags)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700933{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700934 // Stack usage: int/ptr: 3 -- 24
Laurence Lundblade30816f22018-11-10 13:40:22 +0700935 QCBORError nReturn;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700936 uint64_t uTagBits = 0;
937 if(pTags) {
938 pTags->uNumUsed = 0;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700939 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700940
941 for(;;) {
942 nReturn = GetNext_FullItem(me, pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700943 if(nReturn) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700944 goto Done; // Error out of the loop
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700945 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800946
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700947 if(pDecodedItem->uDataType != QCBOR_TYPE_OPTTAG) {
948 // Successful exit from loop; maybe got some tags, maybe not
949 pDecodedItem->uTagBits = uTagBits;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700950 break;
951 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800952
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700953 uint8_t uTagBitIndex;
954 // Tag was mapped, tag was not mapped, error with tag list
955 switch(TagMapper_Lookup(me->pCallerConfiguredTagList, pDecodedItem->val.uTagV, &uTagBitIndex)) {
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800956
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700957 case QCBOR_SUCCESS:
958 // Successfully mapped the tag
959 uTagBits |= 0x01ULL << uTagBitIndex;
960 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800961
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700962 case QCBOR_ERR_BAD_OPT_TAG:
963 // Tag is not recognized. Do nothing
964 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800965
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700966 default:
967 // Error Condition
968 goto Done;
969 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800970
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700971 if(pTags) {
972 // Caller wants all tags recorded in the provided buffer
973 if(pTags->uNumUsed >= pTags->uNumAllocated) {
974 nReturn = QCBOR_ERR_TOO_MANY_TAGS;
975 goto Done;
976 }
977 pTags->puTags[pTags->uNumUsed] = pDecodedItem->val.uTagV;
978 pTags->uNumUsed++;
979 }
980 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800981
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700982 switch(pDecodedItem->uTagBits & TAG_MAPPER_FIRST_FOUR) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700983 case 0:
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700984 // No tags at all or none we know about. Nothing to do.
985 // This is part of the pass-through path of this function
986 // that will mostly be taken when decoding any item.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700987 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800988
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700989 case QCBOR_TAGFLAG_DATE_STRING:
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700990 nReturn = DecodeDateString(pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700991 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800992
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700993 case QCBOR_TAGFLAG_DATE_EPOCH:
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700994 nReturn = DecodeDateEpoch(pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700995 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800996
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700997 case QCBOR_TAGFLAG_POS_BIGNUM:
998 case QCBOR_TAGFLAG_NEG_BIGNUM:
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700999 nReturn = DecodeBigNum(pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001000 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001001
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001002 default:
1003 // Encountering some mixed up CBOR like something that
1004 // is tagged as both a string and integer date.
Laurence Lundblade30816f22018-11-10 13:40:22 +07001005 nReturn = QCBOR_ERR_BAD_OPT_TAG;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001006 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001007
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001008Done:
1009 return nReturn;
1010}
1011
1012
1013/*
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001014 This layer takes care of map entries. It combines the label and data items into one QCBORItem.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001015 */
Laurence Lundblade30816f22018-11-10 13:40:22 +07001016static inline QCBORError GetNext_MapEntry(QCBORDecodeContext *me, QCBORItem *pDecodedItem, QCBORTagListOut *pTags)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001017{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001018 // Stack use: int/ptr 1, QCBORItem -- 56
Laurence Lundblade30816f22018-11-10 13:40:22 +07001019 QCBORError nReturn = GetNext_TaggedItem(me, pDecodedItem, pTags);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001020 if(nReturn)
1021 goto Done;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001022
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001023 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001024 // Break can't be a map entry
Laurence Lundblade742df4a2018-10-13 20:07:17 +08001025 goto Done;
1026 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001027
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001028 if(me->uDecodeMode != QCBOR_DECODE_MODE_MAP_AS_ARRAY) {
1029 // In a map and caller wants maps decoded, not treated as arrays
1030
1031 if(DecodeNesting_TypeIsMap(&(me->nesting))) {
1032 // If in a map and the right decoding mode, get the label
1033
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001034 // Get the next item which will be the real data; Item will be the label
1035 QCBORItem LabelItem = *pDecodedItem;
1036 nReturn = GetNext_TaggedItem(me, pDecodedItem, pTags);
1037 if(nReturn)
1038 goto Done;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001039
Laurence Lundblade57dd1442018-10-15 20:26:28 +05301040 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +09001041
1042 if(LabelItem.uDataType == QCBOR_TYPE_TEXT_STRING) {
1043 // strings are always good labels
1044 pDecodedItem->label.string = LabelItem.val.string;
1045 pDecodedItem->uLabelType = QCBOR_TYPE_TEXT_STRING;
1046 } else if (QCBOR_DECODE_MODE_MAP_STRINGS_ONLY == me->uDecodeMode) {
1047 // It's not a string and we only want strings, probably for easy translation to JSON
1048 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
1049 goto Done;
1050 } else if(LabelItem.uDataType == QCBOR_TYPE_INT64) {
1051 pDecodedItem->label.int64 = LabelItem.val.int64;
1052 pDecodedItem->uLabelType = QCBOR_TYPE_INT64;
1053 } else if(LabelItem.uDataType == QCBOR_TYPE_UINT64) {
1054 pDecodedItem->label.uint64 = LabelItem.val.uint64;
1055 pDecodedItem->uLabelType = QCBOR_TYPE_UINT64;
1056 } else if(LabelItem.uDataType == QCBOR_TYPE_BYTE_STRING) {
1057 pDecodedItem->label.string = LabelItem.val.string;
1058 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
1059 pDecodedItem->uLabelType = QCBOR_TYPE_BYTE_STRING;
1060 } else {
1061 // label is not an int or a string. It is an arrray
1062 // or a float or such and this implementation doesn't handle that.
1063 // Also, tags on labels are ignored.
1064 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
1065 goto Done;
1066 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -08001067 }
1068 } else {
1069 if(pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
1070 // Decoding a map as an array
1071 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
1072 pDecodedItem->val.uCount *= 2;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001073 }
1074 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001075
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001076Done:
1077 return nReturn;
1078}
1079
1080
1081/*
1082 Public function, see header qcbor.h file
1083 */
Laurence Lundblade30816f22018-11-10 13:40:22 +07001084QCBORError QCBORDecode_GetNextWithTags(QCBORDecodeContext *me, QCBORItem *pDecodedItem, QCBORTagListOut *pTags)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001085{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001086 // Stack ptr/int: 2, QCBORItem : 64
1087
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301088 // The public entry point for fetching and parsing the next QCBORItem.
1089 // All the CBOR parsing work is here and in subordinate calls.
Laurence Lundblade30816f22018-11-10 13:40:22 +07001090 QCBORError nReturn;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001091
Laurence Lundbladebb1062e2019-08-12 23:28:54 -07001092 // Check if there are an
1093 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf)) == 0 && !DecodeNesting_IsNested(&(me->nesting))) {
1094 nReturn = QCBOR_ERR_NO_MORE_ITEMS;
1095 goto Done;
1096 }
1097
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001098 nReturn = GetNext_MapEntry(me, pDecodedItem, pTags);
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001099 if(nReturn) {
1100 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001101 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301102
1103 // Break ending arrays/maps are always processed at the end of this function.
1104 // They should never show up here.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301105 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade6de37062018-10-15 12:22:42 +05301106 nReturn = QCBOR_ERR_BAD_BREAK;
1107 goto Done;
Laurence Lundblade5b8c5852018-10-14 21:11:42 +05301108 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001109
Laurence Lundblade6de37062018-10-15 12:22:42 +05301110 // Record the nesting level for this data item before processing any of
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301111 // decrementing and descending.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301112 pDecodedItem->uNestingLevel = DecodeNesting_GetLevel(&(me->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001113
Laurence Lundblade6de37062018-10-15 12:22:42 +05301114 // Process the item just received for descent or decrement, and
1115 // ascent if decrements are enough to close out a definite length array/map
Laurence Lundblade3a760b02018-10-08 13:46:03 +08001116 if(IsMapOrArray(pDecodedItem->uDataType)) {
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001117 // If the new item is array or map, the nesting level descends
Laurence Lundblade3a760b02018-10-08 13:46:03 +08001118 nReturn = DecodeNesting_Descend(&(me->nesting), pDecodedItem);
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001119 // Maps and arrays do count in as items in the map/array that encloses
1120 // them so a decrement needs to be done for them too, but that is done
1121 // only when all the items in them have been processed, not when they
Laurence Lundblade9916b1b2019-09-07 22:33:25 -07001122 // are opened with the exception of an empty map or array.
1123 if(pDecodedItem->val.uCount == 0) {
1124 DecodeNesting_DecrementCount(&(me->nesting));
1125 }
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001126 } else {
1127 // Decrement the count of items in the enclosing map/array
1128 // If the count in the enclosing map/array goes to zero, that
Laurence Lundblade6de37062018-10-15 12:22:42 +05301129 // triggers a decrement in the map/array above that and
1130 // an ascend in nesting level.
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001131 DecodeNesting_DecrementCount(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001132 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05301133 if(nReturn) {
1134 goto Done;
1135 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001136
Laurence Lundblade6de37062018-10-15 12:22:42 +05301137 // For indefinite length maps/arrays, looking at any and
1138 // all breaks that might terminate them. The equivalent
1139 // for definite length maps/arrays happens in
1140 // DecodeNesting_DecrementCount().
1141 if(DecodeNesting_IsNested(&(me->nesting)) && DecodeNesting_IsIndefiniteLength(&(me->nesting))) {
1142 while(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) {
1143 // Peek forward one item to see if it is a break.
1144 QCBORItem Peek;
1145 size_t uPeek = UsefulInputBuf_Tell(&(me->InBuf));
1146 nReturn = GetNext_Item(&(me->InBuf), &Peek, NULL);
1147 if(nReturn) {
1148 goto Done;
1149 }
1150 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
1151 // It is not a break, rewind so it can be processed normally.
1152 UsefulInputBuf_Seek(&(me->InBuf), uPeek);
1153 break;
1154 }
1155 // It is a break. Ascend one nesting level.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301156 // The break is consumed.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301157 nReturn = DecodeNesting_BreakAscend(&(me->nesting));
1158 if(nReturn) {
1159 // break occured outside of an indefinite length array/map
1160 goto Done;
1161 }
1162 }
1163 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001164
Laurence Lundblade6de37062018-10-15 12:22:42 +05301165 // Tell the caller what level is next. This tells them what maps/arrays
1166 // were closed out and makes it possible for them to reconstruct
1167 // the tree with just the information returned by GetNext
1168 pDecodedItem->uNextNestLevel = DecodeNesting_GetLevel(&(me->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001169
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001170Done:
Laurence Lundbladee9482dd2019-10-11 12:58:46 -07001171 if(nReturn != QCBOR_SUCCESS) {
1172 // Make sure uDataType and uLabelType are QCBOR_TYPE_NONE
1173 memset(pDecodedItem, 0, sizeof(QCBORItem));
1174 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001175 return nReturn;
1176}
1177
1178
Laurence Lundblade30816f22018-11-10 13:40:22 +07001179QCBORError QCBORDecode_GetNext(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001180{
1181 return QCBORDecode_GetNextWithTags(me, pDecodedItem, NULL);
1182}
1183
1184
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001185/*
Laurence Lundblade6de37062018-10-15 12:22:42 +05301186 Decoding items is done in 5 layered functions, one calling the
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301187 next one down. If a layer has no work to do for a particular item
1188 it returns quickly.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001189
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301190 - QCBORDecode_GetNext -- The top layer manages the beginnings and
1191 ends of maps and arrays. It tracks descending into and ascending
Laurence Lundblade6de37062018-10-15 12:22:42 +05301192 out of maps/arrays. It processes all breaks that terminate
1193 maps and arrays.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001194
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301195 - GetNext_MapEntry -- This handles the combining of two
1196 items, the label and the data, that make up a map entry.
1197 It only does work on maps. It combines the label and data
1198 items into one labeled item.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001199
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301200 - GetNext_TaggedItem -- This handles the type 6 tagged items.
1201 It accumulates all the tags and combines them with the following
1202 non-tagged item. If the tagged item is something that is understood
1203 like a date, the decoding of that item is invoked.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001204
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301205 - GetNext_FullItem -- This assembles the sub items that make up
1206 an indefinte length string into one string item. It uses the
Laurence Lundblade6de37062018-10-15 12:22:42 +05301207 string allocater to create contiguous space for the item. It
1208 processes all breaks that are part of indefinite length strings.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001209
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301210 - GetNext_Item -- This gets and decodes the most atomic
1211 item in CBOR, the thing with an initial byte containing
1212 the major type.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001213
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001214 Roughly this takes 300 bytes of stack for vars. Need to
1215 evaluate this more carefully and correctly.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001216
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301217 */
1218
1219
1220/*
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001221 Public function, see header qcbor.h file
1222 */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001223int QCBORDecode_IsTagged(QCBORDecodeContext *me, const QCBORItem *pItem, uint64_t uTag)
1224{
1225 const QCBORTagListIn *pCallerConfiguredTagMap = me->pCallerConfiguredTagList;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001226
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001227 uint8_t uTagBitIndex;
1228 // Do not care about errors in pCallerConfiguredTagMap here. They are
1229 // caught during GetNext() before this is called.
1230 if(TagMapper_Lookup(pCallerConfiguredTagMap, uTag, &uTagBitIndex)) {
1231 return 0;
1232 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001233
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001234 const uint64_t uTagBit = 0x01ULL << uTagBitIndex;
1235 return (uTagBit & pItem->uTagBits) != 0;
1236}
1237
1238
1239/*
1240 Public function, see header qcbor.h file
1241 */
Laurence Lundblade30816f22018-11-10 13:40:22 +07001242QCBORError QCBORDecode_Finish(QCBORDecodeContext *me)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001243{
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001244 int nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001245
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001246 // Error out if all the maps/arrays are not closed out
1247 if(DecodeNesting_IsNested(&(me->nesting))) {
1248 nReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
1249 goto Done;
1250 }
1251
1252 // Error out if not all the bytes are consumed
1253 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) {
1254 nReturn = QCBOR_ERR_EXTRA_BYTES;
1255 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001256
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001257Done:
Laurence Lundblade6de37062018-10-15 12:22:42 +05301258 // Call the destructor for the string allocator if there is one.
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001259 // Always called, even if there are errors; always have to clean up
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001260 StringAllocator_Destruct(&(me->StringAllocator));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001261
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001262 return nReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001263}
1264
1265
1266
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001267/*
1268
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001269Decoder errors handled in this file
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001270
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001271 - Hit end of input before it was expected while decoding type and number QCBOR_ERR_HIT_END
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001272
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001273 - negative integer that is too large for C QCBOR_ERR_INT_OVERFLOW
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001274
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001275 - Hit end of input while decoding a text or byte string QCBOR_ERR_HIT_END
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001276
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001277 - Encountered conflicting tags -- e.g., an item is tagged both a date string and an epoch date QCBOR_ERR_UNSUPPORTED
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001278
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001279 - Encontered an array or mapp that has too many items QCBOR_ERR_ARRAY_TOO_LONG
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001280
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001281 - Encountered array/map nesting that is too deep QCBOR_ERR_ARRAY_NESTING_TOO_DEEP
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001282
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001283 - An epoch date > INT64_MAX or < INT64_MIN was encountered QCBOR_ERR_DATE_OVERFLOW
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001284
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001285 - The type of a map label is not a string or int QCBOR_ERR_MAP_LABEL_TYPE
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001286
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001287 - Hit end with arrays or maps still open -- QCBOR_ERR_EXTRA_BYTES
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001288
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001289 */
1290
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001291
1292
Laurence Lundbladef6531662018-12-04 10:42:22 +09001293
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001294/* ===========================================================================
1295 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001296
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001297 This implements a simple sting allocator for indefinite length
1298 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
1299 implements the function type QCBORStringAllocate and allows easy
1300 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09001301
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001302 This particular allocator is built-in for convenience. The caller
1303 can implement their own. All of this following code will get
1304 dead-stripped if QCBORDecode_SetMemPool() is not called.
1305
1306 This is a very primitive memory allocator. It does not track
1307 individual allocations, only a high-water mark. A free or
1308 reallocation must be of the last chunk allocated.
1309
1310 The size of the pool and offset to free memory are packed into the
1311 first 8 bytes of the memory pool so we don't have to keep them in
1312 the decode context. Since the address of the pool may not be
1313 aligned, they have to be packed and unpacked as if they were
1314 serialized data of the wire or such.
1315
1316 The sizes packed in are uint32_t to be the same on all CPU types
1317 and simplify the code.
1318 =========================================================================== */
1319
1320
1321static inline int MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
1322{
1323 // Use of UsefulInputBuf is overkill, but it is convenient.
1324 UsefulInputBuf UIB;
1325
1326 // Just assume the size here. It was checked during SetUp so the assumption is safe.
1327 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem, QCBOR_DECODE_MIN_MEM_POOL_SIZE});
1328 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
1329 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
1330 return UsefulInputBuf_GetError(&UIB);
1331}
1332
1333
1334static inline int MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
1335{
1336 // Use of UsefulOutBuf is overkill, but convenient. The
1337 // length check performed here is useful.
1338 UsefulOutBuf UOB;
1339
1340 UsefulOutBuf_Init(&UOB, Pool);
1341 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
1342 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
1343 return UsefulOutBuf_GetError(&UOB);
1344}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001345
1346
1347/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001348 Internal function for an allocation, reallocation free and destuct.
1349
1350 Having only one function rather than one each per mode saves space in
1351 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001352
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001353 Code Reviewers: THIS FUNCTION DOES POINTER MATH
1354 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001355static UsefulBuf MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001356{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001357 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001358
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001359 uint32_t uPoolSize;
1360 uint32_t uFreeOffset;
1361
1362 if(uNewSize > UINT32_MAX) {
1363 // This allocator is only good up to 4GB. This check should
1364 // optimize out if sizeof(size_t) == sizeof(uint32_t)
1365 goto Done;
1366 }
1367 const uint32_t uNewSize32 = (uint32_t)uNewSize;
1368
1369 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
1370 goto Done;
1371 }
1372
1373 if(uNewSize) {
1374 if(pMem) {
1375 // REALLOCATION MODE
1376 // Calculate pointer to the end of the memory pool. It is
1377 // assumed that pPool + uPoolSize won't wrap around by
1378 // assuming the caller won't pass a pool buffer in that is
1379 // not in legitimate memory space.
1380 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
1381
1382 // Check that the pointer for reallocation is in the range of the
1383 // pool. This also makes sure that pointer math further down
1384 // doesn't wrap under or over.
1385 if(pMem >= pPool && pMem < pPoolEnd) {
1386 // Offset to start of chunk for reallocation. This won't
1387 // wrap under because of check that pMem >= pPool. Cast
1388 // is safe because the pool is always less than UINT32_MAX
1389 // because of check in QCBORDecode_SetMemPool().
1390 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
1391
1392 // Check to see if the allocation will fit. uPoolSize -
1393 // uMemOffset will not wrap under because of check that
1394 // pMem is in the range of the uPoolSize by check above.
1395 if(uNewSize <= uPoolSize - uMemOffset) {
1396 ReturnValue.ptr = pMem;
1397 ReturnValue.len = uNewSize;
1398
1399 // Addition won't wrap around over because uNewSize was
1400 // checked to be sure it is less than the pool size.
1401 uFreeOffset = uMemOffset + uNewSize32;
1402 }
1403 }
1404 } else {
1405 // ALLOCATION MODE
1406 // uPoolSize - uFreeOffset will not underflow because this
1407 // pool implementation makes sure uFreeOffset is always
1408 // smaller than uPoolSize through this check here and
1409 // reallocation case.
1410 if(uNewSize <= uPoolSize - uFreeOffset) {
1411 ReturnValue.len = uNewSize;
1412 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
1413 uFreeOffset += uNewSize;
1414 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001415 }
1416 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001417 if(pMem) {
1418 // FREE MODE
1419 // Cast is safe because of limit on pool size in
1420 // QCBORDecode_SetMemPool()
1421 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
1422 } else {
1423 // DESTRUCT MODE
1424 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001425 }
1426 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001427
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001428 UsefulBuf Pool = {pPool, uPoolSize};
1429 MemPool_Pack(Pool, uFreeOffset);
1430
1431Done:
1432 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001433}
1434
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001435
Laurence Lundbladef6531662018-12-04 10:42:22 +09001436/*
1437 Public function, see header qcbor.h file
1438 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001439QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pMe, UsefulBuf Pool, bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001440{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001441 // The pool size and free mem offset are packed into the beginning
1442 // of the pool memory. This compile time check make sure the
1443 // constant in the header is correct. This check should optimize
1444 // down to nothing.
1445 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundblade30816f22018-11-10 13:40:22 +07001446 return QCBOR_ERR_BUFFER_TOO_SMALL;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001447 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001448
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001449 // The pool size and free offset packed in to the beginning of pool
1450 // memory are only 32-bits. This check will optimize out on 32-bit
1451 // machines.
1452 if(Pool.len > UINT32_MAX) {
1453 return QCBOR_ERR_BUFFER_TOO_LARGE;
1454 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001455
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001456 // This checks that the pool buffer given is big enough.
1457 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
1458 return QCBOR_ERR_BUFFER_TOO_SMALL;
1459 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001460
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001461 pMe->StringAllocator.pfAllocator = MemPool_Function;
1462 pMe->StringAllocator.pAllocateCxt = Pool.ptr;
1463 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001464
Laurence Lundblade30816f22018-11-10 13:40:22 +07001465 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001466}