Skip to content

Commit

Permalink
sync up with master
Browse files Browse the repository at this point in the history
  • Loading branch information
Laurence Lundblade committed May 10, 2024
2 parents c892908 + 1165491 commit a5fc297
Show file tree
Hide file tree
Showing 14 changed files with 441 additions and 50 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
![QCBOR Logo](https://github.com/laurencelundblade/qdv/blob/master/logo.png?raw=true)

**QCBOR** is a powerful, commercial-quality CBOR encoder/decoder that
**QCBOR** is a powerful, commercial-quality CBOR encoder-decoder that
implements these RFCs:

* [RFC8949](https://tools.ietf.org/html/rfc8949) The CBOR Standard. (Nearly everything
Expand Down
2 changes: 1 addition & 1 deletion cmd_line_main.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*==============================================================================
cmd_line_mainc.c -- Runs tests for QCBOR encoder / decoder
cmd_line_mainc.c -- Runs tests for QCBOR encoder-decoder
Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved.
Expand Down
2 changes: 1 addition & 1 deletion inc/qcbor/qcbor_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ extern "C" {


/**
* Error codes returned by QCBOR Encoder and Decoder.
* Error codes returned by QCBOR Encoder-Decoder.
*
* They are grouped to keep the code size of
* QCBORDecode_IsNotWellFormedError() and
Expand Down
62 changes: 52 additions & 10 deletions inc/qcbor/qcbor_decode.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,17 @@ extern "C" {
* # QCBOR Basic Decode
*
* This section discusses decoding assuming familiarity with the
* general description of this encoder / decoder in section @ref
* general description of this encoder-decoder in section @ref
* 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. It is possible to decode any CBOR by only calling
* QCBORDecode_GetNext(), though this doesn't take advantage of many
* QCBOR features.
* 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
* @ref QCBORItem that describes the decoded item including:
Expand Down Expand Up @@ -198,8 +198,8 @@ typedef enum {
} QCBORDecodeMode;

/**
* The maximum size of input to the decoder. Slightly less than UINT32_MAX
* to make room for some special indicator values.
* The maximum size of input to the decoder. Slightly less than
* @c UINT32_MAX to make room for some special indicator values.
*/
#define QCBOR_MAX_DECODE_INPUT_SIZE (UINT32_MAX - 2)

Expand Down Expand Up @@ -1034,6 +1034,48 @@ QCBORError
QCBORDecode_PeekNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem);


/**
* @brief Get the current traversal cursort offset in the input CBOR.
*
* @param[in] pCtx The decoder context.
*
* @returns The traversal cursor offset or @c UINT32_MAX.
* The position returned is always the start of the next item that
* would be next decoded with QCBORDecode_VGetNext(). If the cursor
* is at the end of the input or in the error state, @c 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.
*/
uint32_t
QCBORDecode_Tell(QCBORDecodeContext *pCtx);


/**
* @brief Returns the tag numbers for an item.
*
Expand All @@ -1060,7 +1102,7 @@ QCBORDecode_PeekNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem);
* See also @ref CBORTags, @ref Tag-Usage and @ref Tags-Overview.
*
* To reduce memory used by a QCBORItem, tag numbers larger than
* UINT16_MAX are mapped so the tag numbers in @c uTags should be
* @c UINT16_MAX are mapped so the tag numbers in @c uTags should be
* accessed with this function rather than directly.
*
* This returns @ref CBOR_TAG_INVALID64 if any error occurred when
Expand Down Expand Up @@ -1273,8 +1315,8 @@ QCBORDecode_SetError(QCBORDecodeContext *pCtx, QCBORError uError);
* @return 0 on success -1 if not
*
* When decoding an integer, the CBOR decoder will return the value as
* an int64_t unless the integer is in the range of @c INT64_MAX and @c
* UINT64_MAX. That is, unless the value is so large that it can only be
* an int64_t unless the integer is in the range of @c INT64_MAX and
* @c UINT64_MAX. That is, unless the value is so large that it can only be
* represented as a @c uint64_t, it will be an @c int64_t.
*
* CBOR itself doesn't size the individual integers it carries at
Expand Down Expand Up @@ -1486,7 +1528,7 @@ QCBORDecode_IsTagged(QCBORDecodeContext *pCtx,
* been decoded.
*
* This is not backwards compatibile in two ways. First, it is limited
* to \ref QCBOR_MAX_TAGS_PER_ITEM items whereas previously it was
* to @ref QCBOR_MAX_TAGS_PER_ITEM items whereas previously it was
* unlimited. Second, it will not inlucde the tags that QCBOR decodes
* internally.
*
Expand Down
29 changes: 15 additions & 14 deletions inc/qcbor/qcbor_encode.h
Original file line number Diff line number Diff line change
Expand Up @@ -341,39 +341,40 @@ extern "C" {
* float type as 32-bits and a C double type as 64-bits. Floating-point
* epoch dates will be unsupported.
*
* If USEFULBUF_DISABLE_ALL_FLOATis defined, then floating point
* If USEFULBUF_DISABLE_ALL_FLOAT is defined, then floating point
* support is completely disabled. Decoding functions return
* @ref QCBOR_ERR_ALL_FLOAT_DISABLED if a floating point value is
* encountered during decoding. Functions that are encoding floating
* point values are not available.
*
* ## Limitations
*
* Summary Limits of this implementation:
* Summary limitations:
* - The entire encoded CBOR must fit into contiguous memory.
* - Max size of encoded / decoded CBOR data is a few bytes less than @c UINT32_MAX (4GB).
* - Max array / map nesting level when encoding / decoding is
* - Max size of encoded CBOR data is a few bytes less than
* @c UINT32_MAX (4GB).
* - Max array / map nesting level when encoding or decoding is
* @ref QCBOR_MAX_ARRAY_NESTING (this is typically 15).
* - Max items in an array or map when encoding / decoding is
* - Max items in an array or map when encoding or decoding is
* @ref QCBOR_MAX_ITEMS_IN_ARRAY (typically 65,536).
* - Does not directly support labels in maps other than text strings & integers.
* - Does not directly support integer labels greater than @c INT64_MAX.
* - Does not directly support integer labels beyond whats fits in @c int64_t
* or @c uint64_t.
* - Epoch dates limited to @c INT64_MAX (+/- 292 billion years).
* - Exponents for bigfloats and decimal integers are limited to @c INT64_MAX.
* - Exponents for bigfloats and decimal integers are limited to whats fits in
* @c int64_t.
* - Tags on labels are ignored during decoding.
* - The maximum tag nesting is @c QCBOR_MAX_TAGS_PER_ITEM (typically 4).
* - Works only on 32- and 64-bit CPUs (modifications could make it work
* on 16-bit CPUs).
* - Works only on 32- and 64-bit CPUs.
*
* The public interface uses @c size_t for all lengths. Internally the
* implementation uses 32-bit lengths by design to use less memory and
* fit structures on the stack. This limits the encoded CBOR it can
* work with to size @c UINT32_MAX (4GB) which should be enough.
* work with to size @c UINT32_MAX (4GB).
*
* This implementation assumes two's compliment integer machines.
* @c <stdint.h> also requires this. It is possible to modify this
* implementation for another integer representation, but all modern
* machines seem to be two's compliment.
* This implementation requires two's compliment integers. While
* C doesn't require two's compliment, <stdint.h> does. Other
* parts of this implementation may also require two's compliment.
*/


Expand Down
18 changes: 10 additions & 8 deletions inc/qcbor/qcbor_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -252,13 +252,13 @@ typedef struct __QCBORDecodeNesting {
* 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 tracking. This is for maps and arrays.
* 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 tracking is either for definite or indefinite-length
* 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
Expand All @@ -269,16 +269,16 @@ typedef struct __QCBORDecodeNesting {
* uCountCursor is QCBOR_COUNT_INDICATES_ZERO_LENGTH to indicate
* it is empty.
*
* This also records whether a level is bounded or not. All
* 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. 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 UINT32_MAX.
* 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
* union/struct will be 8 bytes rather than 9 and a lot of
* wasted padding for alignment will be saved.
*/
uint8_t uLevelType;
Expand All @@ -289,6 +289,8 @@ typedef struct __QCBORDecodeNesting {
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 {
Expand Down
19 changes: 8 additions & 11 deletions inc/qcbor/qcbor_spiffy_decode.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,6 @@ extern "C" {
* QCBORDecode_EnterArray() can be used to narrow the traversal to the
* extent of the array.
*
* QCBORDecode_EnterArray() can be used to narrow the traversal to the
* extent of the array.
*
* All the QCBORDecode_GetXxxxInMapX() methods support duplicate label
* detection and will result in an error if the map has duplicate
* labels.
Expand Down Expand Up @@ -701,7 +698,7 @@ QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel);
* The items in the array that was entered do not have to have been
* consumed for this to succeed.
*
* This sets the pre-order traversal cursor to the item after the
* This sets the traversal cursor to the item after the
* array that was exited.
*
* This will result in an error if any item in the array is not well
Expand Down Expand Up @@ -795,7 +792,7 @@ static void QCBORDecode_GetArrayFromMapSZ(QCBORDecodeContext *pCtx,
* fully exited.
*
* While in bounded mode, QCBORDecode_GetNext() works as usual on the
* map and the pre-order traversal cursor is maintained. It starts out
* map and the traversal cursor is maintained. It starts out
* at the first item in the map just entered. Attempts to get items
* off the end of the map will give error @ref QCBOR_ERR_NO_MORE_ITEMS
* rather going to the next item after the map as it would when not in
Expand All @@ -806,12 +803,12 @@ static void QCBORDecode_GetArrayFromMapSZ(QCBORDecodeContext *pCtx,
* non-aggregate items by label behaves differently from entering subordinate
* aggregate items by label. See dicussion in @ref SpiffyDecode.
*
* Exiting leaves the pre-order cursor at the data item following the
* Exiting leaves the traversal cursor at the data item following the
* last entry in the map or at the end of the input CBOR if there
* nothing after the map.
*
* Entering and Exiting a map is a way to skip over an entire map and
* its contents. After QCBORDecode_ExitMap(), the pre-order traversal
* its contents. After QCBORDecode_ExitMap(), the traversal
* cursor will be at the first item after the map.
*
* Please see @ref Decode-Errors-Overview "Decode Errors Overview".
Expand Down Expand Up @@ -843,7 +840,7 @@ QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pCtx, const char *szLabel);
* The items in the map that was entered do not have to have been
* consumed for this to succeed.
*
* This sets the pre-order traversal cursor to the item after the map
* This sets the traversal cursor to the item after the map
* that was exited.
*
* This will result in an error if any item in the map is not well
Expand Down Expand Up @@ -942,7 +939,7 @@ QCBORDecode_Rewind(QCBORDecodeContext *pCtx);
* with little nesting, this is of little consequence, but may be of
* consequence for large deeply nested CBOR structures on slow CPUs.
*
* The position of the pre-order traversal cursor is not changed.
* The position of the traversal cursor is not changed.
*
* Please see @ref Decode-Errors-Overview "Decode Errors Overview".
*
Expand Down Expand Up @@ -989,7 +986,7 @@ QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pCtx,
* QCBORDecode_EnterMapinMapN(), QCBORDecode_EnterArrayInMapN() and
* such to descend into and process maps and arrays.
*
* The position of the pre-order traversal cursor is not changed.
* The position of the traversal cursor is not changed.
*
* Please see @ref Decode-Errors-Overview "Decode Errors Overview".
*
Expand Down Expand Up @@ -1922,7 +1919,7 @@ QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pCtx,
* The items in the wrapped CBOR that was entered do not have to have
* been consumed for this to succeed.
*
* The this sets the pre-order traversal cursor to the item after the
* The this sets the traversal cursor to the item after the
* byte string that was exited.
*/
void
Expand Down
25 changes: 25 additions & 0 deletions src/qcbor_decode.c
Original file line number Diff line number Diff line change
Expand Up @@ -3132,6 +3132,29 @@ QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
}


/*
* Public function, see header qcbor/qcbor_decode.h file
*/
uint32_t
QCBORDecode_Tell(QCBORDecodeContext *pMe)
{
size_t uCursorOffset;

if(pMe->uLastError != QCBOR_SUCCESS) {
return UINT32_MAX;
}

uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));

if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
return UINT32_MAX;
} else {
/* Cast is safe because decoder input size is restricted. */
return (uint32_t)uCursorOffset;
}
}


/**
* @brief Rewind cursor to start as if map or array were just entered.
*
Expand Down Expand Up @@ -3270,6 +3293,7 @@ QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
}

QCBORDecodeNesting SaveNesting;
size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf));
DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);

/* Reposition to search from the start of the map / array */
Expand Down Expand Up @@ -3396,6 +3420,7 @@ QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,

Done:
DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
UsefulInputBuf_Seek(&(pMe->InBuf), uSavePos);

Done2:
/* For all items not found, set the data and label type to QCBOR_TYPE_NONE */
Expand Down
2 changes: 1 addition & 1 deletion src/qcbor_encode.c
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ QCBOREncode_EncodeHead(UsefulBuf Buffer,
/* This expression integer-promotes to type int. The code above in
* function guarantees that nAdditionalInfo will never be larger
* than 0x1f. The caller may pass in a too-large uMajor type. The
* conversion to unint8_t will cause an integer wrap around and
* conversion to uint8_t will cause an integer wrap around and
* incorrect CBOR will be generated, but no security issue will
* occur.
*/
Expand Down
2 changes: 1 addition & 1 deletion test/float_tests.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ struct DoubleTestCase {
* other formats. CDE and DCBOR standards are not complete yet,
* encodings are a guess. C string literals are used because they
* are the shortest notation. They are used __with a length__ . Null
* termination doesn't work because * there are zero bytes.
* termination doesn't work because there are zero bytes.
*/
static const struct DoubleTestCase DoubleTestCases[] = {
/* Zero */
Expand Down
Loading

0 comments on commit a5fc297

Please sign in to comment.