|
QCBOR
|
Go to the source code of this file.
Data Structures | |
| struct | QCBORExpAndMantissa |
| struct | _QCBORItem |
| struct | QCBORTagListIn |
| struct | QCBORTagListOut |
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 = 1 , QCBOR_DECODE_MODE_MAP_AS_ARRAY = 2 } |
Functions | |
| void | QCBORDecode_Init (QCBORDecodeContext *pCtx, UsefulBufC EncodedCBOR, QCBORDecodeMode nMode) |
| QCBORError | QCBORDecode_SetMemPool (QCBORDecodeContext *pCtx, UsefulBuf MemPool, bool bAllStrings) |
| Set up the MemPool string allocator for indefinite-length strings. | |
| 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. | |
| uint64_t | QCBORDecode_GetNthTag (QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint32_t uIndex) |
| Returns the tag numbers for an item. | |
| uint64_t | QCBORDecode_GetNthTagOfLast (const QCBORDecodeContext *pCtx, uint32_t uIndex) |
| Returns the tag numbers for last-decoded item. | |
| 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. | |
| static int | QCBOR_Int64ToInt32 (int64_t src, int32_t *dest) |
| Convert int64_t to smaller integers safely. | |
| static int | QCBOR_Int64ToInt16 (int64_t src, int16_t *dest) |
| static int | QCBOR_Int64ToInt8 (int64_t src, int8_t *dest) |
| static int | QCBOR_Int64ToUInt32 (int64_t src, uint32_t *dest) |
| static int | QCBOR_Int64ToUInt16 (int64_t src, uint16_t *dest) |
| static int | QCBOR_Int64ToUInt8 (int64_t src, uint8_t *dest) |
| static int | QCBOR_Int64ToUInt64 (int64_t src, uint64_t *dest) |
| void | QCBORDecode_SetCallerConfiguredTagList (QCBORDecodeContext *pCtx, const QCBORTagListIn *pTagList) |
| Deprecated – Configure list of caller-selected tags to be recognized. | |
| bool | QCBORDecode_IsTagged (QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint64_t uTag) |
| Deprecated – Determine if a CBOR item is a particular tag. | |
| QCBORError | QCBORDecode_GetNextWithTags (QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem, QCBORTagListOut *pTagList) |
| Deprecated – Gets the next item including full list of tags for item. | |
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.
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_GetAndResetError(). 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_GetAndResetError() 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().
If QCBOR_DISABLE_TAGS is defined, all code for decoding tags will be omitted reducing the core decoder, QCBORDecode_VGetNext(), by about 400 bytes. If a tag number is encountered in the decoder input the unrecoverable error QCBOR_ERR_TAGS_DISABLED will be returned. No input with tags can be decoded.
Decode functions like QCBORDecode_GetEpochDate() and QCBORDecode_GetDecimalFraction() that can decode the tag content even if the tag number is absent are still available. Typically they won't be linked in because of dead stripping. The uTagRequirement parameter has no effect, but if it is QCBOR_TAG_REQUIREMENT_TAG, QCBOR_ERR_TAGS_DISABLED will be set.
| #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_Int64UToInt16 QCBOR_Int64ToUInt16 |
https://github.com/laurencelundblade/QCBOR/pull/243 For backwards compatibility
| #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_GetNthTag().
| #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_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_BIGNUM 19 |
A floating-point number made of base-2 exponent and negative big number mantissa. See expAndMantissa and QCBOREncode_AddTBigFloatBigNum().
| #define QCBOR_TYPE_BIGFLOAT_POS_BIGNUM 18 |
A floating-point number made of base-2 exponent and positive big number mantissa. See expAndMantissa and QCBOREncode_AddTBigFloatBigNum().
| #define QCBOR_TYPE_BINARY_MIME 76 |
Binary MIME per RFC 2045. See also QCBOR_TYPE_MIME. Data is in val.string.
| #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] (https://tools.ietf.org/html/rfc3339) 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_AddTDecimalFractionBigNum().
| #define QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM 15 |
A decimal fraction made of decimal exponent and positive big number mantissa. See expAndMantissa and QCBOREncode_AddTDecimalFractionBigNum().
| #define QCBOR_TYPE_DOUBLE 27 |
Type for a double floating-point number. Data is in val.dfnum.
| #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.
| #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.
| #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.
| #define QCBOR_TYPE_REGEX 47 |
PERL-compatible regular expression. Data is in val.string.
| #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 |
|
inlinestatic |
Convert int64_t to smaller integers safely.
| [in] | src | An int64_t. |
| [out] | dest | A smaller sized integer to convert to. |
When decoding an integer, the CBOR decoder will return the value as an int64_t unless the integer is in the range of INT64_MAX and UINT64_MAX. That is, unless the value is so large that it can only be represented as a uint64_t, it will be an int64_t.
CBOR itself doesn't size the individual integers it carries at all. The only limits it puts on the major integer types is that they are 8 bytes or less in length. Then encoders like this one use the smallest number of 1, 2, 4 or 8 bytes to represent the integer based on its value. There is thus no notion that one data item in CBOR is a 1-byte integer and another is a 4-byte integer.
The interface to this CBOR encoder only uses 64-bit integers. Some CBOR protocols or implementations of CBOR protocols may not want to work with something smaller than a 64-bit integer. Perhaps an array of 1,000 integers needs to be sent and none has a value larger than 50,000 and are represented as uint16_t.
The sending / encoding side is easy. Integers are temporarily widened to 64-bits as a parameter passing through QCBOREncode_AddInt64() and encoded in the smallest way possible for their value, possibly in less than an uint16_t.
On the decoding side the integers will be returned at int64_t even if they are small and were represented by only 1 or 2 bytes in the encoded CBOR. The functions here will convert integers to a small representation with an overflow check.
(The decoder could have support 8 different integer types and represented the integer with the smallest type automatically, but this would have made the decoder more complex and code calling the decoder more complex in most use cases. In most use cases on 64-bit machines it is no burden to carry around even small integers as 64-bit values).
| 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] (https://tools.ietf.org/html/rfc8742). 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.
| QCBORError QCBORDecode_GetNextWithTags | ( | QCBORDecodeContext * | pCtx, |
| QCBORItem * | pDecodedItem, | ||
| QCBORTagListOut * | pTagList ) |
Deprecated – Gets the next item including full list of tags for item.
| [in] | pCtx | The decoder context. |
| [out] | pDecodedItem | Holds the CBOR item just decoded. |
| [in,out] | pTagList | On input array to put tags in; on output the tags on this item. See QCBORTagListOut. |
| QCBOR_ERR_TOO_MANY_TAGS | The size of pTagList is too small. |
This is retained for backwards compatibility. It is replaced by QCBORDecode_GetNthTag() which also returns all the tags that have been decoded.
This is not backwards compatibile in two ways. First, it is limited to QCBOR_MAX_TAGS_PER_ITEM items whereas previously it was unlimited. Second, it will not inlucde the tags that QCBOR decodes internally.
This works the same as QCBORDecode_GetNext() except that it also returns the list of tags for the data item in pTagList.
The 0th tag returned here is the one furthest from the data item. This is opposite the order for QCBORDecode_GetNthTag().
CBOR has no upper bound or limit on the number of tags that can be associated with a data item but in practice the number of tags on an item will usually be small. This will return QCBOR_ERR_TOO_MANY_TAGS if the array in pTagList is too small to hold all the tags for the item.
| uint64_t QCBORDecode_GetNthTag | ( | QCBORDecodeContext * | pCtx, |
| const QCBORItem * | pItem, | ||
| uint32_t | uIndex ) |
Returns the tag numbers for an item.
| [in] | pCtx | The decoder context. |
| [in] | pItem | The CBOR item to get the tag for. |
| [in] | uIndex | The index of the tag to get. |
When QCBOR decodes an item that is a tag, it will fully decode tags it is able to. Tags that it is unable to process are put in a list in the QCBORItem.
Tags nest. Here the tag with index 0 has the data item as its content. The tag with index 1 has the tag at index 0 has its content and so forth.
Deep tag nesting is rare so this implementation imposes a limit of QCBOR_MAX_TAGS_PER_ITEM on nesting and returns QCBOR_ERR_TOO_MANY_TAGS if there are more. This is a limit of this implementation, not of CBOR. (To be able to handle deeper nesting, the constant can be increased and the library recompiled. It will use more memory).
See also CBORTags, Tag-Usage and Tags-Overview.
To reduce memory used by a QCBORItem, tag numbers larger than UINT16_MAX are mapped so the tag numbers in uTags should be accessed with this function rather than directly.
This returns CBOR_TAG_INVALID64 if any error occurred when getting the item. This is also returned if there are no tags on the item or no tag at uIndex.
| uint64_t QCBORDecode_GetNthTagOfLast | ( | const QCBORDecodeContext * | pCtx, |
| uint32_t | uIndex ) |
Returns the tag numbers for last-decoded item.
| [in] | pCtx | The decoder context. |
| [in] | uIndex | The index of the tag to get. |
This returns tags of the most recently decoded item. See QCBORDecode_GetNthTag(). This is particularly of use for spiffy decode functions that don't return a QCBORItem.
This does not work for QCBORDecode_GetNext(), QCBORDecode_PeekNext(), QCBORDecode_VPeekNext() or QCBORDecode_VGetNextConsume() but these all return a QCBORItem, so it is not necessary.
If a decoding error is set, then this returns CBOR_TAG_INVALID64.
| void QCBORDecode_Init | ( | QCBORDecodeContext * | pCtx, |
| UsefulBufC | EncodedCBOR, | ||
| QCBORDecodeMode | nMode ) |
Initialize the CBOR decoder context.
| [in] | pCtx | The context to initialize. |
| [in] | EncodedCBOR | The buffer with CBOR encoded bytes to be decoded. |
| [in] | nMode | See below and QCBORDecodeMode. |
Initialize context for a pre-order traversal of the encoded CBOR tree.
Most CBOR decoding can be completed by calling this function to start and QCBORDecode_GetNext() in a loop.
If indefinite-length strings are to be decoded, then QCBORDecode_SetMemPool() or QCBORDecode_SetUpAllocator() must be called to set up a string allocator.
Three decoding modes are supported. In normal mode, QCBOR_DECODE_MODE_NORMAL, maps are decoded and strings and integers are accepted as map labels. If a label is other than these, the error QCBOR_ERR_MAP_LABEL_TYPE is returned by QCBORDecode_GetNext().
In strings-only mode, QCBOR_DECODE_MODE_MAP_STRINGS_ONLY, only text strings are accepted for map labels. This lines up with CBOR that converts to JSON. The error QCBOR_ERR_MAP_LABEL_TYPE is returned by QCBORDecode_GetNext() if anything but a text string label is encountered.
In QCBOR_DECODE_MODE_MAP_AS_ARRAY maps are treated as special arrays. They will be returned with special uDataType QCBOR_TYPE_MAP_AS_ARRAY and uCount, the number of items, will be double what it would be for a normal map because the labels are also counted. This mode is useful for decoding CBOR that has labels that are not integers or text strings, but the caller must manage much of the map decoding.
|
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. | bool QCBORDecode_IsTagged | ( | QCBORDecodeContext * | pCtx, |
| const QCBORItem * | pItem, | ||
| uint64_t | uTag ) |
Deprecated – Determine if a CBOR item is a particular tag.
| [in] | pCtx | The decoder context. |
| [in] | pItem | The CBOR item to check. |
| [in] | uTag | The tag to check, one of CBOR_TAG_XXX, for example, CBOR_TAG_DATE_STRING. |
See QCBORDecode_GetNext() for the main description of tag handling. For tags that are not fully decoded a bit corresponding to the tag is set in in uTagBits in the QCBORItem. The particular bit depends on an internal mapping table. This function checks for set bits against the mapping table.
Typically, a protocol implementation just wants to know if a particular tag is present. That is what this provides. To get the full list of tags on a data item, see QCBORDecode_GetNextWithTags().
Also see QCBORDecode_SetCallerConfiguredTagList() for the means to add new tags to the internal list so they can be checked for with this function.
|
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.
| void QCBORDecode_SetCallerConfiguredTagList | ( | QCBORDecodeContext * | pCtx, |
| const QCBORTagListIn * | pTagList ) |
Deprecated – Configure list of caller-selected tags to be recognized.
| [in] | pCtx | The decode context. |
| [out] | pTagList | Structure holding the list of tags to configure. |
Tag handling has been revised and it is no longer ncessary to use this. See QCBORDecode_GetNthTag().
|
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.
| void QCBORDecode_SetUpAllocator | ( | QCBORDecodeContext * | pCtx, |
| QCBORStringAllocate | pfAllocateFunction, | ||
| void * | pAllocateContext, | ||
| bool | bAllStrings ) |
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", the CBOR optional tags and the value of the integer.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.
All tags defined in RFC 8949 are automatically fully decoded. There are QCBOR_TYPES and members in QCBORItem for them. For example, the tag 9 will show up in the QCBORItem as type QCBOR_TYPE_POSBIGNUM with the value in QCBORItem.val.bignum. There is also support for some of the tags in the IANA tag registry.
Most tags with a CBOR_TAG_XXX define in qcbor_common.h like CBOR_TAG_DATE_STRING are automaticlly decoded by QCBOR. Those that are defined but not decoded are so noted.
Tags that are not decoded by QCBOR will be identified and recorded in QCBORItem. Use QCBORDecode_GetNthTag() to get them. Only QCBOR_MAX_TAGS_PER_ITEM tags are recorded per item and an error is returned if there are more than that.
Previous versions of QCBOR handled tags in a more complex way using QCBORDecode_SetCallerConfiguredTagList() and QCBORDecode_GetNextWithTags(). This version is largely compatible, but imposes the limit of QCBOR_MAX_TAGS_PER_ITEM tags per item.
See Tags-Overview for a description of how to go about creating custom tags.
This tag decoding design is to be open-ended and flexible to be able to handle newly defined tags, while using very little memory, in particular keeping QCBORItem as small as possible.
See Decode Error OverviewDecode Error Overview.
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:
| Error | Description |
|---|---|
| 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_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.