QCBOR
|
Go to the source code of this file.
Data Structures | |
struct | QCBORExpAndMantissa |
struct | _QCBORItem |
Typedefs | |
typedef struct _QCBORItem | QCBORItem |
typedef UsefulBuf(* | QCBORStringAllocate) (void *pAllocateCxt, void *pOldMem, size_t uNewSize) |
Prototype for the implementation of a string allocator. | |
typedef struct _QCBORDecodeContext | QCBORDecodeContext |
Enumerations | |
enum | QCBORDecodeMode { QCBOR_DECODE_MODE_NORMAL = 0 , QCBOR_DECODE_MODE_MAP_STRINGS_ONLY = 0x01 , QCBOR_DECODE_MODE_MAP_AS_ARRAY = 0x02 , QCBOR_DECODE_ALLOW_UNPROCESSED_TAG_NUMBERS = 0x04 , QCBOR_DECODE_NO_INDEF_LENGTH = 0x08 , QCBOR_DECODE_ONLY_PREFERRED_NUMBERS = 0x10 , QCBOR_DECODE_ONLY_PREFERRED_BIG_NUMBERS = 0x20 , QCBOR_DECODE_ONLY_SORTED_MAPS = 0x40 , QCBOR_DECODE_ONLY_REDUCED_FLOATS = 0x80 , QCBOR_DECODE_DISALLOW_DCBOR_SIMPLES = 0x100 , QCBOR_DECODE_MODE_PREFERRED , QCBOR_DECODE_MODE_CDE , QCBOR_DECODE_MODE_DCBOR } |
Functions | |
void | QCBORDecode_Init (QCBORDecodeContext *pCtx, UsefulBufC EncodedCBOR, QCBORDecodeMode uConfigFlags) |
QCBORError | QCBORDecode_SetMemPool (QCBORDecodeContext *pCtx, UsefulBuf MemPool, bool bAllStrings) |
Set up the MemPool string allocator for indefinite-length strings. | |
static void | QCBORDecode_SetUpAllocator (QCBORDecodeContext *pCtx, QCBORStringAllocate pfAllocateFunction, void *pAllocateContext, bool bAllStrings) |
Sets up a custom string allocator for indefinite-length strings. | |
void | QCBORDecode_VGetNext (QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem) |
Get the next item (integer, byte string, array...) in the preorder traversal of the CBOR tree. | |
QCBORError | QCBORDecode_GetNext (QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem) |
Preorder traversal like QCBORDecode_VGetNext() without use of internal error state. | |
void | QCBORDecode_VGetNextConsume (QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem) |
Get the next item, fully consuming it if it is a map or array. | |
void | QCBORDecode_VPeekNext (QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem) |
Get the next data item without consuming it. | |
QCBORError | QCBORDecode_PeekNext (QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem) |
Get the next data item without consuming it without use of internal error state. | |
static uint32_t | QCBORDecode_Tell (QCBORDecodeContext *pCtx) |
Get the current traversal cursort offset in the input CBOR. | |
QCBORError | QCBORDecode_EndCheck (QCBORDecodeContext *pCtx) |
Tell whether cursor is at end of the input. | |
QCBORError | QCBORDecode_Finish (QCBORDecodeContext *pCtx) |
Check that a decode completed successfully. | |
QCBORError | QCBORDecode_PartialFinish (QCBORDecodeContext *pCtx, size_t *puConsumed) |
Return number of bytes consumed so far. | |
static UsefulBufC | QCBORDecode_RetrieveUndecodedInput (QCBORDecodeContext *pCtx) |
Retrieve the undecoded input buffer. | |
static QCBORError | QCBORDecode_GetError (QCBORDecodeContext *pCtx) |
Get the decoding error. | |
static QCBORError | QCBORDecode_GetAndResetError (QCBORDecodeContext *pCtx) |
Get and reset the decoding error. | |
static bool | QCBORDecode_IsNotWellFormedError (QCBORError uErr) |
Whether an error indicates non-well-formed CBOR. | |
static bool | QCBORDecode_IsUnrecoverableError (QCBORError uErr) |
Whether a decoding error is recoverable. | |
static void | QCBORDecode_SetError (QCBORDecodeContext *pCtx, QCBORError uError) |
Manually set error condition, or set user-defined error. | |
void | QCBORDecode_CompatibilityV1 (QCBORDecodeContext *pCtx) |
[Deprecated] Configure CBOR decoder context for QCBOR v1 compatibility. | |
This section discusses decoding assuming familiarity with the general description of this encoder-decoder in section Overview.
Encoded CBOR has a tree structure where the leaf nodes are non-aggregate types like integers and strings and the intermediate nodes are either arrays or maps. Fundamentally, CBOR decoding is a pre-order traversal of this tree with CBOR sequences a minor exception. Calling QCBORDecode_GetNext() repeatedly will perform this. QCBOR maintains an internal traversal cursor. It is possible to decode any CBOR by only calling QCBORDecode_GetNext(), though this doesn't take advantage of many QCBOR features.
QCBORDecode_GetNext() returns a 56 byte structure called QCBORItem that describes the decoded item including:
For strings, this structure contains a pointer and length back into the original data.
Most of the tags that QCBOR supports directly are decoded into a representation in QCBORItem.
A string allocator must be used when decoding indefinite length strings. See QCBORDecode_SetMemPool() or QCBORDecode_SetUpAllocator(). QCBORItem indicates if a string was allocated with the string allocator.
This pre-order traversal gives natural decoding of arrays where the array members are taken in order. Maps can be decoded this way too, but the SpiffyDecode APIs that allow searching maps by label are often more convenient.
RFC 7049 called tags "optional". This was a mistake. They specify critical type information that can't be ignored by decoders.
QCBOR v1 always returns the tag numbers on an item in QCBORItem and leaves it up to the caller to check. Probably most callers don't know this and never added the check. There decode implementations are tolerant of random tag numbers and they shouldn't be.
QCBOR v2 requires tags numbers to be processed by QCBORDecode_GetNextTagNumber(). If they are not an error will be returned.
This new behavior saves the caller from having to do this check (that they probably didn't know they neeeded). It is more correct behavior.
This behavior is not backwards compatible with v1. The v1 behavior can be restored with QCBOR_DECODE_ALLOW_UNPROCESSED_TAG_NUMBERS. However, the v2 behavior is more correct, so this configuration should not be used.
The simplest way to handle decoding errors is to make use of the internal error tracking. The only error code check necessary is at the end when QCBORDecode_Finish() is called. To do this:
Once an encoding error has been encountered, the error state is entered and further decoding function calls will do nothing. It is safe to continue calling decoding functions after an error. No error checking is necessary making the code to decode a protocol simpler. The two exceptions are QCBORDecode_GetNext() and QCBORDecode_PeekNext() which will try to decode even if the decoder is in the error state. Use QCBORDecode_VGetNext() and QCBORDecode_VPeekNext() instead.
While some protocols are simple enough to be decoded this way, many aren’t because the data items earlier in the protocol determine how later data items are to be decoded. In that case it is necessary to call QCBORDecode_GetError() to know the earlier items were successfully decoded before examining their value or type.
The internal decode error state can be reset by reinitializing the decoder or calling QCBORDecode_GetErrorAndReset(). Code calling QCBOR may take advantage of the internal error state to halt futher decoding and propagate errors it detects using QCBORDecode_SetError().
It is only useful to reset the error state by calling QCBORDecode_GetErrorAndReset() on recoverable errors. Examples of recoverable errors are a map entry not being found or integer overflow or underflow during conversion. Examples of unrecoverable errors are hitting the end of the input and array or map nesting beyond the limits of the implementation. See QCBORDecode_IsUnrecoverableError().Trying to reset and decode after an unrecoverable error will usually just lead to another error.
It is possible to use QCBORDecode_GetNext() and QCBORDecode_PeekNext() to decode an entire protocol. However, that is usually more work, more code and less convenient than using spiffy decode functions.
It is also possible to mix the use of QCBORDecode_GetNext() with QCBORDecode_VGetNext() and the spiffy decode functions, but QCBORDecode_GetError() must be called and return QCBOR_SUCCESS before QCBORDecode_GetNext() is called.
The effect of a decoding error on the traversal cursor position varies by the decoding method called. It is unaffected by spiffy decode methods that get items by map label. QCBORDecode_GetInt64InMapN() is an example of this. The traversal cursor will be advanced by most other decode methods even when there is a decode error, often leaving it in an indeterminate position. If it is necessary to continue to decoding after an error, QCBORDecode_Rewind() can be used to reset it to a known-good position.
When using spiffy decode methods to get an item by label from a map the whole map is internally traversed including nested arrays and maps. If there is any unrecoverable error during that traversal, the retrieval by label will fail. The unrecoverable error will be returned even if it is not because the item being sought is in error. Recoverable errors will be ignored unless they are on the item being sought, in which case the unrecoverable error will be returned. Unrecoverable errors are those indicated by QCBORDecode_IsUnrecoverableError().
#define QBCOR_TYPE_WRAPPED_CBOR 36 |
Encoded CBOR that is wrapped in a byte string. Often used when the CBOR is to be hashed for signing or HMAC. See also QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE. Data is in val.string
.
#define QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE 75 |
A CBOR sequence per RFC 8742. See also @ ref QBCOR_TYPE_WRAPPED_CBOR. Data is in val.string
.
#define QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH UINT16_MAX |
An array or map's length is indefinite when it has this value.
#define QCBOR_DECODE_MIN_MEM_POOL_SIZE 8 |
For the built-in string allocator available via QCBORDecode_SetMemPool(), this is the size overhead needed internally. The amount of memory available for decoded strings is the size of the buffer given to QCBORDecode_SetMemPool() less this amount.
This doesn't apply to custom string allocators, only to the one available via QCBORDecode_SetMemPool().
#define QCBOR_LAST_UNMAPPED_TAG (CBOR_TAG_INVALID16 - QCBOR_NUM_MAPPED_TAGS - 1) |
The largest value in utags
that is unmapped and can be used without mapping it through QCBORDecode_GetNthTagNumber().
#define QCBOR_MAX_DECODE_INPUT_SIZE (UINT32_MAX - 2) |
The maximum size of input to the decoder. Slightly less than UINT32_MAX
to make room for some special indicator values.
#define QCBOR_MAX_TAGS_PER_ITEM QCBOR_MAX_TAGS_PER_ITEM1 |
The maximum number of tags that may occur on an individual nested item. Typically 4.
#define QCBOR_TYPE_65BIT_NEG_INT 28 |
Special type for integers between -2^63 - 1 to -2^64 that can't be returned as QCBOR_TYPE_INT64 because they don't fit in an int64_t. The value is returned in val.uint64
, but this isn't the number transmitted. Do this arithmatic (carefully to avoid over/underflow) to get the value transmitted: - val.uint64 - 1. See QCBOREncode_AddNegativeUInt64() for a longer explanation and warning.
#define QCBOR_TYPE_ANY 1 |
Never used in QCBORItem. Used by functions that match QCBOR types.
#define QCBOR_TYPE_ARRAY 4 |
Type for an array. See comments on val.uCount
.
#define QCBOR_TYPE_BASE64 46 |
Text is base64 encoded in RFC 4648. The base64 encoding is NOT removed. Data is in val.string
.
#define QCBOR_TYPE_BASE64URL 45 |
Text is base64 URL encoded in RFC 4648. The base64 encoding is NOT removed. Data is in val.string
.
#define QCBOR_TYPE_BIGFLOAT 17 |
A floating-point number made of base-2 exponent and integer mantissa. See expAndMantissa and QCBOREncode_AddTBigFloat().
#define QCBOR_TYPE_BIGFLOAT_NEG_BIGMANTISSA 19 |
A floating-point number made of base-2 exponent and negative big number mantissa. See expAndMantissa and QCBOREncode_AddTBigFloatBigMantissa().
#define QCBOR_TYPE_BIGFLOAT_NEG_U64MANTISSA 83 |
A floating-point number made of base-2 exponent and negative big number mantissa. See expAndMantissa and QCBOREncode_AddTBigFloatBigMantissa().
#define QCBOR_TYPE_BIGFLOAT_POS_BIGMANTISSA 18 |
A floating-point number made of base-2 exponent and positive big number mantissa. See expAndMantissa and QCBOREncode_AddTBigFloatBigMantissa().
#define QCBOR_TYPE_BIGFLOAT_POS_U64MANTISSA 82 |
A floating-point number made of base-2 exponent and positive big number mantissa. See expAndMantissa and QCBOREncode_AddTBigFloatBigMantissa().
#define QCBOR_TYPE_BINARY_MIME 76 |
Binary MIME per RFC 2045. See also QCBOR_TYPE_MIME. Data is in val.string
.
#define QCBOR_TYPE_BREAK 31 |
Used internally; never returned
#define QCBOR_TYPE_BYTE_STRING 6 |
Type for a buffer full of bytes. Data is in val.string
.
#define QCBOR_TYPE_DATE_EPOCH 12 |
Type for integer seconds since Jan 1970 + floating-point fraction. Data is in val.epochDate
#define QCBOR_TYPE_DATE_STRING 11 |
Type for RFC 3339 date string, possibly with time zone. Data is in val.string
. Note this was previously in val.dateString
, however this is the same as val.string being the same type in same union. val.dateString will be deprecated..
#define QCBOR_TYPE_DAYS_EPOCH 78 |
Type for integer days since Jan 1 1970 described in RFC 8943. Data is in val.epochDays
#define QCBOR_TYPE_DAYS_STRING 77 |
Type for RFC 8943 date string, a date with no time or time zone info. Data is in val.string
#define QCBOR_TYPE_DECIMAL_FRACTION 14 |
A decimal fraction made of decimal exponent and integer mantissa. See expAndMantissa and QCBOREncode_AddTDecimalFraction().
#define QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM 16 |
A decimal fraction made of decimal exponent and negative big number mantissa. See expAndMantissa and QCBOREncode_AddTDecimalFractionBigMantissa().
#define QCBOR_TYPE_DECIMAL_FRACTION_NEG_U64 80 |
A decimal fraction made of decimal exponent and negative big number mantissa. See expAndMantissa and QCBOREncode_AddTDecimalFractionBigMantissa().
#define QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM 15 |
A decimal fraction made of decimal exponent and positive big number mantissa. See expAndMantissa and QCBOREncode_AddTDecimalFractionBigMantissa().
#define QCBOR_TYPE_DECIMAL_FRACTION_POS_U64 79 |
A decimal fraction made of decimal exponent and positive uint64_t . See QCBOREncode_AddTDecimalFractionBigMantissa().
#define QCBOR_TYPE_DOUBLE 27 |
Type for a double floating-point number. Data is in val.dfnum
.
#define QCBOR_TYPE_END_USER_DEFINED 255 |
End of user-defined data types.
#define QCBOR_TYPE_FALSE 20 |
Type for the simple value false.
#define QCBOR_TYPE_FLOAT 26 |
Type for a floating-point number. Data is in val.fnum
.
#define QCBOR_TYPE_INT64 2 |
Type for an integer that decoded either between INT64_MIN
and INT32_MIN
or INT32_MAX
and INT64_MAX
. Data is in member val.int64
. See also QCBOR_TYPE_65BIT_NEG_INT
#define QCBOR_TYPE_MAP 5 |
Type for a map. See comments on val.uCount
.
#define QCBOR_TYPE_MAP_AS_ARRAY 32 |
For QCBOR_DECODE_MODE_MAP_AS_ARRAY decode mode, a map that is being traversed as an array. See QCBORDecode_Init()
#define QCBOR_TYPE_MIME 48 |
Non-binary MIME per RFC 2045. See also QCBOR_TYPE_BINARY_MIME. Data is in val.string
.
#define QCBOR_TYPE_NEGBIGNUM 10 |
Type for a negative big number. Data is in val.bignum
, a pointer and a length. Type 1 integers in the range of [-2^64, -2^63 - 1] are returned in this type. One must be subtracted from what is returned to get the actual value. This is because of the way CBOR negative numbers are represented. QCBOR doesn't do this because it can't be done without storage allocation and QCBOR avoids storage allocation for the most part. For example, if 1 is subtraced from a negative big number that is the two bytes 0xff 0xff, the result would be 0x01 0x00 0x00, one byte longer than what was received. See QCBORDecode_StringsTagCB(). and CBOR_TAG_NEG_BIGNUM.
#define QCBOR_TYPE_NONE 0 |
The data type is unknown, unset or invalid.
#define QCBOR_TYPE_NULL 22 |
Type for the simple value null.
#define QCBOR_TYPE_POSBIGNUM 9 |
Type for a positive big number. Data is in val.bignum
, a pointer and a length. See QCBORDecode_StringsTagCB() and CBOR_TAG_POS_BIGNUM.
#define QCBOR_TYPE_REGEX 47 |
PERL-compatible regular expression. Data is in val.string
.
#define QCBOR_TYPE_START_USER_DEFINED 128 |
Start of user-defined data types. The range is mainly for user-defined tag content decoders. See QCBORTagContentCallBack
#define QCBOR_TYPE_TAG_NUMBER 127 |
Used internally; never returned
#define QCBOR_TYPE_TEXT_STRING 7 |
Type for a UTF-8 string. It is not NULL-terminated. See QCBOREncode_AddText() for a discussion of line endings in CBOR. Data is in val.string
.
#define QCBOR_TYPE_TRUE 21 |
Type for the simple value true.
#define QCBOR_TYPE_UINT64 3 |
Type for an integer that decoded to a more than INT64_MAX
and UINT64_MAX
. Data is in member val.uint64
.
#define QCBOR_TYPE_UKNOWN_SIMPLE 13 |
The CBOR major type "simple" has a small integer value indicating what it is. The standard CBOR simples are true, false, null, undef (values 20-23) and float-point numbers (values 25-27). The values 0-19 and 32-255 are unassigned and may be used if registered with in the IANA Simple Values Registry. If these unassigned simple values occur in the input they will be decoded as this. The value is in val.uSimple
.
#define QCBOR_TYPE_UNDEF 23 |
Type for the simple value undef.
#define QCBOR_TYPE_URI 44 |
A URI as defined in RFC 3986. Data is in val.string
.
#define QCBOR_TYPE_UUID 49 |
Binary UUID per RFC 4122. Data is in val.string
.
typedef struct _QCBORDecodeContext QCBORDecodeContext |
QCBORDecodeContext holds the context for decoding CBOR. It is about 300 bytes, so it can go on the stack. The contents are opaque, and the caller should not access any internal items. A context may be re-used serially as long as it is re initialized.
typedef struct _QCBORItem QCBORItem |
This holds a decoded data item. It is returned by the QCBORDecode_GetNext(), the principle decoding function. It holds the type, value, label, tags and other details of the decoded data item.
This is typically 56 bytes on 64-bit CPUs and 52 bytes on 32-bit CPUs (the CPU and the system's ABI determine this size).
typedef UsefulBuf(* QCBORStringAllocate) (void *pAllocateCxt, void *pOldMem, size_t uNewSize) |
Prototype for the implementation of a string allocator.
[in] | pAllocateCxt | Pointer to context for the particular allocator implementation. Its contents depend on how a particular string allocator works. Typically, it will contain a pointer to the memory pool and some booking keeping data. |
[in] | pOldMem | Points to some memory previously allocated that is either to be freed or to be reallocated to be larger. It is NULL for new allocations and when called as the destructor. |
[in] | uNewSize | Size of memory to be allocated or new size for a chunk being reallocated. Zero when called to free memory or when called as the destructor. |
This function must be implemented for a custom string allocator. See QCBORDecode_SetUpAllocator().
This is not needed if the built-in string allocator available through QCBORDecode_SetMemPool() is used.
After being set up by a call to QCBORDecode_SetUpAllocator(), this is called back in four modes:
uNewSize
is the amount to allocate. pOldMem
is NULL
.uNewSize
is 0. pOldMem
points to the memory to be freed. When the decoder calls this, it will always be for the most recent block that was either allocated or reallocated.pOldMem
is the block to reallocate. uNewSize
is its new size. When the decoder calls this, it will always be for the most recent block that was either allocated or reallocated.pOldMem
is NULL
and uNewSize
is 0. This is called when the decoding is complete by QCBORDecode_Finish(). Usually, the strings allocated by a string allocator are in use after the decoding is completed so this usually will not free those strings. Many string allocators will not need to do anything in this mode.The strings allocated by this will have uDataAlloc
set to true in the QCBORItem when they are returned. The user of the strings will have to free them. How they free them, depends on the design of the string allocator.
enum QCBORDecodeMode |
These are the decode configuration flags that can be or'd together and passed to QCBORDecode_Init().
Enumerator | |
---|---|
QCBOR_DECODE_MODE_NORMAL | Normal decoding with no flags set. |
QCBOR_DECODE_MODE_MAP_STRINGS_ONLY | Required map labels to be strings. If not QCBOR_ERR_MAP_LABEL_TYPE occurs. |
QCBOR_DECODE_MODE_MAP_AS_ARRAY | Causes maps to be treated as special arrays so all types of map labels can be decoded.. They will be returned with special |
QCBOR_DECODE_ALLOW_UNPROCESSED_TAG_NUMBERS | Makes QCBOR v2 tag decoding compatible with QCBOR v1. The error QCBOR_ERR_UNPROCESSED_TAG_NUMBER is not returned. See v2-Tag-Decoding and QCBORDecode_CompatibilityV1(). |
QCBOR_DECODE_NO_INDEF_LENGTH | Error out on indefinite length strings, arrays and maps. |
QCBOR_DECODE_ONLY_PREFERRED_NUMBERS | Error out if integers or floats are encoded as non-preferred. |
QCBOR_DECODE_ONLY_PREFERRED_BIG_NUMBERS | If big numbers that will fit into normal integers are encountered error XXX will occur. This is to comply with big number preferred serialization. |
QCBOR_DECODE_ONLY_SORTED_MAPS | If maps are not sorted, error QCBOR_ERR_UNSORTED occurs. This is makes map decoding take more CPU time, but that is probably only of consequence with big maps on small CPUs. |
QCBOR_DECODE_ONLY_REDUCED_FLOATS | If whole number floats are present (they are not encoded as integers), error QCBOR_ERR_DCBOR_CONFORMANCE occurs. This is as required for dCBOR. |
QCBOR_DECODE_DISALLOW_DCBOR_SIMPLES | dCBOR allows only the simple types true, false and NULL This enforces that. |
QCBOR_DECODE_MODE_PREFERRED | This checks that the input is encoded with preferred serialization. The checking is performed as each item is decoded. If no QCBORDecode_GetXxx() is called for an item, there's no check on that item. Preferred serialization was first defined in section 4.1 of RFC 8949, but is more sharply in draft-ietf-cbor-cde. Summarizing, the requirements are: the use of definite-length encoding only, integers, including string lengths and tags, must be in shortest form, and floating-point numbers must be reduced to shortest form all the way to half-precision. |
QCBOR_DECODE_MODE_CDE | This checks that maps in the input are sorted by label as described in RFC 8949 section 4.2.1. This also performs duplicate label checking. This mode adds considerable CPU-time expense to decoding, though it is probably only of consequence for large inputs on slow CPUs. This also performs all the checks that QCBOR_DECODE_MODE_PREFERRED does. |
QCBOR_DECODE_MODE_DCBOR | This requires integer-float unification. It performs all the checks that QCBOR_DECODE_MODE_CDE does. |
void QCBORDecode_CompatibilityV1 | ( | QCBORDecodeContext * | pCtx | ) |
[Deprecated] Configure CBOR decoder context for QCBOR v1 compatibility.
[in] | pCtx | The context to configure. |
This performs two actions to make QCBOR v2 decoding compatible with v1.
First, it sets QCBOR_DECODE_ALLOW_UNPROCESSED_TAG_NUMBERS which causes no error to be returned when un processed tag numbers are encountered.
Second, it installs all the same tag content handlers that were hardwired in v1. QCBORDecode_InstallTagDecoders(pMe, QCBORDecode_TagDecoderTablev1, NULL);
This is listed as deprecated even though it is new in QCBOR v2 because it recommended that v1 mode not be used because the tag number processing is too loose. See v2-Tag-Decoding.
This links in a fair bit of object code for all the tag content handlers that were always present in v1. To get the v1 tag number behavior without the object code for the tag content handlers, pass QCBOR_DECODE_ALLOW_UNPROCESSED_TAG_NUMBERS to QCBORDecode_Init().
QCBORError QCBORDecode_EndCheck | ( | QCBORDecodeContext * | pCtx | ) |
Tell whether cursor is at end of the input.
[in] | pCtx | The decoder context. |
This returns the same as QCBORDecode_GetError() except that QCBOR_ERR_NO_MORE_ITEMS is returned if the travseral cursor is at the end of the CBOR input bytes (not the end of an entered array or map).
QCBORError QCBORDecode_Finish | ( | QCBORDecodeContext * | pCtx | ) |
Check that a decode completed successfully.
[in] | pCtx | The context to check. |
Please see Decode Errors Overview.
This should always be called at the end of a decode to determine if it completed successfully. For some protocols, checking the return value here may be the only error check necessary.
This returns the internal tracked error if the decoder is in the error state, the same one returned by QCBORDecode_GetError(). This performs final checks at the end of the decode, and may also return QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN or QCBOR_ERR_EXTRA_BYTES.
This calls the destructor for the string allocator, if one is in use. Because of this, It can't be called multiple times like QCBORDecode_PartialFinish().
Some CBOR protocols use a CBOR sequence defined in RFC 8742. A CBOR sequence typically doesn't start out with a map or an array. The end of the CBOR is determined in some other way, perhaps by external framing, or by the occurrence of some particular CBOR data item or such. The buffer given to decode must start out with valid CBOR, but it can have extra bytes at the end that are not CBOR or CBOR that is to be ignored.
QCBORDecode_Finish() should still be called when decoding CBOR sequences to check that the input decoded was well-formed. If the input was well-formed and there are extra bytes at the end QCBOR_ERR_EXTRA_BYTES will be returned. This can be considered a successful decode. See also QCBORDecode_PartialFinish().
|
inlinestatic |
Get and reset the decoding error.
[in] | pCtx | The decoder context. |
This returns the same as QCBORDecode_GetError() and also resets the error state to QCBOR_SUCCESS.
|
inlinestatic |
Get the decoding error.
[in] | pCtx | The decoder context. |
Please see Decode Errors Overview.
The returns the tracked internal error code. All decoding functions set the internal error except QCBORDecode_GetNext() and QCBORDecode_PeekNext().
For many protocols it is only necessary to check the return code from QCBORDecode_Finish() at the end of all the decoding. It is unnecessary to call this.
For some protocols, the decoding sequence depends on the types, values or labels of data items. If so, this must be called before using decoded values to know the decode was a success and the type, value and label is valid.
Some errors, like integer conversion overflow, date string format may not affect the flow of a protocol. The protocol decoder may wish to proceed even if they occur. In that case QCBORDecode_GetAndResetError() may be called after these data items are fetched.
QCBORError QCBORDecode_GetNext | ( | QCBORDecodeContext * | pCtx, |
QCBORItem * | pDecodedItem ) |
Preorder traversal like QCBORDecode_VGetNext() without use of internal error state.
[in] | pCtx | The decoder context. |
[out] | pDecodedItem | The decoded CBOR item. |
This is the same as QCBORDecode_VGetNext() except it doesn't set the internal decoding error and will attempt to decode even if the decoder is in the error state.
void QCBORDecode_Init | ( | QCBORDecodeContext * | pCtx, |
UsefulBufC | EncodedCBOR, | ||
QCBORDecodeMode | uConfigFlags ) |
Initialize the CBOR decoder context.
[in] | pCtx | The context to initialize. |
[in] | EncodedCBOR | The buffer with CBOR encoded bytes to be decoded. |
[in] | uConfigFlags | See QCBORDecodeMode. |
Initialize the decoder context with the encoded CBOR to be decoded.
For typical use, uConfigFlags
is zero (QCBOR_DECODE_MODE_NORMAL). See configuration flags that can be or'd defined in QCBORDecodeMode.
If indefinite-length strings are to be decoded, then QCBORDecode_SetMemPool() or QCBORDecode_SetUpAllocator() must be additionally called to set up a string allocator.
|
inlinestatic |
Whether an error indicates non-well-formed CBOR.
[in] | uErr | The QCBOR error code. |
true
if the error code indicates non-well-formed CBOR.
|
inlinestatic |
Whether a decoding error is recoverable.
[in] | uErr | The QCBOR error code. |
true
if the error code indicates and uncrecoverable error.When an error is unrecoverable, no further decoding of the input is possible. CBOR is a compact format with almost no redundancy so errors like incorrect lengths or array counts are unrecoverable. Unrecoverable errors also occur when implementation limits such as the limit on array and map nesting are encountered. When the built-in decoding of a tag like an epoch date encounters an error such as a data item of an unexpected type, this is also an unrecoverable error because the internal decoding doesn't try to decode everything in the tag.
The unrecoverable errors are a range of the errors in QCBORError.
QCBORError QCBORDecode_PartialFinish | ( | QCBORDecodeContext * | pCtx, |
size_t * | puConsumed ) |
Return number of bytes consumed so far.
[in] | pCtx | The context to check. |
[out] | puConsumed | The number of bytes consumed so far. May be NULL . |
This is primarily for partially decoding CBOR sequences. It is the same as QCBORDecode_Finish() except it returns the number of bytes consumed and doesn't call the destructor for the string allocator (See QCBORDecode_SetMemPool()).
When this is called before all input bytes are consumed, QCBOR_ERR_EXTRA_BYTES will be returned as QCBORDecode_Finish() does. For typical use of this, that particular error is disregarded.
Decoding with the same QCBORDecodeContext can continue after calling this and this may be called many times.
Another way to resume decoding is to call QCBORDecode_Init() with the bytes not decoded, but this only works on CBOR sequences when the decoding stopped with no open arrays, maps or byte strings.
QCBORError QCBORDecode_PeekNext | ( | QCBORDecodeContext * | pCtx, |
QCBORItem * | pDecodedItem ) |
Get the next data item without consuming it without use of internal error state.
[in] | pCtx | The decoder context. |
[out] | pDecodedItem | The decoded CBOR item. |
This is the same as QCBORDecode_VPeekNext() except it doesn't set the internal decoding error and will attempt to decode even if the decoder is in the error state.
|
inlinestatic |
Retrieve the undecoded input buffer.
[in] | pCtx | The decode context. |
A simple convenience method, should it be useful to get the original input back.
|
inlinestatic |
Manually set error condition, or set user-defined error.
[in] | pCtx | The decoder context. |
[in] | uError | The error code to set. |
Once set, none of the QCBORDecode methods will do anything and the error code set will stay until cleared with QCBORDecode_GetAndResetError(). A user-defined error can be set deep in some decoding layers to short-circuit further decoding and propagate up.
When the error condition is set, QCBORDecode_VGetNext() will always return an item with data and label type as QCBOR_TYPE_NONE.
The main intent of this is to set a user-defined error code in the range of QCBOR_ERR_FIRST_USER_DEFINED to QCBOR_ERR_LAST_USER_DEFINED, but it is OK to set QCBOR-defined error codes too.
QCBORError QCBORDecode_SetMemPool | ( | QCBORDecodeContext * | pCtx, |
UsefulBuf | MemPool, | ||
bool | bAllStrings ) |
Set up the MemPool string allocator for indefinite-length strings.
[in] | pCtx | The decode context. |
[in] | MemPool | The pointer and length of the memory pool. |
[in] | bAllStrings | If true, all strings, even of definite length, will be allocated with the string allocator. |
UINT32_MAX
or less than QCBOR_DECODE_MIN_MEM_POOL_SIZE.Indefinite-length strings (text and byte) cannot be decoded unless there is a string allocator configured. MemPool is a simple built-in string allocator that allocates bytes from a memory pool handed to it by calling this function. The memory pool is just a pointer and length for some block of memory that is to be used for string allocation. It can come from the stack, heap or other.
The memory pool must be QCBOR_DECODE_MIN_MEM_POOL_SIZE plus space for all the strings allocated. There is no overhead per string allocated. A conservative way to size this buffer is to make it the same size as the CBOR being decoded plus QCBOR_DECODE_MIN_MEM_POOL_SIZE.
This memory pool is used for all indefinite-length strings that are text strings or byte strings, including strings used as labels.
The pointers to strings in QCBORItem will point into the memory pool set here. They do not need to be individually freed. Just discard the buffer when they are no longer needed.
If bAllStrings
is set, then the size will be the overhead plus the space to hold all strings, definite and indefinite-length, value or label. The advantage of this is that after the decode is complete, the original memory holding the encoded CBOR does not need to remain valid.
This simple allocator is not hard linked to the QCBOR decoder. Assuming dead-stripping of unused symbols is being performed, this simple allocator will not be linked in unless QCBORDecode_SetMemPool() is called.
See also QCBORDecode_SetUpAllocator() to set up a custom allocator if this one isn't sufficient.
|
inlinestatic |
Sets up a custom string allocator for indefinite-length strings.
[in] | pCtx | The decoder context to set up an allocator for. |
[in] | pfAllocateFunction | Pointer to function that will be called by QCBOR for allocations and frees. |
[in] | pAllocateContext | Context passed to pfAllocateFunction . |
[in] | bAllStrings | If true, all strings, even of definite length, will be allocated with the string allocator. |
Indefinite-length strings (text and byte) cannot be decoded unless a string allocator is configured. QCBORDecode_SetUpAllocator() allows the caller to configure an external string allocator implementation if the internal string allocator is unsuitable. See QCBORDecode_SetMemPool() to configure the internal allocator.
The string allocator configured here is a custom one designed and implemented by the caller. See QCBORStringAllocate for the requirements for a string allocator implementation.
A malloc-based string external allocator can be obtained by calling QCBORDecode_MakeMallocStringAllocator()
. It will return a function and pointer that can be given here as pAllocatorFunction
and pAllocatorContext
. It uses standard malloc()
so free()
must be called on all strings marked by uDataAlloc
==
1
or uLabelAlloc
==
1
in QCBORItem. Note this is in a separate GitHub repository.
|
inlinestatic |
Get the current traversal cursort offset in the input CBOR.
[in] | pCtx | The decoder context. |
UINT32_MAX
.The position returned is always the start of the next item that would be next decoded with QCBORDecode_VGetNext(). The cursor returned may be at the end of the input in which case the next call to QCBORDecode_VGetNext() will result in the QCBOR_ERR_NO_MORE_ITEMS. See also QCBORDecode_AtEnd().
If the decoder is in error state from previous decoding, UINT32_MAX
is returned.
When decoding map items, the position returned is always of the label, never the value.
For indefinite-length arrays and maps, the break byte is consumed when the last item in the array or map is consumed so the cursor is at the next item to be decoded as expected.
There are some special rules for the traversal cursor when fetching map items by label. See the description of SpiffyDecode.
When traversal is bounded because an array or map has been entered (e.g., QCBORDecode_EnterMap()) and all items in the array or map have been consumed, the position returned will be of the item outside of the array or map. The array or map must be exited before QCBORDecode_VGetNext() will decode it.
In many cases the position returned will be in the middle of an array or map. It will not be possible to start decoding at that location with another instance of the decoder and go to the end. It is not valid CBOR. If the input is a CBOR sequence and the position is not in the moddle of an array or map then it is possible to decode to the end.
There is no corresponding seek method because it is too complicated to restore the internal decoder state that tracks nesting.
void QCBORDecode_VGetNext | ( | QCBORDecodeContext * | pCtx, |
QCBORItem * | pDecodedItem ) |
Get the next item (integer, byte string, array...) in the preorder traversal of the CBOR tree.
[in] | pCtx | The decoder context. |
[out] | pDecodedItem | The decoded CBOR item. |
pDecodedItem
is filled from the decoded item. Generally, the following data is returned in the structure:
uDataType
which indicates which member of the val
union the data is in. This decoder figures out the type based on the CBOR major type, the CBOR "additionalInfo", and sometimes by preceding tag numbers.See QCBORItem for all the details about what is returned.
This function handles arrays and maps. When an array or map is first encountered a QCBORItem will be returned with major type QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP. QCBORItem.val.uNestLevel
gives the nesting level of the opening of the array or map. When the next item is fetched, it will be the first one in the array or map and its QCBORItem.val.uNestLevel
will be one more than that of the opening of the array or map.
Nesting level 0 is the top-most nesting level. The first item decoded always has nesting level 0. A map or array at the top level has nesting level 0 and the members of the array or map have nesting level 1.
Here is an example of how the nesting level is reported for a CBOR sequence with no arrays or maps at all.
Here is an example of how the nesting level is reported for a CBOR sequence with a simple array and some top-level items.
Here's a more complex example that is not a CBOR sequence
In QCBORItem, uNextNestLevel
is the nesting level for the next call to QCBORDecode_VGetNext(). It indicates if any maps or arrays were closed out during the processing of the just-fetched QCBORItem. This processing includes a look-ahead for any breaks that close out indefinite-length arrays or maps. This value is needed to be able to understand the hierarchical structure. If uNextNestLevel
is not equal to uNestLevel
the end of the current map or array has been encountered. This works for both definite and indefinite-length arrays so it is the best way to find the end of a map or array. Alternatively, for definite-length arrays, QCBORItem.val.uCount
contains the number of items in the array. For indefinite-length arrays, QCBORItem.val.uCount
is UINT16_MAX
.
If a decoding error occurs or previously occured, uDataType
and uLabelType
will be set to QCBOR_TYPE_NONE. If there is no need to know the specific error, it is sufficient to check for QCBOR_TYPE_NONE.
Errors fall in several categories:
x | Not well-formed errors || | QCBOR_ERR_HIT_END | Partial data item; need more input bytes to complete decoding | | QCBOR_ERR_UNSUPPORTED | Input contains CBOR with reserved additional info values | | QCBOR_ERR_BAD_TYPE_7 | Simple value encoded as two-byte integer rather than one | | QCBOR_ERR_BAD_BREAK | Break occured outside an indefinite-length map or such | | QCBOR_ERR_BAD_INT | Length of integer is bad | | QCBOR_ERR_INDEFINITE_STRING_CHUNK | One of the chunks in indefinite-length string is the wrong type | | Invalid CBOR || | QCBOR_ERR_NO_MORE_ITEMS | Need more input data items to decode | | QCBOR_ERR_BAD_EXP_AND_MANTISSA | The structure of a big float or big number is invalid | | QCBOR_ERR_UNRECOVERABLE_TAG_CONTENT | The content of a tag is of the wrong type | | Implementation Limits || | QCBOR_ERR_INT_OVERFLOW | Input integer smaller than INT64_MIN | | QCBOR_ERR_ARRAY_DECODE_TOO_LONG | Array or map has more elements than can be handled | | QCBOR_ERR_DATE_OVERFLOW | Date larger than can be handled | | QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP | Nesting deeper than can be handled | | QCBOR_ERR_STRING_TOO_LONG | Encountered a string longer than size_t can hold less 4 bytes | | QCBOR_ERR_TOO_MANY_TAGS | Tag nesting deeper than limit, typically 4 | | Configuration errors || | QCBOR_ERR_NO_STRING_ALLOCATOR | Encountered indefinite-length string with no allocator configured | | QCBOR_ERR_MAP_LABEL_TYPE | A map label that is not a string on an integer | | QCBOR_ERR_HALF_PRECISION_DISABLED | Half-precision input, but disabled in QCBOR library | | QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED | Indefinite-length input, but disabled in QCBOR library | | QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED | Indefinite-length input, but disabled in QCBOR library | | QCBOR_ERR_ALL_FLOAT_DISABLED | Library compiled with floating-point support turned off. | | Resource exhaustion errors || | QCBOR_ERR_STRING_ALLOCATE | The string allocator is unable to allocate more memory |
void QCBORDecode_VGetNextConsume | ( | QCBORDecodeContext * | pCtx, |
QCBORItem * | pDecodedItem ) |
Get the next item, fully consuming it if it is a map or array.
[in] | pCtx | The decoder context. |
[out] | pDecodedItem | The decoded CBOR item. |
pItem
returned is the same as QCBORDecode_VGetNext(). If the item is an array or map, the entire contents of the array or map will be consumed leaving the cursor after the array or map.
If an array or map is being consumed by this, an error will occur if any of the items in the array or map are in error.
If the item is a tag the contents of which is an array or map, like a big float, pItem
will identify it as such and the contents will be consumed, but the validity of the tag won't be checked other than for being well-formed.
In order to go back to decode the contents of an array or map consumed by this, the decoder must be rewound using QCBORDecode_Rewind().
void QCBORDecode_VPeekNext | ( | QCBORDecodeContext * | pCtx, |
QCBORItem * | pDecodedItem ) |
Get the next data item without consuming it.
[in] | pCtx | The decoder context. |
[out] | pDecodedItem | The decoded CBOR item. |
This is the same as QCBORDecode_VGetNext() but does not consume the data item. This only looks ahead one item. Calling it repeatedly will just return the same item over and over.
This uses about 200 bytes of stack, far more than anything else here in qcbor_main_decode.h because it saves a copy of most of the decode context temporarily.
This is useful for looking ahead to determine the type of a data item to know which type-specific spiffy decode function to call or decoding protocols where the types of later data items depending on type of earlier ones.
The error must be retrieved with QCBORDecode_GetError() and checked to know the peek was successful before referencing the contents of pDecodedItem
.