blob: a51c597efb4ef27c66d66a5b504e1cc591a88ee3 [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 Lundblade59289e52019-12-30 13:44:37 -080045 12/30/19 llundblade Add support for decimal fractions and bigfloats.
Laurence Lundbladea1ad8782019-11-08 00:12:11 -080046 11/07/19 llundblade Fix long long conversion to double compiler warning
Laurence Lundblade9916b1b2019-09-07 22:33:25 -070047 09/07/19 llundblade Fix bug decoding empty arrays and maps
Laurence Lundbladebb1062e2019-08-12 23:28:54 -070048 07/31/19 llundblade Decode error fixes for some not-well-formed CBOR
49 07/31/19 llundblade New error code for better end of data handling
Laurence Lundblade1d7eb632019-02-17 17:23:38 -080050 02/17/19 llundblade Fixed: QCBORItem.u{Data|Label}Alloc when bAllStrings set
51 02/16/19 llundblade Redesign MemPool to fix memory access alignment bug
Laurence Lundblade4c0cf842019-01-12 03:25:44 -080052 01/10/19 llundblade Clever type and argument decoder is 250 bytes smaller
Laurence Lundblade8b06e2e2018-12-04 12:26:51 +090053 11/9/18 llundblade Error codes are now enums.
54 11/2/18 llundblade Simplify float decoding and align with preferred
55 float encoding
56 10/31/18 llundblade Switch to one license that is almost BSD-3.
57 10/28/18 llundblade Reworked tag decoding
58 10/15/18 llundblade Indefinite length maps and arrays supported
59 10/8/18 llundblade Indefinite length strings supported
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070060 02/04/17 llundbla Work on CPUs that don's require pointer alignment
61 by making use of changes in UsefulBuf
62 03/01/17 llundbla More data types; decoding improvements and fixes
63 11/13/16 llundbla Integrate most TZ changes back into github version.
64 09/30/16 gkanike Porting to TZ.
65 03/15/16 llundbla Initial Version.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080066
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070067 =====================================================================================*/
68
69#include "qcbor.h"
Laurence Lundblade12d32c52018-09-19 11:25:27 -070070#include "ieee754.h"
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070071
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070072
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +053073/*
74 This casts away the const-ness of a pointer, usually so it can be
75 freed or realloced.
76 */
77#define UNCONST_POINTER(ptr) ((void *)(ptr))
78
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070079
80/*
Laurence Lundblade3a760b02018-10-08 13:46:03 +080081 Collection of functions to track the map/array nesting for decoding
Laurence Lundbladeb69cad72018-09-13 11:09:01 -070082 */
83
84inline static int IsMapOrArray(uint8_t uDataType)
85{
86 return uDataType == QCBOR_TYPE_MAP || uDataType == QCBOR_TYPE_ARRAY;
87}
88
89inline static int DecodeNesting_IsNested(const QCBORDecodeNesting *pNesting)
90{
91 return pNesting->pCurrent != &(pNesting->pMapsAndArrays[0]);
92}
93
Laurence Lundblade041ffa52018-10-07 11:43:51 +070094inline static int DecodeNesting_IsIndefiniteLength(const QCBORDecodeNesting *pNesting)
Laurence Lundblade0f99d692018-09-26 14:39:28 -070095{
Laurence Lundblade0f99d692018-09-26 14:39:28 -070096 return pNesting->pCurrent->uCount == UINT16_MAX;
97}
98
Laurence Lundblade3a760b02018-10-08 13:46:03 +080099inline static uint8_t DecodeNesting_GetLevel(QCBORDecodeNesting *pNesting)
100{
101 return pNesting->pCurrent - &(pNesting->pMapsAndArrays[0]);
102}
103
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700104inline static int DecodeNesting_TypeIsMap(const QCBORDecodeNesting *pNesting)
105{
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700106 if(!DecodeNesting_IsNested(pNesting)) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700107 return 0;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700108 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800109
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700110 return CBOR_MAJOR_TYPE_MAP == pNesting->pCurrent->uMajorType;
111}
112
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800113// Process a break. This will either ascend the nesting or error out
Laurence Lundblade30816f22018-11-10 13:40:22 +0700114inline static QCBORError DecodeNesting_BreakAscend(QCBORDecodeNesting *pNesting)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700115{
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800116 // breaks must always occur when there is nesting
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700117 if(!DecodeNesting_IsNested(pNesting)) {
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800118 return QCBOR_ERR_BAD_BREAK;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700119 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800120
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800121 // breaks can only occur when the map/array is indefinite length
122 if(!DecodeNesting_IsIndefiniteLength(pNesting)) {
123 return QCBOR_ERR_BAD_BREAK;
124 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800125
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800126 // if all OK, the break reduces the level of nesting
127 pNesting->pCurrent--;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800128
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800129 return QCBOR_SUCCESS;
130}
131
132// Called on every single item except breaks including the opening of a map/array
133inline static void DecodeNesting_DecrementCount(QCBORDecodeNesting *pNesting)
134{
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700135 while(DecodeNesting_IsNested(pNesting)) {
136 // Not at the top level, so there is decrementing to be done.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800137
Laurence Lundblade9e3651c2018-10-10 11:49:55 +0800138 if(!DecodeNesting_IsIndefiniteLength(pNesting)) {
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700139 // Decrement the current nesting level if it is not indefinite.
Laurence Lundblade9e3651c2018-10-10 11:49:55 +0800140 pNesting->pCurrent->uCount--;
141 }
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700142
143 if(pNesting->pCurrent->uCount != 0) {
144 // Did not close out an array or map, so nothing further
145 break;
146 }
147
148 // Closed out an array or map so level up
149 pNesting->pCurrent--;
150
151 // Continue with loop to see if closing out this doesn't close out more
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700152 }
153}
154
Laurence Lundblade9916b1b2019-09-07 22:33:25 -0700155
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800156// Called on every map/array
Laurence Lundblade30816f22018-11-10 13:40:22 +0700157inline static QCBORError DecodeNesting_Descend(QCBORDecodeNesting *pNesting, QCBORItem *pItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700158{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700159 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800160
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800161 if(pItem->val.uCount == 0) {
162 // Nothing to do for empty definite lenth arrays. They are just are
163 // effectively the same as an item that is not a map or array
164 goto Done;
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530165 // Empty indefinite length maps and arrays are handled elsewhere
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800166 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800167
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800168 // Error out if arrays is too long to handle
169 if(pItem->val.uCount != UINT16_MAX && pItem->val.uCount > QCBOR_MAX_ITEMS_IN_ARRAY) {
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700170 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
171 goto Done;
172 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800173
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800174 // Error out if nesting is too deep
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700175 if(pNesting->pCurrent >= &(pNesting->pMapsAndArrays[QCBOR_MAX_ARRAY_NESTING])) {
176 nReturn = QCBOR_ERR_ARRAY_NESTING_TOO_DEEP;
177 goto Done;
178 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800179
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800180 // The actual descend
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700181 pNesting->pCurrent++;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800182
Laurence Lundblade3a760b02018-10-08 13:46:03 +0800183 // Record a few details for this nesting level
184 pNesting->pCurrent->uMajorType = pItem->uDataType;
185 pNesting->pCurrent->uCount = pItem->val.uCount;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800186
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700187Done:
188 return nReturn;;
189}
190
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700191inline static void DecodeNesting_Init(QCBORDecodeNesting *pNesting)
192{
193 pNesting->pCurrent = &(pNesting->pMapsAndArrays[0]);
194}
195
196
197
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700198/*
199 This list of built-in tags. Only add tags here that are
200 clearly established and useful. Once a tag is added here
201 it can't be taken out as that would break backwards compatibility.
202 There are only 48 slots available forever.
203 */
204static const uint16_t spBuiltInTagMap[] = {
Laurence Lundblade59289e52019-12-30 13:44:37 -0800205 CBOR_TAG_DATE_STRING, // See TAG_MAPPER_FIRST_SIX
206 CBOR_TAG_DATE_EPOCH, // See TAG_MAPPER_FIRST_SIX
207 CBOR_TAG_POS_BIGNUM, // See TAG_MAPPER_FIRST_SIX
208 CBOR_TAG_NEG_BIGNUM, // See TAG_MAPPER_FIRST_SIX
209 CBOR_TAG_DECIMAL_FRACTION, // See TAG_MAPPER_FIRST_SIX
210 CBOR_TAG_BIGFLOAT, // See TAG_MAPPER_FIRST_SIX
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700211 CBOR_TAG_COSE_ENCRYPTO,
212 CBOR_TAG_COSE_MAC0,
213 CBOR_TAG_COSE_SIGN1,
214 CBOR_TAG_ENC_AS_B64URL,
215 CBOR_TAG_ENC_AS_B64,
216 CBOR_TAG_ENC_AS_B16,
217 CBOR_TAG_CBOR,
218 CBOR_TAG_URI,
219 CBOR_TAG_B64URL,
220 CBOR_TAG_B64,
221 CBOR_TAG_REGEX,
222 CBOR_TAG_MIME,
223 CBOR_TAG_BIN_UUID,
224 CBOR_TAG_CWT,
225 CBOR_TAG_ENCRYPT,
226 CBOR_TAG_MAC,
227 CBOR_TAG_SIGN,
228 CBOR_TAG_GEO_COORD,
229 CBOR_TAG_CBOR_MAGIC
230};
231
232// This is used in a bit of cleverness in GetNext_TaggedItem() to
233// keep code size down and switch for the internal processing of
Laurence Lundblade59289e52019-12-30 13:44:37 -0800234// these types. This will break if the first six items in
235// spBuiltInTagMap don't have values 0,1,2,3,4,5. That is the
236// mapping is 0 to 0, 1 to 1, 2 to 2 and 3 to 3....
237#define QCBOR_TAGFLAG_DATE_STRING (0x01LL << CBOR_TAG_DATE_STRING)
238#define QCBOR_TAGFLAG_DATE_EPOCH (0x01LL << CBOR_TAG_DATE_EPOCH)
239#define QCBOR_TAGFLAG_POS_BIGNUM (0x01LL << CBOR_TAG_POS_BIGNUM)
240#define QCBOR_TAGFLAG_NEG_BIGNUM (0x01LL << CBOR_TAG_NEG_BIGNUM)
241#define QCBOR_TAGFLAG_DECIMAL_FRACTION (0x01LL << CBOR_TAG_DECIMAL_FRACTION)
242#define QCBOR_TAGFLAG_BIGFLOAT (0x01LL << CBOR_TAG_BIGFLOAT)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700243
Laurence Lundblade59289e52019-12-30 13:44:37 -0800244#define TAG_MAPPER_FIRST_SIX (QCBOR_TAGFLAG_DATE_STRING |\
245 QCBOR_TAGFLAG_DATE_EPOCH |\
246 QCBOR_TAGFLAG_POS_BIGNUM |\
247 QCBOR_TAGFLAG_NEG_BIGNUM |\
248 QCBOR_TAGFLAG_DECIMAL_FRACTION |\
249 QCBOR_TAGFLAG_BIGFLOAT)
250
251#define TAG_MAPPER_FIRST_FOUR (QCBOR_TAGFLAG_DATE_STRING |\
252 QCBOR_TAGFLAG_DATE_EPOCH |\
253 QCBOR_TAGFLAG_POS_BIGNUM |\
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700254 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 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800269
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700270 if(uTag > UINT16_MAX) {
271 // This tag map works only on 16-bit tags
272 return -1;
273 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800274
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700275 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 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800290
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700291 return -1; // Indicates no match
292}
293
294/*
295 Find the tag bit index for a given tag value, or error out
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800296
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700297 This and the above functions could probably be optimized and made
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800298 clearer and neater.
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700299 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700300static QCBORError TagMapper_Lookup(const QCBORTagListIn *pCallerConfiguredTagMap, uint64_t uTag, uint8_t *puTagBitIndex)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700301{
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 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800308
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700309 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 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800321
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700322 return QCBOR_ERR_BAD_OPT_TAG;
323}
324
325
326
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800327/* ===========================================================================
328 QCBORStringAllocate -- STRING ALLOCATOR INVOCATION
329
330 The following four functions are pretty wrappers for invocation of
331 the string allocator supplied by the caller.
332
333 ==============================================================================*/
334
335static inline void StringAllocator_Free(const QCORInternalAllocator *pMe, void *pMem)
336{
337 (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, 0);
338}
339
340// StringAllocator_Reallocate called with pMem NULL is equal to StringAllocator_Allocate()
341static inline UsefulBuf StringAllocator_Reallocate(const QCORInternalAllocator *pMe, void *pMem, size_t uSize)
342{
343 return (pMe->pfAllocator)(pMe->pAllocateCxt, pMem, uSize);
344}
345
346static inline UsefulBuf StringAllocator_Allocate(const QCORInternalAllocator *pMe, size_t uSize)
347{
348 return (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, uSize);
349}
350
351static inline void StringAllocator_Destruct(const QCORInternalAllocator *pMe)
352{
353 if(pMe->pfAllocator) {
354 (pMe->pfAllocator)(pMe->pAllocateCxt, NULL, 0);
355 }
356}
357
358
359
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700360
361/*
362 Public function, see header file
363 */
Laurence Lundbladed61cbf32018-12-09 11:42:21 -0800364void QCBORDecode_Init(QCBORDecodeContext *me, UsefulBufC EncodedCBOR, QCBORDecodeMode nDecodeMode)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700365{
366 memset(me, 0, sizeof(QCBORDecodeContext));
367 UsefulInputBuf_Init(&(me->InBuf), EncodedCBOR);
368 // Don't bother with error check on decode mode. If a bad value is passed it will just act as
369 // if the default normal mode of 0 was set.
370 me->uDecodeMode = nDecodeMode;
371 DecodeNesting_Init(&(me->nesting));
372}
373
374
375/*
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700376 Public function, see header file
377 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800378void QCBORDecode_SetUpAllocator(QCBORDecodeContext *pMe,
379 QCBORStringAllocate pfAllocateFunction,
380 void *pAllocateContext,
381 bool bAllStrings)
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700382{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800383 pMe->StringAllocator.pfAllocator = pfAllocateFunction;
384 pMe->StringAllocator.pAllocateCxt = pAllocateContext;
385 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700386}
387
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800388
389/*
390 Public function, see header file
391 */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700392void QCBORDecode_SetCallerConfiguredTagList(QCBORDecodeContext *me, const QCBORTagListIn *pTagList)
393{
394 me->pCallerConfiguredTagList = pTagList;
395}
396
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700397
398/*
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700399 This decodes the fundamental part of a CBOR data item, the type and number
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800400
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700401 This is the Counterpart to InsertEncodedTypeAndNumber().
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800402
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700403 This does the network->host byte order conversion. The conversion here
404 also results in the conversion for floats in addition to that for
405 lengths, tags and integer values.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800406
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700407 This returns:
408 pnMajorType -- the major type for the item
409 puNumber -- the "number" which is used a the value for integers, tags and floats and length for strings and arrays
410 puAdditionalInfo -- Pass this along to know what kind of float or if length is indefinite
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800411
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700412 */
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800413inline static QCBORError DecodeTypeAndNumber(UsefulInputBuf *pUInBuf,
414 int *pnMajorType,
415 uint64_t *puArgument,
416 uint8_t *puAdditionalInfo)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700417{
Laurence Lundblade30816f22018-11-10 13:40:22 +0700418 QCBORError nReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800419
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700420 // Get the initial byte that every CBOR data item has
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800421 const uint8_t uInitialByte = UsefulInputBuf_GetByte(pUInBuf);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800422
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700423 // Break down the initial byte
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800424 const uint8_t uTmpMajorType = uInitialByte >> 5;
425 const uint8_t uAdditionalInfo = uInitialByte & 0x1f;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800426
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800427 // Where the number or argument accumulates
428 uint64_t uArgument;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800429
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800430 if(uAdditionalInfo >= LEN_IS_ONE_BYTE && uAdditionalInfo <= LEN_IS_EIGHT_BYTES) {
431 // Need to get 1,2,4 or 8 additional argument bytes
432 // Map LEN_IS_ONE_BYTE.. LEN_IS_EIGHT_BYTES to actual length
433 static const uint8_t aIterate[] = {1,2,4,8};
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800434
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800435 // Loop getting all the bytes in the argument
436 uArgument = 0;
437 for(int i = aIterate[uAdditionalInfo - LEN_IS_ONE_BYTE]; i; i--) {
438 // This shift and add gives the endian conversion
439 uArgument = (uArgument << 8) + UsefulInputBuf_GetByte(pUInBuf);
440 }
441 } else if(uAdditionalInfo >= ADDINFO_RESERVED1 && uAdditionalInfo <= ADDINFO_RESERVED3) {
442 // The reserved and thus-far unused additional info values
443 nReturn = QCBOR_ERR_UNSUPPORTED;
444 goto Done;
445 } else {
446 // Less than 24, additional info is argument or 31, an indefinite length
447 // No more bytes to get
448 uArgument = uAdditionalInfo;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700449 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800450
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700451 if(UsefulInputBuf_GetError(pUInBuf)) {
452 nReturn = QCBOR_ERR_HIT_END;
453 goto Done;
454 }
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800455
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700456 // All successful if we got here.
457 nReturn = QCBOR_SUCCESS;
458 *pnMajorType = uTmpMajorType;
Laurence Lundblade4c0cf842019-01-12 03:25:44 -0800459 *puArgument = uArgument;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700460 *puAdditionalInfo = uAdditionalInfo;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800461
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700462Done:
463 return nReturn;
464}
465
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700466/*
467 CBOR doesn't explicitly specify two's compliment for integers but all CPUs
468 use it these days and the test vectors in the RFC are so. All integers in the CBOR
469 structure are positive and the major type indicates positive or negative.
470 CBOR can express positive integers up to 2^x - 1 where x is the number of bits
471 and negative integers down to 2^x. Note that negative numbers can be one
472 more away from zero than positive.
473 Stdint, as far as I can tell, uses two's compliment to represent
474 negative integers.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800475
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700476 See http://www.unix.org/whitepapers/64bit.html for reasons int isn't
477 used here in any way including in the interface
478 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700479inline static QCBORError DecodeInteger(int nMajorType, uint64_t uNumber, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700480{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700481 // Stack usage: int/ptr 1 -- 8
Laurence Lundblade30816f22018-11-10 13:40:22 +0700482 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800483
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700484 if(nMajorType == CBOR_MAJOR_TYPE_POSITIVE_INT) {
485 if (uNumber <= INT64_MAX) {
486 pDecodedItem->val.int64 = (int64_t)uNumber;
487 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800488
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700489 } else {
490 pDecodedItem->val.uint64 = uNumber;
491 pDecodedItem->uDataType = QCBOR_TYPE_UINT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800492
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700493 }
494 } else {
495 if(uNumber <= INT64_MAX) {
496 pDecodedItem->val.int64 = -uNumber-1;
497 pDecodedItem->uDataType = QCBOR_TYPE_INT64;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800498
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700499 } else {
500 // C can't represent a negative integer in this range
Laurence Lundblade21d1d812019-09-28 22:47:49 -1000501 // so it is an error.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700502 nReturn = QCBOR_ERR_INT_OVERFLOW;
503 }
504 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800505
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700506 return nReturn;
507}
508
509// Make sure #define value line up as DecodeSimple counts on this.
510#if QCBOR_TYPE_FALSE != CBOR_SIMPLEV_FALSE
511#error QCBOR_TYPE_FALSE macro value wrong
512#endif
513
514#if QCBOR_TYPE_TRUE != CBOR_SIMPLEV_TRUE
515#error QCBOR_TYPE_TRUE macro value wrong
516#endif
517
518#if QCBOR_TYPE_NULL != CBOR_SIMPLEV_NULL
519#error QCBOR_TYPE_NULL macro value wrong
520#endif
521
522#if QCBOR_TYPE_UNDEF != CBOR_SIMPLEV_UNDEF
523#error QCBOR_TYPE_UNDEF macro value wrong
524#endif
525
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700526#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
527#error QCBOR_TYPE_BREAK macro value wrong
528#endif
529
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700530#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
531#error QCBOR_TYPE_DOUBLE macro value wrong
532#endif
533
534#if QCBOR_TYPE_FLOAT != SINGLE_PREC_FLOAT
535#error QCBOR_TYPE_FLOAT macro value wrong
536#endif
537
538/*
539 Decode true, false, floats, break...
540 */
541
Laurence Lundblade30816f22018-11-10 13:40:22 +0700542inline static QCBORError DecodeSimple(uint8_t uAdditionalInfo, uint64_t uNumber, QCBORItem *pDecodedItem)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700543{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700544 // Stack usage: 0
Laurence Lundblade30816f22018-11-10 13:40:22 +0700545 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800546
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700547 // uAdditionalInfo is 5 bits from the initial byte
548 // compile time checks above make sure uAdditionalInfo values line up with uDataType values
549 pDecodedItem->uDataType = uAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800550
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700551 switch(uAdditionalInfo) {
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700552 // No check for ADDINFO_RESERVED1 - ADDINFO_RESERVED3 as it is caught before this is called.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800553
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700554 case HALF_PREC_FLOAT:
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700555 pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uNumber);
556 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700557 break;
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700558 case SINGLE_PREC_FLOAT:
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700559 pDecodedItem->val.dfnum = (double)UsefulBufUtil_CopyUint32ToFloat((uint32_t)uNumber);
560 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700561 break;
562 case DOUBLE_PREC_FLOAT:
563 pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uNumber);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700564 pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700565 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800566
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700567 case CBOR_SIMPLEV_FALSE: // 20
568 case CBOR_SIMPLEV_TRUE: // 21
569 case CBOR_SIMPLEV_NULL: // 22
570 case CBOR_SIMPLEV_UNDEF: // 23
Laurence Lundblade0f99d692018-09-26 14:39:28 -0700571 case CBOR_SIMPLE_BREAK: // 31
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700572 break; // nothing to do
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800573
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700574 case CBOR_SIMPLEV_ONEBYTE: // 24
575 if(uNumber <= CBOR_SIMPLE_BREAK) {
576 // This takes out f8 00 ... f8 1f which should be encoded as e0 … f7
Laurence Lundblade077475f2019-04-26 09:06:33 -0700577 nReturn = QCBOR_ERR_BAD_TYPE_7;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700578 goto Done;
579 }
Laurence Lundblade5e390822019-01-06 12:35:01 -0800580 /* FALLTHROUGH */
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700581 // fall through intentionally
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800582
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700583 default: // 0-19
584 pDecodedItem->uDataType = QCBOR_TYPE_UKNOWN_SIMPLE;
585 // DecodeTypeAndNumber will make uNumber equal to uAdditionalInfo when uAdditionalInfo is < 24
586 // This cast is safe because the 2, 4 and 8 byte lengths of uNumber are in the double/float cases above
587 pDecodedItem->val.uSimple = (uint8_t)uNumber;
588 break;
589 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800590
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700591Done:
592 return nReturn;
593}
594
595
596
597/*
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530598 Decode text and byte strings. Call the string allocator if asked to.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700599 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800600inline static QCBORError DecodeBytes(const QCORInternalAllocator *pAllocator,
601 int nMajorType,
602 uint64_t uStrLen,
603 UsefulInputBuf *pUInBuf,
604 QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700605{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700606 // Stack usage: UsefulBuf 2, int/ptr 1 40
Laurence Lundblade30816f22018-11-10 13:40:22 +0700607 QCBORError nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800608
Laurence Lundblade25c6c0a2018-12-17 13:21:59 -0800609 const UsefulBufC Bytes = UsefulInputBuf_GetUsefulBuf(pUInBuf, uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530610 if(UsefulBuf_IsNULLC(Bytes)) {
611 // Failed to get the bytes for this string item
612 nReturn = QCBOR_ERR_HIT_END;
613 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700614 }
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530615
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800616 if(pAllocator) {
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530617 // We are asked to use string allocator to make a copy
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800618 UsefulBuf NewMem = StringAllocator_Allocate(pAllocator, uStrLen);
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530619 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade30816f22018-11-10 13:40:22 +0700620 nReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530621 goto Done;
622 }
623 pDecodedItem->val.string = UsefulBuf_Copy(NewMem, Bytes);
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800624 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530625 } else {
626 // Normal case with no string allocator
627 pDecodedItem->val.string = Bytes;
628 }
629 pDecodedItem->uDataType = (nMajorType == CBOR_MAJOR_TYPE_BYTE_STRING) ? QCBOR_TYPE_BYTE_STRING : QCBOR_TYPE_TEXT_STRING;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800630
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530631Done:
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700632 return nReturn;
633}
634
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700635
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800636
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700637
638
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700639
640
641// Make sure the constants align as this is assumed by the GetAnItem() implementation
642#if QCBOR_TYPE_ARRAY != CBOR_MAJOR_TYPE_ARRAY
643#error QCBOR_TYPE_ARRAY value not lined up with major type
644#endif
645#if QCBOR_TYPE_MAP != CBOR_MAJOR_TYPE_MAP
646#error QCBOR_TYPE_MAP value not lined up with major type
647#endif
648
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700649/*
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700650 This gets a single data item and decodes it including preceding optional tagging. This does not
651 deal with arrays and maps and nesting except to decode the data item introducing them. Arrays and
652 maps are handled at the next level up in GetNext().
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800653
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700654 Errors detected here include: an array that is too long to decode, hit end of buffer unexpectedly,
655 a few forms of invalid encoded CBOR
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700656 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800657static QCBORError GetNext_Item(UsefulInputBuf *pUInBuf,
658 QCBORItem *pDecodedItem,
659 const QCORInternalAllocator *pAllocator)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700660{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700661 // Stack usage: int/ptr 3 -- 24
Laurence Lundblade30816f22018-11-10 13:40:22 +0700662 QCBORError nReturn;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800663
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700664 // Get the major type and the number. Number could be length of more bytes or the value depending on the major type
665 // nAdditionalInfo is an encoding of the length of the uNumber and is needed to decode floats and doubles
666 int uMajorType;
667 uint64_t uNumber;
668 uint8_t uAdditionalInfo;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800669
Laurence Lundblade4b09f632019-10-09 14:34:59 -0700670 memset(pDecodedItem, 0, sizeof(QCBORItem));
671
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700672 nReturn = DecodeTypeAndNumber(pUInBuf, &uMajorType, &uNumber, &uAdditionalInfo);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800673
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700674 // Error out here if we got into trouble on the type and number.
675 // The code after this will not work if the type and number is not good.
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700676 if(nReturn) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700677 goto Done;
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700678 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800679
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700680 // At this point the major type and the value are valid. We've got the type and the number that
681 // starts every CBOR data item.
682 switch (uMajorType) {
683 case CBOR_MAJOR_TYPE_POSITIVE_INT: // Major type 0
684 case CBOR_MAJOR_TYPE_NEGATIVE_INT: // Major type 1
Laurence Lundblade3a6042e2019-06-28 19:58:04 -0700685 if(uAdditionalInfo == LEN_IS_INDEFINITE) {
686 nReturn = QCBOR_ERR_BAD_INT;
687 } else {
688 nReturn = DecodeInteger(uMajorType, uNumber, pDecodedItem);
689 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700690 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800691
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700692 case CBOR_MAJOR_TYPE_BYTE_STRING: // Major type 2
693 case CBOR_MAJOR_TYPE_TEXT_STRING: // Major type 3
694 if(uAdditionalInfo == LEN_IS_INDEFINITE) {
695 pDecodedItem->uDataType = (uMajorType == CBOR_MAJOR_TYPE_BYTE_STRING) ? QCBOR_TYPE_BYTE_STRING : QCBOR_TYPE_TEXT_STRING;
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530696 pDecodedItem->val.string = (UsefulBufC){NULL, SIZE_MAX};
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700697 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800698 nReturn = DecodeBytes(pAllocator, uMajorType, uNumber, pUInBuf, pDecodedItem);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700699 }
700 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800701
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700702 case CBOR_MAJOR_TYPE_ARRAY: // Major type 4
703 case CBOR_MAJOR_TYPE_MAP: // Major type 5
704 // Record the number of items in the array or map
705 if(uNumber > QCBOR_MAX_ITEMS_IN_ARRAY) {
706 nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
707 goto Done;
708 }
709 if(uAdditionalInfo == LEN_IS_INDEFINITE) {
Laurence Lundbladea44d5062018-10-17 18:45:12 +0530710 pDecodedItem->val.uCount = UINT16_MAX; // Indicate indefinite length
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700711 } else {
712 pDecodedItem->val.uCount = (uint16_t)uNumber; // type conversion OK because of check above
713 }
714 pDecodedItem->uDataType = uMajorType; // C preproc #if above makes sure constants align
715 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800716
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700717 case CBOR_MAJOR_TYPE_OPTIONAL: // Major type 6, optional prepended tags
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700718 if(uAdditionalInfo == LEN_IS_INDEFINITE) {
719 nReturn = QCBOR_ERR_BAD_INT;
720 } else {
721 pDecodedItem->val.uTagV = uNumber;
722 pDecodedItem->uDataType = QCBOR_TYPE_OPTTAG;
723 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700724 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800725
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700726 case CBOR_MAJOR_TYPE_SIMPLE: // Major type 7, float, double, true, false, null...
727 nReturn = DecodeSimple(uAdditionalInfo, uNumber, pDecodedItem);
728 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800729
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700730 default: // Should never happen because DecodeTypeAndNumber() should never return > 7
731 nReturn = QCBOR_ERR_UNSUPPORTED;
732 break;
733 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800734
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700735Done:
736 return nReturn;
737}
738
739
740
741/*
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800742 This layer deals with indefinite length strings. It pulls all the
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700743 individual chunk items together into one QCBORItem using the
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530744 string allocator.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800745
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530746 Code Reviewers: THIS FUNCTION DOES A LITTLE POINTER MATH
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700747 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700748static inline QCBORError GetNext_FullItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700749{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700750 // Stack usage; int/ptr 2 UsefulBuf 2 QCBORItem -- 96
Laurence Lundblade30816f22018-11-10 13:40:22 +0700751 QCBORError nReturn;
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800752 const QCORInternalAllocator *pAllocator = me->StringAllocator.pfAllocator ?
753 &(me->StringAllocator) :
754 NULL;
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530755 UsefulBufC FullString = NULLUsefulBufC;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800756
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800757 nReturn = GetNext_Item(&(me->InBuf),
758 pDecodedItem,
759 me->bStringAllocateAll ? pAllocator: NULL);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700760 if(nReturn) {
761 goto Done;
762 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800763
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700764 // To reduce code size by removing support for indefinite length strings, the
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530765 // code in this function from here down can be eliminated. Run tests, except
766 // indefinite length string tests, to be sure all is OK if this is removed.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800767
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800768 // Only do indefinite length processing on strings
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700769 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING && pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
770 goto Done; // no need to do any work here on non-string types
771 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800772
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800773 // Is this a string with an indefinite length?
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530774 if(pDecodedItem->val.string.len != SIZE_MAX) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800775 goto Done; // length is not indefinite, so no work to do here
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700776 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800777
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530778 // Can't do indefinite length strings without a string allocator
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800779 if(pAllocator == NULL) {
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700780 nReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
781 goto Done;
782 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800783
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700784 // There is an indefinite length string to work on...
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800785 // Track which type of string it is
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700786 const uint8_t uStringType = pDecodedItem->uDataType;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800787
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700788 // Loop getting chunk of indefinite string
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700789 for(;;) {
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700790 // Get item for next chunk
791 QCBORItem StringChunkItem;
792 // NULL passed to never string alloc chunk of indefinite length strings
Laurence Lundbladefae26bf2019-02-18 11:15:43 -0800793 nReturn = GetNext_Item(&(me->InBuf), &StringChunkItem, NULL);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700794 if(nReturn) {
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700795 break; // Error getting the next chunk
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700796 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800797
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530798 // See if it is a marker at end of indefinite length string
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700799 if(StringChunkItem.uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800800 // String is complete
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700801 pDecodedItem->val.string = FullString;
Laurence Lundblade57dd1442018-10-15 20:26:28 +0530802 pDecodedItem->uDataAlloc = 1;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700803 break;
804 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800805
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700806 // Match data type of chunk to type at beginning.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530807 // Also catches error of other non-string types that don't belong.
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700808 // Also catches indefinite length strings inside indefinite length strings
809 if(StringChunkItem.uDataType != uStringType || StringChunkItem.val.string.len == SIZE_MAX) {
Laurence Lundblade30816f22018-11-10 13:40:22 +0700810 nReturn = QCBOR_ERR_INDEFINITE_STRING_CHUNK;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700811 break;
812 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800813
Laurence Lundblade471a3fd2018-10-18 21:27:45 +0530814 // Alloc new buffer or expand previously allocated buffer so it can fit
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800815 // The first time throurgh FullString.ptr is NULL and this is
816 // equivalent to StringAllocator_Allocate()
817 UsefulBuf NewMem = StringAllocator_Reallocate(pAllocator,
818 UNCONST_POINTER(FullString.ptr),
819 FullString.len + StringChunkItem.val.string.len);
820
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700821 if(UsefulBuf_IsNULL(NewMem)) {
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530822 // Allocation of memory for the string failed
Laurence Lundblade30816f22018-11-10 13:40:22 +0700823 nReturn = QCBOR_ERR_STRING_ALLOCATE;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700824 break;
825 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800826
Laurence Lundblade2a6850e2018-10-28 20:13:44 +0700827 // Copy new string chunk at the end of string so far.
828 FullString = UsefulBuf_CopyOffset(NewMem, FullString.len, StringChunkItem.val.string);
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700829 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800830
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700831Done:
Laurence Lundblade1d7eb632019-02-17 17:23:38 -0800832 if(nReturn != QCBOR_SUCCESS && !UsefulBuf_IsNULLC(FullString)) {
833 // Getting the item failed, clean up the allocated memory
834 StringAllocator_Free(pAllocator, UNCONST_POINTER(FullString.ptr));
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700835 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800836
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700837 return nReturn;
838}
839
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700840
841/*
Laurence Lundblade59289e52019-12-30 13:44:37 -0800842 Gets all optional tag data items preceding a data item that is not an
843 optional tag and records them as bits in the tag map.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700844 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700845static QCBORError GetNext_TaggedItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem, QCBORTagListOut *pTags)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700846{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700847 // Stack usage: int/ptr: 3 -- 24
Laurence Lundblade30816f22018-11-10 13:40:22 +0700848 QCBORError nReturn;
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700849 uint64_t uTagBits = 0;
850 if(pTags) {
851 pTags->uNumUsed = 0;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700852 }
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700853
Laurence Lundblade59289e52019-12-30 13:44:37 -0800854 // Loop fetching items until the item fetched is not a tag
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700855 for(;;) {
856 nReturn = GetNext_FullItem(me, pDecodedItem);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700857 if(nReturn) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700858 goto Done; // Error out of the loop
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700859 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800860
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700861 if(pDecodedItem->uDataType != QCBOR_TYPE_OPTTAG) {
862 // Successful exit from loop; maybe got some tags, maybe not
863 pDecodedItem->uTagBits = uTagBits;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700864 break;
865 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800866
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700867 uint8_t uTagBitIndex;
868 // Tag was mapped, tag was not mapped, error with tag list
869 switch(TagMapper_Lookup(me->pCallerConfiguredTagList, pDecodedItem->val.uTagV, &uTagBitIndex)) {
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800870
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700871 case QCBOR_SUCCESS:
872 // Successfully mapped the tag
873 uTagBits |= 0x01ULL << uTagBitIndex;
874 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800875
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700876 case QCBOR_ERR_BAD_OPT_TAG:
877 // Tag is not recognized. Do nothing
878 break;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800879
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700880 default:
881 // Error Condition
882 goto Done;
883 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800884
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700885 if(pTags) {
886 // Caller wants all tags recorded in the provided buffer
887 if(pTags->uNumUsed >= pTags->uNumAllocated) {
888 nReturn = QCBOR_ERR_TOO_MANY_TAGS;
889 goto Done;
890 }
891 pTags->puTags[pTags->uNumUsed] = pDecodedItem->val.uTagV;
892 pTags->uNumUsed++;
893 }
894 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800895
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700896Done:
897 return nReturn;
898}
899
900
901/*
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800902 This layer takes care of map entries. It combines the label and data items into one QCBORItem.
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700903 */
Laurence Lundblade30816f22018-11-10 13:40:22 +0700904static inline QCBORError GetNext_MapEntry(QCBORDecodeContext *me, QCBORItem *pDecodedItem, QCBORTagListOut *pTags)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700905{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700906 // Stack use: int/ptr 1, QCBORItem -- 56
Laurence Lundblade30816f22018-11-10 13:40:22 +0700907 QCBORError nReturn = GetNext_TaggedItem(me, pDecodedItem, pTags);
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700908 if(nReturn)
909 goto Done;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800910
Laurence Lundblade742df4a2018-10-13 20:07:17 +0800911 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700912 // Break can't be a map entry
Laurence Lundblade742df4a2018-10-13 20:07:17 +0800913 goto Done;
914 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800915
Laurence Lundbladed61cbf32018-12-09 11:42:21 -0800916 if(me->uDecodeMode != QCBOR_DECODE_MODE_MAP_AS_ARRAY) {
917 // In a map and caller wants maps decoded, not treated as arrays
918
919 if(DecodeNesting_TypeIsMap(&(me->nesting))) {
920 // If in a map and the right decoding mode, get the label
921
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +0900922 // Get the next item which will be the real data; Item will be the label
923 QCBORItem LabelItem = *pDecodedItem;
924 nReturn = GetNext_TaggedItem(me, pDecodedItem, pTags);
925 if(nReturn)
926 goto Done;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800927
Laurence Lundblade57dd1442018-10-15 20:26:28 +0530928 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
Laurence Lundbladeccfb8cd2018-12-07 21:11:30 +0900929
930 if(LabelItem.uDataType == QCBOR_TYPE_TEXT_STRING) {
931 // strings are always good labels
932 pDecodedItem->label.string = LabelItem.val.string;
933 pDecodedItem->uLabelType = QCBOR_TYPE_TEXT_STRING;
934 } else if (QCBOR_DECODE_MODE_MAP_STRINGS_ONLY == me->uDecodeMode) {
935 // It's not a string and we only want strings, probably for easy translation to JSON
936 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
937 goto Done;
938 } else if(LabelItem.uDataType == QCBOR_TYPE_INT64) {
939 pDecodedItem->label.int64 = LabelItem.val.int64;
940 pDecodedItem->uLabelType = QCBOR_TYPE_INT64;
941 } else if(LabelItem.uDataType == QCBOR_TYPE_UINT64) {
942 pDecodedItem->label.uint64 = LabelItem.val.uint64;
943 pDecodedItem->uLabelType = QCBOR_TYPE_UINT64;
944 } else if(LabelItem.uDataType == QCBOR_TYPE_BYTE_STRING) {
945 pDecodedItem->label.string = LabelItem.val.string;
946 pDecodedItem->uLabelAlloc = LabelItem.uDataAlloc;
947 pDecodedItem->uLabelType = QCBOR_TYPE_BYTE_STRING;
948 } else {
949 // label is not an int or a string. It is an arrray
950 // or a float or such and this implementation doesn't handle that.
951 // Also, tags on labels are ignored.
952 nReturn = QCBOR_ERR_MAP_LABEL_TYPE;
953 goto Done;
954 }
Laurence Lundbladed61cbf32018-12-09 11:42:21 -0800955 }
956 } else {
957 if(pDecodedItem->uDataType == QCBOR_TYPE_MAP) {
958 // Decoding a map as an array
959 pDecodedItem->uDataType = QCBOR_TYPE_MAP_AS_ARRAY;
960 pDecodedItem->val.uCount *= 2;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -0700961 }
962 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800963
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700964Done:
965 return nReturn;
966}
967
968
969/*
970 Public function, see header qcbor.h file
971 */
Laurence Lundblade59289e52019-12-30 13:44:37 -0800972QCBORError QCBORDecode_GetNextMapOrArray(QCBORDecodeContext *me, QCBORItem *pDecodedItem, QCBORTagListOut *pTags)
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700973{
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700974 // Stack ptr/int: 2, QCBORItem : 64
975
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530976 // The public entry point for fetching and parsing the next QCBORItem.
977 // All the CBOR parsing work is here and in subordinate calls.
Laurence Lundblade30816f22018-11-10 13:40:22 +0700978 QCBORError nReturn;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800979
Laurence Lundbladebb1062e2019-08-12 23:28:54 -0700980 // Check if there are an
981 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf)) == 0 && !DecodeNesting_IsNested(&(me->nesting))) {
982 nReturn = QCBOR_ERR_NO_MORE_ITEMS;
983 goto Done;
984 }
985
Laurence Lundbladedbe6f212018-10-28 11:37:53 +0700986 nReturn = GetNext_MapEntry(me, pDecodedItem, pTags);
Laurence Lundblade20b533d2018-10-08 20:44:53 +0800987 if(nReturn) {
988 goto Done;
Laurence Lundblade041ffa52018-10-07 11:43:51 +0700989 }
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530990
991 // Break ending arrays/maps are always processed at the end of this function.
992 // They should never show up here.
Laurence Lundblade6de37062018-10-15 12:22:42 +0530993 if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
Laurence Lundblade6de37062018-10-15 12:22:42 +0530994 nReturn = QCBOR_ERR_BAD_BREAK;
995 goto Done;
Laurence Lundblade5b8c5852018-10-14 21:11:42 +0530996 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800997
Laurence Lundblade6de37062018-10-15 12:22:42 +0530998 // Record the nesting level for this data item before processing any of
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +0530999 // decrementing and descending.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301000 pDecodedItem->uNestingLevel = DecodeNesting_GetLevel(&(me->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001001
Laurence Lundblade6de37062018-10-15 12:22:42 +05301002 // Process the item just received for descent or decrement, and
1003 // ascent if decrements are enough to close out a definite length array/map
Laurence Lundblade3a760b02018-10-08 13:46:03 +08001004 if(IsMapOrArray(pDecodedItem->uDataType)) {
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001005 // If the new item is array or map, the nesting level descends
Laurence Lundblade3a760b02018-10-08 13:46:03 +08001006 nReturn = DecodeNesting_Descend(&(me->nesting), pDecodedItem);
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001007 // Maps and arrays do count in as items in the map/array that encloses
1008 // them so a decrement needs to be done for them too, but that is done
1009 // only when all the items in them have been processed, not when they
Laurence Lundblade9916b1b2019-09-07 22:33:25 -07001010 // are opened with the exception of an empty map or array.
1011 if(pDecodedItem->val.uCount == 0) {
1012 DecodeNesting_DecrementCount(&(me->nesting));
1013 }
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001014 } else {
1015 // Decrement the count of items in the enclosing map/array
1016 // If the count in the enclosing map/array goes to zero, that
Laurence Lundblade6de37062018-10-15 12:22:42 +05301017 // triggers a decrement in the map/array above that and
1018 // an ascend in nesting level.
Laurence Lundblade9e3651c2018-10-10 11:49:55 +08001019 DecodeNesting_DecrementCount(&(me->nesting));
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001020 }
Laurence Lundblade6de37062018-10-15 12:22:42 +05301021 if(nReturn) {
1022 goto Done;
1023 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001024
Laurence Lundblade6de37062018-10-15 12:22:42 +05301025 // For indefinite length maps/arrays, looking at any and
1026 // all breaks that might terminate them. The equivalent
1027 // for definite length maps/arrays happens in
1028 // DecodeNesting_DecrementCount().
1029 if(DecodeNesting_IsNested(&(me->nesting)) && DecodeNesting_IsIndefiniteLength(&(me->nesting))) {
1030 while(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) {
1031 // Peek forward one item to see if it is a break.
1032 QCBORItem Peek;
1033 size_t uPeek = UsefulInputBuf_Tell(&(me->InBuf));
1034 nReturn = GetNext_Item(&(me->InBuf), &Peek, NULL);
1035 if(nReturn) {
1036 goto Done;
1037 }
1038 if(Peek.uDataType != QCBOR_TYPE_BREAK) {
1039 // It is not a break, rewind so it can be processed normally.
1040 UsefulInputBuf_Seek(&(me->InBuf), uPeek);
1041 break;
1042 }
1043 // It is a break. Ascend one nesting level.
Laurence Lundblade7e0d13b2018-10-16 19:54:13 +05301044 // The break is consumed.
Laurence Lundblade6de37062018-10-15 12:22:42 +05301045 nReturn = DecodeNesting_BreakAscend(&(me->nesting));
1046 if(nReturn) {
1047 // break occured outside of an indefinite length array/map
1048 goto Done;
1049 }
1050 }
1051 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001052
Laurence Lundblade6de37062018-10-15 12:22:42 +05301053 // Tell the caller what level is next. This tells them what maps/arrays
1054 // were closed out and makes it possible for them to reconstruct
1055 // the tree with just the information returned by GetNext
1056 pDecodedItem->uNextNestLevel = DecodeNesting_GetLevel(&(me->nesting));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001057
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001058Done:
Laurence Lundbladee9482dd2019-10-11 12:58:46 -07001059 if(nReturn != QCBOR_SUCCESS) {
1060 // Make sure uDataType and uLabelType are QCBOR_TYPE_NONE
1061 memset(pDecodedItem, 0, sizeof(QCBORItem));
1062 }
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001063 return nReturn;
1064}
1065
1066
Laurence Lundblade59289e52019-12-30 13:44:37 -08001067/*
1068 Mostly just assign the right data type for the date string.
1069 */
1070inline static QCBORError DecodeDateString(QCBORItem *pDecodedItem)
1071{
1072 // Stack Use: UsefulBuf 1 16
1073 if(pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
1074 return QCBOR_ERR_BAD_OPT_TAG;
1075 }
1076
1077 const UsefulBufC Temp = pDecodedItem->val.string;
1078 pDecodedItem->val.dateString = Temp;
1079 pDecodedItem->uDataType = QCBOR_TYPE_DATE_STRING;
1080 return QCBOR_SUCCESS;
1081}
1082
1083
1084/*
1085 Mostly just assign the right data type for the bignum.
1086 */
1087inline static QCBORError DecodeBigNum(QCBORItem *pDecodedItem)
1088{
1089 // Stack Use: UsefulBuf 1 -- 16
1090 if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
1091 return QCBOR_ERR_BAD_OPT_TAG;
1092 }
1093 const UsefulBufC Temp = pDecodedItem->val.string;
1094 pDecodedItem->val.bigNum = Temp;
1095 pDecodedItem->uDataType = pDecodedItem->uTagBits & QCBOR_TAGFLAG_POS_BIGNUM ? QCBOR_TYPE_POSBIGNUM : QCBOR_TYPE_NEGBIGNUM;
1096 return QCBOR_SUCCESS;
1097}
1098
1099
1100/*
1101 The epoch formatted date. Turns lots of different forms of encoding date into uniform one
1102 */
1103static int DecodeDateEpoch(QCBORItem *pDecodedItem)
1104{
1105 // Stack usage: 1
1106 QCBORError nReturn = QCBOR_SUCCESS;
1107
1108 pDecodedItem->val.epochDate.fSecondsFraction = 0;
1109
1110 switch (pDecodedItem->uDataType) {
1111
1112 case QCBOR_TYPE_INT64:
1113 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.int64;
1114 break;
1115
1116 case QCBOR_TYPE_UINT64:
1117 if(pDecodedItem->val.uint64 > INT64_MAX) {
1118 nReturn = QCBOR_ERR_DATE_OVERFLOW;
1119 goto Done;
1120 }
1121 pDecodedItem->val.epochDate.nSeconds = pDecodedItem->val.uint64;
1122 break;
1123
1124 case QCBOR_TYPE_DOUBLE:
1125 {
1126 // This comparison needs to be done as a float before
1127 // conversion to an int64_t to be able to detect doubles
1128 // that are too large to fit into an int64_t. A double
1129 // has 52 bits of preceision. An int64_t has 63. Casting
1130 // INT64_MAX to a double actually causes a round up which
1131 // is bad and wrong for the comparison because it will
1132 // allow conversion of doubles that can't fit into a
1133 // uint64_t. To remedy this INT64_MAX - 0x7ff is used as
1134 // the cutoff point as if that rounds up in conversion to
1135 // double it will still be less than INT64_MAX. 0x7ff is
1136 // picked because it has 11 bits set.
1137 //
1138 // INT64_MAX seconds is on the order of 10 billion years,
1139 // and the earth is less than 5 billion years old, so for
1140 // most uses this conversion error won't occur even though
1141 // doubles can go much larger.
1142 //
1143 // Without the 0x7ff there is a ~30 minute range of time
1144 // values 10 billion years in the past and in the future
1145 // where this this code would go wrong.
1146 const double d = pDecodedItem->val.dfnum;
1147 if(d > (double)(INT64_MAX - 0x7ff)) {
1148 nReturn = QCBOR_ERR_DATE_OVERFLOW;
1149 goto Done;
1150 }
1151 pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
1152 pDecodedItem->val.epochDate.fSecondsFraction = d - (double)pDecodedItem->val.epochDate.nSeconds;
1153 }
1154 break;
1155
1156 default:
1157 nReturn = QCBOR_ERR_BAD_OPT_TAG;
1158 goto Done;
1159 }
1160 pDecodedItem->uDataType = QCBOR_TYPE_DATE_EPOCH;
1161
1162Done:
1163 return nReturn;
1164}
1165
1166
1167#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
1168/*
1169 Decode decimal fractions and big floats.
1170
1171 When called pDecodedItem must be the array that is tagged as a big
1172 float or decimal fraction, the array that has the two members, the
1173 exponent and mantissa.
1174
1175 This will fetch and decode the exponent and mantissa and put the
1176 result back into pDecodedItem.
1177 */
1178inline static QCBORError
1179QCBORDecode_MantissaAndExponent(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
1180{
1181 QCBORError nReturn;
1182
1183 // --- Make sure it is an array; track nesting level of members ---
1184 if(pDecodedItem->uDataType != QCBOR_TYPE_ARRAY) {
1185 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1186 goto Done;
1187 }
1188
1189 // A check for pDecodedItem->val.uCount == 2 would work for
1190 // definite length arrays, but not for indefnite. Instead remember
1191 // the nesting level the two integers must be at, which is one
1192 // deeper than that of the array.
1193 const int nNestLevel = pDecodedItem->uNestingLevel + 1;
1194
1195 // --- Is it a decimal fraction or a bigfloat? ---
1196 const bool bIsTaggedDecimalFraction = QCBORDecode_IsTagged(me, pDecodedItem, CBOR_TAG_DECIMAL_FRACTION);
1197 pDecodedItem->uDataType = bIsTaggedDecimalFraction ? QCBOR_TYPE_DECIMAL_FRACTION : QCBOR_TYPE_BIGFLOAT;
1198
1199 // --- Get the exponent ---
1200 QCBORItem exponentItem;
1201 nReturn = QCBORDecode_GetNextMapOrArray(me, &exponentItem, NULL);
1202 if(nReturn != QCBOR_SUCCESS) {
1203 goto Done;
1204 }
1205 if(exponentItem.uNestingLevel != nNestLevel) {
1206 // Array is empty or a map/array encountered when expecting an int
1207 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1208 goto Done;
1209 }
1210 if(exponentItem.uDataType == QCBOR_TYPE_INT64) {
1211 // Data arriving as an unsigned int < INT64_MAX has been converted
1212 // to QCBOR_TYPE_INT64 and thus handled here. This is also means
1213 // that the only data arriving here of type QCBOR_TYPE_UINT64 data
1214 // will be too large for this to handle and thus an error that will
1215 // get handled in the next else.
1216 pDecodedItem->val.expAndMantissa.nExponent = exponentItem.val.int64;
1217 } else {
1218 // Wrong type of exponent or a QCBOR_TYPE_UINT64 > INT64_MAX
1219 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1220 goto Done;
1221 }
1222
1223 // --- Get the mantissa ---
1224 QCBORItem mantissaItem;
1225 nReturn = QCBORDecode_GetNextWithTags(me, &mantissaItem, NULL);
1226 if(nReturn != QCBOR_SUCCESS) {
1227 goto Done;
1228 }
1229 if(mantissaItem.uNestingLevel != nNestLevel) {
1230 // Mantissa missing or map/array encountered when expecting number
1231 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1232 goto Done;
1233 }
1234 if(mantissaItem.uDataType == QCBOR_TYPE_INT64) {
1235 // Data arriving as an unsigned int < INT64_MAX has been converted
1236 // to QCBOR_TYPE_INT64 and thus handled here. This is also means
1237 // that the only data arriving here of type QCBOR_TYPE_UINT64 data
1238 // will be too large for this to handle and thus an error that
1239 // will get handled in an else below.
1240 pDecodedItem->val.expAndMantissa.Mantissa.nInt = mantissaItem.val.int64;
1241 } else if(mantissaItem.uDataType == QCBOR_TYPE_POSBIGNUM || mantissaItem.uDataType == QCBOR_TYPE_NEGBIGNUM) {
1242 // Got a good big num mantissa
1243 pDecodedItem->val.expAndMantissa.Mantissa.bigNum = mantissaItem.val.bigNum;
1244 // Depends on numbering of QCBOR_TYPE_XXX
1245 pDecodedItem->uDataType += 1 + mantissaItem.uDataType - QCBOR_TYPE_POSBIGNUM;
1246 } else {
1247 // Wrong type of mantissa or a QCBOR_TYPE_UINT64 > INT64_MAX
1248 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1249 goto Done;
1250 }
1251
1252 // --- Check that array only has the two numbers ---
1253 if(mantissaItem.uNextNestLevel == nNestLevel) {
1254 // Extra items in the decimal fraction / big num
1255 nReturn = QCBOR_ERR_BAD_EXP_AND_MANTISSA;
1256 goto Done;
1257 }
1258
1259Done:
1260
1261 return nReturn;
1262}
1263#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
1264
1265
1266/*
1267 Public function, see header qcbor.h file
1268 */
1269QCBORError QCBORDecode_GetNextWithTags(QCBORDecodeContext *me, QCBORItem *pDecodedItem, QCBORTagListOut *pTags)
1270{
1271 QCBORError nReturn;
1272
1273 nReturn = QCBORDecode_GetNextMapOrArray(me, pDecodedItem, pTags);
1274 if(nReturn != QCBOR_SUCCESS) {
1275 goto Done;
1276 }
1277
1278#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
1279#define TAG_MAPPER_FIRST_XXX TAG_MAPPER_FIRST_SIX
1280#else
1281#define TAG_MAPPER_FIRST_XXX TAG_MAPPER_FIRST_FOUR
1282#endif
1283
1284 // Only pay attention to tags this code knows how to decode.
1285 switch(pDecodedItem->uTagBits & TAG_MAPPER_FIRST_XXX) {
1286 case 0:
1287 // No tags at all or none we know about. Nothing to do.
1288 // This is the pass-through path of this function
1289 // that will mostly be taken when decoding any item.
1290 break;
1291
1292 case QCBOR_TAGFLAG_DATE_STRING:
1293 nReturn = DecodeDateString(pDecodedItem);
1294 break;
1295
1296 case QCBOR_TAGFLAG_DATE_EPOCH:
1297 nReturn = DecodeDateEpoch(pDecodedItem);
1298 break;
1299
1300 case QCBOR_TAGFLAG_POS_BIGNUM:
1301 case QCBOR_TAGFLAG_NEG_BIGNUM:
1302 nReturn = DecodeBigNum(pDecodedItem);
1303 break;
1304
1305#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
1306 case QCBOR_TAGFLAG_DECIMAL_FRACTION:
1307 case QCBOR_TAGFLAG_BIGFLOAT:
1308 // For aggregate tagged types, what goes into pTags is only collected
1309 // from the surrounding data item, not the contents, so pTags is not
1310 // passed on here.
1311
1312 nReturn = QCBORDecode_MantissaAndExponent(me, pDecodedItem);
1313 break;
1314#endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
1315
1316 default:
1317 // Encountering some mixed-up CBOR like something that
1318 // is tagged as both a string and integer date.
1319 nReturn = QCBOR_ERR_BAD_OPT_TAG;
1320 }
1321
1322Done:
1323 if(nReturn != QCBOR_SUCCESS) {
1324 pDecodedItem->uDataType = QCBOR_TYPE_NONE;
1325 pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
1326 }
1327 return nReturn;
1328}
1329
1330
1331/*
1332 Public function, see header qcbor.h file
1333 */
Laurence Lundblade30816f22018-11-10 13:40:22 +07001334QCBORError QCBORDecode_GetNext(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001335{
1336 return QCBORDecode_GetNextWithTags(me, pDecodedItem, NULL);
1337}
1338
1339
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001340/*
Laurence Lundblade6de37062018-10-15 12:22:42 +05301341 Decoding items is done in 5 layered functions, one calling the
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301342 next one down. If a layer has no work to do for a particular item
1343 it returns quickly.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001344
Laurence Lundblade59289e52019-12-30 13:44:37 -08001345 - QCBORDecode_GetNext, GetNextWithTags -- The top layer processes
1346 tagged data items, turning them into the local C representation.
1347 For the most simple it is just associating a QCBOR_TYPE with the data. For
1348 the complex ones that an aggregate of data items, there is some further
1349 decoding and a little bit of recursion.
1350
1351 - QCBORDecode_GetNextMapOrArray - This manages the beginnings and
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301352 ends of maps and arrays. It tracks descending into and ascending
Laurence Lundblade6de37062018-10-15 12:22:42 +05301353 out of maps/arrays. It processes all breaks that terminate
1354 maps and arrays.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001355
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301356 - GetNext_MapEntry -- This handles the combining of two
1357 items, the label and the data, that make up a map entry.
1358 It only does work on maps. It combines the label and data
1359 items into one labeled item.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001360
Laurence Lundblade59289e52019-12-30 13:44:37 -08001361 - GetNext_TaggedItem -- This decodes type 6 tagging. It turns the
1362 tags into bit flags associated with the data item. No actual decoding
1363 of the contents of the tagged item is performed here.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001364
Laurence Lundblade59289e52019-12-30 13:44:37 -08001365 - GetNext_FullItem -- This assembles the sub-items that make up
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301366 an indefinte length string into one string item. It uses the
Laurence Lundblade6de37062018-10-15 12:22:42 +05301367 string allocater to create contiguous space for the item. It
1368 processes all breaks that are part of indefinite length strings.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001369
Laurence Lundblade59289e52019-12-30 13:44:37 -08001370 - GetNext_Item -- This decodes the atomic data items in CBOR. Each
1371 atomic data item has a "major type", an integer "argument" and optionally
1372 some content. For text and byte strings, the content is the bytes
1373 that make up the string. These are the smallest data items that are
1374 considered to be well-formed. The content may also be other data items in
1375 the case of aggregate types. They are not handled in this layer.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001376
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001377 Roughly this takes 300 bytes of stack for vars. Need to
1378 evaluate this more carefully and correctly.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001379
Laurence Lundblade0fb2f642018-10-11 19:33:35 +05301380 */
1381
1382
1383/*
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001384 Public function, see header qcbor.h file
1385 */
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001386int QCBORDecode_IsTagged(QCBORDecodeContext *me, const QCBORItem *pItem, uint64_t uTag)
1387{
1388 const QCBORTagListIn *pCallerConfiguredTagMap = me->pCallerConfiguredTagList;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001389
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001390 uint8_t uTagBitIndex;
1391 // Do not care about errors in pCallerConfiguredTagMap here. They are
1392 // caught during GetNext() before this is called.
1393 if(TagMapper_Lookup(pCallerConfiguredTagMap, uTag, &uTagBitIndex)) {
1394 return 0;
1395 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001396
Laurence Lundbladedbe6f212018-10-28 11:37:53 +07001397 const uint64_t uTagBit = 0x01ULL << uTagBitIndex;
1398 return (uTagBit & pItem->uTagBits) != 0;
1399}
1400
1401
1402/*
1403 Public function, see header qcbor.h file
1404 */
Laurence Lundblade30816f22018-11-10 13:40:22 +07001405QCBORError QCBORDecode_Finish(QCBORDecodeContext *me)
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001406{
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001407 int nReturn = QCBOR_SUCCESS;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001408
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001409 // Error out if all the maps/arrays are not closed out
1410 if(DecodeNesting_IsNested(&(me->nesting))) {
1411 nReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
1412 goto Done;
1413 }
1414
1415 // Error out if not all the bytes are consumed
1416 if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) {
1417 nReturn = QCBOR_ERR_EXTRA_BYTES;
1418 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001419
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001420Done:
Laurence Lundblade6de37062018-10-15 12:22:42 +05301421 // Call the destructor for the string allocator if there is one.
Laurence Lundblade20b533d2018-10-08 20:44:53 +08001422 // Always called, even if there are errors; always have to clean up
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001423 StringAllocator_Destruct(&(me->StringAllocator));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001424
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001425 return nReturn;
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001426}
1427
1428
1429
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001430/*
1431
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001432Decoder errors handled in this file
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001433
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001434 - Hit end of input before it was expected while decoding type and number QCBOR_ERR_HIT_END
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001435
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001436 - negative integer that is too large for C QCBOR_ERR_INT_OVERFLOW
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001437
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001438 - Hit end of input while decoding a text or byte string QCBOR_ERR_HIT_END
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001439
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001440 - 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 -08001441
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001442 - Encontered an array or mapp that has too many items QCBOR_ERR_ARRAY_TOO_LONG
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001443
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001444 - Encountered array/map nesting that is too deep QCBOR_ERR_ARRAY_NESTING_TOO_DEEP
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001445
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001446 - An epoch date > INT64_MAX or < INT64_MIN was encountered QCBOR_ERR_DATE_OVERFLOW
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001447
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001448 - The type of a map label is not a string or int QCBOR_ERR_MAP_LABEL_TYPE
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001449
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001450 - Hit end with arrays or maps still open -- QCBOR_ERR_EXTRA_BYTES
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001451
Laurence Lundbladeb69cad72018-09-13 11:09:01 -07001452 */
1453
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001454
1455
Laurence Lundbladef6531662018-12-04 10:42:22 +09001456
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001457/* ===========================================================================
1458 MemPool -- BUILT-IN SIMPLE STRING ALLOCATOR
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001459
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001460 This implements a simple sting allocator for indefinite length
1461 strings that can be enabled by calling QCBORDecode_SetMemPool(). It
1462 implements the function type QCBORStringAllocate and allows easy
1463 use of it.
Laurence Lundbladef6531662018-12-04 10:42:22 +09001464
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001465 This particular allocator is built-in for convenience. The caller
1466 can implement their own. All of this following code will get
1467 dead-stripped if QCBORDecode_SetMemPool() is not called.
1468
1469 This is a very primitive memory allocator. It does not track
1470 individual allocations, only a high-water mark. A free or
1471 reallocation must be of the last chunk allocated.
1472
1473 The size of the pool and offset to free memory are packed into the
1474 first 8 bytes of the memory pool so we don't have to keep them in
1475 the decode context. Since the address of the pool may not be
1476 aligned, they have to be packed and unpacked as if they were
1477 serialized data of the wire or such.
1478
1479 The sizes packed in are uint32_t to be the same on all CPU types
1480 and simplify the code.
1481 =========================================================================== */
1482
1483
1484static inline int MemPool_Unpack(const void *pMem, uint32_t *puPoolSize, uint32_t *puFreeOffset)
1485{
1486 // Use of UsefulInputBuf is overkill, but it is convenient.
1487 UsefulInputBuf UIB;
1488
1489 // Just assume the size here. It was checked during SetUp so the assumption is safe.
1490 UsefulInputBuf_Init(&UIB, (UsefulBufC){pMem, QCBOR_DECODE_MIN_MEM_POOL_SIZE});
1491 *puPoolSize = UsefulInputBuf_GetUint32(&UIB);
1492 *puFreeOffset = UsefulInputBuf_GetUint32(&UIB);
1493 return UsefulInputBuf_GetError(&UIB);
1494}
1495
1496
1497static inline int MemPool_Pack(UsefulBuf Pool, uint32_t uFreeOffset)
1498{
1499 // Use of UsefulOutBuf is overkill, but convenient. The
1500 // length check performed here is useful.
1501 UsefulOutBuf UOB;
1502
1503 UsefulOutBuf_Init(&UOB, Pool);
1504 UsefulOutBuf_AppendUint32(&UOB, (uint32_t)Pool.len); // size of pool
1505 UsefulOutBuf_AppendUint32(&UOB, uFreeOffset); // first free position
1506 return UsefulOutBuf_GetError(&UOB);
1507}
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001508
1509
1510/*
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001511 Internal function for an allocation, reallocation free and destuct.
1512
1513 Having only one function rather than one each per mode saves space in
1514 QCBORDecodeContext.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001515
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001516 Code Reviewers: THIS FUNCTION DOES POINTER MATH
1517 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001518static UsefulBuf MemPool_Function(void *pPool, void *pMem, size_t uNewSize)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001519{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001520 UsefulBuf ReturnValue = NULLUsefulBuf;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001521
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001522 uint32_t uPoolSize;
1523 uint32_t uFreeOffset;
1524
1525 if(uNewSize > UINT32_MAX) {
1526 // This allocator is only good up to 4GB. This check should
1527 // optimize out if sizeof(size_t) == sizeof(uint32_t)
1528 goto Done;
1529 }
1530 const uint32_t uNewSize32 = (uint32_t)uNewSize;
1531
1532 if(MemPool_Unpack(pPool, &uPoolSize, &uFreeOffset)) {
1533 goto Done;
1534 }
1535
1536 if(uNewSize) {
1537 if(pMem) {
1538 // REALLOCATION MODE
1539 // Calculate pointer to the end of the memory pool. It is
1540 // assumed that pPool + uPoolSize won't wrap around by
1541 // assuming the caller won't pass a pool buffer in that is
1542 // not in legitimate memory space.
1543 const void *pPoolEnd = (uint8_t *)pPool + uPoolSize;
1544
1545 // Check that the pointer for reallocation is in the range of the
1546 // pool. This also makes sure that pointer math further down
1547 // doesn't wrap under or over.
1548 if(pMem >= pPool && pMem < pPoolEnd) {
1549 // Offset to start of chunk for reallocation. This won't
1550 // wrap under because of check that pMem >= pPool. Cast
1551 // is safe because the pool is always less than UINT32_MAX
1552 // because of check in QCBORDecode_SetMemPool().
1553 const uint32_t uMemOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
1554
1555 // Check to see if the allocation will fit. uPoolSize -
1556 // uMemOffset will not wrap under because of check that
1557 // pMem is in the range of the uPoolSize by check above.
1558 if(uNewSize <= uPoolSize - uMemOffset) {
1559 ReturnValue.ptr = pMem;
1560 ReturnValue.len = uNewSize;
1561
1562 // Addition won't wrap around over because uNewSize was
1563 // checked to be sure it is less than the pool size.
1564 uFreeOffset = uMemOffset + uNewSize32;
1565 }
1566 }
1567 } else {
1568 // ALLOCATION MODE
1569 // uPoolSize - uFreeOffset will not underflow because this
1570 // pool implementation makes sure uFreeOffset is always
1571 // smaller than uPoolSize through this check here and
1572 // reallocation case.
1573 if(uNewSize <= uPoolSize - uFreeOffset) {
1574 ReturnValue.len = uNewSize;
1575 ReturnValue.ptr = (uint8_t *)pPool + uFreeOffset;
1576 uFreeOffset += uNewSize;
1577 }
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001578 }
1579 } else {
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001580 if(pMem) {
1581 // FREE MODE
1582 // Cast is safe because of limit on pool size in
1583 // QCBORDecode_SetMemPool()
1584 uFreeOffset = (uint32_t)((uint8_t *)pMem - (uint8_t *)pPool);
1585 } else {
1586 // DESTRUCT MODE
1587 // Nothing to do for this allocator
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001588 }
1589 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001590
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001591 UsefulBuf Pool = {pPool, uPoolSize};
1592 MemPool_Pack(Pool, uFreeOffset);
1593
1594Done:
1595 return ReturnValue;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001596}
1597
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001598
Laurence Lundbladef6531662018-12-04 10:42:22 +09001599/*
1600 Public function, see header qcbor.h file
1601 */
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001602QCBORError QCBORDecode_SetMemPool(QCBORDecodeContext *pMe, UsefulBuf Pool, bool bAllStrings)
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001603{
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001604 // The pool size and free mem offset are packed into the beginning
1605 // of the pool memory. This compile time check make sure the
1606 // constant in the header is correct. This check should optimize
1607 // down to nothing.
1608 if(QCBOR_DECODE_MIN_MEM_POOL_SIZE < 2 * sizeof(uint32_t)) {
Laurence Lundblade30816f22018-11-10 13:40:22 +07001609 return QCBOR_ERR_BUFFER_TOO_SMALL;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001610 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001611
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001612 // The pool size and free offset packed in to the beginning of pool
1613 // memory are only 32-bits. This check will optimize out on 32-bit
1614 // machines.
1615 if(Pool.len > UINT32_MAX) {
1616 return QCBOR_ERR_BUFFER_TOO_LARGE;
1617 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001618
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001619 // This checks that the pool buffer given is big enough.
1620 if(MemPool_Pack(Pool, QCBOR_DECODE_MIN_MEM_POOL_SIZE)) {
1621 return QCBOR_ERR_BUFFER_TOO_SMALL;
1622 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001623
Laurence Lundblade1d7eb632019-02-17 17:23:38 -08001624 pMe->StringAllocator.pfAllocator = MemPool_Function;
1625 pMe->StringAllocator.pAllocateCxt = Pool.ptr;
1626 pMe->bStringAllocateAll = bAllStrings;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001627
Laurence Lundblade30816f22018-11-10 13:40:22 +07001628 return QCBOR_SUCCESS;
Laurence Lundblade041ffa52018-10-07 11:43:51 +07001629}