blob: db761d4f0023cae9c547e9595f104836967d65b0 [file] [log] [blame]
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001/*==============================================================================
2Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
3
4Redistribution and use in source and binary forms, with or without
5modification, are permitted provided that the following conditions are
6met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above
10 copyright notice, this list of conditions and the following
11 disclaimer in the documentation and/or other materials provided
12 with the distribution.
13 * Neither the name of The Linux Foundation nor the names of its
14 contributors may be used to endorse or promote products derived
15 from this software without specific prior written permission.
16
17THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28==============================================================================*/
29
Laurence Lundblade624405d2018-09-18 20:10:47 -070030/*==============================================================================
31 Modifications beyond the version released on CAF are under the MIT license:
32
33 Copyright 2018 Laurence Lundblade
34
35 Permission is hereby granted, free of charge, to any person obtaining
36 a copy of this software and associated documentation files (the
37 "Software"), to deal in the Software without restriction, including
38 without limitation the rights to use, copy, modify, merge, publish,
39 distribute, sublicense, and/or sell copies of the Software, and to
40 permit persons to whom the Software is furnished to do so, subject to
41 the following conditions:
42
43 The above copyright notice and this permission notice shall be included
44 in all copies or substantial portions of the Software.
45
46 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
47 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
48 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
49 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
50 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
51 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
52 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
53 SOFTWARE.
54 ==============================================================================*/
55
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070056/*===================================================================================
57 FILE: qcbor_decode.c
58
59 DESCRIPTION: This file contains the implementation of QCBOR.
60
61 EDIT HISTORY FOR FILE:
62
63 This section contains comments describing changes made to the module.
64 Notice that changes are listed in reverse chronological order.
65
66 when who what, where, why
67 -------- ---- ---------------------------------------------------
68 02/04/17 llundbla Work on CPUs that don's require pointer alignment
69 by making use of changes in UsefulBuf
70 03/01/17 llundbla More data types; decoding improvements and fixes
71 11/13/16 llundbla Integrate most TZ changes back into github version.
72 09/30/16 gkanike Porting to TZ.
73 03/15/16 llundbla Initial Version.
74
75 =====================================================================================*/
76
77#include "qcbor.h"
Laurence Lundblade12d32c52018-09-19 11:25:27 -070078#include "ieee754.h"
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070079
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070080
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +053081/*
82 This casts away the const-ness of a pointer, usually so it can be
83 freed or realloced.
84 */
85#define UNCONST_POINTER(ptr) ((void *)(ptr))
86
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070087
88/*
Laurence Lundblade3a760b02018-10-08 13:46:03 +080089 Collection of functions to track the map/array nesting for decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070090 */
91
92inline static int IsMapOrArray(uint8_t uDataType)
93{
94 return uDataType == QCBOR_TYPE_MAP || uDataType == QCBOR_TYPE_ARRAY;
95}
96
97inline static int DecodeNesting_IsNested(const QCBORDecodeNesting *pNesting)
98{
99 return pNesting->pCurrent != &(pNesting->pMapsAndArrays[0]);
100}
101
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700102inline static int DecodeNesting_IsIndefiniteLength(const QCBORDecodeNesting *pNesting)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700103{
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700104 return pNesting->pCurrent->uCount == UINT16_MAX;
105}
106
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800107inline static uint8_t DecodeNesting_GetLevel(QCBORDecodeNesting *pNesting)
108{
109 return pNesting->pCurrent - &(pNesting->pMapsAndArrays[0]);
110}
111
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700112inline static int DecodeNesting_TypeIsMap(const QCBORDecodeNesting *pNesting)
113{
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700114 if(!DecodeNesting_IsNested(pNesting)) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700115 return 0;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700116 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700117
118 return CBOR_MAJOR_TYPE_MAP == pNesting->pCurrent->uMajorType;
119}
120
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800121// Process a break. This will either ascend the nesting or error out
122inline static int DecodeNesting_BreakAscend(QCBORDecodeNesting *pNesting)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700123{
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800124 // breaks must always occur when there is nesting
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700125 if(!DecodeNesting_IsNested(pNesting)) {
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800126 return QCBOR_ERR_BAD_BREAK;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700127 }
128
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800129 // breaks can only occur when the map/array is indefinite length
130 if(!DecodeNesting_IsIndefiniteLength(pNesting)) {
131 return QCBOR_ERR_BAD_BREAK;
132 }
133
134 // if all OK, the break reduces the level of nesting
135 pNesting->pCurrent--;
136
137 return QCBOR_SUCCESS;
138}
139
140// Called on every single item except breaks including the opening of a map/array
141inline static void DecodeNesting_DecrementCount(QCBORDecodeNesting *pNesting)
142{
143 if(!DecodeNesting_IsNested(pNesting)) {
144 // at top level where there is no tracking
145 return;
146 }
147
148 if(DecodeNesting_IsIndefiniteLength(pNesting)) {
149 // There is no count for indefinite length arrays/maps
150 return;
151 }
152
153 // Decrement the count of items in this array/map
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700154 pNesting->pCurrent->uCount--;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700155
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800156 // Pop up nesting levels if the counts at the levels are zero
157 while(DecodeNesting_IsNested(pNesting) && 0 == pNesting->pCurrent->uCount) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700158 pNesting->pCurrent--;
Laurence Lundblade9e3651c2018-10-10 11:49:55 +0800159 if(!DecodeNesting_IsIndefiniteLength(pNesting)) {
160 pNesting->pCurrent->uCount--;
161 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700162 }
163}
164
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800165// Called on every map/array
166inline static int DecodeNesting_Descend(QCBORDecodeNesting *pNesting, QCBORItem *pItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700167{
168 int nReturn = QCBOR_SUCCESS;
169
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800170 if(pItem->val.uCount == 0) {
171 // Nothing to do for empty definite lenth arrays. They are just are
172 // effectively the same as an item that is not a map or array
173 goto Done;
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530174 // Empty indefinite length maps and arrays are handled elsewhere
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800175 }
176
177 // Error out if arrays is too long to handle
178 if(pItem->val.uCount != UINT16_MAX && pItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700179 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
180 goto Done;
181 }
182
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800183 // Error out if nesting is too deep
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700184 if(pNesting->pCurrent >= &(pNesting->pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING])) {
185 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
186 goto Done;
187 }
188
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800189 // The actual descend
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700190 pNesting->pCurrent++;
191
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800192 // Record a few details for this nesting level
193 pNesting->pCurrent->uMajorType = pItem->uDataType;
194 pNesting->pCurrent->uCount = pItem->val.uCount;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700195
196Done:
197 return nReturn;;
198}
199
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700200inline static void DecodeNesting_Init(QCBORDecodeNesting *pNesting)
201{
202 pNesting->pCurrent = &(pNesting->pMapsAndArrays[0]);
203}
204
205
206
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700207/*
208 This list of built-in tags. Only add tags here that are
209 clearly established and useful. Once a tag is added here
210 it can't be taken out as that would break backwards compatibility.
211 There are only 48 slots available forever.
212 */
213static const uint16_t spBuiltInTagMap[] = {
214 CBOR_TAG_DATE_STRING, // See TAG_MAPPER_FIRST_FOUR
215 CBOR_TAG_DATE_EPOCH, // See TAG_MAPPER_FIRST_FOUR
216 CBOR_TAG_POS_BIGNUM, // See TAG_MAPPER_FIRST_FOUR
217 CBOR_TAG_NEG_BIGNUM, // See TAG_MAPPER_FIRST_FOUR
218 CBOR_TAG_FRACTION,
219 CBOR_TAG_BIGFLOAT,
220 CBOR_TAG_COSE_ENCRYPTO,
221 CBOR_TAG_COSE_MAC0,
222 CBOR_TAG_COSE_SIGN1,
223 CBOR_TAG_ENC_AS_B64URL,
224 CBOR_TAG_ENC_AS_B64,
225 CBOR_TAG_ENC_AS_B16,
226 CBOR_TAG_CBOR,
227 CBOR_TAG_URI,
228 CBOR_TAG_B64URL,
229 CBOR_TAG_B64,
230 CBOR_TAG_REGEX,
231 CBOR_TAG_MIME,
232 CBOR_TAG_BIN_UUID,
233 CBOR_TAG_CWT,
234 CBOR_TAG_ENCRYPT,
235 CBOR_TAG_MAC,
236 CBOR_TAG_SIGN,
237 CBOR_TAG_GEO_COORD,
238 CBOR_TAG_CBOR_MAGIC
239};
240
241// This is used in a bit of cleverness in GetNext_TaggedItem() to
242// keep code size down and switch for the internal processing of
243// these types. This will break if the first four items in
244// spBuiltInTagMap don't have values 0,1,2,3. That is the
245// mapping is 0 to 0, 1 to 1, 2 to 2 and 3 to 3.
246#define QCBOR_TAGFLAG_DATE_STRING (0x01LL << CBOR_TAG_DATE_STRING)
247#define QCBOR_TAGFLAG_DATE_EPOCH (0x01LL << CBOR_TAG_DATE_EPOCH)
248#define QCBOR_TAGFLAG_POS_BIGNUM (0x01LL << CBOR_TAG_POS_BIGNUM)
249#define QCBOR_TAGFLAG_NEG_BIGNUM (0x01LL << CBOR_TAG_NEG_BIGNUM)
250
251#define TAG_MAPPER_FIRST_FOUR (QCBOR_TAGFLAG_DATE_STRING |\
252 QCBOR_TAGFLAG_DATE_EPOCH |\
253 QCBOR_TAGFLAG_POS_BIGNUM |\
254 QCBOR_TAGFLAG_NEG_BIGNUM)
255
256#define TAG_MAPPER_TOTAL_TAG_BITS 64 // Number of bits in a uint64_t
257#define TAG_MAPPER_CUSTOM_TAGS_BASE_INDEX (TAG_MAPPER_TOTAL_TAG_BITS - QCBOR_MAX_CUSTOM_TAGS) // 48
258#define TAG_MAPPER_MAX_SIZE_BUILT_IN_TAGS (TAG_MAPPER_TOTAL_TAG_BITS - QCBOR_MAX_CUSTOM_TAGS ) // 48
259
260static inline int TagMapper_LookupBuiltIn(uint64_t uTag)
261{
262 if(sizeof(spBuiltInTagMap)/sizeof(uint16_t) > TAG_MAPPER_MAX_SIZE_BUILT_IN_TAGS) {
263 // This is a cross-check to make sure the above array doesn't
264 // accidentally get made too big.
265 // In normal conditions the above test should optimize out
266 // as all the values are known at compile time.
267 return -1;
268 }
269
270 if(uTag > UINT16_MAX) {
271 // This tag map works only on 16-bit tags
272 return -1;
273 }
274
275 for(int nTagBitIndex = 0; nTagBitIndex < (int)(sizeof(spBuiltInTagMap)/sizeof(uint16_t)); nTagBitIndex++) {
276 if(spBuiltInTagMap[nTagBitIndex] == uTag) {
277 return nTagBitIndex;
278 }
279 }
280 return -1; // Indicates no match
281}
282
283static inline int TagMapper_LookupCallerConfigured(const QCBORTagListIn *pCallerConfiguredTagMap, uint64_t uTag)
284{
285 for(int nTagBitIndex = 0; nTagBitIndex < pCallerConfiguredTagMap->uNumTags; nTagBitIndex++) {
286 if(pCallerConfiguredTagMap->puTags[nTagBitIndex] == uTag) {
287 return nTagBitIndex + TAG_MAPPER_CUSTOM_TAGS_BASE_INDEX;
288 }
289 }
290
291 return -1; // Indicates no match
292}
293
294/*
295 Find the tag bit index for a given tag value, or error out
296
297 This and the above functions could probably be optimized and made
298 clearer and neater.
299 */
300static int TagMapper_Lookup(const QCBORTagListIn *pCallerConfiguredTagMap, uint64_t uTag, uint8_t *puTagBitIndex)
301{
302 int nTagBitIndex = TagMapper_LookupBuiltIn(uTag);
303 if(nTagBitIndex >= 0) {
304 // Cast is safe because TagMapper_LookupBuiltIn never returns > 47
305 *puTagBitIndex = (uint8_t)nTagBitIndex;
306 return QCBOR_SUCCESS;
307 }
308
309 if(pCallerConfiguredTagMap) {
310 if(pCallerConfiguredTagMap->uNumTags > QCBOR_MAX_CUSTOM_TAGS) {
311 return QCBOR_ERR_TOO_MANY_TAGS;
312 }
313 nTagBitIndex = TagMapper_LookupCallerConfigured(pCallerConfiguredTagMap, uTag);
314 if(nTagBitIndex >= 0) {
315 // Cast is safe because TagMapper_LookupBuiltIn never returns > 63
316
317 *puTagBitIndex = (uint8_t)nTagBitIndex;
318 return QCBOR_SUCCESS;
319 }
320 }
321
322 return QCBOR_ERR_BAD_OPT_TAG;
323}
324
325
326
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700327
328/*
329 Public function, see header file
330 */
331void QCBORDecode_Init(QCBORDecodeContext *me, UsefulBufC EncodedCBOR, int8_t nDecodeMode)
332{
333 memset(me, 0, sizeof(QCBORDecodeContext));
334 UsefulInputBuf_Init(&(me->InBuf), EncodedCBOR);
335 // Don't bother with error check on decode mode. If a bad value is passed it will just act as
336 // if the default normal mode of 0 was set.
337 me->uDecodeMode = nDecodeMode;
338 DecodeNesting_Init(&(me->nesting));
339}
340
341
342/*
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700343 Public function, see header file
344 */
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530345void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pCtx, const QCBORStringAllocator *pAllocator, bool bAllocAll)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700346{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700347 pCtx->pStringAllocator = (void *)pAllocator;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530348 pCtx->bStringAllocateAll = bAllocAll;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700349}
350
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700351void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *me, const QCBORTagListIn *pTagList)
352{
353 me->pCallerConfiguredTagList = pTagList;
354}
355
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700356
357/*
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700358 This decodes the fundamental part of a CBOR data item, the type and number
359
360 This is the Counterpart to InsertEncodedTypeAndNumber().
361
362 This does the network->host byte order conversion. The conversion here
363 also results in the conversion for floats in addition to that for
364 lengths, tags and integer values.
365
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700366 This returns:
367 pnMajorType -- the major type for the item
368 puNumber -- the "number" which is used a the value for integers, tags and floats and length for strings and arrays
369 puAdditionalInfo -- Pass this along to know what kind of float or if length is indefinite
370
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700371 */
372inline static int DecodeTypeAndNumber(UsefulInputBuf *pUInBuf, int *pnMajorType, uint64_t *puNumber, uint8_t *puAdditionalInfo)
373{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700374 // Stack usage: int/ptr 5 -- 40
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700375 int nReturn;
376
377 // Get the initial byte that every CBOR data item has
378 const uint8_t InitialByte = UsefulInputBuf_GetByte(pUInBuf);
379
380 // Break down the initial byte
381 const uint8_t uTmpMajorType = InitialByte >> 5;
382 const uint8_t uAdditionalInfo = InitialByte & 0x1f;
383
384 // Get the integer that follows the major type. Do not know if this is a length, value, float or tag at this point
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700385 // Also convert from network byte order.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700386 uint64_t uTmpValue;
387 switch(uAdditionalInfo) {
388
389 case LEN_IS_ONE_BYTE:
390 uTmpValue = UsefulInputBuf_GetByte(pUInBuf);
391 break;
392
393 case LEN_IS_TWO_BYTES:
394 uTmpValue = UsefulInputBuf_GetUint16(pUInBuf);
395 break;
396
397 case LEN_IS_FOUR_BYTES:
398 uTmpValue = UsefulInputBuf_GetUint32(pUInBuf);
399 break;
400
401 case LEN_IS_EIGHT_BYTES:
402 uTmpValue = UsefulInputBuf_GetUint64(pUInBuf);
403 break;
404
405 case ADDINFO_RESERVED1: // reserved by CBOR spec
406 case ADDINFO_RESERVED2: // reserved by CBOR spec
407 case ADDINFO_RESERVED3: // reserved by CBOR spec
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700408 nReturn = QCBOR_ERR_UNSUPPORTED;
409 goto Done;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700410
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700411 default:
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700412 // This is when the "number" is in the additional info
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700413 uTmpValue = uAdditionalInfo;
414 break;
415 }
416
417 // If any of the UsefulInputBuf_Get calls fail we will get here with uTmpValue as 0.
418 // There is no harm in this. This following check takes care of catching all of
419 // these errors.
420
421 if(UsefulInputBuf_GetError(pUInBuf)) {
422 nReturn = QCBOR_ERR_HIT_END;
423 goto Done;
424 }
425
426 // All successful if we got here.
427 nReturn = QCBOR_SUCCESS;
428 *pnMajorType = uTmpMajorType;
429 *puNumber = uTmpValue;
430 *puAdditionalInfo = uAdditionalInfo;
431
432Done:
433 return nReturn;
434}
435
436
437/*
438 CBOR doesn't explicitly specify two's compliment for integers but all CPUs
439 use it these days and the test vectors in the RFC are so. All integers in the CBOR
440 structure are positive and the major type indicates positive or negative.
441 CBOR can express positive integers up to 2^x - 1 where x is the number of bits
442 and negative integers down to 2^x. Note that negative numbers can be one
443 more away from zero than positive.
444 Stdint, as far as I can tell, uses two's compliment to represent
445 negative integers.
446
447 See http://www.unix.org/whitepapers/64bit.html for reasons int isn't
448 used here in any way including in the interface
449 */
450inline static int DecodeInteger(int nMajorType, uint64_t uNumber, QCBORItem *pDecodedItem)
451{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700452 // Stack usage: int/ptr 1 -- 8
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700453 int nReturn = QCBOR_SUCCESS;
454
455 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
456 if (uNumber <= INT64_MAX) {
457 pDecodedItem->val.int64 = (int64_t)uNumber;
458 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
459
460 } else {
461 pDecodedItem->val.uint64 = uNumber;
462 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
463
464 }
465 } else {
466 if(uNumber <= INT64_MAX) {
467 pDecodedItem->val.int64 = -uNumber-1;
468 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
469
470 } else {
471 // C can't represent a negative integer in this range
472 // so it is an error. todo -- test this condition
473 nReturn = QCBOR_ERR_INT_OVERFLOW;
474 }
475 }
476
477 return nReturn;
478}
479
480// Make sure #define value line up as DecodeSimple counts on this.
481#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
482#error QCBOR_TYPE_FALSE macro value wrong
483#endif
484
485#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
486#error QCBOR_TYPE_TRUE macro value wrong
487#endif
488
489#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
490#error QCBOR_TYPE_NULL macro value wrong
491#endif
492
493#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
494#error QCBOR_TYPE_UNDEF macro value wrong
495#endif
496
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700497#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
498#error QCBOR_TYPE_BREAK macro value wrong
499#endif
500
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700501#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
502#error QCBOR_TYPE_DOUBLE macro value wrong
503#endif
504
505#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
506#error QCBOR_TYPE_FLOAT macro value wrong
507#endif
508
509/*
510 Decode true, false, floats, break...
511 */
512
513inline static int DecodeSimple(uint8_t uAdditionalInfo, uint64_t uNumber, QCBORItem *pDecodedItem)
514{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700515 // Stack usage: 0
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700516 int nReturn = QCBOR_SUCCESS;
517
518 // uAdditionalInfo is 5 bits from the initial byte
519 // compile time checks above make sure uAdditionalInfo values line up with uDataType values
520 pDecodedItem->uDataType = uAdditionalInfo;
521
522 switch(uAdditionalInfo) {
523 case ADDINFO_RESERVED1: // 28
524 case ADDINFO_RESERVED2: // 29
525 case ADDINFO_RESERVED3: // 30
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700526 nReturn = QCBOR_ERR_UNSUPPORTED;
527 break;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700528
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700529 case HALF_PREC_FLOAT:
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700530 pDecodedItem->val.fnum = IEEE754_HalfToFloat((uint16_t)uNumber);
531 pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
532 break;
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700533 case SINGLE_PREC_FLOAT:
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700534 pDecodedItem->val.fnum = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uNumber);
535 break;
536 case DOUBLE_PREC_FLOAT:
537 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uNumber);
538 break;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700539
540 case CBOR_SIMPLEV_FALSE: // 20
541 case CBOR_SIMPLEV_TRUE: // 21
542 case CBOR_SIMPLEV_NULL: // 22
543 case CBOR_SIMPLEV_UNDEF: // 23
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700544 case CBOR_SIMPLE_BREAK: // 31
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700545 break; // nothing to do
546
547 case CBOR_SIMPLEV_ONEBYTE: // 24
548 if(uNumber <= CBOR_SIMPLE_BREAK) {
549 // This takes out f8 00 ... f8 1f which should be encoded as e0 … f7
550 nReturn = QCBOR_ERR_INVALID_CBOR;
551 goto Done;
552 }
553 // fall through intentionally
554
555 default: // 0-19
556 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
557 // DecodeTypeAndNumber will make uNumber equal to uAdditionalInfo when uAdditionalInfo is < 24
558 // This cast is safe because the 2, 4 and 8 byte lengths of uNumber are in the double/float cases above
559 pDecodedItem->val.uSimple = (uint8_t)uNumber;
560 break;
561 }
562
563Done:
564 return nReturn;
565}
566
567
568
569/*
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530570 Decode text and byte strings. Call the string allocator if asked to.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700571 */
Laurence Lundbladefab1b522018-10-19 13:40:52 +0530572inline static int DecodeBytes(const QCBORStringAllocator *pAlloc, int nMajorType, uint64_t uStrLen, UsefulInputBuf *pUInBuf, QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700573{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700574 // Stack usage: UsefulBuf 2, int/ptr 1 40
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530575 int nReturn = QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700576
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530577 UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, uStrLen);
578 if(UsefulBuf_IsNULLC(Bytes)) {
579 // Failed to get the bytes for this string item
580 nReturn = QCBOR_ERR_HIT_END;
581 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700582 }
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530583
584 if(pAlloc) {
585 // We are asked to use string allocator to make a copy
586 UsefulBuf NewMem = pAlloc->fAllocate(pAlloc->pAllocaterContext, NULL, uStrLen);
587 if(UsefulBuf_IsNULL(NewMem)) {
588 nReturn = QCBOR_ERR_STRING_ALLOC;
589 goto Done;
590 }
591 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
592 } else {
593 // Normal case with no string allocator
594 pDecodedItem->val.string = Bytes;
595 }
596 pDecodedItem->uDataType = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING) ? QCBOR_TYPE_BYTE_STRING : QCBOR_TYPE_TEXT_STRING;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700597
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530598Done:
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700599 return nReturn;
600}
601
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700602
603/*
604 Mostly just assign the right data type for the date string.
605 */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700606inline static int DecodeDateString(QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700607{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700608 // Stack Use: UsefulBuf 1 16
609 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700610 return QCBOR_ERR_BAD_OPT_TAG;
611 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700612
613 UsefulBufC Temp = pDecodedItem->val.string;
614 pDecodedItem->val.dateString = Temp;
615 pDecodedItem->uDataType = QCBOR_TYPE_DATE_STRING;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700616 return QCBOR_SUCCESS;
617}
618
619
620/*
621 Mostly just assign the right data type for the bignum.
622 */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700623inline static int DecodeBigNum(QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700624{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700625 // Stack Use: UsefulBuf 1 -- 16
626 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700627 return QCBOR_ERR_BAD_OPT_TAG;
628 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700629 UsefulBufC Temp = pDecodedItem->val.string;
630 pDecodedItem->val.bigNum = Temp;
631 pDecodedItem->uDataType = pDecodedItem->uTagBits & QCBOR_TAGFLAG_POS_BIGNUM ? QCBOR_TYPE_POSBIGNUM : QCBOR_TYPE_NEGBIGNUM; // TODO: check this
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700632 return QCBOR_SUCCESS;
633}
634
635
636/*
637 The epoch formatted date. Turns lots of different forms of encoding date into uniform one
638 */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700639static int DecodeDateEpoch(QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700640{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700641 // Stack usage: 1
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700642 int nReturn = QCBOR_SUCCESS;
643
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700644 pDecodedItem->val.epochDate.fSecondsFraction = 0;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700645 double d = pDecodedItem->val.dfnum; // Might not use this, but keeps code flow neater below
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700646
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700647 switch (pDecodedItem->uDataType) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700648
649 case QCBOR_TYPE_INT64:
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700650 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700651 break;
652
653 case QCBOR_TYPE_UINT64:
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700654 if(pDecodedItem->val.uint64 > INT64_MAX) {
655 nReturn = QCBOR_ERR_DATE_OVERFLOW;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700656 goto Done;
657 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700658 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.uint64;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700659 break;
660
Laurence Lundblade9e3651c2018-10-10 11:49:55 +0800661 case QCBOR_TYPE_FLOAT:
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700662 d = pDecodedItem->val.fnum;
663 // Fall through
664
Laurence Lundblade9e3651c2018-10-10 11:49:55 +0800665 case QCBOR_TYPE_DOUBLE:
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700666 if(d > INT64_MAX) {
Laurence Lundblade9e3651c2018-10-10 11:49:55 +0800667 nReturn = QCBOR_ERR_DATE_OVERFLOW;
668 goto Done;
669 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700670 pDecodedItem->val.epochDate.nSeconds = d; // Float to integer conversion happening here.
671 pDecodedItem->val.epochDate.fSecondsFraction = d - pDecodedItem->val.epochDate.nSeconds;
Laurence Lundblade9e3651c2018-10-10 11:49:55 +0800672 break;
673
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700674 default:
675 nReturn = QCBOR_ERR_BAD_OPT_TAG;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700676 goto Done;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700677 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700678 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700679
680Done:
681 return nReturn;
682}
683
684
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700685
686
687// Make sure the constants align as this is assumed by the GetAnItem() implementation
688#if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
689#error QCBOR_TYPE_ARRAY value not lined up with major type
690#endif
691#if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
692#error QCBOR_TYPE_MAP value not lined up with major type
693#endif
694
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700695/*
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700696 This gets a single data item and decodes it including preceding optional tagging. This does not
697 deal with arrays and maps and nesting except to decode the data item introducing them. Arrays and
698 maps are handled at the next level up in GetNext().
699
700 Errors detected here include: an array that is too long to decode, hit end of buffer unexpectedly,
701 a few forms of invalid encoded CBOR
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700702 */
Laurence Lundbladefab1b522018-10-19 13:40:52 +0530703static int GetNext_Item(UsefulInputBuf *pUInBuf, QCBORItem *pDecodedItem, const QCBORStringAllocator *pAlloc)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700704{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700705 // Stack usage: int/ptr 3 -- 24
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700706 int nReturn;
707
708 // Get the major type and the number. Number could be length of more bytes or the value depending on the major type
709 // nAdditionalInfo is an encoding of the length of the uNumber and is needed to decode floats and doubles
710 int uMajorType;
711 uint64_t uNumber;
712 uint8_t uAdditionalInfo;
713
714 nReturn = DecodeTypeAndNumber(pUInBuf, &uMajorType, &uNumber, &uAdditionalInfo);
715
716 // Error out here if we got into trouble on the type and number.
717 // The code after this will not work if the type and number is not good.
718 if(nReturn)
719 goto Done;
720
Laurence Lundbladefab1b522018-10-19 13:40:52 +0530721 memset(pDecodedItem, 0, sizeof(QCBORItem));
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700722
723 // At this point the major type and the value are valid. We've got the type and the number that
724 // starts every CBOR data item.
725 switch (uMajorType) {
726 case CBOR_MAJOR_TYPE_POSITIVE_INT: // Major type 0
727 case CBOR_MAJOR_TYPE_NEGATIVE_INT: // Major type 1
728 nReturn = DecodeInteger(uMajorType, uNumber, pDecodedItem);
729 break;
730
731 case CBOR_MAJOR_TYPE_BYTE_STRING: // Major type 2
732 case CBOR_MAJOR_TYPE_TEXT_STRING: // Major type 3
733 if(uAdditionalInfo == LEN_IS_INDEFINITE) {
734 pDecodedItem->uDataType = (uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING) ? QCBOR_TYPE_BYTE_STRING : QCBOR_TYPE_TEXT_STRING;
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530735 pDecodedItem->val.string = (UsefulBufC){NULL, SIZE_MAX};
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700736 } else {
737 nReturn = DecodeBytes(pAlloc, uMajorType, uNumber, pUInBuf, pDecodedItem);
738 }
739 break;
740
741 case CBOR_MAJOR_TYPE_ARRAY: // Major type 4
742 case CBOR_MAJOR_TYPE_MAP: // Major type 5
743 // Record the number of items in the array or map
744 if(uNumber > QCBOR_MAX_ITEMS_IN_ARRAY) {
745 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
746 goto Done;
747 }
748 if(uAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530749 pDecodedItem->val.uCount = UINT16_MAX; // Indicate indefinite length
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700750 } else {
751 pDecodedItem->val.uCount = (uint16_t)uNumber; // type conversion OK because of check above
752 }
753 pDecodedItem->uDataType = uMajorType; // C preproc #if above makes sure constants align
754 break;
755
756 case CBOR_MAJOR_TYPE_OPTIONAL: // Major type 6, optional prepended tags
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700757 pDecodedItem->val.uTagV = uNumber;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700758 pDecodedItem->uDataType = QCBOR_TYPE_OPTTAG;
759 break;
760
761 case CBOR_MAJOR_TYPE_SIMPLE: // Major type 7, float, double, true, false, null...
762 nReturn = DecodeSimple(uAdditionalInfo, uNumber, pDecodedItem);
763 break;
764
765 default: // Should never happen because DecodeTypeAndNumber() should never return > 7
766 nReturn = QCBOR_ERR_UNSUPPORTED;
767 break;
768 }
769
770Done:
771 return nReturn;
772}
773
774
775
776/*
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800777 This layer deals with indefinite length strings. It pulls all the
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700778 individual chunk items together into one QCBORItem using the
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530779 string allocator.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530780
781 Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700782 */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700783static inline int GetNext_FullItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700784{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700785 // Stack usage; int/ptr 2 UsefulBuf 2 QCBORItem -- 96
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700786 int nReturn;
Laurence Lundblade5b8c5852018-10-14 21:11:42 +0530787 QCBORStringAllocator *pAlloc = (QCBORStringAllocator *)me->pStringAllocator;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530788 UsefulBufC FullString = NULLUsefulBufC;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700789
790 nReturn = GetNext_Item(&(me->InBuf), pDecodedItem, me->bStringAllocateAll ? pAlloc: NULL);
791 if(nReturn) {
792 goto Done;
793 }
794
795 // To reduce code size by removing support for indefinite length strings, the
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530796 // code in this function from here down can be eliminated. Run tests, except
797 // indefinite length string tests, to be sure all is OK if this is removed.
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700798
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800799 // Only do indefinite length processing on strings
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700800 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING && pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
801 goto Done; // no need to do any work here on non-string types
802 }
803
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800804 // Is this a string with an indefinite length?
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530805 if(pDecodedItem->val.string.len != SIZE_MAX) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800806 goto Done; // length is not indefinite, so no work to do here
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700807 }
808
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530809 // Can't do indefinite length strings without a string allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700810 if(pAlloc == NULL) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700811 nReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
812 goto Done;
813 }
814
815 // There is an indefinite length string to work on...
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800816 // Track which type of string it is
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700817 const uint8_t uStringType = pDecodedItem->uDataType;
818
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700819 // Loop getting chunk of indefinite string
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700820 for(;;) {
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700821 // Get item for next chunk
822 QCBORItem StringChunkItem;
823 // NULL passed to never string alloc chunk of indefinite length strings
824 nReturn = GetNext_Item(&(me->InBuf), &StringChunkItem, NULL);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700825 if(nReturn) {
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700826 break; // Error getting the next chunk
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700827 }
828
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530829 // See if it is a marker at end of indefinite length string
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700830 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800831 // String is complete
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700832 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +0530833 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700834 break;
835 }
836
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700837 // Match data type of chunk to type at beginning.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530838 // Also catches error of other non-string types that don't belong.
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700839 if(StringChunkItem.uDataType != uStringType) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700840 nReturn = QCBOR_ERR_INDEFINITE_STRING_SEG;
841 break;
842 }
843
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530844 // Alloc new buffer or expand previously allocated buffer so it can fit
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530845 UsefulBuf NewMem = (*pAlloc->fAllocate)(pAlloc->pAllocaterContext,
846 UNCONST_POINTER(FullString.ptr),
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700847 FullString.len + StringChunkItem.val.string.len);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700848 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530849 // Allocation of memory for the string failed
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700850 nReturn = QCBOR_ERR_STRING_ALLOC;
851 break;
852 }
853
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700854 // Copy new string chunk at the end of string so far.
855 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700856 }
857
858Done:
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530859 if(pAlloc && nReturn && !UsefulBuf_IsNULLC(FullString)) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700860 // Getting item failed, clean up the allocated memory
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530861 (pAlloc->fFree)(pAlloc->pAllocaterContext, UNCONST_POINTER(FullString.ptr));
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700862 }
863
864 return nReturn;
865}
866
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700867
868/*
869 Returns an error if there was something wrong with the optional item or it couldn't
870 be handled.
871 */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700872static int GetNext_TaggedItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem, QCBORTagListOut *pTags)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700873{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700874 // Stack usage: int/ptr: 3 -- 24
875 int nReturn;
876 uint64_t uTagBits = 0;
877 if(pTags) {
878 pTags->uNumUsed = 0;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700879 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700880
881 for(;;) {
882 nReturn = GetNext_FullItem(me, pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700883 if(nReturn) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700884 goto Done; // Error out of the loop
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700885 }
886
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700887 if(pDecodedItem->uDataType != QCBOR_TYPE_OPTTAG) {
888 // Successful exit from loop; maybe got some tags, maybe not
889 pDecodedItem->uTagBits = uTagBits;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700890 break;
891 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700892
893 uint8_t uTagBitIndex;
894 // Tag was mapped, tag was not mapped, error with tag list
895 switch(TagMapper_Lookup(me->pCallerConfiguredTagList, pDecodedItem->val.uTagV, &uTagBitIndex)) {
896
897 case QCBOR_SUCCESS:
898 // Successfully mapped the tag
899 uTagBits |= 0x01ULL << uTagBitIndex;
900 break;
901
902 case QCBOR_ERR_BAD_OPT_TAG:
903 // Tag is not recognized. Do nothing
904 break;
905
906 default:
907 // Error Condition
908 goto Done;
909 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700910
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700911 if(pTags) {
912 // Caller wants all tags recorded in the provided buffer
913 if(pTags->uNumUsed >= pTags->uNumAllocated) {
914 nReturn = QCBOR_ERR_TOO_MANY_TAGS;
915 goto Done;
916 }
917 pTags->puTags[pTags->uNumUsed] = pDecodedItem->val.uTagV;
918 pTags->uNumUsed++;
919 }
920 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700921
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700922 switch(pDecodedItem->uTagBits & TAG_MAPPER_FIRST_FOUR) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700923 case 0:
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700924 // No tags at all or none we know about. Nothing to do.
925 // This is part of the pass-through path of this function
926 // that will mostly be taken when decoding any item.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700927 break;
928
929 case QCBOR_TAGFLAG_DATE_STRING:
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700930 nReturn = DecodeDateString(pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700931 break;
932
933 case QCBOR_TAGFLAG_DATE_EPOCH:
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700934 nReturn = DecodeDateEpoch(pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700935 break;
936
937 case QCBOR_TAGFLAG_POS_BIGNUM:
938 case QCBOR_TAGFLAG_NEG_BIGNUM:
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700939 nReturn = DecodeBigNum(pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700940 break;
941
942 default:
943 // Encountering some mixed up CBOR like something that
944 // is tagged as both a string and integer date.
945 nReturn = QCBOR_ERR_BAD_OPT_TAG ;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700946 }
947
948Done:
949 return nReturn;
950}
951
952
953/*
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800954 This layer takes care of map entries. It combines the label and data items into one QCBORItem.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700955 */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700956static inline int GetNext_MapEntry(QCBORDecodeContext *me, QCBORItem *pDecodedItem, QCBORTagListOut *pTags)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700957{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700958 // Stack use: int/ptr 1, QCBORItem -- 56
959 int nReturn = GetNext_TaggedItem(me, pDecodedItem, pTags);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700960 if(nReturn)
961 goto Done;
962
Laurence Lundblade742df4a2018-10-13 20:07:17 +0800963 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700964 // Break can't be a map entry
Laurence Lundblade742df4a2018-10-13 20:07:17 +0800965 goto Done;
966 }
967
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700968 // If in a map and the right decoding mode, get the label
969 if(DecodeNesting_TypeIsMap(&(me->nesting)) && me->uDecodeMode != QCBOR_DECODE_MODE_MAP_AS_ARRAY) {
970 // In a map and caller wants maps decoded, not treated as arrays
971
972 // Get the next item which will be the real data; Item will be the label
973 QCBORItem LabelItem = *pDecodedItem;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700974 nReturn = GetNext_TaggedItem(me, pDecodedItem, pTags);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700975 if(nReturn)
976 goto Done;
977
Laurence Lundbladefab1b522018-10-19 13:40:52 +0530978 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
979
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700980 if(LabelItem.uDataType == QCBOR_TYPE_TEXT_STRING) {
981 // strings are always good labels
982 pDecodedItem->label.string = LabelItem.val.string;
983 pDecodedItem->uLabelType = QCBOR_TYPE_TEXT_STRING;
984 } else if (QCBOR_DECODE_MODE_MAP_STRINGS_ONLY == me->uDecodeMode) {
985 // It's not a string and we only want strings, probably for easy translation to JSON
986 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
987 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700988 } else if(LabelItem.uDataType == QCBOR_TYPE_INT64) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700989 pDecodedItem->label.int64 = LabelItem.val.int64;
990 pDecodedItem->uLabelType = QCBOR_TYPE_INT64;
991 } else if(LabelItem.uDataType == QCBOR_TYPE_UINT64) {
992 pDecodedItem->label.uint64 = LabelItem.val.uint64;
993 pDecodedItem->uLabelType = QCBOR_TYPE_UINT64;
994 } else if(LabelItem.uDataType == QCBOR_TYPE_BYTE_STRING) {
995 pDecodedItem->label.string = LabelItem.val.string;
Laurence Lundblade57dd1442018-10-15 20:26:28 +0530996 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700997 pDecodedItem->uLabelType = QCBOR_TYPE_BYTE_STRING;
998 } else {
999 // label is not an int or a string. It is an arrray
1000 // or a float or such and this implementation doesn't handle that.
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001001 // Also, tags on labels are ignored.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001002 nReturn = QCBOR_ERR_MAP_LABEL_TYPE ;
1003 goto Done;
1004 }
1005 }
1006
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001007Done:
1008 return nReturn;
1009}
1010
1011
1012/*
1013 Public function, see header qcbor.h file
1014 */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001015int QCBORDecode_GetNextWithTags(QCBORDecodeContext *me, QCBORItem *pDecodedItem, QCBORTagListOut *pTags)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001016{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001017 // Stack ptr/int: 2, QCBORItem : 64
1018
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301019 // The public entry point for fetching and parsing the next QCBORItem.
1020 // All the CBOR parsing work is here and in subordinate calls.
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001021 int nReturn;
1022
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001023 nReturn = GetNext_MapEntry(me, pDecodedItem, pTags);
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001024 if(nReturn) {
1025 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001026 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301027
1028 // Break ending arrays/maps are always processed at the end of this function.
1029 // They should never show up here.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301030 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade6de37062018-10-15 12:22:42 +05301031 nReturn = QCBOR_ERR_BAD_BREAK;
1032 goto Done;
Laurence Lundblade5b8c5852018-10-14 21:11:42 +05301033 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001034
Laurence Lundblade6de37062018-10-15 12:22:42 +05301035 // Record the nesting level for this data item before processing any of
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301036 // decrementing and descending.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301037 pDecodedItem->uNestingLevel = DecodeNesting_GetLevel(&(me->nesting));
1038
1039 // Process the item just received for descent or decrement, and
1040 // ascent if decrements are enough to close out a definite length array/map
Laurence Lundblade3a760b02018-10-08 13:46:03 +08001041 if(IsMapOrArray(pDecodedItem->uDataType)) {
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001042 // If the new item is array or map, the nesting level descends
Laurence Lundblade3a760b02018-10-08 13:46:03 +08001043 nReturn = DecodeNesting_Descend(&(me->nesting), pDecodedItem);
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001044 // Maps and arrays do count in as items in the map/array that encloses
1045 // them so a decrement needs to be done for them too, but that is done
1046 // only when all the items in them have been processed, not when they
1047 // are opened.
1048 } else {
1049 // Decrement the count of items in the enclosing map/array
1050 // If the count in the enclosing map/array goes to zero, that
Laurence Lundblade6de37062018-10-15 12:22:42 +05301051 // triggers a decrement in the map/array above that and
1052 // an ascend in nesting level.
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001053 DecodeNesting_DecrementCount(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001054 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05301055 if(nReturn) {
1056 goto Done;
1057 }
1058
1059 // For indefinite length maps/arrays, looking at any and
1060 // all breaks that might terminate them. The equivalent
1061 // for definite length maps/arrays happens in
1062 // DecodeNesting_DecrementCount().
1063 if(DecodeNesting_IsNested(&(me->nesting)) && DecodeNesting_IsIndefiniteLength(&(me->nesting))) {
1064 while(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) {
1065 // Peek forward one item to see if it is a break.
1066 QCBORItem Peek;
1067 size_t uPeek = UsefulInputBuf_Tell(&(me->InBuf));
1068 nReturn = GetNext_Item(&(me->InBuf), &Peek, NULL);
1069 if(nReturn) {
1070 goto Done;
1071 }
1072 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
1073 // It is not a break, rewind so it can be processed normally.
1074 UsefulInputBuf_Seek(&(me->InBuf), uPeek);
1075 break;
1076 }
1077 // It is a break. Ascend one nesting level.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301078 // The break is consumed.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301079 nReturn = DecodeNesting_BreakAscend(&(me->nesting));
1080 if(nReturn) {
1081 // break occured outside of an indefinite length array/map
1082 goto Done;
1083 }
1084 }
1085 }
1086
1087 // Tell the caller what level is next. This tells them what maps/arrays
1088 // were closed out and makes it possible for them to reconstruct
1089 // the tree with just the information returned by GetNext
1090 pDecodedItem->uNextNestLevel = DecodeNesting_GetLevel(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001091
1092Done:
1093 return nReturn;
1094}
1095
1096
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001097int QCBORDecode_GetNext(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
1098{
1099 return QCBORDecode_GetNextWithTags(me, pDecodedItem, NULL);
1100}
1101
1102
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001103/*
Laurence Lundblade6de37062018-10-15 12:22:42 +05301104 Decoding items is done in 5 layered functions, one calling the
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301105 next one down. If a layer has no work to do for a particular item
1106 it returns quickly.
1107
1108 - QCBORDecode_GetNext -- The top layer manages the beginnings and
1109 ends of maps and arrays. It tracks descending into and ascending
Laurence Lundblade6de37062018-10-15 12:22:42 +05301110 out of maps/arrays. It processes all breaks that terminate
1111 maps and arrays.
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301112
1113 - GetNext_MapEntry -- This handles the combining of two
1114 items, the label and the data, that make up a map entry.
1115 It only does work on maps. It combines the label and data
1116 items into one labeled item.
1117
1118 - GetNext_TaggedItem -- This handles the type 6 tagged items.
1119 It accumulates all the tags and combines them with the following
1120 non-tagged item. If the tagged item is something that is understood
1121 like a date, the decoding of that item is invoked.
1122
1123 - GetNext_FullItem -- This assembles the sub items that make up
1124 an indefinte length string into one string item. It uses the
Laurence Lundblade6de37062018-10-15 12:22:42 +05301125 string allocater to create contiguous space for the item. It
1126 processes all breaks that are part of indefinite length strings.
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301127
1128 - GetNext_Item -- This gets and decodes the most atomic
1129 item in CBOR, the thing with an initial byte containing
1130 the major type.
1131
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001132 Roughly this takes 300 bytes of stack for vars. Need to
1133 evaluate this more carefully and correctly.
1134
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301135 */
1136
1137
1138/*
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001139 Public function, see header qcbor.h file
1140 */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001141int QCBORDecode_IsTagged(QCBORDecodeContext *me, const QCBORItem *pItem, uint64_t uTag)
1142{
1143 const QCBORTagListIn *pCallerConfiguredTagMap = me->pCallerConfiguredTagList;
1144
1145 uint8_t uTagBitIndex;
1146 // Do not care about errors in pCallerConfiguredTagMap here. They are
1147 // caught during GetNext() before this is called.
1148 if(TagMapper_Lookup(pCallerConfiguredTagMap, uTag, &uTagBitIndex)) {
1149 return 0;
1150 }
1151
1152 const uint64_t uTagBit = 0x01ULL << uTagBitIndex;
1153 return (uTagBit & pItem->uTagBits) != 0;
1154}
1155
1156
1157/*
1158 Public function, see header qcbor.h file
1159 */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001160int QCBORDecode_Finish(QCBORDecodeContext *me)
1161{
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001162 int nReturn = QCBOR_SUCCESS;
1163
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001164 // Error out if all the maps/arrays are not closed out
1165 if(DecodeNesting_IsNested(&(me->nesting))) {
1166 nReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
1167 goto Done;
1168 }
1169
1170 // Error out if not all the bytes are consumed
1171 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) {
1172 nReturn = QCBOR_ERR_EXTRA_BYTES;
1173 }
1174
1175Done:
Laurence Lundblade6de37062018-10-15 12:22:42 +05301176 // Call the destructor for the string allocator if there is one.
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001177 // Always called, even if there are errors; always have to clean up
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001178 if(me->pStringAllocator) {
1179 QCBORStringAllocator *pAllocator = (QCBORStringAllocator *)me->pStringAllocator;
1180 if(pAllocator->fDestructor) {
1181 (pAllocator->fDestructor)(pAllocator->pAllocaterContext);
1182 }
1183 }
1184
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001185 return nReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001186}
1187
1188
1189
Laurence Lundblade7023b952018-10-02 01:54:24 -07001190/*
1191
1192 Use the 64-bit map. 48 8-bit tags built in, 1 16 bit tag, 15 64-bit tags can be assigned as of interest
1193
1194 There is a tag map.
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301195
Laurence Lundblade7023b952018-10-02 01:54:24 -07001196
1197 */
1198
1199
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001200/*
1201
1202Decoder errors handled in this file
1203
1204 - Hit end of input before it was expected while decoding type and number QCBOR_ERR_HIT_END
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001205
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001206 - negative integer that is too large for C QCBOR_ERR_INT_OVERFLOW
1207
1208 - Hit end of input while decoding a text or byte string QCBOR_ERR_HIT_END
1209
1210 - Encountered conflicting tags -- e.g., an item is tagged both a date string and an epoch date QCBOR_ERR_UNSUPPORTED
Laurence Lundblade5b8c5852018-10-14 21:11:42 +05301211
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001212 - Encontered an array or mapp that has too many items QCBOR_ERR_ARRAY_TOO_LONG
1213
1214 - Encountered array/map nesting that is too deep QCBOR_ERR_ARRAY_NESTING_TOO_DEEP
1215
1216 - An epoch date > INT64_MAX or < INT64_MIN was encountered QCBOR_ERR_DATE_OVERFLOW
1217
1218 - The type of a map label is not a string or int QCBOR_ERR_MAP_LABEL_TYPE
1219
1220 - Hit end with arrays or maps still open -- QCBOR_ERR_EXTRA_BYTES
1221
1222 */
1223
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001224
1225
1226typedef struct {
1227 QCBORStringAllocator StringAllocator;
1228 uint8_t *pStart;
1229 uint8_t *pEnd;
1230 uint8_t *pFree;
1231} MemPool;
1232
1233
1234/*
1235 Code Reviewers: THIS FUNCTION DOES POINTER MATH
1236 */
1237static UsefulBuf MemPool_Alloc(void *ctx, void *pMem, size_t uNewSize)
1238{
1239 MemPool *me = (MemPool *)ctx;
1240 void *pReturn = NULL;
1241
1242 if(pMem) {
1243 // Realloc case
1244 // TODO: review this pointer math
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001245 if((uint8_t *)pMem + uNewSize <= me->pEnd) {//} && (uint8_t *)pMem > me->pStart) {
1246 me->pFree = (uint8_t *)pMem + uNewSize;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001247 pReturn = pMem;
1248 }
1249 } else {
1250 // New chunk case
1251 if(me->pFree + uNewSize <= me->pEnd) {
1252 pReturn = me->pFree;
1253 me->pFree += uNewSize;
1254 }
1255 }
1256
1257 return (UsefulBuf){pReturn, uNewSize};
1258}
1259
1260
1261static void MemPool_Free(void *ctx, void *pOldMem)
1262{
1263 MemPool *me = (MemPool *)ctx;
1264 me->pFree = pOldMem;
1265}
1266
1267
Laurence Lundblade5b8c5852018-10-14 21:11:42 +05301268int QCBORDecode_SetMemPool(QCBORDecodeContext *me, UsefulBuf Pool, bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001269{
1270 if(Pool.len < sizeof(MemPool)+1) {
Laurence Lundblade5b8c5852018-10-14 21:11:42 +05301271 return 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001272 }
1273
1274 MemPool *pMP = (MemPool *)Pool.ptr;
1275
1276 pMP->StringAllocator.fAllocate = MemPool_Alloc;
1277 pMP->StringAllocator.fFree = MemPool_Free;
1278 pMP->StringAllocator.fDestructor = NULL;
1279
Laurence Lundblade570fab52018-10-13 18:28:27 +08001280 pMP->pStart = (uint8_t *)Pool.ptr + sizeof(MemPool);
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001281 pMP->pFree = pMP->pStart;
Laurence Lundblade570fab52018-10-13 18:28:27 +08001282 pMP->pEnd = (uint8_t *)Pool.ptr + Pool.len;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001283 pMP->StringAllocator.pAllocaterContext = pMP;
1284
1285 me->pStringAllocator = pMP;
1286 me->bStringAllocateAll = bAllStrings;
Laurence Lundblade5b8c5852018-10-14 21:11:42 +05301287
1288 return 0;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001289}
1290
1291
1292