empty map/array fix. Other clean spiffy decode clean up
diff --git a/inc/qcbor/qcbor_decode.h b/inc/qcbor/qcbor_decode.h
index 233c09b..c3056c9 100644
--- a/inc/qcbor/qcbor_decode.h
+++ b/inc/qcbor/qcbor_decode.h
@@ -157,7 +157,7 @@
/* Do not renumber these. Code depends on some of these values. */
/** The data type is unknown, unset or invalid. */
#define QCBOR_TYPE_NONE 0
-// TODO: comment
+/** Never used in QCBORItem. Used by functions that match QCBOR types. */
#define QCBOR_TYPE_ANY 1
/** Type for an integer that decoded either between @c INT64_MIN and
@@ -167,10 +167,9 @@
/** Type for an integer that decoded to a more than @c INT64_MAX and
@c UINT64_MAX. Data is in member @c val.uint64. */
#define QCBOR_TYPE_UINT64 3
-/** Type for an array. The number of items in the array is in @c
- val.uCount. */
+/** Type for an array. See comments on @c val.uCount. */
#define QCBOR_TYPE_ARRAY 4
-/** Type for a map; number of items in map is in @c val.uCount. */
+/** Type for a map. See comments on @c val.uCount. */
#define QCBOR_TYPE_MAP 5
/** Type for a buffer full of bytes. Data is in @c val.string. */
#define QCBOR_TYPE_BYTE_STRING 6
@@ -309,6 +308,9 @@
/** The "value" for @c uDataType @ref QCBOR_TYPE_ARRAY or @ref
QCBOR_TYPE_MAP -- the number of items in the array or map.
It is @c UINT16_MAX when decoding indefinite-lengths maps
+ and arrays. Detection of the end of a map or array is
+ best done with uNextLevel and uNextNestLevel so as to
+ work for both definite and indefinite length maps
and arrays. */
uint16_t uCount;
/** The value for @c uDataType @ref QCBOR_TYPE_DOUBLE. */
diff --git a/inc/qcbor/qcbor_private.h b/inc/qcbor/qcbor_private.h
index 4e960b0..86baf29 100644
--- a/inc/qcbor/qcbor_private.h
+++ b/inc/qcbor/qcbor_private.h
@@ -152,9 +152,11 @@
Item tracking can either be 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
- uCountCursor is UINT16_MAX if the map/array is not consumed and
- zero if it is consumed in the pre-order traversal.
+ QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH (UINT16_MAX). Also
+ for indefinte length uCountCursor is UINT16_MAX if
+ unconsumed, UINT16_MAX, QCBOR_COUNT_INDICATES_ZERO_LENGTH
+ if zero length (and in bounded mode) and zero when consumed
+ in the pre-order traversal.
This also records whether a level is bounded or not. All
byte-count tracked levels (the top-level sequence and
diff --git a/inc/qcbor/qcbor_spiffy_decode.h b/inc/qcbor/qcbor_spiffy_decode.h
index 21abc6c..836cf1a 100644
--- a/inc/qcbor/qcbor_spiffy_decode.h
+++ b/inc/qcbor/qcbor_spiffy_decode.h
@@ -758,6 +758,43 @@
+/**
+ @brief Decode the next item as a big float.
+
+ @param[in] pCtx The decode context.
+ @param[in] uTagRequirement One of @c QCBOR_TAGSPEC_MATCH_XXX.
+ @param[out] pnMantissa The mantissa.
+ @param[out] pnExponent The base 2 exponent.
+
+ See @ref Decode-Errors for discussion on how error handling works.
+
+ You can compute the value of this by:
+
+ mantissa * ( 2 ** exponent )
+
+ In the encoded CBOR, the mantissa may be a type 0 (unsigned),
+ type 1 (signed integer), type 2 tag xx (positive big number) or
+ type 2 tag xx (negative big number). This implementation will attempt
+ to convert all of these to an int64_t. If the value won't fit,
+ @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW
+ or QCBOR_ERR_BAD_EXP_AND_MANTISSA will be
+ set.
+
+ The encoded CBOR exponent may be a type 0 (unsigned integer)
+ or type 1 (signed integer). This implementation will attempt
+ to convert all of these to an int64_t. If the value won't fit,
+ @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW
+ or QCBOR_ERR_BAD_EXP_AND_MANTISSA will be
+ set.
+
+ Various format and type issues will result in
+ @ref QCBOR_ERR_BAD_EXP_AND_MANTISSA being set.
+
+ See @ref Tag-Matcing for discussion on tag requirements.
+
+ See also QCBORDecode_GetInt64ConvertAll(), QCBORDecode_GetUInt64ConvertAll()
+ and QCBORDecode_GetDoubleConvertAll() which can convert big floats.
+ */
// TODO: actually implement these
void QCBORDecode_GetBigFloat(QCBORDecodeContext *pCtx,
uint8_t uTagRequirement,
@@ -777,6 +814,35 @@
int64_t *pnExponent);
+/**
+ @brief Decode the next item as a big float with a big number mantissa.
+
+ @param[in] pCtx The decode context.
+ @param[in] uTagRequirement One of @c QCBOR_TAGSPEC_MATCH_XXX.
+ @param[in] MantissaBuffer The buffer in which to put the mantissa.
+ @param[out] pMantissa The big num mantissa.
+ @param[out] pbMantissaIsNegative Is @c true if @c pMantissa is negative.
+ @param[out] pnExponent The base 2 exponent.
+
+ See @ref Decode-Errors for discussion on how error handling works.
+
+ You can compute the value of this by:
+
+ mantissa * ( 2 ** exponent )
+
+ In the encoded CBOR, the mantissa may be a type 0 (unsigned),
+ type 1 (signed integer), type 2 tag xx (positive big number) or
+ type 2 tag xx (negative big number). This implementation will
+ all these to a big number. The limit to this conversion is the
+ size of @c MantissaBuffer.
+
+ The exponent is handled the same as for QCBORDecode_GetDecimalFraction().
+
+ See @ref Tag-Matcing for discussion on tag requirements.
+
+ See also QCBORDecode_GetInt64ConvertAll(), QCBORDecode_GetUInt64ConvertAll()
+ and QCBORDecode_GetDoubleConvertAll() which can convert big floats.
+ */
// TODO: actually implement these
void QCBORDecode_GetBigFloatBig(QCBORDecodeContext *pCtx,
uint8_t uTagRequirement,
@@ -998,10 +1064,7 @@
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 bounded
mode.
-
- TODO: You can rewind the inorder traversal cursor to the
- beginning of the map with RewindMap().
-
+
Exiting leaves the pre-order 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.
@@ -1170,15 +1233,6 @@
void QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pCtx);
-/*
- TODO: fix this; make it rewind bounded
- Restarts fetching of items in a map to the start of the
- map. This is for GetNext. It has no effect on
- GetByLabel (which always searches from the start).
- */
-void QCBORDecode_RewindMap(QCBORDecodeContext *pCtxt);
-
-
/**
@brief Indicate if decoder is in bound mode.
@param[in] pCtx The decode context.
@@ -1312,50 +1366,6 @@
-
-
-
-
-/*
- Normally decoding is just in-order traversal. You can get next
- of any type, get next of a particular type including conversions.
-
- If the cursor is at a map and you enter it, then you can use
- methods that Get things by label, either numeric or string.
-
- These methods work only at the particular level in the map.
- To go into a map nested in a map call the special method
- to enter a map by label.
-
- When in a map, the GetNext methods work too, but only
- to the end of the map. You can't traverse off the end of the
- map.
-
- You can rewind to the start of the map and traverse it again
- with the MapRestart method.
-
- The exit map method will leave the traversal cursor at the first itme after
- the map.
-
-
- The beginning of each map must be recorded so the scan can be done
- through the whole map.
-
-
-
-
-
-
-
-
-
-
-
- */
-
-
-
-
/* ===========================================================================
BEGINNING OF PRIVATE INLINE IMPLEMENTATION
========================================================================== */
@@ -1364,12 +1374,12 @@
// Semi-private
void QCBORDecode_EnterBoundedMapOrArray(QCBORDecodeContext *pMe, uint8_t uType);
-
+// Semi-private
inline static void QCBORDecode_EnterMap(QCBORDecodeContext *pMe) {
QCBORDecode_EnterBoundedMapOrArray(pMe, QCBOR_TYPE_MAP);
}
-
+// Semi-private
inline static void QCBORDecode_EnterArray(QCBORDecodeContext *pMe) {
QCBORDecode_EnterBoundedMapOrArray(pMe, QCBOR_TYPE_ARRAY);
}
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index da191e6..a0e39bb 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -2827,7 +2827,7 @@
goto Done;
}
- const bool bIsEmpty = (Item.uNestingLevel == Item.uNextNestLevel);
+ const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
if(bIsEmpty) {
if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
// Undo decrement done by QCBORDecode_GetNext() so the the
@@ -2941,14 +2941,6 @@
}
-void QCBORDecode_RewindMap(QCBORDecodeContext *pMe)
-{
- // TODO: check for map mode; test this
- //pMe->nesting.pCurrent->uCount = pMe->nesting.pCurrent->u.ma.uCountTotal;
- UsefulInputBuf_Seek(&(pMe->InBuf), pMe->nesting.pCurrent->u.ma.uStartOffset);
-}
-
-
static QCBORError InternalEnterBstrWrapped(QCBORDecodeContext *pMe,
const QCBORItem *pItem,
@@ -4548,12 +4540,12 @@
#ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA
static void ProcessDecimalFractionBig(QCBORDecodeContext *pMe,
- uint8_t uTagRequirement,
- QCBORItem *pItem,
- UsefulBuf BufferForMantissa,
- UsefulBufC *pMantissa,
- bool *pbIsNegative,
- int64_t *pnExponent)
+ uint8_t uTagRequirement,
+ QCBORItem *pItem,
+ UsefulBuf BufferForMantissa,
+ UsefulBufC *pMantissa,
+ bool *pbIsNegative,
+ int64_t *pnExponent)
{
const TagSpecification TagSpec = {uTagRequirement,
@@ -4671,47 +4663,4 @@
#endif /* ndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */
-/*
- TODO: do something with this text
- The main mode of decoding is a pre-order travesal of the tree of leaves (numbers, strings...)
- formed by intermediate nodes (arrays and maps). The cursor for the traversal
- is the byte offset in the encoded input and a leaf counter for definite
- length maps and arrays. Indefinite length maps and arrays are handled
- by look ahead for the break.
-
- The view presented to the caller has tags, labels and the chunks of
- indefinite length strings aggregated into one decorated data item.
-
- The caller understands the nesting level in pre-order traversal by
- the fact that a data item that is a map or array is presented to
- the caller when it is first encountered in the pre-order traversal and that all data items are presented with its nesting level
- and the nesting level of the next item.
-
- The caller traverse maps and arrays in a special mode that often more convenient
- that tracking by nesting level. When an array or map is expected or encountered
- the EnterMap or EnteryArray can be called.
-
- When entering a map or array like this, the cursor points to the first
- item in the map or array. When exiting, it points to the item after
- the map or array, regardless of whether the items in the map or array were
- all traversed.
-
- When in a map or array, the cursor functions as normal, but traversal
- cannot go past the end of the map or array that was entered. If this
- is attempted the QCBOR_ERR_NO_MORE_ITEMS error is returned. To
- go past the end of the map or array ExitMap() or ExitArray() must
- be called. It can be called any time regardless of the position
- of the cursor.
-
- When a map is entered, a special function allows fetching data items
- by label. This call will traversal the whole map looking for the
- labeled item. The whole map is traversed so as to detect duplicates.
- This type of fetching items does not affect the normal traversal
- cursor.
-
-
- When a data item is presented to the caller, the nesting level of the data
- item is presented along with the nesting level of the item that would be
- next consumed.
- */
diff --git a/test/qcbor_decode_tests.c b/test/qcbor_decode_tests.c
index 473701b..569b0bf 100644
--- a/test/qcbor_decode_tests.c
+++ b/test/qcbor_decode_tests.c
@@ -4048,36 +4048,54 @@
static const uint8_t spArrayOfEmpty[] = {0x84, 0x40, 0xa0, 0x80, 0x00};
-// {0: [], 9: [[], []], 8: {1: [], 2: {}, 3: []}, 4: {}, 5: [], 6: [[], []]}
-static const uint8_t spMapOfEmpty[] = {0xa6, 0x00, 0x80, 0x09, 0x82, 0x80, 0x80, 0x08, 0xa3, 0x01, 0x80, 0x02, 0xa0, 0x03, 0x80, 0x04, 0xa0, 0x05, 0x9f, 0xff, 0x06, 0x9f, 0x80, 0x9f, 0xff, 0xff};
-
-
-
+/*
+ {
+ 0: [],
+ 9: [
+ [],
+ []
+ ],
+ 8: {
+ 1: [],
+ 2: {},
+ 3: []
+ },
+ 4: {},
+ 5: [],
+ 6: [
+ [],
+ []
+ ]
+ }
+ */
+static const uint8_t spMapOfEmpty[] = {
+ 0xa6, 0x00, 0x80, 0x09, 0x82, 0x80, 0x80, 0x08, 0xa3, 0x01,
+ 0x80, 0x02, 0xa0, 0x03, 0x80, 0x04, 0xa0, 0x05, 0x9f, 0xff,
+ 0x06, 0x9f, 0x80, 0x9f, 0xff, 0xff};
int32_t EnterMapTest()
{
- QCBORItem Item1;
+ QCBORItem Item1;
QCBORDecodeContext DCtx;
-
- int32_t nReturn;
-
- QCBORError uErr;
+ int32_t nReturn;
+ QCBORError uErr;
QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spMapOfEmpty), 0);
QCBORDecode_EnterMap(&DCtx);
- QCBORDecode_EnterArray(&DCtx);
+
+ QCBORDecode_EnterArray(&DCtx); // Label 0
QCBORDecode_ExitArray(&DCtx);
- QCBORDecode_EnterArray(&DCtx);
+ QCBORDecode_EnterArray(&DCtx); // Label 9
QCBORDecode_EnterArray(&DCtx);
QCBORDecode_ExitArray(&DCtx);
QCBORDecode_EnterArray(&DCtx);
QCBORDecode_ExitArray(&DCtx);
QCBORDecode_ExitArray(&DCtx);
- QCBORDecode_EnterMap(&DCtx);
+ QCBORDecode_EnterMap(&DCtx); // Label 8
QCBORDecode_EnterArray(&DCtx);
QCBORDecode_ExitArray(&DCtx);
QCBORDecode_EnterMap(&DCtx);
@@ -4086,13 +4104,13 @@
QCBORDecode_ExitArray(&DCtx);
QCBORDecode_ExitMap(&DCtx);
- QCBORDecode_EnterMap(&DCtx);
+ QCBORDecode_EnterMap(&DCtx); // Label4
QCBORDecode_ExitMap(&DCtx);
- QCBORDecode_EnterArray(&DCtx);
+ QCBORDecode_EnterArray(&DCtx); // Label 5
QCBORDecode_ExitArray(&DCtx);
- QCBORDecode_EnterArray(&DCtx);
+ QCBORDecode_EnterArray(&DCtx); // Label 6
QCBORDecode_EnterArray(&DCtx);
QCBORDecode_ExitArray(&DCtx);
QCBORDecode_EnterArray(&DCtx);