blob: 20e99badfaa85fd51100211c076ee668224a765b [file] [log] [blame]
/* ==========================================================================
* Copyright (c) 2016-2018, The Linux Foundation.
* Copyright (c) 2018-2024, Laurence Lundblade.
* Copyright (c) 2021, Arm Limited.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors, nor the name "Laurence Lundblade" may be used to
* endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ========================================================================= */
#ifndef qcbor_private_h
#define qcbor_private_h
#include <stdint.h>
#include "UsefulBuf.h"
#include "qcbor/qcbor_common.h"
#ifdef __cplusplus
extern "C" {
#if 0
} // Keep editor indention formatting happy
#endif
#endif
/* This was originally defined as QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA,
* but this is inconsistent with all the other QCBOR_DISABLE_
* #defines, so the name was changed and this was added for backwards
* compatibility
*/
#ifdef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
#define QCBOR_DISABLE_EXP_AND_MANTISSA
#endif
/* If USEFULBUF_DISABLE_ALL_FLOATis defined then define
* QCBOR_DISABLE_FLOAT_HW_USE and QCBOR_DISABLE_PREFERRED_FLOAT
*/
#ifdef USEFULBUF_DISABLE_ALL_FLOAT
#ifndef QCBOR_DISABLE_FLOAT_HW_USE
#define QCBOR_DISABLE_FLOAT_HW_USE
#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
#define QCBOR_DISABLE_PREFERRED_FLOAT
#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
/*
* Convenience macro for selecting the proper return value in case floating
* point feature(s) are disabled.
*
* The macros:
*
* FLOAT_ERR_CODE_NO_FLOAT(x) Can be used when disabled floating point should
* result error, and all other cases should return
* 'x'.
*
* The below macros always return QCBOR_ERR_ALL_FLOAT_DISABLED when all
* floating point is disabled.
*
* FLOAT_ERR_CODE_NO_HALF_PREC(x) Can be used when disabled preferred float
* results in error, and all other cases should
* return 'x'.
* FLOAT_ERR_CODE_NO_FLOAT_HW(x) Can be used when disabled hardware floating
* point results in error, and all other cases
* should return 'x'.
* FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) Can be used when either disabled
* preferred float or disabling
* hardware floating point results
* in error, and all other cases
* should return 'x'.
*/
#ifdef USEFULBUF_DISABLE_ALL_FLOAT
#define FLOAT_ERR_CODE_NO_FLOAT(x) QCBOR_ERR_ALL_FLOAT_DISABLED
#define FLOAT_ERR_CODE_NO_HALF_PREC(x) QCBOR_ERR_ALL_FLOAT_DISABLED
#define FLOAT_ERR_CODE_NO_FLOAT_HW(x) QCBOR_ERR_ALL_FLOAT_DISABLED
#define FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) QCBOR_ERR_ALL_FLOAT_DISABLED
#else /* USEFULBUF_DISABLE_ALL_FLOAT*/
#define FLOAT_ERR_CODE_NO_FLOAT(x) x
#ifdef QCBOR_DISABLE_PREFERRED_FLOAT
#define FLOAT_ERR_CODE_NO_HALF_PREC(x) QCBOR_ERR_HALF_PRECISION_DISABLED
#define FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) QCBOR_ERR_HALF_PRECISION_DISABLED
#else /* QCBOR_DISABLE_PREFERRED_FLOAT */
#define FLOAT_ERR_CODE_NO_HALF_PREC(x) x
#ifdef QCBOR_DISABLE_FLOAT_HW_USE
#define FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) QCBOR_ERR_HW_FLOAT_DISABLED
#else
#define FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) x
#endif
#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
#ifdef QCBOR_DISABLE_FLOAT_HW_USE
#define FLOAT_ERR_CODE_NO_FLOAT_HW(x) QCBOR_ERR_HW_FLOAT_DISABLED
#else /* QCBOR_DISABLE_FLOAT_HW_USE */
#define FLOAT_ERR_CODE_NO_FLOAT_HW(x) x
#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
#endif /*USEFULBUF_DISABLE_ALL_FLOAT*/
/*
* These are special values for the AdditionalInfo bits that are part of
* the first byte. Mostly they encode the length of the data item.
*/
#define LEN_IS_ONE_BYTE 24
#define LEN_IS_TWO_BYTES 25
#define LEN_IS_FOUR_BYTES 26
#define LEN_IS_EIGHT_BYTES 27
#define ADDINFO_RESERVED1 28
#define ADDINFO_RESERVED2 29
#define ADDINFO_RESERVED3 30
#define LEN_IS_INDEFINITE 31
/*
* 24 is a special number for CBOR. Integers and lengths
* less than it are encoded in the same byte as the major type.
*/
#define CBOR_TWENTY_FOUR 24
/*
* Values for the 5 bits for items of major type 7
*/
#define CBOR_SIMPLEV_FALSE 20
#define CBOR_SIMPLEV_TRUE 21
#define CBOR_SIMPLEV_NULL 22
#define CBOR_SIMPLEV_UNDEF 23
#define CBOR_SIMPLEV_ONEBYTE 24
#define HALF_PREC_FLOAT 25
#define SINGLE_PREC_FLOAT 26
#define DOUBLE_PREC_FLOAT 27
#define CBOR_SIMPLE_BREAK 31
#define CBOR_SIMPLEV_RESERVED_START CBOR_SIMPLEV_ONEBYTE
#define CBOR_SIMPLEV_RESERVED_END CBOR_SIMPLE_BREAK
/* The largest offset to the start of an array or map. It is slightly
* less than UINT32_MAX so the error condition can be tested on 32-bit
* machines. UINT32_MAX comes from uStart in QCBORTrackNesting being
* a uin32_t.
*
* This will cause trouble on a machine where size_t is less than 32-bits.
*
* TODO: make this public?
*/
#define QCBOR_MAX_ARRAY_OFFSET (UINT32_MAX - 100)
/* The number of tags that are 16-bit or larger that can be handled
* in a decode.
*/
#define QCBOR_NUM_MAPPED_TAGS 4
/* The number of tags (of any size) recorded for an individual item. */
#define QCBOR_MAX_TAGS_PER_ITEM1 4
/*
* PRIVATE DATA STRUCTURE
*
* Holds the data for tracking array and map nesting during
* encoding. Pairs up with the Nesting_xxx functions to make an
* "object" to handle nesting encoding.
*
* uStart is a uint32_t instead of a size_t to keep the size of this
* struct down so it can be on the stack without any concern. It
* would be about double if size_t was used instead.
*
* Size approximation (varies with CPU/compiler):
* 64-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 8 = 136 bytes
* 32-bit machine: (15 + 1) * (4 + 2 + 1 + 1 pad) + 4 = 132 bytes
*/
typedef struct __QCBORTrackNesting {
/* PRIVATE DATA STRUCTURE */
struct {
/* See QCBOREncode_OpenMapOrArray() for details on how this works */
uint32_t uStart; /* uStart is the position where the array starts */
uint16_t uCount; /* Number of items in the arrary or map; counts items
* in a map, not pairs of items */
uint8_t uMajorType; /* Indicates if item is a map or an array */
} pArrays[QCBOR_MAX_ARRAY_NESTING+1], /* stored state for nesting levels */
*pCurrentNesting; /* the current nesting level */
} QCBORTrackNesting;
/*
* PRIVATE DATA STRUCTURE
*
* Context / data object for encoding some CBOR. Used by all encode
* functions to form a public "object" that does the job of encdoing.
*
* Size approximation (varies with CPU/compiler):
* 64-bit machine: 27 + 1 (+ 4 padding) + 136 = 32 + 136 = 168 bytes
* 32-bit machine: 15 + 1 + 132 = 148 bytes
*/
typedef struct _QCBOREncodeContext QCBORPrivateEncodeContext;
/* These are in order of increasing strictness. Order is relied upon in
* implementation. */
#define QCBOR_ENCODE_MODE_ANY 0
#define QCBOR_ENCODE_MODE_PREFERRED 1
#define QCBOR_ENCODE_MODE_CDE 2
#define QCBOR_ENCODE_MODE_DCBOR 3
struct _QCBOREncodeContext {
/* PRIVATE DATA STRUCTURE */
UsefulOutBuf OutBuf; /* Pointer to output buffer, its length and
* position in it. */
uint8_t uError; /* Error state, always from QCBORError enum */
uint8_t uMode; /* @ref QCBOR_ENCODE_MODE_PREFERRED or related */
uint8_t uAllow; /* @ref QCBOR_ENCODE_ALLOW_NAN_PAYLOAD, ... */
void (*pfnCloseMap)(QCBORPrivateEncodeContext *); /* Use of function
* pointer explained in QCBOREncode_SerializationCDE() */
QCBORTrackNesting nesting; /* Keep track of array and map nesting */
};
/*
* PRIVATE DATA STRUCTURE
*
* Holds the data for array and map nesting for decoding work. This
* structure and the DecodeNesting_Xxx() functions in qcbor_decode.c
* form an "object" that does the work for arrays and maps. All access
* to this structure is through DecodeNesting_Xxx() functions.
*
* 64-bit machine size
* 128 = 16 * 8 for the two unions
* 64 = 16 * 4 for the uLevelType, 1 byte padded to 4 bytes for alignment
* 16 = 16 bytes for two pointers
* 208 TOTAL
*
* 32-bit machine size is 200 bytes
*/
typedef struct __QCBORDecodeNesting {
/* PRIVATE DATA STRUCTURE */
struct nesting_decode_level {
/*
* This keeps tracking info for each nesting level. There are two
* main types of levels:
* 1) Byte count tracking. This is for the top level input CBOR
* which might be a single item or a CBOR sequence and byte
* string wrapped encoded CBOR.
* 2) Item count tracking. This is for maps and arrays.
*
* uLevelType has value QCBOR_TYPE_BYTE_STRING for 1) and
* QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP_AS_ARRAY
* for 2).
*
* Item count tracking is either for definite or indefinite-length
* maps/arrays. For definite lengths, the total count and items
* unconsumed are tracked. For indefinite-length, uTotalCount is
* QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH (UINT16_MAX) and
* there is no per-item count of members. For indefinite-length
* maps and arrays, uCountCursor is UINT16_MAX if not consumed
* and zero if it is consumed in the pre-order
* traversal. Additionally, if entered in bounded mode,
* uCountCursor is QCBOR_COUNT_INDICATES_ZERO_LENGTH to indicate
* it is empty.
*
* This also records whether a level is bounded or not. All
* byte-count tracked levels (the top-level sequence and
* bstr-wrapped CBOR) are bounded implicitly. Maps and arrays
* may or may not be bounded. They are bounded if they were
* Entered() and not if they were traversed with GetNext(). They
* are marked as bounded by uStartOffset not being @c UINT32_MAX.
*/
/*
* If uLevelType can put in a separately indexed array, the
* union/struct will be 8 bytes rather than 9 and a lot of
* wasted padding for alignment will be saved.
*/
uint8_t uLevelType;
union {
struct {
#define QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH UINT16_MAX
#define QCBOR_COUNT_INDICATES_ZERO_LENGTH UINT16_MAX-1
uint16_t uCountTotal;
uint16_t uCountCursor;
#define QCBOR_NON_BOUNDED_OFFSET UINT32_MAX
/* The start of the array or map in bounded mode so
* the input can be rewound for GetInMapXx() by label. */
uint32_t uStartOffset;
} ma; /* for maps and arrays */
struct {
/* The end of the input before the bstr was entered so that
* it can be restored when the bstr is exited. */
uint32_t uSavedEndOffset;
/* The beginning of the bstr so that it can be rewound. */
uint32_t uBstrStartOffset;
} bs; /* for top-level sequence and bstr-wrapped CBOR */
} u;
} pLevels[QCBOR_MAX_ARRAY_NESTING+1],
*pCurrent,
*pCurrentBounded;
/*
* pCurrent is for item-by-item pre-order traversal.
*
* pCurrentBounded points to the current bounding level or is NULL
* if there isn't one.
*
* pCurrent must always be below pCurrentBounded as the pre-order
* traversal is always bounded by the bounding level.
*
* When a bounded level is entered, the pre-order traversal is set
* to the first item in the bounded level. When a bounded level is
* exited, the pre-order traversl is set to the next item after the
* map, array or bstr. This may be more than one level up, or even
* the end of the input CBOR.
*/
} QCBORDecodeNesting;
typedef struct {
/* PRIVATE DATA STRUCTURE */
void *pAllocateCxt;
UsefulBuf (* pfAllocator)(void *pAllocateCxt, void *pOldMem, size_t uNewSize);
} QCBORInternalAllocator;
/*
* PRIVATE DATA STRUCTURE
*
* The decode context. This data structure plus the public
* QCBORDecode_xxx functions form an "object" that does CBOR decoding.
*
* Size approximation (varies with CPU/compiler):
* 64-bit machine: 32 + 1 + 1 + 6 bytes padding + 72 + 16 + 8 + 8 = 144 bytes
* 32-bit machine: 16 + 1 + 1 + 2 bytes padding + 68 + 8 + 8 + 4 = 108 bytes
*/
struct _QCBORDecodeContext {
/* PRIVATE DATA STRUCTURE */
UsefulInputBuf InBuf;
QCBORDecodeNesting nesting;
/* If a string allocator is configured for indefinite-length
* strings, it is configured here.
*/
QCBORInternalAllocator StringAllocator;
/* These are special for the internal MemPool allocator. They are
* not used otherwise. We tried packing these in the MemPool
* itself, but there are issues with memory alignment.
*/
uint32_t uMemPoolSize;
uint32_t uMemPoolFreeOffset;
/* A cached offset to the end of the current map 0 if no value is
* cached.
*/
#define QCBOR_MAP_OFFSET_CACHE_INVALID UINT32_MAX
uint32_t uMapEndOffsetCache;
uint8_t uDecodeMode;
uint8_t bStringAllocateAll;
uint8_t uLastError; /* QCBORError stuffed into a uint8_t */
/* See MapTagNumber() for description of how tags are mapped. */
uint64_t auMappedTags[QCBOR_NUM_MAPPED_TAGS];
uint16_t uLastTags[QCBOR_MAX_TAGS_PER_ITEM1];
};
/* Used internally in the impementation here Must not conflict with
* any of the official CBOR types
*/
#define CBOR_MAJOR_NONE_TYPE_RAW 9
#define CBOR_MAJOR_NONE_TAG_LABEL_REORDER 10
#define CBOR_MAJOR_NONE_TYPE_OPEN_BSTR 12
/* Add this to types to indicate they are to be encoded as indefinite lengths */
#define QCBOR_INDEFINITE_LEN_TYPE_MODIFIER 0x80
#define CBOR_MAJOR_NONE_TYPE_ARRAY_INDEFINITE_LEN \
CBOR_MAJOR_TYPE_ARRAY + QCBOR_INDEFINITE_LEN_TYPE_MODIFIER
#define CBOR_MAJOR_NONE_TYPE_MAP_INDEFINITE_LEN \
CBOR_MAJOR_TYPE_MAP + QCBOR_INDEFINITE_LEN_TYPE_MODIFIER
#define CBOR_MAJOR_NONE_TYPE_SIMPLE_BREAK \
CBOR_MAJOR_TYPE_SIMPLE + QCBOR_INDEFINITE_LEN_TYPE_MODIFIER
/* Value of QCBORItem.val.string.len when the string length is
* indefinite. Used temporarily in the implementation and never
* returned in the public interface.
*/
#define QCBOR_STRING_LENGTH_INDEFINITE SIZE_MAX
/* The number of elements in a C array of a particular type */
#define C_ARRAY_COUNT(array, type) (sizeof(array)/sizeof(type))
#ifdef __cplusplus
}
#endif
#endif /* qcbor_private_h */