Move tag-related and spiffy-related code to their own source files
qcbor_decode.c was just too big
* Move all tag-related code into qcbor_tag_decode.[ch]
* split out spiffy decode source and DecodeNesting
---------
Co-authored-by: Laurence Lundblade <lgl@securitytheory.com>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c37cb38..adffeeb 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -40,6 +40,7 @@
PRIVATE
src/ieee754.c
src/qcbor_decode.c
+ src/qcbor_spiffy_decode.c
src/qcbor_tag_decode.c
src/qcbor_number_decode.c
src/qcbor_encode.c
diff --git a/Makefile b/Makefile
index 5f6d993..2f6c351 100644
--- a/Makefile
+++ b/Makefile
@@ -24,7 +24,7 @@
CFLAGS=$(CMD_LINE) -I inc -I test -Os -fPIC
-QCBOR_OBJ=src/UsefulBuf.o src/qcbor_encode.o src/qcbor_decode.o src/qcbor_number_decode.o src/qcbor_tag_decode.o src/ieee754.o src/qcbor_err_to_str.o
+QCBOR_OBJ=src/UsefulBuf.o src/qcbor_encode.o src/qcbor_decode.o src/qcbor_spiffy_decode.o src/qcbor_number_decode.o src/qcbor_tag_decode.o src/ieee754.o src/qcbor_err_to_str.o
TEST_OBJ=test/UsefulBuf_Tests.o test/qcbor_encode_tests.o \
test/qcbor_decode_tests.o test/run_tests.o \
diff --git a/QCBOR.xcodeproj/project.pbxproj b/QCBOR.xcodeproj/project.pbxproj
index f9456a6..fb65bee 100644
--- a/QCBOR.xcodeproj/project.pbxproj
+++ b/QCBOR.xcodeproj/project.pbxproj
@@ -11,6 +11,7 @@
0FA9BEBA216DC7AD00BA646B /* qcbor_encode_tests.c in Sources */ = {isa = PBXBuildFile; fileRef = 0FA9BEB8216DC7AD00BA646B /* qcbor_encode_tests.c */; };
0FA9BEBD216DE31700BA646B /* UsefulBuf_Tests.c in Sources */ = {isa = PBXBuildFile; fileRef = 0FA9BEBC216DE31700BA646B /* UsefulBuf_Tests.c */; };
E7180F232CF1657B00513186 /* qcbor_number_decode.c in Sources */ = {isa = PBXBuildFile; fileRef = E7180F222CF1657A00513186 /* qcbor_number_decode.c */; };
+ E7180F262CF8F2EB00513186 /* qcbor_spiffy_decode.c in Sources */ = {isa = PBXBuildFile; fileRef = E7180F252CF8F2EB00513186 /* qcbor_spiffy_decode.c */; };
E73B57592161CA690080D658 /* ieee754.c in Sources */ = {isa = PBXBuildFile; fileRef = E73B57582161CA690080D658 /* ieee754.c */; };
E73B575E2161CA7C0080D658 /* float_tests.c in Sources */ = {isa = PBXBuildFile; fileRef = E73B575A2161CA7C0080D658 /* float_tests.c */; };
E73B575F2161CA7C0080D658 /* half_to_double_from_rfc7049.c in Sources */ = {isa = PBXBuildFile; fileRef = E73B575D2161CA7C0080D658 /* half_to_double_from_rfc7049.c */; };
@@ -161,6 +162,8 @@
E7180F212CF1638F00513186 /* decode_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = decode_private.h; path = src/decode_private.h; sourceTree = "<group>"; };
E7180F222CF1657A00513186 /* qcbor_number_decode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = qcbor_number_decode.c; path = src/qcbor_number_decode.c; sourceTree = "<group>"; };
E7180F242CF2390100513186 /* qcbor_number_decode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qcbor_number_decode.h; path = inc/qcbor/qcbor_number_decode.h; sourceTree = "<group>"; };
+ E7180F252CF8F2EB00513186 /* qcbor_spiffy_decode.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = qcbor_spiffy_decode.c; path = src/qcbor_spiffy_decode.c; sourceTree = "<group>"; };
+ E7180F272CF917D200513186 /* decode_nesting.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = decode_nesting.h; path = src/decode_nesting.h; sourceTree = "<group>"; };
E73B57572161CA680080D658 /* ieee754.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.h; name = ieee754.h; path = src/ieee754.h; sourceTree = "<group>"; tabWidth = 3; };
E73B57582161CA690080D658 /* ieee754.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = ieee754.c; path = src/ieee754.c; sourceTree = "<group>"; tabWidth = 3; };
E73B575A2161CA7C0080D658 /* float_tests.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = float_tests.c; path = test/float_tests.c; sourceTree = "<group>"; tabWidth = 3; };
@@ -294,8 +297,10 @@
children = (
E776E08D214AE07500E67947 /* UsefulBuf.c */,
E776E08C214AE07400E67947 /* qcbor_encode.c */,
+ E7180F272CF917D200513186 /* decode_nesting.h */,
E7180F212CF1638F00513186 /* decode_private.h */,
E776E08E214AE07500E67947 /* qcbor_decode.c */,
+ E7180F252CF8F2EB00513186 /* qcbor_spiffy_decode.c */,
E7180F222CF1657A00513186 /* qcbor_number_decode.c */,
E7CA1F1D2C8C337E0008F454 /* qcbor_tag_decode.c */,
E73B57572161CA680080D658 /* ieee754.h */,
@@ -564,6 +569,7 @@
E7C960B92800A09E00FB537C /* ub-example.c in Sources */,
E743D0F324AD08020017899F /* example.c in Sources */,
0FA9BEBD216DE31700BA646B /* UsefulBuf_Tests.c in Sources */,
+ E7180F262CF8F2EB00513186 /* qcbor_spiffy_decode.c in Sources */,
E7180F232CF1657B00513186 /* qcbor_number_decode.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
diff --git a/README.md b/README.md
index d40430d..f51bebe 100644
--- a/README.md
+++ b/README.md
@@ -123,6 +123,19 @@
includes mixed definite and indefinte maps and arrays. (Some work
remains to support map searching with indefinite length strings.)
+## v2
+
+** Tag decoding
+
+** Map Sorting
+
+** Serialization Modes
+
+** Files Rearrangement
+
+** Bignumber ??
+
+
## Comparison to TinyCBOR
TinyCBOR is a popular widely used implementation. Like QCBOR,
diff --git a/inc/qcbor/qcbor_decode.h b/inc/qcbor/qcbor_decode.h
index 0f31e26..2f7a118 100644
--- a/inc/qcbor/qcbor_decode.h
+++ b/inc/qcbor/qcbor_decode.h
@@ -1214,137 +1214,6 @@
QCBORDecode_EndCheck(QCBORDecodeContext *pCtx);
-#ifndef QCBOR_DISABLE_TAGS
-/**
- * @brief Returns the tag numbers for an item.
- *
- * @param[in] pCtx The decoder context.
- * @param[out] puTagNumber The returned tag number.
- *
- * In QCBOR v2, all tag numbers on an item MUST be fetched with this
- * method. If not, @ref QCBOR_ERR_UNPROCESSED_TAG_NUMBER will
- * occur. This is a major change from QCBORv1. The QCBOR v1 behavior
- * is too lax for proper CBOR decoding. When a tag number occurs it
- * indicates the item is a new data type (except for a few tag numbers
- * that are hints). Note also that in RFC 7049, tag numbers were
- * incorrectly characterized as optional implying they could be
- * ignored.
- *
- * In typical item decoding, tag numbers are not used, not present and
- * not expected. There's no need to call this.
- *
- * When the protocol being decoded does use a tag number then this
- * must be called for the items were the tag numbers occur before the
- * items themselves are decoded. Making this call prevents the
- * @ref QCBOR_ERR_UNPROCESSED_TAG_NUMBER error, but the caller still has to
- * check that the tag number is the right one. Probably the tag number
- * will be used to switch the flow of the decoder.
- *
- * It's possible that an item might use the presence/absence of a tag
- * number to switch the flow of decoding. If there's a possibility of
- * a tag number then this must be called.
- *
- * If this is called and there is no tag number, then this will return
- * @ref QCBOR_SUCCESS and the tag number returned will be
- * @ref CBOR_TAG_INVALID64.
- *
- * Usually there is only one tag number per item, but CBOR allows
- * more. That it allows nesting of tags where the content of one tag
- * is another tag. If there are multiple tag numbers, this must be
- * called multiple times. This only returns one tag number at a time,
- * because tag numbers are typically processed one at a time.
- *
- * If there is an error decoding the tag or the item it is on, the
- * error code will be set and the tag number @ref CBOR_TAG_INVALID64
- * will be returned. That is, @ref CBOR_TAG_INVALID64 will be returned if
- * there is a decode error or there is no tag number.
- */
-void
-QCBORDecode_VGetNextTagNumber(QCBORDecodeContext *pCtx, uint64_t *puTagNumber);
-
-
-/**
- * @brief Returns the tag numbers for an item.
- *
- * @param[in] pCtx The decoder context.
- * @param[out] puTagNumber The returned tag number.
- *
- * @return See error table of decoding errors set by QCBORDecode_VGetNext().
- *
- * Like QCBORDecode_VGetNextTagNumber(), but returns the
- * error rather than set last error.
- */
-QCBORError
-QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pCtx, uint64_t *puTagNumber);
-
-
-/**
- * @brief Returns the tag numbers for a decoded item.
- *
- * @param[in] pCtx The decoder context.
- * @param[in] pItem The CBOR item to get the tag for.
- * @param[in] uIndex The index of the tag to get.
- *
- * @returns The nth tag number or @ref CBOR_TAG_INVALID64.
- *
- * Typically, this is only used with @ref QCBOR_DECODE_CONFIG_UNPROCESSED_TAG_NUMBERS.
- * Normally, tag numbers are processed QCBORDecode_VGetNextTagNumber() or
- * QCBORTagContentCallBack.
- *
- * 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 is the outermost, the one
- * furthest form the data item that is the tag content. This is
- * the opposite order of QCBORDecode_GetNthTag(), but more
- * useful.
- *
- * Deep tag nesting is rare so this implementation imposes a limit of
- * @ref QCBOR_MAX_TAGS_PER_ITEM on nesting and returns @ref
- * 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 @ref Tag-Decoding @ref CBORTags, @ref Tag-Usage and @ref Tags-Overview.
- *
- * To reduce memory used by a @ref QCBORItem, tag numbers larger than
- * @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
- * getting the item. This is also returned if there are no tags on the
- * item or no tag at @c uIndex.
- */
-uint64_t
-QCBORDecode_GetNthTagNumber(const QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint8_t uIndex);
-
-
-/**
- * @brief Returns the tag numbers for last-decoded item.
- *
- * @param[in] pCtx The decoder context.
- * @param[in] uIndex The index of the tag to get.
- *
- * @returns The nth tag number or @ref CBOR_TAG_INVALID64.
- *
- * This returns tags of the most recently decoded item. See
- * QCBORDecode_GetNthTagNumber(). This is particularly of use for spiffy
- * decode functions that don't return a @ref QCBORItem.
- *
- * This does not work for QCBORDecode_GetNext(),
- * QCBORDecode_PeekNext(), QCBORDecode_VPeekNext() or
- * QCBORDecode_VGetNextConsume() but these all return a
- * @ref QCBORItem, so it is not necessary.
- *
- * If a decoding error is set, then this returns @ref CBOR_TAG_INVALID64.
- */
-uint64_t
-QCBORDecode_GetNthTagNumberOfLast(QCBORDecodeContext *pCtx, uint8_t uIndex);
-
-#endif /* ! QCBOR_DISABLE_TAGS */
-
/**
* @brief Check that a decode completed successfully.
@@ -1551,12 +1420,12 @@
* which causes no error to be returned when un processed tag numbers
* are encountered.
*
- * Second, it installs all the same tag content handlers that v1 had hardwwired.
+ * 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.
+ * number processing is too loose. See @ref 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 behavior
@@ -1568,43 +1437,6 @@
QCBORDecode_CompatibilityV1(QCBORDecodeContext *pCtx);
-
-#ifndef QCBOR_DISABLE_TAGS
-
-/**
- * @brief Returns the tag numbers for an item. (deprecated).
- *
- * @param[in] pCtx The decoder context.
- * @param[in] uIndex The index of the tag to get.
- *
- * This is the same as QCBORDecode_GetNthTagNumber() but the order is
- * opposite when there are multiple tags. @c uIndex 0 is the tag
- * number closest to the tag content. QCBORDecode_GetNthTagNumber() is
- * more useful for checking the next tag number and switching the
- * decode flow.
- */
-uint64_t
-QCBORDecode_GetNthTag(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint32_t uIndex);
-
-
-/**
- * @brief Returns the tag numbers for last-decoded item (deprecated).
- *
- * @param[in] pCtx The decoder context.
- * @param[in] uIndex The index of the tag to get.
- *
- * @returns The nth tag number or CBOR_TAG_INVALID64.
- *
- * This is the same as QCBORDecode_GetNthTagNumberOfLast() but the
- * order is opposite when there are multiple tags. @c uIndex 0 is the
- * tag number closest to the tag content.
- * QCBORDecode_GetNthTagNumber() is more useful for checking
- * the next tag number and switching the decode flow.
- */
-uint64_t
-QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pCtx, uint32_t uIndex);
-
-#endif /* ! QCBOR_DISABLE_TAGS */
/* ========================================================================= *
* END OF DEPRECATED FUNCTIONS *
* ========================================================================= */
diff --git a/inc/qcbor/qcbor_number_decode.h b/inc/qcbor/qcbor_number_decode.h
index a995447..8c525ec 100644
--- a/inc/qcbor/qcbor_number_decode.h
+++ b/inc/qcbor/qcbor_number_decode.h
@@ -1401,7 +1401,7 @@
* ========================================================================= */
-/* Semi-private funcion used by public inline functions. See qcbor_decode.c */
+/* Semi-private funcion used by public inline functions. See qcbor_number_decode.c */
void
QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pCtx,
uint32_t uConvertTypes,
@@ -1409,7 +1409,7 @@
QCBORItem *pItem);
-/* Semi-private funcion used by public inline functions. See qcbor_decode.c */
+/* Semi-private funcion used by public inline functions. See qcbor_number_decode.c */
void
QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pCtx,
int64_t nLabel,
@@ -1418,7 +1418,7 @@
QCBORItem *pItem);
-/* Semi-private funcion used by public inline functions. See qcbor_decode.c */
+/* Semi-private funcion used by public inline functions. See qcbor_number_decode.c */
void
QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pCtx,
const char *szLabel,
@@ -1426,14 +1426,14 @@
uint64_t *puValue,
QCBORItem *pItem);
-/* Semi-private funcion used by public inline functions. See qcbor_decode.c */
+/* Semi-private funcion used by public inline functions. See qcbor_number_decode.c */
void
QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pCtx,
uint32_t uConvertTypes,
int64_t *pnValue,
QCBORItem *pItem);
-/* Semi-private funcion used by public inline functions. See qcbor_decode.c */
+/* Semi-private funcion used by public inline functions. See qcbor_number_decode.c */
void
QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pCtx,
int64_t nLabel,
@@ -1441,7 +1441,7 @@
int64_t *pnValue,
QCBORItem *pItem);
-/* Semi-private funcion used by public inline functions. See qcbor_decode.c */
+/* Semi-private funcion used by public inline functions. See qcbor_number_decode.c */
void
QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pCtx,
const char *szLabel,
@@ -1451,14 +1451,14 @@
#ifndef USEFULBUF_DISABLE_ALL_FLOAT
-/* Semi-private funcion used by public inline functions. See qcbor_decode.c */
+/* Semi-private funcion used by public inline functions. See qcbor_number_decode.c */
void
QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pCtx,
uint32_t uConvertTypes,
double *pValue,
QCBORItem *pItem);
-/* Semi-private funcion used by public inline functions. See qcbor_decode.c */
+/* Semi-private funcion used by public inline functions. See qcbor_number_decode.c */
void
QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pCtx,
int64_t nLabel,
@@ -1466,7 +1466,7 @@
double *pdValue,
QCBORItem *pItem);
-/* Semi-private funcion used by public inline functions. See qcbor_decode.c */
+/* Semi-private funcion used by public inline functions. See qcbor_number_decode.c */
void
QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pCtx,
const char *szLabel,
@@ -1476,7 +1476,7 @@
#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */
-/* Semi-private funcion used by public inline functions. See qcbor_decode.c */
+/* Semi-private funcion used by public inline functions. See qcbor_tag_decode.c */
void
QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
uint8_t uTagRequirement,
@@ -1484,6 +1484,8 @@
uint64_t uTagNumber,
UsefulBufC *pBstr);
+
+/* Semi-private funcion used by public inline functions. See qcbor_tag_decode.c */
void
QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
const int64_t nLabel,
@@ -1493,11 +1495,7 @@
UsefulBufC *pString);
-
-
-
-
-
+/* Semi-private funcion used by public inline functions. See qcbor_tag_decode.c */
void
QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
const char *szLabel,
@@ -1650,7 +1648,7 @@
double *pdValue)
{
QCBORItem Item;
- QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item);
+ QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item);
}
static inline void
@@ -1684,7 +1682,7 @@
static inline void
QCBORDecode_GetDouble(QCBORDecodeContext *pMe, double *pValue)
{
- QCBORDecode_GetDoubleConvert(pMe, QCBOR_CONVERT_TYPE_FLOAT, pValue);
+ QCBORDecode_GetDoubleConvert(pMe, QCBOR_CONVERT_TYPE_FLOAT, pValue);
}
static inline void
@@ -1805,7 +1803,13 @@
bool *pbMantissaIsNegative,
int64_t *pnExponent)
{
- QCBORDecode_GetTDecimalFractionBigMantissaRawInMapN(pMe, nLabel, uTagRequirement, MantissaBuffer, pMantissa, pbMantissaIsNegative, pnExponent);
+ QCBORDecode_GetTDecimalFractionBigMantissaRawInMapN(pMe,
+ nLabel,
+ uTagRequirement,
+ MantissaBuffer,
+ pMantissa,
+ pbMantissaIsNegative,
+ pnExponent);
}
static inline void /* Deprecated */
diff --git a/inc/qcbor/qcbor_spiffy_decode.h b/inc/qcbor/qcbor_spiffy_decode.h
index 155df7c..26902d7 100644
--- a/inc/qcbor/qcbor_spiffy_decode.h
+++ b/inc/qcbor/qcbor_spiffy_decode.h
@@ -34,7 +34,9 @@
*
* This section discusses spiffy decoding assuming familiarity with
* the general description of decoding in the
- * @ref BasicDecode section.
+ * @ref BasicDecode section. See also qcbor_tag_decode.h
+ * and qcbor_number_decode.h for more spiffy decode
+ * functions.
*
* Spiffy decode is extra decode features over and above the @ref
* BasicDecode features that generally are easier to use, mirror the
@@ -106,88 +108,11 @@
* quantified). One way ease this is to use
* QCBORDecode_GetItemsInMap() which allows decoding of a list of
* items expected in an map in one traveral.
- *
- * @anchor Tag-Usage
- * ## Tag Usage
- *
- * Data types beyond the basic CBOR types of numbers, strings, maps and
- * arrays are called tags. The main registry of these new types is in
- * the IANA CBOR tags registry. These new types may be simple such a
- * number that is to be interpreted as a date, or of moderate complexity
- * such as defining a decimal fraction that is an array containing a
- * mantissa and exponent, or complex such as format for signing and
- * encryption.
- *
- * When a tag occurs in a protocol it is encoded as an integer tag
- * number plus the content of the tag.
- *
- * The content format of a tag may also be "borrowed". For example, a
- * protocol definition may say that a particular data item is an epoch
- * date just like tag 1, but not actually tag 1. In practice the
- * difference is the presence or absence of the integer tag number in
- * the encoded CBOR.
- *
- * The decoding functions for these new types takes a tag requirement
- * parameter to say whether the item is a tag, is just borrowing the
- * content format and is not a tag, or whether either is OK.
- *
- * If the parameter indicates the item must be a tag (@ref
- * QCBOR_TAG_REQUIREMENT_TAG), then @ref QCBOR_ERR_UNEXPECTED_TYPE is
- * set if it is not one of the expected tag types. To decode correctly
- * the contents of the tag must also be of the correct type. For
- * example, to decode an epoch date tag the content must be an integer
- * or floating-point value.
- *
- * If the parameter indicates it should not be a tag
- * (@ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG), then
- * @ref QCBOR_ERR_UNEXPECTED_TYPE set if it is a tag or the type of the
- * encoded CBOR is not what is expected. In the example of an epoch
- * date, the data type must be an integer or floating-point value. This
- * is the case where the content format of a tag is borrowed.
- *
- * The parameter can also indicate that either a tag or no tag is
- * allowed ( @ref QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG ). A good protocol
- * design should however be clear and choose one or the other and not
- * need this option. This is a way to implement "be liberal in what you
- * accept", however these days that is less in favor. See
- * https://tools.ietf.org/id/draft-thomson-postel-was-wrong-03.html.
- *
- * Map searching works with indefinite length strings. A string
- * allocator must be set up the same as for any handling of indefinite
- * length strings. However, It currently over-allocates memory from the
- * string pool and thus requires a much larger string pool than it
- * should. The over-allocation happens every time a map is searched by
- * label. (This may be corrected in the future).
*/
-/** The data item must be a tag of the expected type. It is an error
- * if it is not. For example when calling QCBORDecode_GetEpochDate(),
- * the data item must be an @ref CBOR_TAG_DATE_EPOCH tag. See
- * @ref Tag-Usage. */
-#define QCBOR_TAG_REQUIREMENT_TAG 0
-
-/** The data item must be of the type expected for content data type
- * being fetched. It is an error if it is not. For example, when
- * calling QCBORDecode_GetEpochDate() and it must not be an @ref
- * CBOR_TAG_DATE_EPOCH tag. See @ref Tag-Usage. */
-#define QCBOR_TAG_REQUIREMENT_NOT_A_TAG 1
-
-/** Either of the above two are allowed. This allows implementation of
- * being liberal in what you receive, but it is better if CBOR-based
- * protocols pick one and stick to and not required the reciever to
- * take either. See @ref Tag-Usage. */
-#define QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG 2
-
-/** Add this into the above value if other tags not processed by QCBOR
- * are to be allowed to surround the data item. See @ref Tag-Usage. */
-#define QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS 0x80
-
-
-
-
/**
* @brief Decode the next item as a byte string
*
@@ -200,6 +125,8 @@
*
* If the CBOR item to decode is not a byte string, the
* @ref QCBOR_ERR_UNEXPECTED_TYPE error is set.
+ *
+ * See also QCBORDecode_EnterBstrWrapped().
*/
static void
QCBORDecode_GetByteString(QCBORDecodeContext *pCtx,
@@ -746,13 +673,6 @@
void *pCallbackCtx,
QCBORItemCallback pfCB);
-
-QCBORError
-QCBORDecode_GetNextTagNumberInMapN(QCBORDecodeContext *pCtx, int64_t nLabel, uint64_t *puTagNumber);
-
-QCBORError
-QCBORDecode_GetNextTagNumberInMapSZ(QCBORDecodeContext *pCtx, const char *szLabel, uint64_t *puTagNumber);
-
/**
* @brief Decode the next item as a Boolean.
*
@@ -856,500 +776,6 @@
-/**
- * @brief Decode the next item as a date string.
- *
- * @param[in] pCtx The decode context.
- * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
- * @param[out] pDateString The decoded date.
- *
- * This decodes the standard CBOR date/time string tag, integer tag
- * number of 0, or encoded CBOR that is not a tag, but borrows the
- * date string content format.
- *
- * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
- *
- * See @ref Tag-Usage for discussion on tag requirements.
- *
- * See also @ref CBOR_TAG_DATE_STRING, QCBOREncode_AddDateString() and
- * @ref QCBOR_TYPE_DATE_STRING.
- */
-static void
-QCBORDecode_GetDateString(QCBORDecodeContext *pCtx,
- uint8_t uTagRequirement,
- UsefulBufC *pDateString);
-
-static void
-QCBORDecode_GetDateStringInMapN(QCBORDecodeContext *pCtx,
- int64_t nLabel,
- uint8_t uTagRequirement,
- UsefulBufC *pDateString);
-
-static void
-QCBORDecode_GetDateStringInMapSZ(QCBORDecodeContext *pCtx,
- const char *szLabel,
- uint8_t uTagRequirement,
- UsefulBufC *pDateString);
-
-
-/**
- * @brief Decode the next item as a date-only string.
- *
- * @param[in] pCtx The decode context.
- * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
- * @param[out] pDateString The decoded date.
- *
- * This decodes the CBOR date-only string tag, integer tag number of
- * 1004, or encoded CBOR that is not a tag, but borrows the date-only
- * string content format. An example of the format is "1985-04-12".
- *
- * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
- *
- * See @ref Tag-Usage for discussion on tag requirements.
- *
- * See also @ref CBOR_TAG_DAYS_STRING, QCBOREncode_AddDaysString() and
- * @ref QCBOR_TYPE_DAYS_STRING.
- */
-static void
-QCBORDecode_GetDaysString(QCBORDecodeContext *pCtx,
- uint8_t uTagRequirement,
- UsefulBufC *pDateString);
-
-static void
-QCBORDecode_GetDaysStringInMapN(QCBORDecodeContext *pCtx,
- int64_t nLabel,
- uint8_t uTagRequirement,
- UsefulBufC *pDateString);
-
-static void
-QCBORDecode_GetDaysStringInMapSZ(QCBORDecodeContext *pCtx,
- const char *szLabel,
- uint8_t uTagRequirement,
- UsefulBufC *pDateString);
-
-
-/**
- * @brief Decode the next item as an epoch date.
- *
- * @param[in] pCtx The decode context.
- * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
- * @param[out] pnTime The decoded epoch date.
- *
- * This decodes the standard CBOR epoch date/time tag, integer tag
- * number of 1. This will also decode any integer or floating-point
- * number as an epoch date (a tag 1 epoch date is just an integer or
- * floating-point number).
- *
- * This will set @ref QCBOR_ERR_DATE_OVERFLOW if the input integer
- * will not fit in an @c int64_t. Note that an @c int64_t can
- * represent a range of over 500 billion years with one second
- * resolution.
- *
- * Floating-point dates are always returned as an @c int64_t. The
- * fractional part is discarded.
- *
- * If the input is a floating-point date and the QCBOR library is
- * compiled with some or all floating-point features disabled, the
- * following errors will be set. If the input is half-precision and
- * half-precision is disabled @ref QCBOR_ERR_HALF_PRECISION_DISABLED
- * is set. This function needs hardware floating-point to convert the
- * floating-point value to an integer so if HW floating point is
- * disabled @ref QCBOR_ERR_HW_FLOAT_DISABLED is set. If all
- * floating-point is disabled then @ref QCBOR_ERR_ALL_FLOAT_DISABLED
- * is set. A previous version of this function would return
- * @ref QCBOR_ERR_FLOAT_DATE_DISABLED in some, but not all, cases when
- * floating-point decoding was disabled.
- *
- * Floating-point dates that are plus infinity, minus infinity or NaN
- * (not-a-number) will result in the @ref QCBOR_ERR_DATE_OVERFLOW
- * error.
- *
- * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
- *
- * See @ref Tag-Usage for discussion on tag requirements.
- *
- * See also @ref CBOR_TAG_DATE_EPOCH, QCBOREncode_AddTDateEpoch() and
- * @ref QCBOR_TYPE_DATE_EPOCH.
-*/
-void
-QCBORDecode_GetEpochDate(QCBORDecodeContext *pCtx,
- uint8_t uTagRequirement,
- int64_t *pnTime);
-
-void
-QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pCtx,
- int64_t nLabel,
- uint8_t uTagRequirement,
- int64_t *pnTime);
-
-void
-QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pCtx,
- const char *szLabel,
- uint8_t uTagRequirement,
- int64_t *pnTime);
-
-
-/**
- * @brief Decode the next item as an days-count epoch date.
- *
- * @param[in] pCtx The decode context.
- * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
- * @param[out] pnDays The decoded epoch date.
- *
- * This decodes the CBOR epoch date tag, integer tag number of 100, or
- * encoded CBOR that is not a tag, but borrows the content format. The
- * date is the number of days (not number of seconds) before or after
- * Jan 1, 1970.
- *
- * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
- *
- * See @ref Tag-Usage for discussion on tag requirements.
- *
- * See also @ref CBOR_TAG_DAYS_EPOCH, QCBOREncode_AddTDaysEpoch() and
- * @ref QCBOR_TYPE_DAYS_EPOCH.
-*/
-void
-QCBORDecode_GetEpochDays(QCBORDecodeContext *pCtx,
- uint8_t uTagRequirement,
- int64_t *pnDays);
-
-void
-QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pCtx,
- int64_t nLabel,
- uint8_t uTagRequirement,
- int64_t *pnDays);
-
-void
-QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pCtx,
- const char *szLabel,
- uint8_t uTagRequirement,
- int64_t *pnDays);
-
-
-
-
-/**
- * @brief Decode the next item as a URI.
- *
- * @param[in] pCtx The decode context.
- * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
- * @param[out] pURI The decoded URI.
- *
- * This decodes a standard CBOR URI tag, integer tag number of 32, or
- * encoded CBOR that is not a tag, that is a URI encoded in a text
- * string.
- *
- * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
- *
- * See @ref Tag-Usage for discussion on tag requirements.
- *
- * See also @ref CBOR_TAG_URI, QCBOREncode_AddTURI() and
- * @ref QCBOR_TYPE_URI.
- */
-static void
-QCBORDecode_GetURI(QCBORDecodeContext *pCtx,
- uint8_t uTagRequirement,
- UsefulBufC *pURI);
-
-static void
-QCBORDecode_GetURIInMapN(QCBORDecodeContext *pCtx,
- int64_t nLabel,
- uint8_t uTagRequirement,
- UsefulBufC *pURI);
-
-static void
-QCBORDecode_GetURIInMapSZ(QCBORDecodeContext *pCtx,
- const char * szLabel,
- uint8_t uTagRequirement,
- UsefulBufC *pURI);
-
-
-/**
- * @brief Decode the next item as base64 encoded text.
- *
- * @param[in] pCtx The decode context.
- * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
- * @param[out] pB64Text The decoded base64 text.
- *
- * This decodes a standard CBOR base64 tag, integer tag number of 34,
- * or encoded CBOR that is not a tag, that is base64 encoded bytes
- * encoded in a text string.
- *
- * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
- *
- * See @ref Tag-Usage for discussion on tag requirements.
- *
- * Note that this does not actually remove the base64 encoding.
- *
- * See also @ref CBOR_TAG_B64, QCBOREncode_AddB64Text() and
- * @ref QCBOR_TYPE_BASE64.
- */
-static void
-QCBORDecode_GetB64(QCBORDecodeContext *pCtx,
- uint8_t uTagRequirement,
- UsefulBufC *pB64Text);
-
-static void
-QCBORDecode_GetB64InMapN(QCBORDecodeContext *pCtx,
- int64_t nLabel,
- uint8_t uTagRequirement,
- UsefulBufC *pB64Text);
-
-static void
-QCBORDecode_GetB64InMapSZ(QCBORDecodeContext *pCtx,
- const char *szLabel,
- uint8_t uTagRequirement,
- UsefulBufC *pB64Text);
-
-/**
- * @brief Decode the next item as base64URL encoded text.
- *
- * @param[in] pCtx The decode context.
- * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
- * @param[out] pB64Text The decoded base64 text.
- *
- * This decodes a standard CBOR base64url tag, integer tag number of
- * 33, or encoded CBOR that is not a tag, that is base64url encoded
- * bytes encoded in a text string.
- *
- * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
- *
- * See @ref Tag-Usage for discussion on tag requirements.
- *
- * Note that this does not actually remove the base64url encoding.
- *
- * See also @ref CBOR_TAG_B64URL, QCBOREncode_AddTB64URLText() and
- * @ref QCBOR_TYPE_BASE64URL.
- */
-static void
-QCBORDecode_GetB64URL(QCBORDecodeContext *pCtx,
- uint8_t uTagRequirement,
- UsefulBufC *pB64Text);
-
-static void
-QCBORDecode_GetB64URLInMapN(QCBORDecodeContext *pCtx,
- int64_t nLabel,
- uint8_t uTagRequirement,
- UsefulBufC *pB64Text);
-
-static void
-QCBORDecode_GetB64URLInMapSZ(QCBORDecodeContext *pCtx,
- const char *szLabel,
- uint8_t uTagRequirement,
- UsefulBufC *pB64Text);
-
-/**
- * @brief Decode the next item as a regular expression.
- *
- * @param[in] pCtx The decode context.
- * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
- * @param[out] pRegex The decoded regular expression.
- *
- * This decodes a standard CBOR regex tag, integer tag number of 35,
- * or encoded CBOR that is not a tag, that is a PERL-compatible
- * regular expression encoded in a text string.
- *
- * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
- *
- * See @ref Tag-Usage for discussion on tag requirements.
- *
- * See also @ref CBOR_TAG_REGEX, QCBOREncode_AddTRegex() and
- * @ref QCBOR_TYPE_REGEX.
- */
-static void
-QCBORDecode_GetRegex(QCBORDecodeContext *pCtx,
- uint8_t uTagRequirement,
- UsefulBufC *pRegex);
-
-static void
-QCBORDecode_GetRegexInMapN(QCBORDecodeContext *pCtx,
- int64_t nLabel,
- uint8_t uTagRequirement,
- UsefulBufC *pRegex);
-
-static void
-QCBORDecode_GetRegexInMapSZ(QCBORDecodeContext *pCtx,
- const char * szLabel,
- uint8_t uTagRequirement,
- UsefulBufC *pRegex);
-
-
-/**
- * @brief Decode the next item as a MIME message.
- *
- * @param[in] pCtx The decode context.
- * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
- * @param[out] pMessage The decoded regular expression.
- * @param[out] pbIsTag257 @c true if tag was 257. May be @c NULL.
- *
- * This decodes the standard CBOR MIME and binary MIME tags, integer
- * tag numbers of 36 or 257, or encoded CBOR that is not a tag, that
- * is a MIME message encoded in a text or binary string.
- *
- * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
- *
- * See @ref Tag-Usage for discussion on tag requirements.
- *
- * The MIME message itself is not parsed.
- *
- * This decodes both tag 36 and 257. If it is tag 257, pbIsTag257 is
- * @c true. The difference between the two is that tag 36 is utf8 and
- * tag 257 is a byte string that can carry binary MIME. QCBOR
- * processes them exactly the same. Possibly the difference can be
- * ignored. NULL can be passed to have no value returned.
- *
- * See also @ref CBOR_TAG_MIME, @ref CBOR_TAG_BINARY_MIME,
- * QCBOREncode_AddTMIMEData(), @ref QCBOR_TYPE_MIME and
- * @ref QCBOR_TYPE_BINARY_MIME.
- *
- * This does no translation of line endings. See QCBOREncode_AddText()
- * for a discussion of line endings in CBOR.
- */
-void
-QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pCtx,
- uint8_t uTagRequirement,
- UsefulBufC *pMessage,
- bool *pbIsTag257);
-
- void
-QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pCtx,
- int64_t nLabel,
- uint8_t uTagRequirement,
- UsefulBufC *pMessage,
- bool *pbIsTag257);
-
-
-void
-QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pCtx,
- const char *szLabel,
- uint8_t uTagRequirement,
- UsefulBufC *pMessage,
- bool *pbIsTag257);
-
-/**
- * @brief Decode the next item as a UUID.
- *
- * @param[in] pCtx The decode context.
- * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
- * @param[out] pUUID The decoded UUID
- *
- * This decodes a standard CBOR UUID tag, integer tag number of 37, or
- * encoded CBOR that is not a tag, that is a UUID encoded in a byte
- * string.
- *
- * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
- *
- * See @ref Tag-Usage for discussion on tag requirements.
- *
- * See also @ref CBOR_TAG_BIN_UUID, QCBOREncode_AddTBinaryUUID() and
- * @ref QCBOR_TYPE_UUID.
- */
-static void
-QCBORDecode_GetBinaryUUID(QCBORDecodeContext *pCtx,
- uint8_t uTagRequirement,
- UsefulBufC *pUUID);
-
-static void
-QCBORDecode_GetBinaryUUIDInMapN(QCBORDecodeContext *pCtx,
- int64_t nLabel,
- uint8_t uTagRequirement,
- UsefulBufC *pUUID);
-
-static void
-QCBORDecode_GetBinaryUUIDInMapSZ(QCBORDecodeContext *pCtx,
- const char *szLabel,
- uint8_t uTagRequirement,
- UsefulBufC *pUUID);
-
-
-
-/**
- * @brief Decode some byte-string wrapped CBOR.
- *
- * @param[in] pCtx The decode context.
- * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
- * @param[out] pBstr Pointer and length of byte-string wrapped CBOR (optional).
- *
- * This is for use on some CBOR that has been wrapped in a byte
- * string. There are several ways that this can occur.
- *
- * First is tag 24 and tag 63. Tag 24 wraps a single CBOR data item
- * and 63 a CBOR sequence. This implementation doesn't distinguish
- * between the two (it would be more code and doesn't seem important).
- *
- * The @ref Tag-Usage discussion on the tag requirement applies here
- * just the same as any other tag.
- *
- * In other cases, CBOR is wrapped in a byte string, but it is
- * identified as CBOR by other means. The contents of a COSE payload
- * are one example of that. They can be identified by the COSE content
- * type, or they can be identified as CBOR indirectly by the protocol
- * that uses COSE. for example, if a blob of CBOR is identified as a
- * CWT, then the COSE payload is CBOR. To enter into CBOR of this
- * type use the @ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG as the \c
- * uTagRequirement argument.
- *
- * Note that byte string wrapped CBOR can also be decoded by getting
- * the byte string with QCBORDecode_GetItem() or
- * QCBORDecode_GetByteString() and feeding it into another instance of
- * QCBORDecode. Doing it with this function has the advantage of using
- * less memory as another instance of QCBORDecode is not necessary.
- *
- * When the wrapped CBOR is entered with this function, the pre-order
- * traversal and such are bounded to the wrapped
- * CBOR. QCBORDecode_ExitBstrWrapped() must be called to resume
- * processing CBOR outside the wrapped CBOR.
- *
- * This does not work on indefinite-length strings. The
- * error @ref QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING will be set.
- *
- * If @c pBstr is not @c NULL the pointer and length of the wrapped
- * CBOR will be returned. This is usually not needed, but sometimes
- * useful, particularly in the case of verifying signed data like the
- * COSE payload. This is usually the pointer and length of the data is
- * that is hashed or MACed.
- *
- * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
- *
- * See also QCBORDecode_ExitBstrWrapped(), QCBORDecode_EnterMap() and
- * QCBORDecode_EnterArray().
- */
-void
-QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pCtx,
- uint8_t uTagRequirement,
- UsefulBufC *pBstr);
-
-void
-QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pCtx,
- int64_t nLabel,
- uint8_t uTagRequirement,
- UsefulBufC *pBstr);
-
-void
-QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pCtx,
- const char *szLabel,
- uint8_t uTagRequirement,
- UsefulBufC *pBstr);
-
-
-/**
- * @brief Exit some bstr-wrapped CBOR has been enetered.
- *
- * @param[in] pCtx The decode context.
- *
- * Bstr-wrapped CBOR must have been entered for this to succeed.
- *
- * The items in the wrapped CBOR that was entered do not have to have
- * been consumed for this to succeed.
- *
- * The this sets the traversal cursor to the item after the
- * byte string that was exited.
- */
-void
-QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pCtx);
-
-
-
/* ========================================================================= *
@@ -1368,36 +794,20 @@
QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pCtx,
uint8_t uType);
+/* Semi-private funcion used by public inline functions. See qcbor_decode.c */
+void
+QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pCtx,
+ uint8_t uType,
+ QCBORItem *pItem,
+ UsefulBufC *pEncodedCBOR);
+
/* Semi-private funcion used by public inline functions. See qcbor_decode.c */
void
-QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
- uint8_t uTagRequirement,
- uint8_t uQCBOR_Type,
- uint64_t uTagNumber,
- UsefulBufC *pBstr);
-
-void
-QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
- const int64_t nLabel,
- const uint8_t uTagRequirement,
- const uint8_t uQCBOR_Type,
- const uint64_t uTagNumber,
- UsefulBufC *pString);
-
-
-
-
-
-
-
-void
-QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- uint8_t uTagRequirement,
- uint8_t uQCBOR_Type,
- uint64_t uTagNumber,
- UsefulBufC *pString);
+QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pCtx,
+ QCBORItem *pTarget,
+ QCBORItem *pItem,
+ UsefulBufC *pEncodedCBOR);
@@ -1425,22 +835,6 @@
}
-/* Semi-private funcion used by public inline functions. See qcbor_decode.c */
-void
-QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pCtx,
- uint8_t uType,
- QCBORItem *pItem,
- UsefulBufC *pEncodedCBOR);
-
-
-/* Semi-private funcion used by public inline functions. See qcbor_decode.c */
-void
-QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pCtx,
- QCBORItem *pTarget,
- QCBORItem *pItem,
- UsefulBufC *pEncodedCBOR);
-
-
static inline void
QCBORDecode_GetArray(QCBORDecodeContext *pMe,
QCBORItem *pItem,
@@ -1687,296 +1081,6 @@
}
-
-static inline void
-QCBORDecode_GetDateString(QCBORDecodeContext *pMe,
- const uint8_t uTagRequirement,
- UsefulBufC *pValue)
-{
- QCBORDecode_Private_GetTaggedString(pMe,
- uTagRequirement,
- QCBOR_TYPE_DATE_STRING,
- CBOR_TAG_DATE_STRING,
- pValue);
-}
-
-static inline void
-QCBORDecode_GetDateStringInMapN(QCBORDecodeContext *pMe,
- const int64_t nLabel,
- const uint8_t uTagRequirement,
- UsefulBufC *pText)
-{
- QCBORDecode_Private_GetTaggedStringInMapN(pMe,
- nLabel,
- uTagRequirement,
- QCBOR_TYPE_DATE_STRING,
- CBOR_TAG_DATE_STRING,
- pText);
-}
-
-static inline void
-QCBORDecode_GetDateStringInMapSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- const uint8_t uTagRequirement,
- UsefulBufC *pText)
-{
- QCBORDecode_Private_GetTaggedStringInMapSZ(pMe,
- szLabel,
- uTagRequirement,
- QCBOR_TYPE_DATE_STRING,
- CBOR_TAG_DATE_STRING,
- pText);
-}
-
-static inline void
-QCBORDecode_GetDaysString(QCBORDecodeContext *pMe,
- const uint8_t uTagRequirement,
- UsefulBufC *pValue)
-{
- QCBORDecode_Private_GetTaggedString(pMe,
- uTagRequirement,
- QCBOR_TYPE_DATE_STRING,
- CBOR_TAG_DATE_STRING,
- pValue);
-}
-
-static inline void
-QCBORDecode_GetDaysStringInMapN(QCBORDecodeContext *pMe,
- const int64_t nLabel,
- const uint8_t uTagRequirement,
- UsefulBufC *pText)
-{
- QCBORDecode_Private_GetTaggedStringInMapN(pMe,
- nLabel,
- uTagRequirement,
- QCBOR_TYPE_DAYS_STRING,
- CBOR_TAG_DAYS_STRING,
- pText);
-}
-
-
-static inline void
-QCBORDecode_GetDaysStringInMapSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- const uint8_t uTagRequirement,
- UsefulBufC *pText)
-{
- QCBORDecode_Private_GetTaggedStringInMapSZ(pMe,
- szLabel,
- uTagRequirement,
- QCBOR_TYPE_DAYS_STRING,
- CBOR_TAG_DAYS_STRING,
- pText);
-
-}
-
-
-
-static inline void
-QCBORDecode_GetURI(QCBORDecodeContext *pMe,
- const uint8_t uTagRequirement,
- UsefulBufC *pUUID)
-{
- QCBORDecode_Private_GetTaggedString(pMe,
- uTagRequirement,
- QCBOR_TYPE_URI,
- CBOR_TAG_URI,
- pUUID);
-}
-
-static inline void
-QCBORDecode_GetURIInMapN(QCBORDecodeContext *pMe,
- const int64_t nLabel,
- const uint8_t uTagRequirement,
- UsefulBufC *pUUID)
-{
- QCBORDecode_Private_GetTaggedStringInMapN(pMe,
- nLabel,
- uTagRequirement,
- QCBOR_TYPE_URI,
- CBOR_TAG_URI,
- pUUID);
-}
-
-static inline void
-QCBORDecode_GetURIInMapSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- const uint8_t uTagRequirement,
- UsefulBufC *pUUID)
-{
- QCBORDecode_Private_GetTaggedStringInMapSZ(pMe,
- szLabel,
- uTagRequirement,
- QCBOR_TYPE_URI,
- CBOR_TAG_URI,
- pUUID);
-}
-
-
-static inline void
-QCBORDecode_GetB64(QCBORDecodeContext *pMe,
- const uint8_t uTagRequirement,
- UsefulBufC *pB64Text)
-{
- QCBORDecode_Private_GetTaggedString(pMe,
- uTagRequirement,
- QCBOR_TYPE_BASE64,
- CBOR_TAG_B64,
- pB64Text);
-}
-
-static inline void
-QCBORDecode_GetB64InMapN(QCBORDecodeContext *pMe,
- const int64_t nLabel,
- const uint8_t uTagRequirement,
- UsefulBufC *pB64Text)
-{
- QCBORDecode_Private_GetTaggedStringInMapN(pMe,
- nLabel,
- uTagRequirement,
- QCBOR_TYPE_BASE64,
- CBOR_TAG_B64,
- pB64Text);
-}
-
-static inline void
-QCBORDecode_GetB64InMapSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- const uint8_t uTagRequirement,
- UsefulBufC *pB64Text)
-{
- QCBORDecode_Private_GetTaggedStringInMapSZ(pMe,
- szLabel,
- uTagRequirement,
- QCBOR_TYPE_BASE64,
- CBOR_TAG_B64,
- pB64Text);
-}
-
-
-static inline void
-QCBORDecode_GetB64URL(QCBORDecodeContext *pMe,
- const uint8_t uTagRequirement,
- UsefulBufC *pB64Text)
-{
- QCBORDecode_Private_GetTaggedString(pMe,
- uTagRequirement,
- QCBOR_TYPE_BASE64URL,
- CBOR_TAG_B64URL,
- pB64Text);
-}
-
-static inline void
-QCBORDecode_GetB64URLInMapN(QCBORDecodeContext *pMe,
- const int64_t nLabel,
- const uint8_t uTagRequirement,
- UsefulBufC *pB64Text)
-{
- QCBORDecode_Private_GetTaggedStringInMapN(pMe,
- nLabel,
- uTagRequirement,
- QCBOR_TYPE_BASE64URL,
- CBOR_TAG_B64URL,
- pB64Text);
-}
-
-static inline void
-QCBORDecode_GetB64URLInMapSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- const uint8_t uTagRequirement,
- UsefulBufC *pB64Text)
-{
- QCBORDecode_Private_GetTaggedStringInMapSZ(pMe,
- szLabel,
- uTagRequirement,
- QCBOR_TYPE_BASE64URL,
- CBOR_TAG_B64URL,
- pB64Text);
-}
-
-
-static inline void
-QCBORDecode_GetRegex(QCBORDecodeContext *pMe,
- const uint8_t uTagRequirement,
- UsefulBufC *pRegex)
-{
- QCBORDecode_Private_GetTaggedString(pMe,
- uTagRequirement,
- QCBOR_TYPE_REGEX,
- CBOR_TAG_REGEX,
- pRegex);
-}
-
-static inline void
-QCBORDecode_GetRegexInMapN(QCBORDecodeContext *pMe,
- const int64_t nLabel,
- const uint8_t uTagRequirement,
- UsefulBufC *pRegex)
-{
- QCBORDecode_Private_GetTaggedStringInMapN(pMe,
- nLabel,
- uTagRequirement,
- QCBOR_TYPE_REGEX,
- CBOR_TAG_REGEX,
- pRegex);
-}
-
-
-static inline void
-QCBORDecode_GetRegexInMapSZ(QCBORDecodeContext *pMe,
- const char * szLabel,
- const uint8_t uTagRequirement,
- UsefulBufC *pRegex)
-{
- QCBORDecode_Private_GetTaggedStringInMapSZ(pMe,
- szLabel,
- uTagRequirement,
- QCBOR_TYPE_REGEX,
- CBOR_TAG_REGEX,
- pRegex);
-}
-
-
-static inline void
-QCBORDecode_GetBinaryUUID(QCBORDecodeContext *pMe,
- const uint8_t uTagRequirement,
- UsefulBufC *pUUID)
-{
- QCBORDecode_Private_GetTaggedString(pMe,
- uTagRequirement,
- QCBOR_TYPE_UUID,
- CBOR_TAG_BIN_UUID,
- pUUID);
-}
-
-static inline void
-QCBORDecode_GetBinaryUUIDInMapN(QCBORDecodeContext *pMe,
- const int64_t nLabel,
- const uint8_t uTagRequirement,
- UsefulBufC *pUUID)
-{
- QCBORDecode_Private_GetTaggedStringInMapN(pMe,
- nLabel,
- uTagRequirement,
- QCBOR_TYPE_UUID,
- CBOR_TAG_BIN_UUID,
- pUUID);
-}
-
-static inline void
-QCBORDecode_GetBinaryUUIDInMapSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- const uint8_t uTagRequirement,
- UsefulBufC *pUUID)
-{
- QCBORDecode_Private_GetTaggedStringInMapSZ(pMe,
- szLabel,
- uTagRequirement,
- QCBOR_TYPE_UUID,
- CBOR_TAG_BIN_UUID,
- pUUID);
-}
-
/* ======================================================================== *
* END OF PRIVATE INLINE IMPLEMENTATION *
* ======================================================================== */
diff --git a/inc/qcbor/qcbor_tag_decode.h b/inc/qcbor/qcbor_tag_decode.h
index d952387..7f92a48 100644
--- a/inc/qcbor/qcbor_tag_decode.h
+++ b/inc/qcbor/qcbor_tag_decode.h
@@ -1,5 +1,5 @@
/* ==========================================================================
- * qcbor_tag_decode.h -- Tag content decoders
+ * qcbor_tag_decode.h -- Tag decoding
*
* Copyright (c) 2024, Laurence Lundblade. All rights reserved.
*
@@ -7,7 +7,7 @@
*
* See BSD-3-Clause license in README.md
*
- * Created on 9/5/24
+ * Forked from qcbor_decode.c on 9/5/24
* ========================================================================== */
#ifndef qcbor_tag_decode_h
@@ -42,34 +42,742 @@
* ## Tags Decoding
*
* TODO: lots to write here
+ *
+ * * @anchor Tag-Usage
+ * ## Tag Usage
+ *
+ * Data types beyond the basic CBOR types of numbers, strings, maps and
+ * arrays are called tags. The main registry of these new types is in
+ * the IANA CBOR tags registry. These new types may be simple such a
+ * number that is to be interpreted as a date, or of moderate complexity
+ * such as defining a decimal fraction that is an array containing a
+ * mantissa and exponent, or complex such as format for signing and
+ * encryption.
+ *
+ * When a tag occurs in a protocol it is encoded as an integer tag
+ * number plus the content of the tag.
+ *
+ * The content format of a tag may also be "borrowed". For example, a
+ * protocol definition may say that a particular data item is an epoch
+ * date just like tag 1, but not actually tag 1. In practice the
+ * difference is the presence or absence of the integer tag number in
+ * the encoded CBOR.
+ *
+ * The decoding functions for these new types takes a tag requirement
+ * parameter to say whether the item is a tag, is just borrowing the
+ * content format and is not a tag, or whether either is OK.
+ *
+ * If the parameter indicates the item must be a tag (@ref
+ * QCBOR_TAG_REQUIREMENT_TAG), then @ref QCBOR_ERR_UNEXPECTED_TYPE is
+ * set if it is not one of the expected tag types. To decode correctly
+ * the contents of the tag must also be of the correct type. For
+ * example, to decode an epoch date tag the content must be an integer
+ * or floating-point value.
+ *
+ * If the parameter indicates it should not be a tag
+ * (@ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG), then
+ * @ref QCBOR_ERR_UNEXPECTED_TYPE set if it is a tag or the type of the
+ * encoded CBOR is not what is expected. In the example of an epoch
+ * date, the data type must be an integer or floating-point value. This
+ * is the case where the content format of a tag is borrowed.
+ *
+ * The parameter can also indicate that either a tag or no tag is
+ * allowed ( @ref QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG ). A good protocol
+ * design should however be clear and choose one or the other and not
+ * need this option. This is a way to implement "be liberal in what you
+ * accept", however these days that is less in favor. See
+ * https://tools.ietf.org/id/draft-thomson-postel-was-wrong-03.html.
+ *
+ * Map searching works with indefinite length strings. A string
+ * allocator must be set up the same as for any handling of indefinite
+ * length strings. However, It currently over-allocates memory from the
+ * string pool and thus requires a much larger string pool than it
+ * should. The over-allocation happens every time a map is searched by
+ * label. (This may be corrected in the future).
+ *
+ *
+ * TODO: this text isn't right
+ * In v1, some spiffy decode functions ignored tag numbers and
+ * some didn't. For example, GetInt64 ignored and GetString didn't.
+ * The "GetXxx" where Xxxx is a tag ignore conditionally based
+ * on an argument.
+ * (Would be good to verify this with tests)
+ *
+ * Do we fix the behavior of GetString in v1? Relax so it
+ * allows tag numbers like the rest? Probably.
+ *
+ * In v2, the whole mechanism is with GetTagNumbers. They are
+ * never ignored and they must always be consumed.
+ *
+ * With v2 in v1 mode, the functions that were ignoring
+ * tags must go back to ignoring them.
+ *
+ * How does TagRequirement work in v2?
+ *
+ * GetInt64 and GetString require all tag numbs to be processed
+ * to work.
*/
-/*
- TODO: integrate this
- In v1, some spiffy decode functions ignored tag numbers and
- some didn't. For example, GetInt64 ignored and GetString didn't.
- The "GetXxx" where Xxxx is a tag ignore conditionally based
- on an argument.
- (Would be good to verify this with tests)
+/** The data item must be a tag of the expected type. It is an error
+ * if it is not. For example when calling QCBORDecode_GetEpochDate(),
+ * the data item must be an @ref CBOR_TAG_DATE_EPOCH tag. See
+ * @ref Tag-Usage. */
+#define QCBOR_TAG_REQUIREMENT_TAG 0
- Do we fix the behavior of GetString in v1? Relax so it
- allows tag numbers like the rest? Probably.
+/** The data item must be of the type expected for content data type
+ * being fetched. It is an error if it is not. For example, when
+ * calling QCBORDecode_GetEpochDate() and it must not be an @ref
+ * CBOR_TAG_DATE_EPOCH tag. See @ref Tag-Usage. */
+#define QCBOR_TAG_REQUIREMENT_NOT_A_TAG 1
- In v2, the whole mechanism is with GetTagNumbers. They are
- never ignored and they must always be consumed.
+/** Either of the above two are allowed. This allows implementation of
+ * being liberal in what you receive, but it is better if CBOR-based
+ * protocols pick one and stick to and not required the reciever to
+ * take either. See @ref Tag-Usage. */
+#define QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG 2
- With v2 in v1 mode, the functions that were ignoring
- tags must go back to ignoring them.
-
- How does TagRequirement work in v2?
-
- GetInt64 and GetString require all tag numbs to be processed
- to work.
+/** Add this into the above value if other tags not processed by QCBOR
+ * are to be allowed to surround the data item. See @ref Tag-Usage. */
+#define QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS 0x80
+#ifndef QCBOR_DISABLE_TAGS
+/**
+ * @brief Returns the tag numbers for an item.
+ *
+ * @param[in] pCtx The decoder context.
+ * @param[out] puTagNumber The returned tag number.
+ *
+ * In QCBOR v2, all tag numbers on an item MUST be fetched with this
+ * method. If not, @ref QCBOR_ERR_UNPROCESSED_TAG_NUMBER will
+ * occur. This is a major change from QCBORv1. The QCBOR v1 behavior
+ * is too lax for proper CBOR decoding. When a tag number occurs it
+ * indicates the item is a new data type (except for a few tag numbers
+ * that are hints). Note also that in RFC 7049, tag numbers were
+ * incorrectly characterized as optional implying they could be
+ * ignored.
+ *
+ * In typical item decoding, tag numbers are not used, not present and
+ * not expected. There's no need to call this.
+ *
+ * When the protocol being decoded does use a tag number then this
+ * must be called for the items were the tag numbers occur before the
+ * items themselves are decoded. Making this call prevents the
+ * @ref QCBOR_ERR_UNPROCESSED_TAG_NUMBER error, but the caller still has to
+ * check that the tag number is the right one. Probably the tag number
+ * will be used to switch the flow of the decoder.
+ *
+ * It's possible that an item might use the presence/absence of a tag
+ * number to switch the flow of decoding. If there's a possibility of
+ * a tag number then this must be called.
+ *
+ * If this is called and there is no tag number, then this will return
+ * @ref QCBOR_SUCCESS and the tag number returned will be
+ * @ref CBOR_TAG_INVALID64.
+ *
+ * Usually there is only one tag number per item, but CBOR allows
+ * more. That it allows nesting of tags where the content of one tag
+ * is another tag. If there are multiple tag numbers, this must be
+ * called multiple times. This only returns one tag number at a time,
+ * because tag numbers are typically processed one at a time.
+ *
+ * If there is an error decoding the tag or the item it is on, the
+ * error code will be set and the tag number @ref CBOR_TAG_INVALID64
+ * will be returned. That is, @ref CBOR_TAG_INVALID64 will be returned if
+ * there is a decode error or there is no tag number.
*/
+void
+QCBORDecode_VGetNextTagNumber(QCBORDecodeContext *pCtx, uint64_t *puTagNumber);
+
+
+/**
+ * @brief Returns the tag numbers for an item.
+ *
+ * @param[in] pCtx The decoder context.
+ * @param[out] puTagNumber The returned tag number.
+ *
+ * @return See error table of decoding errors set by QCBORDecode_VGetNext().
+ *
+ * Like QCBORDecode_VGetNextTagNumber(), but returns the
+ * error rather than set last error.
+ */
+QCBORError
+QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pCtx, uint64_t *puTagNumber);
+
+QCBORError
+QCBORDecode_GetNextTagNumberInMapN(QCBORDecodeContext *pCtx, int64_t nLabel, uint64_t *puTagNumber);
+
+
+QCBORError
+QCBORDecode_GetNextTagNumberInMapSZ(QCBORDecodeContext *pCtx, const char *szLabel, uint64_t *puTagNumber);
+
+
+
+/**
+ * @brief Returns the tag numbers for a decoded item.
+ *
+ * @param[in] pCtx The decoder context.
+ * @param[in] pItem The CBOR item to get the tag for.
+ * @param[in] uIndex The index of the tag to get.
+ *
+ * @returns The nth tag number or @ref CBOR_TAG_INVALID64.
+ *
+ * Typically, this is only used with @ref QCBOR_DECODE_CONFIG_UNPROCESSED_TAG_NUMBERS.
+ * Normally, tag numbers are processed QCBORDecode_VGetNextTagNumber() or
+ * QCBORTagContentCallBack.
+ *
+ * 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 is the outermost, the one
+ * furthest form the data item that is the tag content. This is
+ * the opposite order of QCBORDecode_GetNthTag(), but more
+ * useful.
+ *
+ * Deep tag nesting is rare so this implementation imposes a limit of
+ * @ref QCBOR_MAX_TAGS_PER_ITEM on nesting and returns @ref
+ * 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 @ref Tag-Decoding @ref CBORTags, @ref Tag-Usage and @ref Tags-Overview.
+ *
+ * To reduce memory used by a @ref QCBORItem, tag numbers larger than
+ * @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
+ * getting the item. This is also returned if there are no tags on the
+ * item or no tag at @c uIndex.
+ */
+uint64_t
+QCBORDecode_GetNthTagNumber(const QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint8_t uIndex);
+
+
+/**
+ * @brief Returns the tag numbers for last-decoded item.
+ *
+ * @param[in] pCtx The decoder context.
+ * @param[in] uIndex The index of the tag to get.
+ *
+ * @returns The nth tag number or @ref CBOR_TAG_INVALID64.
+ *
+ * This returns tags of the most recently decoded item. See
+ * QCBORDecode_GetNthTagNumber(). This is particularly of use for spiffy
+ * decode functions that don't return a @ref QCBORItem.
+ *
+ * This does not work for QCBORDecode_GetNext(),
+ * QCBORDecode_PeekNext(), QCBORDecode_VPeekNext() or
+ * QCBORDecode_VGetNextConsume() but these all return a
+ * @ref QCBORItem, so it is not necessary.
+ *
+ * If a decoding error is set, then this returns @ref CBOR_TAG_INVALID64.
+ */
+uint64_t
+QCBORDecode_GetNthTagNumberOfLast(QCBORDecodeContext *pCtx, uint8_t uIndex);
+
+#endif /* ! QCBOR_DISABLE_TAGS */
+
+
+
+
+/**
+ * @brief Decode some byte-string wrapped CBOR.
+ *
+ * @param[in] pCtx The decode context.
+ * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
+ * @param[out] pBstr Pointer and length of byte-string wrapped CBOR (optional).
+ *
+ * This is for use on some CBOR that has been wrapped in a byte
+ * string. There are several ways that this can occur.
+ *
+ * First is tag 24 and tag 63. Tag 24 wraps a single CBOR data item
+ * and 63 a CBOR sequence. This implementation doesn't distinguish
+ * between the two (it would be more code and doesn't seem important).
+ *
+ * The @ref Tag-Usage discussion on the tag requirement applies here
+ * just the same as any other tag.
+ *
+ * In other cases, CBOR is wrapped in a byte string, but it is
+ * identified as CBOR by other means. The contents of a COSE payload
+ * are one example of that. They can be identified by the COSE content
+ * type, or they can be identified as CBOR indirectly by the protocol
+ * that uses COSE. for example, if a blob of CBOR is identified as a
+ * CWT, then the COSE payload is CBOR. To enter into CBOR of this
+ * type use the @ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG as the \c
+ * uTagRequirement argument.
+ *
+ * Note that byte string wrapped CBOR can also be decoded by getting
+ * the byte string with QCBORDecode_GetItem() or
+ * QCBORDecode_GetByteString() and feeding it into another instance of
+ * QCBORDecode. Doing it with this function has the advantage of using
+ * less memory as another instance of QCBORDecode is not necessary.
+ *
+ * When the wrapped CBOR is entered with this function, the pre-order
+ * traversal and such are bounded to the wrapped
+ * CBOR. QCBORDecode_ExitBstrWrapped() must be called to resume
+ * processing CBOR outside the wrapped CBOR.
+ *
+ * This does not work on indefinite-length strings. The
+ * error @ref QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING will be set.
+ *
+ * If @c pBstr is not @c NULL the pointer and length of the wrapped
+ * CBOR will be returned. This is usually not needed, but sometimes
+ * useful, particularly in the case of verifying signed data like the
+ * COSE payload. This is usually the pointer and length of the data is
+ * that is hashed or MACed.
+ *
+ * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
+ *
+ * See also QCBORDecode_ExitBstrWrapped(), QCBORDecode_EnterMap() and
+ * QCBORDecode_EnterArray().
+ */
+void
+QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pCtx,
+ uint8_t uTagRequirement,
+ UsefulBufC *pBstr);
+
+void
+QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pCtx,
+ int64_t nLabel,
+ uint8_t uTagRequirement,
+ UsefulBufC *pBstr);
+
+void
+QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pCtx,
+ const char *szLabel,
+ uint8_t uTagRequirement,
+ UsefulBufC *pBstr);
+
+
+/**
+ * @brief Exit some bstr-wrapped CBOR has been enetered.
+ *
+ * @param[in] pCtx The decode context.
+ *
+ * Bstr-wrapped CBOR must have been entered for this to succeed.
+ *
+ * The items in the wrapped CBOR that was entered do not have to have
+ * been consumed for this to succeed.
+ *
+ * The this sets the traversal cursor to the item after the
+ * byte string that was exited.
+ */
+void
+QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pCtx);
+
+
+
+
+/**
+ * @brief Decode the next item as a date string.
+ *
+ * @param[in] pCtx The decode context.
+ * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
+ * @param[out] pDateString The decoded date.
+ *
+ * This decodes the standard CBOR date/time string tag, integer tag
+ * number of 0, or encoded CBOR that is not a tag, but borrows the
+ * date string content format.
+ *
+ * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
+ *
+ * See @ref Tag-Usage for discussion on tag requirements.
+ *
+ * See also @ref CBOR_TAG_DATE_STRING, QCBOREncode_AddDateString() and
+ * @ref QCBOR_TYPE_DATE_STRING.
+ */
+static void
+QCBORDecode_GetDateString(QCBORDecodeContext *pCtx,
+ uint8_t uTagRequirement,
+ UsefulBufC *pDateString);
+
+static void
+QCBORDecode_GetDateStringInMapN(QCBORDecodeContext *pCtx,
+ int64_t nLabel,
+ uint8_t uTagRequirement,
+ UsefulBufC *pDateString);
+
+static void
+QCBORDecode_GetDateStringInMapSZ(QCBORDecodeContext *pCtx,
+ const char *szLabel,
+ uint8_t uTagRequirement,
+ UsefulBufC *pDateString);
+
+
+/**
+ * @brief Decode the next item as an epoch date.
+ *
+ * @param[in] pCtx The decode context.
+ * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
+ * @param[out] pnTime The decoded epoch date.
+ *
+ * This decodes the standard CBOR epoch date/time tag, integer tag
+ * number of 1. This will also decode any integer or floating-point
+ * number as an epoch date (a tag 1 epoch date is just an integer or
+ * floating-point number).
+ *
+ * This will set @ref QCBOR_ERR_DATE_OVERFLOW if the input integer
+ * will not fit in an @c int64_t. Note that an @c int64_t can
+ * represent a range of over 500 billion years with one second
+ * resolution.
+ *
+ * Floating-point dates are always returned as an @c int64_t. The
+ * fractional part is discarded.
+ *
+ * If the input is a floating-point date and the QCBOR library is
+ * compiled with some or all floating-point features disabled, the
+ * following errors will be set. If the input is half-precision and
+ * half-precision is disabled @ref QCBOR_ERR_HALF_PRECISION_DISABLED
+ * is set. This function needs hardware floating-point to convert the
+ * floating-point value to an integer so if HW floating point is
+ * disabled @ref QCBOR_ERR_HW_FLOAT_DISABLED is set. If all
+ * floating-point is disabled then @ref QCBOR_ERR_ALL_FLOAT_DISABLED
+ * is set. A previous version of this function would return
+ * @ref QCBOR_ERR_FLOAT_DATE_DISABLED in some, but not all, cases when
+ * floating-point decoding was disabled.
+ *
+ * Floating-point dates that are plus infinity, minus infinity or NaN
+ * (not-a-number) will result in the @ref QCBOR_ERR_DATE_OVERFLOW
+ * error.
+ *
+ * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
+ *
+ * See @ref Tag-Usage for discussion on tag requirements.
+ *
+ * See also @ref CBOR_TAG_DATE_EPOCH, QCBOREncode_AddTDateEpoch() and
+ * @ref QCBOR_TYPE_DATE_EPOCH.
+*/
+void
+QCBORDecode_GetEpochDate(QCBORDecodeContext *pCtx,
+ uint8_t uTagRequirement,
+ int64_t *pnTime);
+
+void
+QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pCtx,
+ int64_t nLabel,
+ uint8_t uTagRequirement,
+ int64_t *pnTime);
+
+void
+QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pCtx,
+ const char *szLabel,
+ uint8_t uTagRequirement,
+ int64_t *pnTime);
+
+
+
+/**
+ * @brief Decode the next item as a date-only string.
+ *
+ * @param[in] pCtx The decode context.
+ * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
+ * @param[out] pDateString The decoded date.
+ *
+ * This decodes the CBOR date-only string tag, integer tag number of
+ * 1004, or encoded CBOR that is not a tag, but borrows the date-only
+ * string content format. An example of the format is "1985-04-12".
+ *
+ * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
+ *
+ * See @ref Tag-Usage for discussion on tag requirements.
+ *
+ * See also @ref CBOR_TAG_DAYS_STRING, QCBOREncode_AddDaysString() and
+ * @ref QCBOR_TYPE_DAYS_STRING.
+ */
+static void
+QCBORDecode_GetDaysString(QCBORDecodeContext *pCtx,
+ uint8_t uTagRequirement,
+ UsefulBufC *pDateString);
+
+static void
+QCBORDecode_GetDaysStringInMapN(QCBORDecodeContext *pCtx,
+ int64_t nLabel,
+ uint8_t uTagRequirement,
+ UsefulBufC *pDateString);
+
+static void
+QCBORDecode_GetDaysStringInMapSZ(QCBORDecodeContext *pCtx,
+ const char *szLabel,
+ uint8_t uTagRequirement,
+ UsefulBufC *pDateString);
+
+
+/**
+ * @brief Decode the next item as an days-count epoch date.
+ *
+ * @param[in] pCtx The decode context.
+ * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
+ * @param[out] pnDays The decoded epoch date.
+ *
+ * This decodes the CBOR epoch date tag, integer tag number of 100, or
+ * encoded CBOR that is not a tag, but borrows the content format. The
+ * date is the number of days (not number of seconds) before or after
+ * Jan 1, 1970.
+ *
+ * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
+ *
+ * See @ref Tag-Usage for discussion on tag requirements.
+ *
+ * See also @ref CBOR_TAG_DAYS_EPOCH, QCBOREncode_AddTDaysEpoch() and
+ * @ref QCBOR_TYPE_DAYS_EPOCH.
+*/
+void
+QCBORDecode_GetEpochDays(QCBORDecodeContext *pCtx,
+ uint8_t uTagRequirement,
+ int64_t *pnDays);
+
+void
+QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pCtx,
+ int64_t nLabel,
+ uint8_t uTagRequirement,
+ int64_t *pnDays);
+
+void
+QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pCtx,
+ const char *szLabel,
+ uint8_t uTagRequirement,
+ int64_t *pnDays);
+
+
+/**
+ * @brief Decode the next item as a URI.
+ *
+ * @param[in] pCtx The decode context.
+ * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
+ * @param[out] pURI The decoded URI.
+ *
+ * This decodes a standard CBOR URI tag, integer tag number of 32, or
+ * encoded CBOR that is not a tag, that is a URI encoded in a text
+ * string.
+ *
+ * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
+ *
+ * See @ref Tag-Usage for discussion on tag requirements.
+ *
+ * See also @ref CBOR_TAG_URI, QCBOREncode_AddTURI() and
+ * @ref QCBOR_TYPE_URI.
+ */
+static void
+QCBORDecode_GetURI(QCBORDecodeContext *pCtx,
+ uint8_t uTagRequirement,
+ UsefulBufC *pURI);
+
+static void
+QCBORDecode_GetURIInMapN(QCBORDecodeContext *pCtx,
+ int64_t nLabel,
+ uint8_t uTagRequirement,
+ UsefulBufC *pURI);
+
+static void
+QCBORDecode_GetURIInMapSZ(QCBORDecodeContext *pCtx,
+ const char * szLabel,
+ uint8_t uTagRequirement,
+ UsefulBufC *pURI);
+
+
+/**
+ * @brief Decode the next item as base64 encoded text.
+ *
+ * @param[in] pCtx The decode context.
+ * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
+ * @param[out] pB64Text The decoded base64 text.
+ *
+ * This decodes a standard CBOR base64 tag, integer tag number of 34,
+ * or encoded CBOR that is not a tag, that is base64 encoded bytes
+ * encoded in a text string.
+ *
+ * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
+ *
+ * See @ref Tag-Usage for discussion on tag requirements.
+ *
+ * Note that this does not actually remove the base64 encoding.
+ *
+ * See also @ref CBOR_TAG_B64, QCBOREncode_AddB64Text() and
+ * @ref QCBOR_TYPE_BASE64.
+ */
+static void
+QCBORDecode_GetB64(QCBORDecodeContext *pCtx,
+ uint8_t uTagRequirement,
+ UsefulBufC *pB64Text);
+
+static void
+QCBORDecode_GetB64InMapN(QCBORDecodeContext *pCtx,
+ int64_t nLabel,
+ uint8_t uTagRequirement,
+ UsefulBufC *pB64Text);
+
+static void
+QCBORDecode_GetB64InMapSZ(QCBORDecodeContext *pCtx,
+ const char *szLabel,
+ uint8_t uTagRequirement,
+ UsefulBufC *pB64Text);
+
+/**
+ * @brief Decode the next item as base64URL encoded text.
+ *
+ * @param[in] pCtx The decode context.
+ * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
+ * @param[out] pB64Text The decoded base64 text.
+ *
+ * This decodes a standard CBOR base64url tag, integer tag number of
+ * 33, or encoded CBOR that is not a tag, that is base64url encoded
+ * bytes encoded in a text string.
+ *
+ * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
+ *
+ * See @ref Tag-Usage for discussion on tag requirements.
+ *
+ * Note that this does not actually remove the base64url encoding.
+ *
+ * See also @ref CBOR_TAG_B64URL, QCBOREncode_AddTB64URLText() and
+ * @ref QCBOR_TYPE_BASE64URL.
+ */
+static void
+QCBORDecode_GetB64URL(QCBORDecodeContext *pCtx,
+ uint8_t uTagRequirement,
+ UsefulBufC *pB64Text);
+
+static void
+QCBORDecode_GetB64URLInMapN(QCBORDecodeContext *pCtx,
+ int64_t nLabel,
+ uint8_t uTagRequirement,
+ UsefulBufC *pB64Text);
+
+static void
+QCBORDecode_GetB64URLInMapSZ(QCBORDecodeContext *pCtx,
+ const char *szLabel,
+ uint8_t uTagRequirement,
+ UsefulBufC *pB64Text);
+
+/**
+ * @brief Decode the next item as a regular expression.
+ *
+ * @param[in] pCtx The decode context.
+ * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
+ * @param[out] pRegex The decoded regular expression.
+ *
+ * This decodes a standard CBOR regex tag, integer tag number of 35,
+ * or encoded CBOR that is not a tag, that is a PERL-compatible
+ * regular expression encoded in a text string.
+ *
+ * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
+ *
+ * See @ref Tag-Usage for discussion on tag requirements.
+ *
+ * See also @ref CBOR_TAG_REGEX, QCBOREncode_AddTRegex() and
+ * @ref QCBOR_TYPE_REGEX.
+ */
+static void
+QCBORDecode_GetRegex(QCBORDecodeContext *pCtx,
+ uint8_t uTagRequirement,
+ UsefulBufC *pRegex);
+
+static void
+QCBORDecode_GetRegexInMapN(QCBORDecodeContext *pCtx,
+ int64_t nLabel,
+ uint8_t uTagRequirement,
+ UsefulBufC *pRegex);
+
+static void
+QCBORDecode_GetRegexInMapSZ(QCBORDecodeContext *pCtx,
+ const char * szLabel,
+ uint8_t uTagRequirement,
+ UsefulBufC *pRegex);
+
+
+/**
+ * @brief Decode the next item as a MIME message.
+ *
+ * @param[in] pCtx The decode context.
+ * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
+ * @param[out] pMessage The decoded regular expression.
+ * @param[out] pbIsTag257 @c true if tag was 257. May be @c NULL.
+ *
+ * This decodes the standard CBOR MIME and binary MIME tags, integer
+ * tag numbers of 36 or 257, or encoded CBOR that is not a tag, that
+ * is a MIME message encoded in a text or binary string.
+ *
+ * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
+ *
+ * See @ref Tag-Usage for discussion on tag requirements.
+ *
+ * The MIME message itself is not parsed.
+ *
+ * This decodes both tag 36 and 257. If it is tag 257, pbIsTag257 is
+ * @c true. The difference between the two is that tag 36 is utf8 and
+ * tag 257 is a byte string that can carry binary MIME. QCBOR
+ * processes them exactly the same. Possibly the difference can be
+ * ignored. NULL can be passed to have no value returned.
+ *
+ * See also @ref CBOR_TAG_MIME, @ref CBOR_TAG_BINARY_MIME,
+ * QCBOREncode_AddTMIMEData(), @ref QCBOR_TYPE_MIME and
+ * @ref QCBOR_TYPE_BINARY_MIME.
+ *
+ * This does no translation of line endings. See QCBOREncode_AddText()
+ * for a discussion of line endings in CBOR.
+ */
+void
+QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pCtx,
+ uint8_t uTagRequirement,
+ UsefulBufC *pMessage,
+ bool *pbIsTag257);
+
+ void
+QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pCtx,
+ int64_t nLabel,
+ uint8_t uTagRequirement,
+ UsefulBufC *pMessage,
+ bool *pbIsTag257);
+
+
+void
+QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pCtx,
+ const char *szLabel,
+ uint8_t uTagRequirement,
+ UsefulBufC *pMessage,
+ bool *pbIsTag257);
+
+/**
+ * @brief Decode the next item as a UUID.
+ *
+ * @param[in] pCtx The decode context.
+ * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
+ * @param[out] pUUID The decoded UUID
+ *
+ * This decodes a standard CBOR UUID tag, integer tag number of 37, or
+ * encoded CBOR that is not a tag, that is a UUID encoded in a byte
+ * string.
+ *
+ * Please see @ref Decode-Errors-Overview "Decode Errors Overview".
+ *
+ * See @ref Tag-Usage for discussion on tag requirements.
+ *
+ * See also @ref CBOR_TAG_BIN_UUID, QCBOREncode_AddTBinaryUUID() and
+ * @ref QCBOR_TYPE_UUID.
+ */
+static void
+QCBORDecode_GetBinaryUUID(QCBORDecodeContext *pCtx,
+ uint8_t uTagRequirement,
+ UsefulBufC *pUUID);
+
+static void
+QCBORDecode_GetBinaryUUIDInMapN(QCBORDecodeContext *pCtx,
+ int64_t nLabel,
+ uint8_t uTagRequirement,
+ UsefulBufC *pUUID);
+
+static void
+QCBORDecode_GetBinaryUUIDInMapSZ(QCBORDecodeContext *pCtx,
+ const char *szLabel,
+ uint8_t uTagRequirement,
+ UsefulBufC *pUUID);
+
+
/**
@@ -355,9 +1063,88 @@
/* ========================================================================= *
+ * BEGINNING OF DEPRECATED FUNCTIONS *
+ * *
+ * There is no plan to remove these in future versions. *
+ * They just have been replaced by something better. *
+ * ========================================================================= */
+
+#ifndef QCBOR_DISABLE_TAGS
+
+/**
+ * @brief Returns the tag numbers for an item. (deprecated).
+ *
+ * @param[in] pCtx The decoder context.
+ * @param[in] uIndex The index of the tag to get.
+ *
+ * This is the same as QCBORDecode_GetNthTagNumber() but the order is
+ * opposite when there are multiple tags. @c uIndex 0 is the tag
+ * number closest to the tag content. QCBORDecode_GetNthTagNumber() is
+ * more useful for checking the next tag number and switching the
+ * decode flow.
+ */
+uint64_t
+QCBORDecode_GetNthTag(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint32_t uIndex);
+
+
+/**
+ * @brief Returns the tag numbers for last-decoded item (deprecated).
+ *
+ * @param[in] pCtx The decoder context.
+ * @param[in] uIndex The index of the tag to get.
+ *
+ * @returns The nth tag number or CBOR_TAG_INVALID64.
+ *
+ * This is the same as QCBORDecode_GetNthTagNumberOfLast() but the
+ * order is opposite when there are multiple tags. @c uIndex 0 is the
+ * tag number closest to the tag content.
+ * QCBORDecode_GetNthTagNumber() is more useful for checking
+ * the next tag number and switching the decode flow.
+ */
+uint64_t
+QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pCtx, uint32_t uIndex);
+
+#endif /* ! QCBOR_DISABLE_TAGS */
+
+
+/* ========================================================================= *
+ * END OF DEPRECATED FUNCTIONS *
+ * ========================================================================= */
+
+
+
+/* ========================================================================= *
* BEGINNING OF PRIVATE INLINE IMPLEMENTATION *
* ========================================================================= */
+/* Semi-private used by public inline functions. See qcbor_tag_decode.c */
+void
+QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
+ uint8_t uTagRequirement,
+ uint8_t uQCBOR_Type,
+ uint64_t uTagNumber,
+ UsefulBufC *pBstr);
+
+/* Semi-private used by public inline functions. See qcbor_tag_decode.c */
+void
+QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
+ const int64_t nLabel,
+ const uint8_t uTagRequirement,
+ const uint8_t uQCBOR_Type,
+ const uint64_t uTagNumber,
+ UsefulBufC *pString);
+
+/* Semi-private used by public inline functions. See qcbor_tag_decode.c */
+void
+QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ uint8_t uTagRequirement,
+ uint8_t uQCBOR_Type,
+ uint64_t uTagNumber,
+ UsefulBufC *pString);
+
+
+
#ifndef QCBOR_DISABLE_TAGS
static inline void
@@ -372,6 +1159,295 @@
#endif /* ! QCBOR_DISABLE_TAGS */
+
+
+static inline void
+QCBORDecode_GetDateString(QCBORDecodeContext *pMe,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pValue)
+{
+ QCBORDecode_Private_GetTaggedString(pMe,
+ uTagRequirement,
+ QCBOR_TYPE_DATE_STRING,
+ CBOR_TAG_DATE_STRING,
+ pValue);
+}
+
+static inline void
+QCBORDecode_GetDateStringInMapN(QCBORDecodeContext *pMe,
+ const int64_t nLabel,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pText)
+{
+ QCBORDecode_Private_GetTaggedStringInMapN(pMe,
+ nLabel,
+ uTagRequirement,
+ QCBOR_TYPE_DATE_STRING,
+ CBOR_TAG_DATE_STRING,
+ pText);
+}
+
+static inline void
+QCBORDecode_GetDateStringInMapSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pText)
+{
+ QCBORDecode_Private_GetTaggedStringInMapSZ(pMe,
+ szLabel,
+ uTagRequirement,
+ QCBOR_TYPE_DATE_STRING,
+ CBOR_TAG_DATE_STRING,
+ pText);
+}
+
+static inline void
+QCBORDecode_GetDaysString(QCBORDecodeContext *pMe,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pValue)
+{
+ QCBORDecode_Private_GetTaggedString(pMe,
+ uTagRequirement,
+ QCBOR_TYPE_DATE_STRING,
+ CBOR_TAG_DATE_STRING,
+ pValue);
+}
+
+static inline void
+QCBORDecode_GetDaysStringInMapN(QCBORDecodeContext *pMe,
+ const int64_t nLabel,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pText)
+{
+ QCBORDecode_Private_GetTaggedStringInMapN(pMe,
+ nLabel,
+ uTagRequirement,
+ QCBOR_TYPE_DAYS_STRING,
+ CBOR_TAG_DAYS_STRING,
+ pText);
+}
+
+static inline void
+QCBORDecode_GetDaysStringInMapSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pText)
+{
+ QCBORDecode_Private_GetTaggedStringInMapSZ(pMe,
+ szLabel,
+ uTagRequirement,
+ QCBOR_TYPE_DAYS_STRING,
+ CBOR_TAG_DAYS_STRING,
+ pText);
+
+}
+
+
+static inline void
+QCBORDecode_GetURI(QCBORDecodeContext *pMe,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pUUID)
+{
+ QCBORDecode_Private_GetTaggedString(pMe,
+ uTagRequirement,
+ QCBOR_TYPE_URI,
+ CBOR_TAG_URI,
+ pUUID);
+}
+
+static inline void
+QCBORDecode_GetURIInMapN(QCBORDecodeContext *pMe,
+ const int64_t nLabel,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pUUID)
+{
+ QCBORDecode_Private_GetTaggedStringInMapN(pMe,
+ nLabel,
+ uTagRequirement,
+ QCBOR_TYPE_URI,
+ CBOR_TAG_URI,
+ pUUID);
+}
+
+static inline void
+QCBORDecode_GetURIInMapSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pUUID)
+{
+ QCBORDecode_Private_GetTaggedStringInMapSZ(pMe,
+ szLabel,
+ uTagRequirement,
+ QCBOR_TYPE_URI,
+ CBOR_TAG_URI,
+ pUUID);
+}
+
+
+static inline void
+QCBORDecode_GetB64(QCBORDecodeContext *pMe,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pB64Text)
+{
+ QCBORDecode_Private_GetTaggedString(pMe,
+ uTagRequirement,
+ QCBOR_TYPE_BASE64,
+ CBOR_TAG_B64,
+ pB64Text);
+}
+
+static inline void
+QCBORDecode_GetB64InMapN(QCBORDecodeContext *pMe,
+ const int64_t nLabel,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pB64Text)
+{
+ QCBORDecode_Private_GetTaggedStringInMapN(pMe,
+ nLabel,
+ uTagRequirement,
+ QCBOR_TYPE_BASE64,
+ CBOR_TAG_B64,
+ pB64Text);
+}
+
+static inline void
+QCBORDecode_GetB64InMapSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pB64Text)
+{
+ QCBORDecode_Private_GetTaggedStringInMapSZ(pMe,
+ szLabel,
+ uTagRequirement,
+ QCBOR_TYPE_BASE64,
+ CBOR_TAG_B64,
+ pB64Text);
+}
+
+
+static inline void
+QCBORDecode_GetB64URL(QCBORDecodeContext *pMe,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pB64Text)
+{
+ QCBORDecode_Private_GetTaggedString(pMe,
+ uTagRequirement,
+ QCBOR_TYPE_BASE64URL,
+ CBOR_TAG_B64URL,
+ pB64Text);
+}
+
+static inline void
+QCBORDecode_GetB64URLInMapN(QCBORDecodeContext *pMe,
+ const int64_t nLabel,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pB64Text)
+{
+ QCBORDecode_Private_GetTaggedStringInMapN(pMe,
+ nLabel,
+ uTagRequirement,
+ QCBOR_TYPE_BASE64URL,
+ CBOR_TAG_B64URL,
+ pB64Text);
+}
+
+static inline void
+QCBORDecode_GetB64URLInMapSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pB64Text)
+{
+ QCBORDecode_Private_GetTaggedStringInMapSZ(pMe,
+ szLabel,
+ uTagRequirement,
+ QCBOR_TYPE_BASE64URL,
+ CBOR_TAG_B64URL,
+ pB64Text);
+}
+
+
+static inline void
+QCBORDecode_GetRegex(QCBORDecodeContext *pMe,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pRegex)
+{
+ QCBORDecode_Private_GetTaggedString(pMe,
+ uTagRequirement,
+ QCBOR_TYPE_REGEX,
+ CBOR_TAG_REGEX,
+ pRegex);
+}
+
+static inline void
+QCBORDecode_GetRegexInMapN(QCBORDecodeContext *pMe,
+ const int64_t nLabel,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pRegex)
+{
+ QCBORDecode_Private_GetTaggedStringInMapN(pMe,
+ nLabel,
+ uTagRequirement,
+ QCBOR_TYPE_REGEX,
+ CBOR_TAG_REGEX,
+ pRegex);
+}
+
+static inline void
+QCBORDecode_GetRegexInMapSZ(QCBORDecodeContext *pMe,
+ const char * szLabel,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pRegex)
+{
+ QCBORDecode_Private_GetTaggedStringInMapSZ(pMe,
+ szLabel,
+ uTagRequirement,
+ QCBOR_TYPE_REGEX,
+ CBOR_TAG_REGEX,
+ pRegex);
+}
+
+
+static inline void
+QCBORDecode_GetBinaryUUID(QCBORDecodeContext *pMe,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pUUID)
+{
+ QCBORDecode_Private_GetTaggedString(pMe,
+ uTagRequirement,
+ QCBOR_TYPE_UUID,
+ CBOR_TAG_BIN_UUID,
+ pUUID);
+}
+
+static inline void
+QCBORDecode_GetBinaryUUIDInMapN(QCBORDecodeContext *pMe,
+ const int64_t nLabel,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pUUID)
+{
+ QCBORDecode_Private_GetTaggedStringInMapN(pMe,
+ nLabel,
+ uTagRequirement,
+ QCBOR_TYPE_UUID,
+ CBOR_TAG_BIN_UUID,
+ pUUID);
+}
+
+static inline void
+QCBORDecode_GetBinaryUUIDInMapSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pUUID)
+{
+ QCBORDecode_Private_GetTaggedStringInMapSZ(pMe,
+ szLabel,
+ uTagRequirement,
+ QCBOR_TYPE_UUID,
+ CBOR_TAG_BIN_UUID,
+ pUUID);
+}
+
+
/* ======================================================================== *
* END OF PRIVATE INLINE IMPLEMENTATION *
* ======================================================================== */
diff --git a/src/decode_nesting.h b/src/decode_nesting.h
new file mode 100644
index 0000000..0e1c3a1
--- /dev/null
+++ b/src/decode_nesting.h
@@ -0,0 +1,419 @@
+/* ==========================================================================
+ * decode_nesting.c -- All inline implementation of QCBORDecodeNesting
+ *
+ * Copyright (c) 2016-2018, The Linux Foundation.
+ * Copyright (c) 2018-2024, Laurence Lundblade.
+ * Copyright (c) 2021, Arm Limited.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Forked from qcbor_decode.c on 11/28/24
+ * ========================================================================== */
+
+#ifndef decode_nesting_h
+#define decode_nesting_h
+
+#include "qcbor/qcbor_private.h"
+
+
+/* When this was not all explicitly inline, the compiler decided to
+ * inline everything on its own, so we know there's no loss by
+ * making it all inline.
+ */
+
+static inline void
+DecodeNesting_Init(QCBORDecodeNesting *pNesting)
+{
+ /* Assumes that *pNesting has been zero'd before this call. */
+ pNesting->pLevels[0].uLevelType = QCBOR_TYPE_BYTE_STRING;
+ pNesting->pCurrent = &(pNesting->pLevels[0]);
+}
+
+
+static inline bool
+DecodeNesting_IsCurrentDefiniteLength(const QCBORDecodeNesting *pNesting)
+{
+ if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
+ /* Not a map or array */
+ return false;
+ }
+
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
+ if(pNesting->pCurrent->u.ma.uCountTotal == QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
+ /* Is indefinite */
+ return false;
+ }
+
+#endif /* ! QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
+
+ /* All checks passed; is a definte length map or array */
+ return true;
+}
+
+
+static inline bool
+DecodeNesting_IsBoundedType(const QCBORDecodeNesting *pNesting, uint8_t uType)
+{
+ if(pNesting->pCurrentBounded == NULL) {
+ return false;
+ }
+
+ uint8_t uItemDataType = pNesting->pCurrentBounded->uLevelType;
+#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
+ if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
+ uItemDataType = QCBOR_TYPE_ARRAY;
+ }
+#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+
+ if(uItemDataType != uType) {
+ return false;
+ }
+
+ return true;
+}
+
+
+static inline bool
+DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting *pNesting)
+{
+ if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
+ return true;
+ }
+ if(pNesting->pCurrent->u.ma.uStartOffset != QCBOR_NON_BOUNDED_OFFSET) {
+ return true;
+ }
+ return false;
+}
+
+
+static inline bool
+DecodeNesting_IsBoundedEmpty(const QCBORDecodeNesting *pNesting)
+{
+ if(pNesting->pCurrentBounded->u.ma.uCountCursor == QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+static inline bool
+DecodeNesting_IsAtEndOfBoundedLevel(const QCBORDecodeNesting *pNesting)
+{
+ if(pNesting->pCurrentBounded == NULL) {
+ /* No bounded map or array set up */
+ return false;
+ }
+ if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
+ /* Not a map or array; end of those is by byte count */
+ return false;
+ }
+ if(!DecodeNesting_IsCurrentBounded(pNesting)) {
+ /* In a traveral at a level deeper than the bounded level */
+ return false;
+ }
+ /* Works for both definite- and indefinitelength maps/arrays */
+ if(pNesting->pCurrentBounded->u.ma.uCountCursor != 0 &&
+ pNesting->pCurrentBounded->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
+ /* Count is not zero, still unconsumed item */
+ return false;
+ }
+ /* All checks passed, got to the end of an array or map*/
+ return true;
+}
+
+
+static inline bool
+DecodeNesting_IsEndOfDefiniteLengthMapOrArray(const QCBORDecodeNesting *pNesting)
+{
+ /* Must only be called on map / array */
+ if(pNesting->pCurrent->u.ma.uCountCursor == 0) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+static inline bool
+DecodeNesting_IsCurrentTypeMap(const QCBORDecodeNesting *pNesting)
+{
+ if(pNesting->pCurrent->uLevelType == CBOR_MAJOR_TYPE_MAP) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+static inline bool
+DecodeNesting_IsCurrentAtTop(const QCBORDecodeNesting *pNesting)
+{
+ if(pNesting->pCurrent == &(pNesting->pLevels[0])) {
+ return true;
+ } else {
+ return false;
+ }
+}
+
+
+static inline bool
+DecodeNesting_IsCurrentBstrWrapped(const QCBORDecodeNesting *pNesting)
+{
+ if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
+ /* is a byte string */
+ return true;
+ }
+ return false;
+}
+
+
+static inline uint8_t
+DecodeNesting_GetCurrentLevel(const QCBORDecodeNesting *pNesting)
+{
+ const ptrdiff_t nLevel = pNesting->pCurrent - &(pNesting->pLevels[0]);
+ /* Limit in DecodeNesting_Descend against more than
+ * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
+ */
+ return (uint8_t)nLevel;
+}
+
+
+
+
+static inline void
+DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(QCBORDecodeNesting *pNesting)
+{
+ /* Only call on a definite-length array / map */
+ pNesting->pCurrent->u.ma.uCountCursor--;
+}
+
+
+static inline void
+DecodeNesting_ZeroMapOrArrayCount(QCBORDecodeNesting *pNesting)
+{
+ pNesting->pCurrent->u.ma.uCountCursor = 0;
+}
+
+static inline void
+DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting)
+{
+ if(pNesting->pCurrent->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
+ pNesting->pCurrentBounded->u.ma.uCountCursor = pNesting->pCurrentBounded->u.ma.uCountTotal;
+ }
+}
+
+static inline void
+DecodeNesting_ReverseDecrement(QCBORDecodeNesting *pNesting)
+{
+ /* Only call on a definite-length array / map */
+ pNesting->pCurrent->u.ma.uCountCursor++;
+}
+
+
+
+
+static inline void
+DecodeNesting_ClearBoundedMode(QCBORDecodeNesting *pNesting)
+{
+ pNesting->pCurrent->u.ma.uStartOffset = QCBOR_NON_BOUNDED_OFFSET;
+}
+
+
+static inline QCBORError
+DecodeNesting_Descend(QCBORDecodeNesting *pNesting, uint8_t uType)
+{
+ /* Error out if nesting is too deep */
+ if(pNesting->pCurrent >= &(pNesting->pLevels[QCBOR_MAX_ARRAY_NESTING])) {
+ return QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP;
+ }
+
+ /* The actual descend */
+ pNesting->pCurrent++;
+
+ pNesting->pCurrent->uLevelType = uType;
+
+ return QCBOR_SUCCESS;
+}
+
+static inline QCBORError
+DecodeNesting_DescendMapOrArray(QCBORDecodeNesting *pNesting,
+ const uint8_t uQCBORType,
+ const uint16_t uCount)
+{
+ QCBORError uError = QCBOR_SUCCESS;
+
+ if(uCount == 0) {
+ /* Nothing to do for empty definite-length arrays. They are just are
+ * effectively the same as an item that is not a map or array.
+ */
+ goto Done;
+ /* Empty indefinite-length maps and arrays are handled elsewhere */
+ }
+
+ /* Rely on check in QCBOR_Private_DecodeArrayOrMap() for definite-length
+ * arrays and maps that are too long */
+
+ uError = DecodeNesting_Descend(pNesting, uQCBORType);
+ if(uError != QCBOR_SUCCESS) {
+ goto Done;
+ }
+
+ pNesting->pCurrent->u.ma.uCountCursor = uCount;
+ pNesting->pCurrent->u.ma.uCountTotal = uCount;
+
+ DecodeNesting_ClearBoundedMode(pNesting);
+
+Done:
+ return uError;;
+}
+
+
+static inline QCBORError
+DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting,
+ uint32_t uEndOffset,
+ uint32_t uStartOffset)
+{
+ QCBORError uError;
+
+ uError = DecodeNesting_Descend(pNesting, QCBOR_TYPE_BYTE_STRING);
+ if(uError != QCBOR_SUCCESS) {
+ goto Done;
+ }
+
+ /* Fill in the new byte string level */
+ pNesting->pCurrent->u.bs.uSavedEndOffset = uEndOffset;
+ pNesting->pCurrent->u.bs.uBstrStartOffset = uStartOffset;
+
+ /* Bstr wrapped levels are always bounded */
+ pNesting->pCurrentBounded = pNesting->pCurrent;
+
+Done:
+ return uError;;
+}
+
+
+static inline void
+DecodeNesting_Ascend(QCBORDecodeNesting *pNesting)
+{
+ pNesting->pCurrent--;
+}
+
+
+
+
+static inline void
+DecodeNesting_SetCurrentToBoundedLevel(QCBORDecodeNesting *pNesting)
+{
+ pNesting->pCurrent = pNesting->pCurrentBounded;
+}
+
+static inline void
+DecodeNesting_SetMapOrArrayBoundedMode(QCBORDecodeNesting *pNesting, bool bIsEmpty, size_t uStart)
+{
+ /* Should be only called on maps and arrays */
+ /*
+ * DecodeNesting_EnterBoundedMode() checks to be sure uStart is not
+ * larger than DecodeNesting_EnterBoundedMode which keeps it less than
+ * uin32_t so the cast is safe.
+ */
+ pNesting->pCurrent->u.ma.uStartOffset = (uint32_t)uStart;
+
+ if(bIsEmpty) {
+ pNesting->pCurrent->u.ma.uCountCursor = QCBOR_COUNT_INDICATES_ZERO_LENGTH;
+ }
+}
+
+static inline QCBORError
+DecodeNesting_EnterBoundedMapOrArray(QCBORDecodeNesting *pNesting,
+ bool bIsEmpty,
+ size_t uOffset)
+{
+ /*
+ * Should only be called on map/array.
+ *
+ * Have descended into this before this is called. The job here is
+ * just to mark it in bounded mode.
+ *
+ * Check against QCBOR_MAX_DECODE_INPUT_SIZE make sure that
+ * uOffset doesn't collide with QCBOR_NON_BOUNDED_OFFSET.
+ *
+ * Cast of uOffset to uint32_t for cases where SIZE_MAX < UINT32_MAX.
+ */
+ if((uint32_t)uOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
+ return QCBOR_ERR_INPUT_TOO_LARGE;
+ }
+
+ pNesting->pCurrentBounded = pNesting->pCurrent;
+
+ DecodeNesting_SetMapOrArrayBoundedMode(pNesting, bIsEmpty, uOffset);
+
+ return QCBOR_SUCCESS;
+}
+
+
+static inline uint32_t
+DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe)
+{
+ return pMe->pCurrentBounded->u.bs.uSavedEndOffset;
+}
+
+
+static inline uint8_t
+DecodeNesting_GetBoundedModeLevel(const QCBORDecodeNesting *pNesting)
+{
+ const ptrdiff_t nLevel = pNesting->pCurrentBounded - &(pNesting->pLevels[0]);
+ /* Limit in DecodeNesting_Descend against more than
+ * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
+ */
+ return (uint8_t)nLevel;
+}
+
+
+
+
+static inline uint32_t
+DecodeNesting_GetMapOrArrayStart(const QCBORDecodeNesting *pNesting)
+{
+ return pNesting->pCurrentBounded->u.ma.uStartOffset;
+}
+
+
+static inline void
+DecodeNesting_LevelUpCurrent(QCBORDecodeNesting *pNesting)
+{
+ pNesting->pCurrent = pNesting->pCurrentBounded - 1;
+}
+
+
+static inline void
+DecodeNesting_LevelUpBounded(QCBORDecodeNesting *pNesting)
+{
+ while(pNesting->pCurrentBounded != &(pNesting->pLevels[0])) {
+ pNesting->pCurrentBounded--;
+ if(DecodeNesting_IsCurrentBounded(pNesting)) {
+ break;
+ }
+ }
+}
+
+
+
+
+static inline void
+DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting,
+ QCBORDecodeNesting *pSave)
+{
+ *pSave = *pNesting;
+}
+
+
+static inline void
+DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting,
+ const QCBORDecodeNesting *pSave)
+{
+ *pNesting = *pSave;
+}
+
+#endif /* decode_nesting_h */
diff --git a/src/decode_private.h b/src/decode_private.h
index 506c668..c1d6f9f 100644
--- a/src/decode_private.h
+++ b/src/decode_private.h
@@ -1,79 +1,113 @@
-/*==============================================================================
- Copyright (c) 2016-2018, The Linux Foundation.
- Copyright (c) 2018-2024, Laurence Lundblade.
- Copyright (c) 2021, Arm Limited.
- All rights reserved.
+/* ==========================================================================
+ * decode_private.c -- semi-private & inline functions for qcbor_decode.c
+ *
+ * Copyright (c) 2016-2018, The Linux Foundation.
+ * Copyright (c) 2018-2024, Laurence Lundblade.
+ * Copyright (c) 2021, Arm Limited.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Forked from qcbor_decode.c on 11/14/24
+ * ========================================================================== */
- Created on 11/14/24 from qcbor_decode.c
-
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials provided
- with the distribution.
- * Neither the name of The Linux Foundation nor the names of its
- contributors, nor the name "Laurence Lundblade" may be used to
- endorse or promote products derived from this software without
- specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
-WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
-ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
-BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
-OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
-IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- =============================================================================*/
#ifndef decode_private_h
#define decode_private_h
+#include "qcbor/qcbor_decode.h"
+#include "qcbor/qcbor_spiffy_decode.h" /* For QCBORItemCallback */
+/* These are decode functions used by the spiffy decode and number decode
+ * implementation. They are internal linkage and nothing to do with
+ * the public decode interface.
+ */
+
+/* Semi-private function. See qcbor_decode.c */
QCBORError
QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe,
QCBORItem *pDecodedItem);
-void
-QCBORDecode_Private_ProcessTagItemMulti(QCBORDecodeContext *pMe,
- QCBORItem *pItem,
- const uint8_t uTagRequirement,
- const uint8_t uQCBORTypes[],
- const uint64_t uTagNumbers[],
- QCBORTagContentCallBack *pfCB,
- size_t uOffset);
-
-void
-QCBORDecode_Private_ProcessTagItem(QCBORDecodeContext *pMe,
- QCBORItem *pItem,
- const uint8_t uTagRequirement,
- const uint8_t uQCBORTypes[],
- const uint64_t uTagNumber,
- QCBORTagContentCallBack *pfCB,
- size_t uOffset);
-
+/* Semi-private function. See qcbor_decode.c */
void
QCBORDecode_Private_GetItemInMapNoCheckSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- const uint8_t uQcborType,
- QCBORItem *pItem,
- size_t *puOffset);
+ const char *szLabel,
+ const uint8_t uQcborType,
+ QCBORItem *pItem,
+ size_t *puOffset);
+/* Semi-private function. See qcbor_decode.c */
void
QCBORDecode_Private_GetItemInMapNoCheckN(QCBORDecodeContext *pMe,
- const int64_t nLabel,
- const uint8_t uQcborType,
- QCBORItem *pItem,
- size_t *puOffset);
+ const int64_t nLabel,
+ const uint8_t uQcborType,
+ QCBORItem *pItem,
+ size_t *puOffset);
+
+
+/* Semi-private function. See qcbor_decode.c */
+uint64_t
+QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe,
+ const uint16_t uMappedTagNumber);
+
+/* Semi-private function. See qcbor_decode.c */
+QCBORError
+QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
+ const QCBORItem *pItemToConsume,
+ bool *pbBreak,
+ uint8_t *puNextNestLevel);
+
+/* Semi-private function. See qcbor_decode.c */
+QCBORError
+QCBORDecode_Private_GetItemChecks(QCBORDecodeContext *pMe,
+ QCBORError uErr,
+ const size_t uOffset,
+ QCBORItem *pDecodedItem);
+
+/* Semi-private function. See qcbor_decode.c */
+QCBORError
+QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe,
+ bool bMarkEnd,
+ bool *pbBreak);
+
+
+typedef struct {
+ void *pCBContext;
+ QCBORItemCallback pfCallback;
+} MapSearchCallBack;
+
+typedef struct {
+ size_t uStartOffset;
+ uint16_t uItemCount;
+} MapSearchInfo;
+
+/* Semi-private function. See qcbor_decode.c */
+QCBORError
+QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
+ QCBORItem *pItemArray,
+ MapSearchInfo *pInfo,
+ MapSearchCallBack *pCallBack);
+
+
+/* Semi-private function. See qcbor_decode.c */
+QCBORError
+QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
+ const uint32_t uEndOffset);
+
+
+static inline void
+QCBORDecode_Private_SaveTagNumbers(QCBORDecodeContext *pMe, const QCBORItem *pItem)
+{
+#ifndef QCBOR_DISABLE_TAGS
+ memcpy(pMe->auLastTags, pItem->auTagNumbers, sizeof(pItem->auTagNumbers));
+#else /* ! QCBOR_DISABLE_TAGS */
+ (void)pMe;
+ (void)pItem;
+#endif /* ! QCBOR_DISABLE_TAGS */
+}
+
+
static inline void
QCBORDecode_Private_GetAndTell(QCBORDecodeContext *pMe, QCBORItem *Item, size_t *uOffset)
@@ -84,7 +118,7 @@
}
*uOffset = QCBORDecode_Tell(pMe);
-#else
+#else /* ! QCBOR_DISABLE_TAGS */
*uOffset = SIZE_MAX;
#endif /* ! QCBOR_DISABLE_TAGS */
@@ -92,4 +126,25 @@
}
+
+
+/* Semi-private function. See qcbor_tag_decode.c */
+void
+QCBORDecode_Private_ProcessTagItemMulti(QCBORDecodeContext *pMe,
+ QCBORItem *pItem,
+ const uint8_t uTagRequirement,
+ const uint8_t uQCBORTypes[],
+ const uint64_t uTagNumbers[],
+ QCBORTagContentCallBack *pfCB,
+ size_t uOffset);
+
+/* Semi-private function. See qcbor_tag_decode.c */
+void
+QCBORDecode_Private_ProcessTagItem(QCBORDecodeContext *pMe,
+ QCBORItem *pItem,
+ const uint8_t uTagRequirement,
+ const uint8_t uQCBORTypes[],
+ const uint64_t uTagNumber,
+ QCBORTagContentCallBack *pfCB,
+ size_t uOffset);
#endif /* decode_private_h */
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 7e2abad..257f8e7 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -36,6 +36,9 @@
#include "qcbor/qcbor_spiffy_decode.h"
#include "qcbor/qcbor_tag_decode.h"
#include "ieee754.h" /* Does not use math.h */
+#include "decode_private.h"
+#include "decode_nesting.h"
+
#if (defined(__GNUC__) && !defined(__clang__))
@@ -127,453 +130,6 @@
#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
}
-/* Return true if the labels in Item1 and Item2 are the same.
- Works only for integer and string labels. Returns false
- for any other type. */
-static bool
-QCBORItem_MatchLabel(const QCBORItem Item1, const QCBORItem Item2)
-{
- if(Item1.uLabelType == QCBOR_TYPE_INT64) {
- if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
- return true;
- }
-#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
- } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
- if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
- return true;
- }
- } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
- if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
- return true;
- }
- } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
- if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
- return true;
- }
-#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
- }
-
- /* Other label types are never matched */
- return false;
-}
-
-
-/*
- Returns true if Item1 and Item2 are the same type
- or if either are of QCBOR_TYPE_ANY.
- */
-static bool
-QCBORItem_MatchType(const QCBORItem Item1, const QCBORItem Item2)
-{
- if(Item1.uDataType == Item2.uDataType) {
- return true;
- } else if(Item1.uDataType == QCBOR_TYPE_ANY) {
- return true;
- } else if(Item2.uDataType == QCBOR_TYPE_ANY) {
- return true;
- }
- return false;
-}
-
-
-/*===========================================================================
- DecodeNesting -- Tracking array/map/sequence/bstr-wrapped nesting
- ===========================================================================*/
-
-/*
- * See comments about and typedef of QCBORDecodeNesting in qcbor_private.h,
- * the data structure all these functions work on.
- */
-
-
-static uint8_t
-DecodeNesting_GetCurrentLevel(const QCBORDecodeNesting *pNesting)
-{
- const ptrdiff_t nLevel = pNesting->pCurrent - &(pNesting->pLevels[0]);
- /* Limit in DecodeNesting_Descend against more than
- * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
- */
- return (uint8_t)nLevel;
-}
-
-
-static uint8_t
-DecodeNesting_GetBoundedModeLevel(const QCBORDecodeNesting *pNesting)
-{
- const ptrdiff_t nLevel = pNesting->pCurrentBounded - &(pNesting->pLevels[0]);
- /* Limit in DecodeNesting_Descend against more than
- * QCBOR_MAX_ARRAY_NESTING gaurantees cast is safe
- */
- return (uint8_t)nLevel;
-}
-
-
-static uint32_t
-DecodeNesting_GetMapOrArrayStart(const QCBORDecodeNesting *pNesting)
-{
- return pNesting->pCurrentBounded->u.ma.uStartOffset;
-}
-
-
-static bool
-DecodeNesting_IsBoundedEmpty(const QCBORDecodeNesting *pNesting)
-{
- if(pNesting->pCurrentBounded->u.ma.uCountCursor == QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
- return true;
- } else {
- return false;
- }
-}
-
-
-static bool
-DecodeNesting_IsCurrentAtTop(const QCBORDecodeNesting *pNesting)
-{
- if(pNesting->pCurrent == &(pNesting->pLevels[0])) {
- return true;
- } else {
- return false;
- }
-}
-
-
-static bool
-DecodeNesting_IsCurrentDefiniteLength(const QCBORDecodeNesting *pNesting)
-{
- if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
- /* Not a map or array */
- return false;
- }
-
-#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
- if(pNesting->pCurrent->u.ma.uCountTotal == QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) {
- /* Is indefinite */
- return false;
- }
-
-#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
-
- /* All checks passed; is a definte length map or array */
- return true;
-}
-
-static bool
-DecodeNesting_IsCurrentBstrWrapped(const QCBORDecodeNesting *pNesting)
-{
- if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
- /* is a byte string */
- return true;
- }
- return false;
-}
-
-
-static bool
-DecodeNesting_IsCurrentBounded(const QCBORDecodeNesting *pNesting)
-{
- if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
- return true;
- }
- if(pNesting->pCurrent->u.ma.uStartOffset != QCBOR_NON_BOUNDED_OFFSET) {
- return true;
- }
- return false;
-}
-
-
-static void
-DecodeNesting_SetMapOrArrayBoundedMode(QCBORDecodeNesting *pNesting, bool bIsEmpty, size_t uStart)
-{
- /* Should be only called on maps and arrays */
- /*
- * DecodeNesting_EnterBoundedMode() checks to be sure uStart is not
- * larger than DecodeNesting_EnterBoundedMode which keeps it less than
- * uin32_t so the cast is safe.
- */
- pNesting->pCurrent->u.ma.uStartOffset = (uint32_t)uStart;
-
- if(bIsEmpty) {
- pNesting->pCurrent->u.ma.uCountCursor = QCBOR_COUNT_INDICATES_ZERO_LENGTH;
- }
-}
-
-
-static void
-DecodeNesting_ClearBoundedMode(QCBORDecodeNesting *pNesting)
-{
- pNesting->pCurrent->u.ma.uStartOffset = QCBOR_NON_BOUNDED_OFFSET;
-}
-
-
-static bool
-DecodeNesting_IsAtEndOfBoundedLevel(const QCBORDecodeNesting *pNesting)
-{
- if(pNesting->pCurrentBounded == NULL) {
- /* No bounded map or array set up */
- return false;
- }
- if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) {
- /* Not a map or array; end of those is by byte count */
- return false;
- }
- if(!DecodeNesting_IsCurrentBounded(pNesting)) {
- /* In a traveral at a level deeper than the bounded level */
- return false;
- }
- /* Works for both definite- and indefinitelength maps/arrays */
- if(pNesting->pCurrentBounded->u.ma.uCountCursor != 0 &&
- pNesting->pCurrentBounded->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
- /* Count is not zero, still unconsumed item */
- return false;
- }
- /* All checks passed, got to the end of an array or map*/
- return true;
-}
-
-
-static bool
-DecodeNesting_IsEndOfDefiniteLengthMapOrArray(const QCBORDecodeNesting *pNesting)
-{
- /* Must only be called on map / array */
- if(pNesting->pCurrent->u.ma.uCountCursor == 0) {
- return true;
- } else {
- return false;
- }
-}
-
-
-static bool
-DecodeNesting_IsCurrentTypeMap(const QCBORDecodeNesting *pNesting)
-{
- if(pNesting->pCurrent->uLevelType == CBOR_MAJOR_TYPE_MAP) {
- return true;
- } else {
- return false;
- }
-}
-
-
-static bool
-DecodeNesting_IsBoundedType(const QCBORDecodeNesting *pNesting, uint8_t uType)
-{
- if(pNesting->pCurrentBounded == NULL) {
- return false;
- }
-
- uint8_t uItemDataType = pNesting->pCurrentBounded->uLevelType;
-#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
- if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
- uItemDataType = QCBOR_TYPE_ARRAY;
- }
-#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
-
- if(uItemDataType != uType) {
- return false;
- }
-
- return true;
-}
-
-
-static void
-DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(QCBORDecodeNesting *pNesting)
-{
- /* Only call on a definite-length array / map */
- pNesting->pCurrent->u.ma.uCountCursor--;
-}
-
-
-static void
-DecodeNesting_ReverseDecrement(QCBORDecodeNesting *pNesting)
-{
- /* Only call on a definite-length array / map */
- pNesting->pCurrent->u.ma.uCountCursor++;
-}
-
-
-static void
-DecodeNesting_Ascend(QCBORDecodeNesting *pNesting)
-{
- pNesting->pCurrent--;
-}
-
-
-static QCBORError
-DecodeNesting_Descend(QCBORDecodeNesting *pNesting, uint8_t uType)
-{
- /* Error out if nesting is too deep */
- if(pNesting->pCurrent >= &(pNesting->pLevels[QCBOR_MAX_ARRAY_NESTING])) {
- return QCBOR_ERR_ARRAY_DECODE_NESTING_TOO_DEEP;
- }
-
- /* The actual descend */
- pNesting->pCurrent++;
-
- pNesting->pCurrent->uLevelType = uType;
-
- return QCBOR_SUCCESS;
-}
-
-
-static QCBORError
-DecodeNesting_EnterBoundedMapOrArray(QCBORDecodeNesting *pNesting,
- bool bIsEmpty,
- size_t uOffset)
-{
- /*
- * Should only be called on map/array.
- *
- * Have descended into this before this is called. The job here is
- * just to mark it in bounded mode.
- *
- * Check against QCBOR_MAX_DECODE_INPUT_SIZE make sure that
- * uOffset doesn't collide with QCBOR_NON_BOUNDED_OFFSET.
- *
- * Cast of uOffset to uint32_t for cases where SIZE_MAX < UINT32_MAX.
- */
- if((uint32_t)uOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
- return QCBOR_ERR_INPUT_TOO_LARGE;
- }
-
- pNesting->pCurrentBounded = pNesting->pCurrent;
-
- DecodeNesting_SetMapOrArrayBoundedMode(pNesting, bIsEmpty, uOffset);
-
- return QCBOR_SUCCESS;
-}
-
-
-static QCBORError
-DecodeNesting_DescendMapOrArray(QCBORDecodeNesting *pNesting,
- const uint8_t uQCBORType,
- const uint16_t uCount)
-{
- QCBORError uError = QCBOR_SUCCESS;
-
- if(uCount == 0) {
- /* Nothing to do for empty definite-length arrays. They are just are
- * effectively the same as an item that is not a map or array.
- */
- goto Done;
- /* Empty indefinite-length maps and arrays are handled elsewhere */
- }
-
- /* Rely on check in QCBOR_Private_DecodeArrayOrMap() for definite-length
- * arrays and maps that are too long */
-
- uError = DecodeNesting_Descend(pNesting, uQCBORType);
- if(uError != QCBOR_SUCCESS) {
- goto Done;
- }
-
- pNesting->pCurrent->u.ma.uCountCursor = uCount;
- pNesting->pCurrent->u.ma.uCountTotal = uCount;
-
- DecodeNesting_ClearBoundedMode(pNesting);
-
-Done:
- return uError;;
-}
-
-
-static void
-DecodeNesting_LevelUpCurrent(QCBORDecodeNesting *pNesting)
-{
- pNesting->pCurrent = pNesting->pCurrentBounded - 1;
-}
-
-
-static void
-DecodeNesting_LevelUpBounded(QCBORDecodeNesting *pNesting)
-{
- while(pNesting->pCurrentBounded != &(pNesting->pLevels[0])) {
- pNesting->pCurrentBounded--;
- if(DecodeNesting_IsCurrentBounded(pNesting)) {
- break;
- }
- }
-}
-
-
-static void
-DecodeNesting_SetCurrentToBoundedLevel(QCBORDecodeNesting *pNesting)
-{
- pNesting->pCurrent = pNesting->pCurrentBounded;
-}
-
-
-static QCBORError
-DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting,
- uint32_t uEndOffset,
- uint32_t uStartOffset)
-{
- QCBORError uError;
-
- uError = DecodeNesting_Descend(pNesting, QCBOR_TYPE_BYTE_STRING);
- if(uError != QCBOR_SUCCESS) {
- goto Done;
- }
-
- /* Fill in the new byte string level */
- pNesting->pCurrent->u.bs.uSavedEndOffset = uEndOffset;
- pNesting->pCurrent->u.bs.uBstrStartOffset = uStartOffset;
-
- /* Bstr wrapped levels are always bounded */
- pNesting->pCurrentBounded = pNesting->pCurrent;
-
-Done:
- return uError;;
-}
-
-
-static void
-DecodeNesting_ZeroMapOrArrayCount(QCBORDecodeNesting *pNesting)
-{
- pNesting->pCurrent->u.ma.uCountCursor = 0;
-}
-
-
-static void
-DecodeNesting_ResetMapOrArrayCount(QCBORDecodeNesting *pNesting)
-{
- if(pNesting->pCurrent->u.ma.uCountCursor != QCBOR_COUNT_INDICATES_ZERO_LENGTH) {
- pNesting->pCurrentBounded->u.ma.uCountCursor = pNesting->pCurrentBounded->u.ma.uCountTotal;
- }
-}
-
-
-static void
-DecodeNesting_Init(QCBORDecodeNesting *pNesting)
-{
- /* Assumes that *pNesting has been zero'd before this call. */
- pNesting->pLevels[0].uLevelType = QCBOR_TYPE_BYTE_STRING;
- pNesting->pCurrent = &(pNesting->pLevels[0]);
-}
-
-
-static void
-DecodeNesting_PrepareForMapSearch(QCBORDecodeNesting *pNesting,
- QCBORDecodeNesting *pSave)
-{
- *pSave = *pNesting;
-}
-
-
-static void
-DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting,
- const QCBORDecodeNesting *pSave)
-{
- *pNesting = *pSave;
-}
-
-
-static uint32_t
-DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe)
-{
- return pMe->pCurrentBounded->u.bs.uSavedEndOffset;
-}
-
@@ -1791,7 +1347,7 @@
*
* This is the reverse of MapTagNumber()
*/
-static uint64_t
+uint64_t
QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe,
const uint16_t uMappedTagNumber)
{
@@ -2121,7 +1677,7 @@
*
* Improvement: this could reduced further if indef is disabled
*/
-static QCBORError
+QCBORError
QCBORDecode_Private_NestLevelAscender(QCBORDecodeContext *pMe, bool bMarkEnd, bool *pbBreak)
{
QCBORError uReturn;
@@ -2253,7 +1809,7 @@
* item count or finding CBOR breaks. It detects the ends of the
* top-level sequence and of bstr-wrapped CBOR by byte count.
*/
-static QCBORError
+QCBORError
QCBORDecode_Private_GetNextMapOrArray(QCBORDecodeContext *pMe,
bool *pbBreak,
QCBORItem *pDecodedItem,
@@ -2440,7 +1996,7 @@
* map. In that case, this is just a pass through for @c puNextNestLevel
* since there is nothing to do.
*/
-static QCBORError
+QCBORError
QCBORDecode_Private_ConsumeItem(QCBORDecodeContext *pMe,
const QCBORItem *pItemToConsume,
bool *pbBreak,
@@ -2644,7 +2200,7 @@
}
#endif /* ! QCBOR_DISABLE_DECODE_CONFORMANCE */
-static QCBORError
+QCBORError
QCBORDecode_Private_GetItemChecks(QCBORDecodeContext *pMe,
QCBORError uErr,
const size_t uOffset,
@@ -2732,17 +2288,6 @@
}
-static void
-QCBORDecode_Private_SaveTagNumbers(QCBORDecodeContext *pMe, const QCBORItem *pItem)
-{
-#ifndef QCBOR_DISABLE_TAGS
- memcpy(pMe->auLastTags, pItem->auTagNumbers, sizeof(pItem->auTagNumbers));
-#else
- (void)pMe;
- (void)pItem;
-#endif
-}
-
/*
* Public function, see header qcbor/qcbor_decode.h file
*/
@@ -2809,99 +2354,18 @@
}
-#ifndef QCBOR_DISABLE_TAGS
/*
* Public function, see header qcbor/qcbor_decode.h file
*/
-uint64_t
-QCBORDecode_GetNthTagNumber(const QCBORDecodeContext *pMe,
- const QCBORItem *pItem,
- uint8_t uIndex)
+void
+QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
{
- if(pItem->uDataType == QCBOR_TYPE_NONE) {
- return CBOR_TAG_INVALID64;
+ QCBORDecode_VGetNext(pMe, pDecodedItem);
+
+ if(pMe->uLastError == QCBOR_SUCCESS) {
+ pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL,
+ &pDecodedItem->uNextNestLevel);
}
- if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
- return CBOR_TAG_INVALID64;
- }
-
- return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->auTagNumbers[uIndex]);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-uint64_t
-QCBORDecode_GetNthTagNumberOfLast(QCBORDecodeContext *pMe,
- uint8_t uIndex)
-{
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return CBOR_TAG_INVALID64;
- }
- if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
- return CBOR_TAG_INVALID64;
- }
-
- return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->auLastTags[uIndex]);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-static uint64_t
-QCBORDecode_Private_GetNthTagNumberReverse(const QCBORDecodeContext *pMe,
- const uint16_t puTagNumbers[],
- const uint32_t uIndex)
-{
- uint32_t uArrayIndex;
-
- /* Find number of tag numbers */
- for(uArrayIndex = QCBOR_MAX_TAGS_PER_ITEM-1; uArrayIndex > 0; uArrayIndex--) {
- if(puTagNumbers[uArrayIndex] != CBOR_TAG_INVALID16) {
- break;
- }
- }
- if(uIndex > uArrayIndex) {
- return CBOR_TAG_INVALID64;
- }
-
- return QCBORDecode_Private_UnMapTagNumber(pMe, puTagNumbers[uArrayIndex - uIndex]);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-uint64_t
-QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
- const QCBORItem *pItem,
- const uint32_t uIndex)
-{
- if(pItem->uDataType == QCBOR_TYPE_NONE) {
- return CBOR_TAG_INVALID64;
- }
-
- return QCBORDecode_Private_GetNthTagNumberReverse(pMe, pItem->auTagNumbers, uIndex);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-uint64_t
-QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe,
- uint32_t uIndex)
-{
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return CBOR_TAG_INVALID64;
- }
- if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
- return CBOR_TAG_INVALID64;
- }
-
- return QCBORDecode_Private_GetNthTagNumberReverse(pMe, pMe->auLastTags, uIndex);
}
@@ -2909,52 +2373,129 @@
* Public function, see header qcbor/qcbor_decode.h file
*/
QCBORError
-QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pMe, uint64_t *puTagNumber)
+QCBORDecode_EndCheck(QCBORDecodeContext *pMe)
{
- QCBORItem Item;
- size_t uOffset;
- QCBORError uErr;
+ size_t uCursorOffset;
+ QCBORError uErr;
- const QCBORDecodeNesting SaveNesting = pMe->nesting;
- const UsefulInputBuf Save = pMe->InBuf;
-
- uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
- if(uOffset == pMe->uTagNumberCheckOffset) {
- pMe->uTagNumberIndex++;
- } else {
- pMe->uTagNumberIndex = 0;
- }
-
- *puTagNumber = CBOR_TAG_INVALID64;
- uErr = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
- if(uErr) {
+ uErr = QCBORDecode_GetError(pMe);
+ if(uErr != QCBOR_SUCCESS) {
return uErr;
}
- *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &Item, pMe->uTagNumberIndex);
- if(*puTagNumber == CBOR_TAG_INVALID64 ||
- QCBORDecode_GetNthTagNumber(pMe, &Item, pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
- pMe->uTagNumberIndex = QCBOR_ALL_TAGS_PROCESSED;
- }
- pMe->uTagNumberCheckOffset = uOffset;
+ uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
- pMe->nesting = SaveNesting;
- pMe->InBuf = Save;
+ if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
+ return QCBOR_ERR_NO_MORE_ITEMS;
+ }
return QCBOR_SUCCESS;
}
-/*
- * Public function, see header qcbor/qcbor_decode.h file
+/**
+ * @brief Semi-private. Get pointer, length and item for an array or map.
+ *
+ * @param[in] pMe The decode context.
+ * @param[in] uType CBOR major type, either array/map.
+ * @param[out] pItem The item for the array/map.
+ * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
+ *
+ * The next item to be decoded must be a map or array as specified by @c uType.
+ *
+ * @c pItem will be filled in with the label and tags of the array or map
+ * in addition to @c pEncodedCBOR giving the pointer and length of the
+ * encoded CBOR.
+ *
+ * When this is complete, the traversal cursor is at the end of the array or
+ * map that was retrieved.
*/
void
-QCBORDecode_VGetNextTagNumber(QCBORDecodeContext *pMe, uint64_t *puTagNumber)
+QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe,
+ const uint8_t uType,
+ QCBORItem *pItem,
+ UsefulBufC *pEncodedCBOR)
{
- pMe->uLastError = (uint8_t)QCBORDecode_GetNextTagNumber(pMe, puTagNumber);
+ QCBORError uErr;
+ uint8_t uNestLevel;
+ size_t uStartingCursor;
+ size_t uStartOfReturned;
+ size_t uEndOfReturned;
+ size_t uTempSaveCursor;
+ bool bInMap;
+ QCBORItem LabelItem;
+ bool EndedByBreak;
+
+ uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
+ bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting));
+
+ /* Could call GetNext here, but don't need to because this
+ * is only interested in arrays and maps. TODO: switch to GetNext()? */
+ uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem, NULL);
+ if(uErr != QCBOR_SUCCESS) {
+ pMe->uLastError = (uint8_t)uErr;
+ return;
+ }
+
+ uint8_t uItemDataType = pItem->uDataType;
+#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
+ if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
+ uItemDataType = QCBOR_TYPE_ARRAY;
+ }
+#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+
+ if(uItemDataType != uType) {
+ pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
+ return;
+ }
+
+ if(bInMap) {
+ /* If the item is in a map, the start of the array/map
+ * itself, not the label, must be found. Do this by
+ * rewinding to the starting position and fetching
+ * just the label data item. QCBORDecode_Private_GetNextTagNumber()
+ * doesn't do any of the array/map item counting or nesting
+ * level tracking. Used here it will just fetech the label
+ * data item.
+ *
+ * Have to save the cursor and put it back to the position
+ * after the full item once the label as been fetched by
+ * itself.
+ */
+ uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
+ UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor);
+
+ /* Item has been fetched once so safe to ignore error */
+ (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem);
+
+ uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
+ UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor);
+ } else {
+ uStartOfReturned = uStartingCursor;
+ }
+
+ /* Consume the entire array/map to find the end */
+ uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel);
+ if(uErr != QCBOR_SUCCESS) {
+ pMe->uLastError = (uint8_t)uErr;
+ goto Done;
+ }
+
+ /* Fill in returned values */
+ uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
+ if(EndedByBreak) {
+ /* When ascending nesting levels, a break for the level above
+ * was consumed. That break is not a part of what is consumed here. */
+ uEndOfReturned--;
+ }
+ pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned);
+ pEncodedCBOR->len = uEndOfReturned - uStartOfReturned;
+
+Done:
+ return;
}
-#endif /* ! QCBOR_DISABLE_TAGS */
+
#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
@@ -3147,2108 +2688,6 @@
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
-{
- QCBORDecode_VGetNext(pMe, pDecodedItem);
-
- if(pMe->uLastError == QCBOR_SUCCESS) {
- pMe->uLastError = (uint8_t)QCBORDecode_Private_ConsumeItem(pMe, pDecodedItem, NULL,
- &pDecodedItem->uNextNestLevel);
- }
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-QCBORError
-QCBORDecode_EndCheck(QCBORDecodeContext *pMe)
-{
- size_t uCursorOffset;
- QCBORError uErr;
-
- uErr = QCBORDecode_GetError(pMe);
- if(uErr != QCBOR_SUCCESS) {
- return uErr;
- }
-
- uCursorOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
-
- if(uCursorOffset == UsefulInputBuf_GetBufferLength(&(pMe->InBuf))) {
- return QCBOR_ERR_NO_MORE_ITEMS;
- }
-
- return QCBOR_SUCCESS;
-}
-
-
-/**
- * @brief Rewind cursor to start as if map or array were just entered.
- *
- * @param[in] pMe The decoding context
- *
- * This affects the nesting tracking and the UsefulInputBuf.
- */
-static void
-QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe)
-{
- /* Reset nesting tracking to the deepest bounded level */
- DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
-
- DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
-
- /* Reposition traversal cursor to the start of the map/array */
- UsefulInputBuf_Seek(&(pMe->InBuf),
- DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_Rewind(QCBORDecodeContext *pMe)
-{
- if(pMe->nesting.pCurrentBounded != NULL) {
- /* In a bounded map, array or bstr-wrapped CBOR */
-
- if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
- /* In bstr-wrapped CBOR. */
-
- /* Reposition traversal cursor to start of wrapping byte string */
- UsefulInputBuf_Seek(&(pMe->InBuf),
- pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
- DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
-
- } else {
- /* In a map or array */
- QCBORDecode_Private_RewindMapOrArray(pMe);
- }
-
- } else {
- /* Not in anything bounded */
-
- /* Reposition traversal cursor to the start of input CBOR */
- UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
-
- /* Reset nesting tracking to beginning of input. */
- DecodeNesting_Init(&(pMe->nesting));
- }
-
- pMe->uLastError = QCBOR_SUCCESS;
-}
-
-
-
-
-
-typedef struct {
- void *pCBContext;
- QCBORItemCallback pfCallback;
-} MapSearchCallBack;
-
-typedef struct {
- size_t uStartOffset;
- uint16_t uItemCount;
-} MapSearchInfo;
-
-
-/**
- * @brief Search a map for a set of items.
- *
- * @param[in] pMe The decode context to search.
- * @param[in,out] pItemArray The items to search for and the items found.
- * @param[out] pInfo Several bits of meta-info returned by search.
- * @param[in] pCallBack Callback object or @c NULL.
- *
- * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map.
- *
- * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label)
- * were found for one of the labels being
- * search for. This duplicate detection is
- * only performed for items in pItemArray,
- * not every item in the map.
- *
- * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was
- * wrong for the matchd label.
- *
- * @retval Also errors returned by QCBORDecode_GetNext().
- *
- * On input, @c pItemArray contains a list of labels and data types of
- * items to be found.
- *
- * On output, the fully retrieved items are filled in with values and
- * such. The label was matched, so it never changes.
- *
- * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE.
- *
- * This also finds the ends of maps and arrays when they are exited.
- */
-static QCBORError
-QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
- QCBORItem *pItemArray,
- MapSearchInfo *pInfo,
- MapSearchCallBack *pCallBack)
-{
- QCBORError uReturn;
- uint64_t uFoundItemBitMap = 0;
-
- if(pMe->uLastError != QCBOR_SUCCESS) {
- uReturn = pMe->uLastError;
- goto Done2;
- }
-
- if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) &&
- pItemArray->uLabelType != QCBOR_TYPE_NONE) {
- /* QCBOR_TYPE_NONE as first item indicates just looking
- for the end of an array, so don't give error. */
- uReturn = QCBOR_ERR_MAP_NOT_ENTERED;
- goto Done2;
- }
-
- if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) {
- // It is an empty bounded array or map
- if(pItemArray->uLabelType == QCBOR_TYPE_NONE) {
- // Just trying to find the end of the map or array
- pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting));
- uReturn = QCBOR_SUCCESS;
- } else {
- // Nothing is ever found in an empty array or map. All items
- // are marked as not found below.
- uReturn = QCBOR_SUCCESS;
- }
- goto Done2;
- }
-
- QCBORDecodeNesting SaveNesting;
- size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf));
- DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
-
- /* Reposition to search from the start of the map / array */
- QCBORDecode_Private_RewindMapOrArray(pMe);
-
- /*
- Loop over all the items in the map or array. Each item
- could be a map or array, but label matching is only at
- the main level. This handles definite- and indefinite-
- length maps and arrays. The only reason this is ever
- called on arrays is to find their end position.
-
- This will always run over all items in order to do
- duplicate detection.
-
- This will exit with failure if it encounters an
- unrecoverable error, but continue on for recoverable
- errors.
-
- If a recoverable error occurs on a matched item, then
- that error code is returned.
- */
- const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
- if(pInfo) {
- pInfo->uItemCount = 0;
- }
- uint8_t uNextNestLevel;
- do {
- /* Remember offset of the item because sometimes it has to be returned */
- const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
-
- /* Get the item */
- QCBORItem Item;
- /* QCBORDecode_Private_GetNextTagContent() rather than GetNext()
- * because a label match is performed on recoverable errors to
- * be able to return the the error code for the found item. */
- QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
- if(QCBORDecode_IsUnrecoverableError(uResult)) {
- /* The map/array can't be decoded when unrecoverable errors occur */
- uReturn = uResult;
- goto Done;
- }
- if(uResult == QCBOR_ERR_NO_MORE_ITEMS) {
- /* Unexpected end of map or array. */
- uReturn = uResult;
- goto Done;
- }
-
- /* See if item has one of the labels that are of interest */
- bool bMatched = false;
- for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) {
- if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) {
- /* A label match has been found */
- if(uFoundItemBitMap & (0x01ULL << nIndex)) {
- uReturn = QCBOR_ERR_DUPLICATE_LABEL;
- goto Done;
- }
- if(uResult != QCBOR_SUCCESS) {
- /* The label matches, but the data item is in error.
- * It is OK to have recoverable errors on items that
- * are not matched. */
- uReturn = uResult;
- goto Done;
- }
- if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) {
- /* The data item is not of the type(s) requested */
- uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
- goto Done;
- }
-
- /* Successful match. Return the item. */
- pItemArray[nIndex] = Item;
- uFoundItemBitMap |= 0x01ULL << nIndex;
- if(pInfo) {
- pInfo->uStartOffset = uOffset;
- }
- bMatched = true;
- }
- }
-
-
- if(!bMatched && pCallBack != NULL) {
- /*
- Call the callback on unmatched labels.
- (It is tempting to do duplicate detection here, but that would
- require dynamic memory allocation because the number of labels
- that might be encountered is unbounded.)
- */
- uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item);
- if(uReturn != QCBOR_SUCCESS) {
- goto Done;
- }
- }
-
- /*
- Consume the item whether matched or not. This
- does the work of traversing maps and array and
- everything in them. In this loop only the
- items at the current nesting level are examined
- to match the labels.
- */
- uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel);
- if(uReturn != QCBOR_SUCCESS) {
- goto Done;
- }
-
- if(pInfo) {
- pInfo->uItemCount++;
- }
-
- } while (uNextNestLevel >= uMapNestLevel);
-
- uReturn = QCBOR_SUCCESS;
-
- const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
-
- // Check here makes sure that this won't accidentally be
- // QCBOR_MAP_OFFSET_CACHE_INVALID which is larger than
- // QCBOR_MAX_DECODE_INPUT_SIZE.
- // Cast to uint32_t to possibly address cases where SIZE_MAX < UINT32_MAX
- if((uint32_t)uEndOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
- uReturn = QCBOR_ERR_INPUT_TOO_LARGE;
- goto Done;
- }
- /* Cast OK because encoded CBOR is limited to UINT32_MAX */
- pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
-
- 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 */
- for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
- if(!(uFoundItemBitMap & (0x01ULL << i))) {
- pItemArray[i].uDataType = QCBOR_TYPE_NONE;
- pItemArray[i].uLabelType = QCBOR_TYPE_NONE;
- }
- }
-
- return uReturn;
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_SeekToLabelN(QCBORDecodeContext *pMe, int64_t nLabel)
-{
- MapSearchInfo Info;
- QCBORItem OneItemSeach[2];
-
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return;
- }
-
- OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
- OneItemSeach[0].label.int64 = nLabel;
- OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
- OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
-
- pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
- if(pMe->uLastError == QCBOR_SUCCESS) {
- UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
- }
-}
-
-
-void
-QCBORDecode_SeekToLabelSZ(QCBORDecodeContext *pMe, const char *szLabel)
-{
-#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
- MapSearchInfo Info;
- QCBORItem OneItemSeach[2];
-
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return;
- }
-
- OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
- OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
- OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
- OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
-
- pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
- if(pMe->uLastError == QCBOR_SUCCESS) {
- UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
- }
-#else
- (void)pMe;
- (void)szLabel;
- pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
-#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
-}
-
-
-void
-QCBORDecode_Private_GetItemInMapNoCheck(QCBORDecodeContext *pMe,
- QCBORItem *OneItemSeach,
- QCBORItem *pItem,
- size_t *puOffset)
-{
- QCBORError uErr;
- MapSearchInfo SearchInfo;
-
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return;
- }
-
- uErr = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &SearchInfo, NULL);
-
- if(uErr == QCBOR_SUCCESS && OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
- uErr = QCBOR_ERR_LABEL_NOT_FOUND;
- }
- *pItem = OneItemSeach[0];
- *puOffset = SearchInfo.uStartOffset;
-
- if(uErr == QCBOR_SUCCESS) {
- QCBORDecode_Private_SaveTagNumbers(pMe, pItem);
- }
-
- pMe->uLastError = (uint8_t)uErr;
-}
-
-
-static void
-QCBORDecode_Private_GetItemInMap(QCBORDecodeContext *pMe, QCBORItem *OneItemSeach, QCBORItem *pItem)
-{
- QCBORError uErr;
- size_t uOffset;
-
- QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, &uOffset);
-
- uErr = QCBORDecode_Private_GetItemChecks(pMe, pMe->uLastError, uOffset, pItem);
- if(uErr != QCBOR_SUCCESS) {
- goto Done;
- }
-
- QCBORDecode_Private_SaveTagNumbers(pMe, pItem);
-
-Done:
- pMe->uLastError = (uint8_t)uErr;
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
- const int64_t nLabel,
- const uint8_t uQcborType,
- QCBORItem *pItem)
-{
- QCBORItem OneItemSeach[2];
-
- OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
- OneItemSeach[0].label.int64 = nLabel;
- OneItemSeach[0].uDataType = uQcborType;
- OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
-
- QCBORDecode_Private_GetItemInMap(pMe, OneItemSeach, pItem);
-}
-
-
-/**
- * @brief Get an item by label by type.
- *
- * @param[in] pMe The decode context.
- * @param[in] nLabel The label to search map for.
- * @param[in] uQcborType The QCBOR type to look for.
- * @param[out] pItem The item found.
- * @param[out] puOffset The offset of item for tag consumption check.
- *
- * This finds the item with the given label in currently open
- * map. This does not call QCBORDecode_Private_GetItemChecks()
- * to check tag number consumption or decode conformance.
- */
-void
-QCBORDecode_Private_GetItemInMapNoCheckN(QCBORDecodeContext *pMe,
- const int64_t nLabel,
- const uint8_t uQcborType,
- QCBORItem *pItem,
- size_t *puOffset)
-{
- QCBORItem OneItemSeach[2];
-
- OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
- OneItemSeach[0].label.int64 = nLabel;
- OneItemSeach[0].uDataType = uQcborType;
- OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
-
- QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, puOffset);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- const uint8_t uQcborType,
- QCBORItem *pItem)
-{
-#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
- QCBORItem OneItemSeach[2];
-
- OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
- OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
- OneItemSeach[0].uDataType = uQcborType;
- OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
-
- QCBORDecode_Private_GetItemInMap(pMe, OneItemSeach, pItem);
-
-#else
- (void)pMe;
- (void)szLabel;
- (void)uQcborType;
- (void)pItem;
- pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
-#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
-}
-
-/**
- * @brief Get an item by string label of a particular type
- *
- * @param[in] pMe The decode context.
- * @param[in] szLabel The label to search map for.
- * @param[in] uQcborType The QCBOR type to look for.
- * @param[out] pItem The item found.
- * @param[out] puOffset The offset of item for tag consumption check.
- *
- * This finds the item with the given label in currently open
- * map. This does not call QCBORDecode_Private_GetItemChecks()
- * to check tag number consumption or decode conformance.
- */
-void
-QCBORDecode_Private_GetItemInMapNoCheckSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- const uint8_t uQcborType,
- QCBORItem *pItem,
- size_t *puOffset)
-{
-#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
- QCBORItem OneItemSeach[2];
-
- OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
- OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
- OneItemSeach[0].uDataType = uQcborType;
- OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
-
- QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, puOffset);
-
-#else
- (void)pMe;
- (void)szLabel;
- (void)uQcborType;
- (void)pItem;
- (void)puOffset;
- pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
-#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
-}
-
-
-
-
-/**
- * @brief Semi-private. Get pointer, length and item for an array or map.
- *
- * @param[in] pMe The decode context.
- * @param[in] uType CBOR major type, either array/map.
- * @param[out] pItem The item for the array/map.
- * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
- *
- * The next item to be decoded must be a map or array as specified by @c uType.
- *
- * @c pItem will be filled in with the label and tags of the array or map
- * in addition to @c pEncodedCBOR giving the pointer and length of the
- * encoded CBOR.
- *
- * When this is complete, the traversal cursor is at the end of the array or
- * map that was retrieved.
- */
-void
-QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pMe,
- const uint8_t uType,
- QCBORItem *pItem,
- UsefulBufC *pEncodedCBOR)
-{
- QCBORError uErr;
- uint8_t uNestLevel;
- size_t uStartingCursor;
- size_t uStartOfReturned;
- size_t uEndOfReturned;
- size_t uTempSaveCursor;
- bool bInMap;
- QCBORItem LabelItem;
- bool EndedByBreak;
-
- uStartingCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
- bInMap = DecodeNesting_IsCurrentTypeMap(&(pMe->nesting));
-
- /* Could call GetNext here, but don't need to because this
- * is only interested in arrays and maps. TODO: switch to GetNext()? */
- uErr = QCBORDecode_Private_GetNextMapOrArray(pMe, NULL, pItem, NULL);
- if(uErr != QCBOR_SUCCESS) {
- pMe->uLastError = (uint8_t)uErr;
- return;
- }
-
- uint8_t uItemDataType = pItem->uDataType;
-#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
- if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) {
- uItemDataType = QCBOR_TYPE_ARRAY;
- }
-#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
-
- if(uItemDataType != uType) {
- pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
- return;
- }
-
- if(bInMap) {
- /* If the item is in a map, the start of the array/map
- * itself, not the label, must be found. Do this by
- * rewinding to the starting position and fetching
- * just the label data item. QCBORDecode_Private_GetNextTagNumber()
- * doesn't do any of the array/map item counting or nesting
- * level tracking. Used here it will just fetech the label
- * data item.
- *
- * Have to save the cursor and put it back to the position
- * after the full item once the label as been fetched by
- * itself.
- */
- uTempSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
- UsefulInputBuf_Seek(&(pMe->InBuf), uStartingCursor);
-
- /* Item has been fetched once so safe to ignore error */
- (void)QCBORDecode_Private_GetNextTagNumber(pMe, &LabelItem);
-
- uStartOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
- UsefulInputBuf_Seek(&(pMe->InBuf), uTempSaveCursor);
- } else {
- uStartOfReturned = uStartingCursor;
- }
-
- /* Consume the entire array/map to find the end */
- uErr = QCBORDecode_Private_ConsumeItem(pMe, pItem, &EndedByBreak, &uNestLevel);
- if(uErr != QCBOR_SUCCESS) {
- pMe->uLastError = (uint8_t)uErr;
- goto Done;
- }
-
- /* Fill in returned values */
- uEndOfReturned = UsefulInputBuf_Tell(&(pMe->InBuf));
- if(EndedByBreak) {
- /* When ascending nesting levels, a break for the level above
- * was consumed. That break is not a part of what is consumed here. */
- uEndOfReturned--;
- }
- pEncodedCBOR->ptr = UsefulInputBuf_OffsetToPointer(&(pMe->InBuf), uStartOfReturned);
- pEncodedCBOR->len = uEndOfReturned - uStartOfReturned;
-
-Done:
- return;
-}
-
-
-/**
- * @brief Semi-private. Get pointer, length and item count of an array or map.
- *
- * @param[in] pMe The decode context.
- * @param[in] pTarget The label and type of the array or map to retrieve.
- * @param[out] pItem The item for the array/map.
- * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
- *
- * The next item to be decoded must be a map or array as specified by @c uType.
- *
- * When this is complete, the traversal cursor is unchanged.
- */void
-QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe,
- QCBORItem *pTarget,
- QCBORItem *pItem,
- UsefulBufC *pEncodedCBOR)
-{
- MapSearchInfo Info;
- QCBORDecodeNesting SaveNesting;
- size_t uSaveCursor;
-
- pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL);
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return;
- }
- pMe->uLastError = (uint8_t)QCBORDecode_Private_GetItemChecks(pMe, pMe->uLastError, Info.uStartOffset, pItem);
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return;
- }
-
- /* Save the whole position of things so they can be restored.
- * so the cursor position is unchanged by this operation, like
- * all the other GetXxxxInMap() operations. */
- DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
- uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
-
- DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
- UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
- QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR);
-
- UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor);
- DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
-}
-
-
-
-
-static void
-QCBORDecode_Private_ProcessTagOne(QCBORDecodeContext *pMe,
- QCBORItem *pItem,
- const uint8_t uTagRequirement,
- const uint8_t uQCBORType,
- const uint64_t uTagNumber,
- QCBORTagContentCallBack *pfCB,
- size_t uOffset);
-
-/**
- * @brief Semi-private to get an string by label to match a tag specification.
- *
- * @param[in] pMe The decode context.
- * @param[in] nLabel Label to search map for.
- * @param[in] uTagRequirement Whether or not tag number is required.
- * See @ref QCBOR_TAG_REQUIREMENT_TAG.
- * @param[in] uQCBOR_Type QCBOR type to search for.
- * @param[in] uTagNumber Tag number to match.
- * @param[out] pString The string found.
- *
- * This finds the string with the given label in currently open
- * map. Then checks that its tag number and types matches the tag
- * specification. If not, an error is set in the decode context.
- */
-void
-QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
- const int64_t nLabel,
- const uint8_t uTagRequirement,
- const uint8_t uQCBOR_Type,
- const uint64_t uTagNumber,
- UsefulBufC *pString)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
- QCBORDecode_Private_ProcessTagOne(pMe,
- &Item,
- uTagRequirement,
- uQCBOR_Type,
- uTagNumber,
- QCBORDecode_StringsTagCB,
- uOffset);
-
- if(pMe->uLastError == QCBOR_SUCCESS) {
- *pString = Item.val.string;
- }
-}
-
-
-/**
- * @brief Semi-private to get an string by label to match a tag specification.
- *
- * @param[in] pMe The decode context.
- * @param[in] szLabel Label to search map for.
- * @param[in] uTagRequirement Whether or not tag number is required.
- * See @ref QCBOR_TAG_REQUIREMENT_TAG.
- * @param[in] uQCBOR_Type QCBOR type to search for.
- * @param[in] uTagNumber Tag number to match.
- * @param[out] pString The string found.
- *
- * This finds the string with the given label in currently open
- * map. Then checks that its tag number and types matches the tag
- * specification. If not, an error is set in the decode context.
- */
-void
-QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- uint8_t uTagRequirement,
- uint8_t uQCBOR_Type,
- uint64_t uTagNumber,
- UsefulBufC *pString)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
- QCBORDecode_Private_ProcessTagOne(pMe,
- &Item,
- uTagRequirement,
- uQCBOR_Type,
- uTagNumber,
- QCBORDecode_StringsTagCB,
- uOffset);
-
-
- if(pMe->uLastError == QCBOR_SUCCESS) {
- *pString = Item.val.string;
- }
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
-{
- pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL);
-}
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe,
- QCBORItem *pItemList,
- void *pCallbackCtx,
- QCBORItemCallback pfCB)
-{
- MapSearchCallBack CallBack;
-
- CallBack.pCBContext = pCallbackCtx;
- CallBack.pfCallback = pfCB;
-
- pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack);
-}
-
-
-#ifndef QCBOR_DISABLE_TAGS
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-QCBORError
-QCBORDecode_GetNextTagNumberInMapN(QCBORDecodeContext *pMe, const int64_t nLabel, uint64_t *puTagNumber)
-{
- size_t uOffset;
- MapSearchInfo Info;
- QCBORItem OneItemSeach[2];
-
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return pMe->uLastError;
- }
-
- OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
- OneItemSeach[0].label.int64 = nLabel;
- OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
- OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
-
- QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
-
- uOffset = Info.uStartOffset;
- if(uOffset == pMe->uTagNumberCheckOffset) {
- pMe->uTagNumberIndex++;
- } else {
- pMe->uTagNumberIndex = 0;
- }
-
- *puTagNumber = CBOR_TAG_INVALID64;
-
- *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex);
- if(*puTagNumber == CBOR_TAG_INVALID64 ||
- QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
- pMe->uTagNumberIndex = QCBOR_ALL_TAGS_PROCESSED;
- }
- pMe->uTagNumberCheckOffset = uOffset;
-
- return uReturn;
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-QCBORError
-QCBORDecode_GetNextTagNumberInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint64_t *puTagNumber)
-{
-#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
- size_t uOffset;
- MapSearchInfo Info;
- QCBORItem OneItemSeach[2];
-
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return pMe->uLastError;
- }
-
- OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
- OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
- OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
- OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
-
- QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
-
-
- uOffset = Info.uStartOffset;
- if(uOffset == pMe->uTagNumberCheckOffset) {
- pMe->uTagNumberIndex++;
- } else {
- pMe->uTagNumberIndex = 0;
- }
-
- *puTagNumber = CBOR_TAG_INVALID64;
-
- *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex);
- if(*puTagNumber == CBOR_TAG_INVALID64 ||
- QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
- pMe->uTagNumberIndex = 255; /* All tags clear for this item */
- }
- pMe->uTagNumberCheckOffset = uOffset;
-
- return uReturn;
-#else
- (void)pMe;
- (void)szLabel;
- (void)puTagNumber;
- return QCBOR_ERR_LABEL_NOT_FOUND;
-#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
-}
-#endif /* ! QCBOR_DISABLE_TAGS */
-
-
-/**
- * @brief Search for a map/array by label and enter it
- *
- * @param[in] pMe The decode context.
- * @param[in] pSearch The map/array to search for.
- *
- * @c pSearch is expected to contain one item of type map or array
- * with the label specified. The current bounded map will be searched for
- * this and if found will be entered.
- *
- * If the label is not found, or the item found is not a map or array,
- * the error state is set.
- */
-static void
-QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
-{
- QCBORError uErr;
- MapSearchInfo SearchInfo;
-
- // The first item in pSearch is the one that is to be
- // entered. It should be the only one filled in. Any other
- // will be ignored unless it causes an error.
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return;
- }
-
- uErr = QCBORDecode_Private_MapSearch(pMe, pSearch, &SearchInfo, NULL);
-
- pMe->uLastError = (uint8_t)QCBORDecode_Private_GetItemChecks(pMe, uErr, SearchInfo.uStartOffset, pSearch);
-
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return;
- }
-
- if(pSearch->uDataType == QCBOR_TYPE_NONE) {
- pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
- return;
- }
-
-
- /* The map or array was found. Now enter it.
- *
- * QCBORDecode_EnterBoundedMapOrArray() used here, requires the
- * next item for the pre-order traversal cursor to be the map/array
- * found by MapSearch(). The next few lines of code force the
- * cursor to that.
- *
- * There is no need to retain the old cursor because
- * QCBORDecode_EnterBoundedMapOrArray() will set it to the
- * beginning of the map/array being entered.
- *
- * The cursor is forced by: 1) setting the input buffer position to
- * the item offset found by MapSearch(), 2) setting the map/array
- * counter to the total in the map/array, 3) setting the nesting
- * level. Setting the map/array counter to the total is not
- * strictly correct, but this is OK because this cursor only needs
- * to be used to get one item and MapSearch() has already found it
- * confirming it exists.
- */
- UsefulInputBuf_Seek(&(pMe->InBuf), SearchInfo.uStartOffset);
-
- DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
-
- DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
-
- QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
-{
- QCBORItem OneItemSeach[2];
- OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
- OneItemSeach[0].label.int64 = nLabel;
- OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
- OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
-
- /* The map to enter was found, now finish off entering it. */
- QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
-{
-#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
- QCBORItem OneItemSeach[2];
- OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
- OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
- OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
- OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
-
- QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
-#else
- (void)szLabel;
- pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
-#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
-}
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
-{
- QCBORItem OneItemSeach[2];
- OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
- OneItemSeach[0].label.int64 = nLabel;
- OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
- OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
-
- QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
-}
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
-{
-#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
- QCBORItem OneItemSeach[2];
- OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
- OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
- OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
- OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
-
- QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
-#else
- (void)szLabel;
- pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
-#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
-}
-
-
-/**
- * @brief Semi-private to do the the work for EnterMap() and EnterArray().
- *
- * @param[in] pMe The decode context
- * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY.
- * @param[out] pItem The data item for the map or array entered.
- *
- * The next item in the traversal must be a map or array. This
- * consumes that item and does the book keeping to enter the map or
- * array.
- */
-void
-QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe,
- const uint8_t uType,
- QCBORItem *pItem)
-{
- QCBORError uErr;
-
- /* Must only be called on maps and arrays. */
- if(pMe->uLastError != QCBOR_SUCCESS) {
- // Already in error state; do nothing.
- return;
- }
-
- /* Get the data item that is the map or array being entered. */
- QCBORItem Item;
- uErr = QCBORDecode_GetNext(pMe, &Item);
- if(uErr != QCBOR_SUCCESS) {
- goto Done;
- }
-
- uint8_t uItemDataType = Item.uDataType;
-
-#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
- if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) {
- uItemDataType = QCBOR_TYPE_ARRAY;
- }
-#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
-
- if(uItemDataType != uType) {
- uErr = QCBOR_ERR_UNEXPECTED_TYPE;
- goto Done;
- }
-
- QCBORDecode_Private_SaveTagNumbers(pMe, &Item);
-
-
- const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
- if(bIsEmpty) {
- if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
- // Undo decrement done by QCBORDecode_GetNext() so the the
- // the decrement when exiting the map/array works correctly
- pMe->nesting.pCurrent->u.ma.uCountCursor++;
- }
- // Special case to increment nesting level for zero-length maps
- // and arrays entered in bounded mode.
- DecodeNesting_Descend(&(pMe->nesting), uType);
- }
-
- pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
-
- uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty,
- UsefulInputBuf_Tell(&(pMe->InBuf)));
-
- if(pItem != NULL) {
- *pItem = Item;
- }
-
-Done:
- pMe->uLastError = (uint8_t)uErr;
-}
-
-
-/**
- * @brief Exit a bounded map, array or bstr (semi-private).
- *
- * @param[in] pMe Decode context.
- * @param[in] uEndOffset The input buffer offset of the end of item exited.
- *
- * @returns QCBOR_SUCCESS or an error code.
- *
- * This is the common work for exiting a level that is a bounded map,
- * array or bstr wrapped CBOR.
- *
- * One chunk of work is to set up the pre-order traversal so it is at
- * the item just after the bounded map, array or bstr that is being
- * exited. This is somewhat complex.
- *
- * The other work is to level-up the bounded mode to next higest
- * bounded mode or the top level if there isn't one.
- */
-static QCBORError
-QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
- const uint32_t uEndOffset)
-{
- QCBORError uErr;
-
- /*
- * First the pre-order-traversal byte offset is positioned to the
- * item just after the bounded mode item that was just consumed.
- */
- UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
-
- /*
- * Next, set the current nesting level to one above the bounded
- * level that was just exited.
- *
- * DecodeNesting_CheckBoundedType() is always called before this
- * and makes sure pCurrentBounded is valid.
- */
- DecodeNesting_LevelUpCurrent(&(pMe->nesting));
-
- /*
- * This does the complex work of leveling up the pre-order
- * traversal when the end of a map or array or another bounded
- * level is reached. It may do nothing, or ascend all the way to
- * the top level.
- */
- uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false);
- if(uErr != QCBOR_SUCCESS) {
- goto Done;
- }
-
- /*
- * This makes the next highest bounded level the current bounded
- * level. If there is no next highest level, then no bounded mode
- * is in effect.
- */
- DecodeNesting_LevelUpBounded(&(pMe->nesting));
-
- pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
-
-Done:
- return uErr;
-}
-
-
-/**
- * @brief Get started exiting a map or array (semi-private)
- *
- * @param[in] pMe The decode context
- * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP
- *
- * This does some work for map and array exiting (but not
- * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel()
- * is called to do the rest.
- */
-void
-QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe,
- const uint8_t uType)
-{
- if(pMe->uLastError != QCBOR_SUCCESS) {
- /* Already in error state; do nothing. */
- return;
- }
-
- QCBORError uErr;
-
- if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) {
- uErr = QCBOR_ERR_EXIT_MISMATCH;
- goto Done;
- }
-
- /*
- Have to set the offset to the end of the map/array
- that is being exited. If there is no cached value,
- from previous map search, then do a dummy search.
- */
- if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) {
- QCBORItem Dummy;
- Dummy.uLabelType = QCBOR_TYPE_NONE;
- uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL);
- if(uErr != QCBOR_SUCCESS) {
- goto Done;
- }
- }
-
- uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache);
-
-Done:
- pMe->uLastError = (uint8_t)uErr;
-}
-
-
-// TODO: re order this file with tags stuff last. bstr is a tag thing
-static QCBORError
-QCBORDecode_Private_CheckTagNType(QCBORDecodeContext *pMe,
- const QCBORItem *pItem,
- const size_t uOffset,
- const uint8_t *uQCBORTypes,
- const uint64_t *uTagNumbers,
- const uint8_t uTagRequirement,
- bool *bTypeMatched);
-
-/**
- * @brief The main work of entering some byte-string wrapped CBOR.
- *
- * @param[in] pMe The decode context.
- * @param[in] pItem The byte string item.
- * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX
- * @param[out] pBstr Pointer and length of byte string entered.
- *
- * This is called once the byte string item has been decoded to do all
- * the book keeping work for descending a nesting level into the
- * nested CBOR.
- *
- * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement.
- */
-static QCBORError
-QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe,
- const QCBORItem *pItem,
- const uint8_t uTagRequirement,
- const size_t uOffset,
- UsefulBufC *pBstr)
-{
- bool bTypeMatched;
- QCBORError uError;
-
- const uint8_t uTypes[] = {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE};
- const uint64_t uTagNumbers[] = {CBOR_TAG_CBOR, CBOR_TAG_CBOR_SEQUENCE, CBOR_TAG_INVALID64};
-
-
- if(pBstr) {
- *pBstr = NULLUsefulBufC;
- }
-
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return pMe->uLastError;
- }
-
- if(pItem->uDataAlloc) {
- return QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
- }
-
- uError = QCBORDecode_Private_CheckTagNType(pMe,
- pItem,
- uOffset,
- uTypes, // TODO: maybe this should be empty
- uTagNumbers,
- uTagRequirement,
- &bTypeMatched);
-
- if(pItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
- uError = QCBOR_ERR_BAD_TAG_CONTENT; // TODO: error
- }
-
-
- if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
- /* Reverse the decrement done by GetNext() for the bstr so the
- * increment in QCBORDecode_NestLevelAscender() called by
- * ExitBoundedLevel() will work right.
- */
- DecodeNesting_ReverseDecrement(&(pMe->nesting));
- }
-
- if(pBstr) {
- *pBstr = pItem->val.string;
- }
-
- /* This saves the current length of the UsefulInputBuf and then
- * narrows the UsefulInputBuf to start and length of the wrapped
- * CBOR that is being entered.
- *
- * Most of these calls are simple inline accessors so this doesn't
- * amount to much code.
- */
-
- const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
- /* This check makes the cast of uPreviousLength to uint32_t below safe. */
- if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
- uError = QCBOR_ERR_INPUT_TOO_LARGE;
- goto Done;
- }
-
- const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
- pItem->val.string.ptr);
- /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
- if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
- /* This should never happen because pItem->val.string.ptr should
- * always be valid since it was just returned.
- */
- uError = QCBOR_ERR_INPUT_TOO_LARGE;
- goto Done;
- }
-
- const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
-
- UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
- UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
-
- uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
- (uint32_t)uPreviousLength,
- (uint32_t)uStartOfBstr);
-Done:
- return uError;
-}
-
-
-static void
-QCBORDecode_Private_GetAndTell(QCBORDecodeContext *pMe, QCBORItem *Item, size_t *uOffset)
-{
-#ifndef QCBOR_DISABLE_TAGS
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return;
- }
-
- *uOffset = QCBORDecode_Tell(pMe);
-#else
- *uOffset = SIZE_MAX;
-
-#endif /* ! QCBOR_DISABLE_TAGS */
- pMe->uLastError = (uint8_t)QCBORDecode_Private_GetNextTagContent(pMe, Item);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe,
- const uint8_t uTagRequirement,
- UsefulBufC *pBstr)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
- pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
- &Item,
- uTagRequirement,
- uOffset,
- pBstr);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe,
- const int64_t nLabel,
- const uint8_t uTagRequirement,
- UsefulBufC *pBstr)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_BYTE_STRING, &Item, &uOffset);
- pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
- &Item,
- uTagRequirement,
- uOffset,
- pBstr);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- const uint8_t uTagRequirement,
- UsefulBufC *pBstr)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_BYTE_STRING, &Item, &uOffset);
- pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
- &Item,
- uTagRequirement,
- uOffset,
- pBstr);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
-{
- if(pMe->uLastError != QCBOR_SUCCESS) {
- // Already in error state; do nothing.
- return;
- }
-
- if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
- pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH;
- return;
- }
-
- const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
-
- /*
- Reset the length of the UsefulInputBuf to what it was before
- the bstr wrapped CBOR was entered.
- */
- UsefulInputBuf_SetBufferLength(&(pMe->InBuf),
- DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
-
-
- QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr);
- pMe->uLastError = (uint8_t)uErr;
-}
-
-
-
-/**
- * @brief Process simple type true and false, a boolean
- *
- * @param[in] pMe The decode context.
- * @param[in] pItem The item with either true or false.
- * @param[out] pBool The boolean value output.
- *
- * Sets the internal error if the item isn't a true or a false. Also
- * records any tag numbers as the tag numbers of the last item.
- */
-static void
-QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe,
- const QCBORItem *pItem,
- bool *pBool)
-{
- if(pMe->uLastError != QCBOR_SUCCESS) {
- /* Already in error state, do nothing */
- return;
- }
-
- switch(pItem->uDataType) {
- case QCBOR_TYPE_TRUE:
- *pBool = true;
- break;
-
- case QCBOR_TYPE_FALSE:
- *pBool = false;
- break;
-
- default:
- pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
- break;
- }
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
-{
- QCBORItem Item;
- QCBORDecode_VGetNext(pMe, &Item);
- QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe,
- const int64_t nLabel,
- bool *pValue)
-{
- QCBORItem Item;
- QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
- QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- bool *pValue)
-{
- QCBORItem Item;
- QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
- QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
-}
-
-
-/**
- * @brief Process simple values.
- *
- * @param[in] pMe The decode context.
- * @param[in] pItem The item with the simple value.
- * @param[out] puSimple The simple value output.
- *
- * Sets the internal error if the item isn't a true or a false. Also
- * records any tag numbers as the tag numbers of the last item.
- */
-static void
-QCBORDecode_Private_ProcessSimple(QCBORDecodeContext *pMe,
- const QCBORItem *pItem,
- uint8_t *puSimple)
-{
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return;
- }
-
- /* It's kind of lame to remap true...undef back to simple values, but
- * this function isn't used much and to not do it would require
- * changing GetNext() behavior in an incompatible way.
- */
- switch(pItem->uDataType) {
- case QCBOR_TYPE_UKNOWN_SIMPLE:
- *puSimple = pItem->val.uSimple;
- break;
-
- case QCBOR_TYPE_TRUE:
- *puSimple = CBOR_SIMPLEV_TRUE;
- break;
-
- case QCBOR_TYPE_FALSE:
- *puSimple = CBOR_SIMPLEV_FALSE;
- break;
-
- case QCBOR_TYPE_NULL:
- *puSimple = CBOR_SIMPLEV_NULL;
- break;
-
- case QCBOR_TYPE_UNDEF:
- *puSimple = CBOR_SIMPLEV_UNDEF;
- break;
-
- default:
- pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
- return;
- }
-}
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_GetSimple(QCBORDecodeContext *pMe, uint8_t *puSimple)
-{
- QCBORItem Item;
- QCBORDecode_VGetNext(pMe, &Item);
- QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimple);
-}
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_GetSimpleInMapN(QCBORDecodeContext *pMe,
- int64_t nLabel,
- uint8_t *puSimpleValue)
-{
- QCBORItem Item;
- QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
- QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
-}
-
-/*
- * Public function, see header qcbor/qcbor_decode.h file
- */
-void
-QCBORDecode_GetSimpleInMapSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- uint8_t *puSimpleValue)
-{
- QCBORItem Item;
- QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
- QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
-}
-
-
-
-
-#ifndef QCBOR_DISABLE_TAGS
-// TODO: uTagNumber might be better a list than calling this multiple times
-static QCBORError
-QCBORDecode_Private_Check1TagNumber(const QCBORDecodeContext *pMe,
- const QCBORItem *pItem,
- const uint64_t uTagNumber,
- const size_t uOffset)
-{
- if(pItem->auTagNumbers[0] == CBOR_TAG_INVALID16) {
- /* There are no tag numbers at all, so no unprocessed */
- return QCBOR_SUCCESS;
- }
-
- /* There are some tag numbers, so keep checking. This check passes
- * if there is one and only one tag number that matches uTagNumber
- */
-
- // TODO: behave different in v1 and v2?
-
- const uint64_t uInnerTag = QCBORDecode_GetNthTagNumber(pMe, pItem, 0);
-
- if(uInnerTag == uTagNumber && pItem->auTagNumbers[1] == CBOR_TAG_INVALID16 ) {
- /* The only tag number is the one we are processing so no unprocessed */
- return QCBOR_SUCCESS;
- }
-
- if(uOffset != pMe->uTagNumberCheckOffset) {
- /* processed tag numbers are for some other item, not us */
- return QCBOR_ERR_UNPROCESSED_TAG_NUMBER;
- }
-
- if(pMe->uTagNumberIndex != 1) {
- return QCBOR_ERR_UNPROCESSED_TAG_NUMBER;
- }
-
- return QCBOR_SUCCESS;
-}
-#endif
-
-
-static QCBORError
-QCBORDecode_Private_CheckTagNType(QCBORDecodeContext *pMe,
- const QCBORItem *pItem,
- const size_t uOffset,
- const uint8_t *uQCBORTypes,
- const uint64_t *uTagNumbers,
- const uint8_t uTagRequirement,
- bool *bTypeMatched)
-{
- const int nTagReq = uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
-
- *bTypeMatched = false;
- for(const uint8_t *pTNum = uQCBORTypes; *pTNum != QCBOR_TYPE_NONE; pTNum++) {
- if(pItem->uDataType == *pTNum) {
- *bTypeMatched = true;
- break;
- }
- }
-
-#ifndef QCBOR_DISABLE_TAGS
- bool bTagNumberMatched;
- QCBORError uErr;
- const uint64_t uInnerTag = QCBORDecode_GetNthTagNumber(pMe, pItem, 0);
-
- bTagNumberMatched = false;
- for(const uint64_t *pQType = uTagNumbers; *pQType != CBOR_TAG_INVALID64; pQType++) {
- if(uInnerTag == *pQType) {
- bTagNumberMatched = true;
- break;
- }
- }
-
-
- if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
- /* There must be a tag number */
- if(!bTagNumberMatched && !*bTypeMatched) {
- return QCBOR_ERR_UNEXPECTED_TYPE; // TODO: error code
- }
-
- } else if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
- if(bTagNumberMatched || *bTypeMatched) {
- return QCBOR_ERR_UNEXPECTED_TYPE; // TODO: error code
- }
-
- } else if(nTagReq == QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG) {
- /* No check necessary */
- }
-
- /* Now check if there are extra tags and if there's an error in them */
- if(!(uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS)) {
- /* The flag to ignore extra is not set, so keep checking */
- for(const uint64_t *pTNum = uTagNumbers; *pTNum != CBOR_TAG_INVALID64; pTNum++) {
- uErr = QCBORDecode_Private_Check1TagNumber(pMe, pItem, *pTNum, uOffset);
- if(uErr != QCBOR_SUCCESS) {
- return uErr;
- }
- }
- }
-
- return QCBOR_SUCCESS;
-#else
- (void)pMe;
- (void)uOffset;
- (void)uTagNumbers;
-
- if(nTagReq != QCBOR_TAG_REQUIREMENT_TAG && bTypeMatched) {
- return QCBOR_SUCCESS;
- } else {
- return QCBOR_ERR_UNEXPECTED_TYPE;
- }
-
-#endif
-
-}
-
-
-void
-QCBORDecode_Private_ProcessTagItemMulti(QCBORDecodeContext *pMe,
- QCBORItem *pItem,
- const uint8_t uTagRequirement,
- const uint8_t uQCBORTypes[],
- const uint64_t uTagNumbers[],
- QCBORTagContentCallBack *pfCB,
- size_t uOffset)
-{
- QCBORError uErr;
- bool bTypeMatched;
-
- if(pMe->uLastError != QCBOR_SUCCESS) {
- return;
- }
-
- uErr = QCBORDecode_Private_CheckTagNType(pMe,
- pItem,
- uOffset,
- uQCBORTypes,
- uTagNumbers,
- uTagRequirement,
- &bTypeMatched);
- if(uErr != QCBOR_SUCCESS) {
- goto Done;
- }
-
- if(!bTypeMatched) {
- /* Tag content wasn't previously processed, do it now */
- uErr = (*pfCB)(pMe, NULL, uTagNumbers[0], pItem);
- if(uErr != QCBOR_SUCCESS) {
- goto Done;
- }
- }
-
-Done:
- pMe->uLastError = (uint8_t)uErr;
-}
-
-
-/*
- **/
-void
-QCBORDecode_Private_ProcessTagItem(QCBORDecodeContext *pMe,
- QCBORItem *pItem,
- const uint8_t uTagRequirement,
- const uint8_t uQCBORTypes[],
- const uint64_t uTagNumber,
- QCBORTagContentCallBack *pfCB,
- size_t uOffset)
-{
- uint64_t auTagNumbers[2];
-
- auTagNumbers[0] = uTagNumber;
- auTagNumbers[1] = CBOR_TAG_INVALID64;
-
- QCBORDecode_Private_ProcessTagItemMulti(pMe,
- pItem,
- uTagRequirement,
- uQCBORTypes,
- auTagNumbers,
- pfCB,
- uOffset);
-}
-
-
-static void
-QCBORDecode_Private_ProcessTagOne(QCBORDecodeContext *pMe,
- QCBORItem *pItem,
- const uint8_t uTagRequirement,
- const uint8_t uQCBORType,
- const uint64_t uTagNumber,
- QCBORTagContentCallBack *pfCB,
- const size_t uOffset)
-{
- uint8_t auQCBORType[2];
-
- auQCBORType[0] = uQCBORType;
- auQCBORType[1] = QCBOR_TYPE_NONE;
-
- QCBORDecode_Private_ProcessTagItem(pMe,
- pItem,
- uTagRequirement,
- auQCBORType,
- uTagNumber,
- pfCB,
- uOffset);
-}
-
-
-
-
-/*
- * Public function, see header qcbor/qcbor_spiffy_decode.h file
- */
-void
-QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
- uint8_t uTagRequirement,
- int64_t *pnTime)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
- QCBORDecode_Private_ProcessTagOne(pMe,
- &Item,
- uTagRequirement,
- QCBOR_TYPE_DATE_EPOCH,
- CBOR_TAG_DATE_EPOCH,
- QCBORDecode_DateEpochTagCB,
- uOffset);
- *pnTime = Item.val.epochDate.nSeconds;
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_spiffy_decode.h file
- */
-void
-QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
- int64_t nLabel,
- uint8_t uTagRequirement,
- int64_t *pnTime)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
- QCBORDecode_Private_ProcessTagOne(pMe,
- &Item,
- uTagRequirement,
- QCBOR_TYPE_DATE_EPOCH,
- CBOR_TAG_DATE_EPOCH,
- QCBORDecode_DateEpochTagCB,
- uOffset);
- *pnTime = Item.val.epochDate.nSeconds;
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_spiffy_decode.h file
- */
-void
-QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- uint8_t uTagRequirement,
- int64_t *pnTime)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
- QCBORDecode_Private_ProcessTagOne(pMe,
- &Item,
- uTagRequirement,
- QCBOR_TYPE_DATE_EPOCH,
- CBOR_TAG_DATE_EPOCH,
- QCBORDecode_DateEpochTagCB,
- uOffset);
- *pnTime = Item.val.epochDate.nSeconds;
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h
- */
-void
-QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe,
- uint8_t uTagRequirement,
- int64_t *pnDays)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
- QCBORDecode_Private_ProcessTagOne(pMe,
- &Item,
- uTagRequirement,
- QCBOR_TYPE_DAYS_EPOCH,
- CBOR_TAG_DAYS_EPOCH,
- QCBORDecode_DaysEpochTagCB,
- uOffset);
- *pnDays = Item.val.epochDays;
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h
- */
-void
-QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe,
- int64_t nLabel,
- uint8_t uTagRequirement,
- int64_t *pnDays)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
- QCBORDecode_Private_ProcessTagOne(pMe,
- &Item,
- uTagRequirement,
- QCBOR_TYPE_DAYS_EPOCH,
- CBOR_TAG_DAYS_EPOCH,
- QCBORDecode_DaysEpochTagCB,
- uOffset);
- *pnDays = Item.val.epochDays;
-}
-
-
-/*
- * Public function, see header qcbor/qcbor_decode.h
- */
-void
-QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- uint8_t uTagRequirement,
- int64_t *pnDays)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
- QCBORDecode_Private_ProcessTagOne(pMe,
- &Item,
- uTagRequirement,
- QCBOR_TYPE_DAYS_EPOCH,
- CBOR_TAG_DAYS_EPOCH,
- QCBORDecode_DaysEpochTagCB,
- uOffset);
- *pnDays = Item.val.epochDays;
-}
-
-
-
-
-void
-QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
- const uint8_t uTagRequirement,
- const uint8_t uQCBOR_Type,
- const uint64_t uTagNumber,
- UsefulBufC *pStr)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
- QCBORDecode_Private_ProcessTagOne(pMe,
- &Item,
- uTagRequirement,
- uQCBOR_Type,
- uTagNumber,
- QCBORDecode_StringsTagCB,
- uOffset);
-
- if(pMe->uLastError == QCBOR_SUCCESS) {
- *pStr = Item.val.string;
- } else {
- *pStr = NULLUsefulBufC;
- }
-}
-
-
-
-static void
-QCBORDecode_Private_GetMIME(QCBORDecodeContext *pMe,
- const uint8_t uTagRequirement,
- QCBORItem *pItem,
- UsefulBufC *pValue,
- bool *pbIsTag257,
- size_t uOffset)
-{
- QCBORError uErr;
-
- const uint8_t puTypes[] = {QCBOR_TYPE_MIME, QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE};
-
- const uint64_t puTNs[] = {CBOR_TAG_MIME, CBOR_TAG_BINARY_MIME, CBOR_TAG_INVALID64};
-
- QCBORDecode_Private_ProcessTagItemMulti(pMe,
- pItem,
- uTagRequirement,
- puTypes,
- puTNs,
- QCBORDecode_MIMETagCB,
- uOffset);
- if(pMe->uLastError) {
- return;
- }
-
- if(pItem->uDataType == QCBOR_TYPE_MIME) {
- *pbIsTag257 = false;
- } else if(pItem->uDataType == QCBOR_TYPE_BINARY_MIME) {
- *pbIsTag257 = true;
- }
- *pValue = pItem->val.string;
-
-
- uErr = QCBOR_SUCCESS;
-
- pMe->uLastError = (uint8_t)uErr;
-}
-
-
-void
-QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pMe,
- const uint8_t uTagRequirement,
- UsefulBufC *pMessage,
- bool *pbIsTag257)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
- QCBORDecode_Private_GetMIME(pMe,
- uTagRequirement,
- &Item,
- pMessage,
- pbIsTag257,
- uOffset);
-}
-
-void
-QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pMe,
- const int64_t nLabel,
- const uint8_t uTagRequirement,
- UsefulBufC *pMessage,
- bool *pbIsTag257)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
- QCBORDecode_Private_GetMIME(pMe,
- uTagRequirement,
- &Item,
- pMessage,
- pbIsTag257,
- uOffset);
-}
-
-void
-QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pMe,
- const char *szLabel,
- const uint8_t uTagRequirement,
- UsefulBufC *pMessage,
- bool *pbIsTag257)
-{
- QCBORItem Item;
- size_t uOffset;
-
- QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
- QCBORDecode_Private_GetMIME(pMe,
- uTagRequirement,
- &Item,
- pMessage,
- pbIsTag257,
- uOffset);
-}
-
-
-
// Improvement: add methods for wrapped CBOR, a simple alternate
// to EnterBstrWrapped
diff --git a/src/qcbor_number_decode.c b/src/qcbor_number_decode.c
index 6873b94..5c6f3e3 100644
--- a/src/qcbor_number_decode.c
+++ b/src/qcbor_number_decode.c
@@ -1,5 +1,5 @@
/* ==========================================================================
- * number_decode.c -- Number decoding beyond the basic ints and floats
+ * qcbor_number_decode.c -- Number decoding beyond the basic ints and floats
*
* Copyright (c) 2016-2018, The Linux Foundation.
* Copyright (c) 2018-2024, Laurence Lundblade.
@@ -10,7 +10,7 @@
*
* See BSD-3-Clause license in README.md
*
- * Created on 11/14/24 from qcbor_decode.c
+ * Created on 11/14/24 from qcbor_decode.c
* ========================================================================== */
diff --git a/src/qcbor_spiffy_decode.c b/src/qcbor_spiffy_decode.c
new file mode 100644
index 0000000..5c25f54
--- /dev/null
+++ b/src/qcbor_spiffy_decode.c
@@ -0,0 +1,1197 @@
+
+
+/* ==========================================================================
+ * qcbor_spiffy_decode.c -- "Spiffy" QCBOR decoding
+ *
+ * Copyright (c) 2016-2018, The Linux Foundation.
+ * Copyright (c) 2018-2024, Laurence Lundblade.
+ * Copyright (c) 2021, Arm Limited.
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * See BSD-3-Clause license in README.md
+ *
+ * Created on 11/28/24 from qcbor_decode.c
+ * ========================================================================== */
+
+
+#include "qcbor/qcbor_decode.h"
+#include "qcbor/qcbor_spiffy_decode.h"
+// TODO: see about removing these two includes
+#include "qcbor/qcbor_tag_decode.h"
+#include "ieee754.h" /* Does not use math.h */
+#include "decode_private.h"
+#include "decode_nesting.h"
+
+
+
+#if (defined(__GNUC__) && !defined(__clang__))
+/*
+ * This is how the -Wmaybe-uninitialized compiler warning is
+ * handled. It can’t be ignored because some version of gcc enable it
+ * with -Wall which is a common and useful gcc warning option. It also
+ * can’t be ignored because it is the goal of QCBOR to compile clean
+ * out of the box in all environments.
+ *
+ * The big problem with -Wmaybe-uninitialized is that it generates
+ * false positives. It complains things are uninitialized when they
+ * are not. This is because it is not a thorough static analyzer. This
+ * is why “maybe” is in its name. The problem is it is just not
+ * thorough enough to understand all the code (and someone saw fit to
+ * put it in gcc and worse to enable it with -Wall).
+ *
+ * One solution would be to change the code so -Wmaybe-uninitialized
+ * doesn’t get confused, for example adding an unnecessary extra
+ * initialization to zero. (If variables were truly uninitialized, the
+ * correct path is to understand the code thoroughly and set them to
+ * the correct value at the correct time; in essence this is already
+ * done; -Wmaybe-uninitialized just can’t tell). This path is not
+ * taken because it makes the code bigger and is kind of the tail
+ * wagging the dog.
+ *
+ * The solution here is to just use a pragma to disable it for the
+ * whole file. Disabling it for each line makes the code fairly ugly
+ * requiring #pragma to push, pop and ignore. Another reason is the
+ * warnings issues vary by version of gcc and which optimization
+ * optimizations are selected. Another reason is that compilers other
+ * than gcc don’t have -Wmaybe-uninitialized.
+ *
+ * One may ask how to be sure these warnings are false positives and
+ * not real issues. 1) The code has been read carefully to check. 2)
+ * Testing is pretty thorough. 3) This code has been run through
+ * thorough high-quality static analyzers.
+ *
+ * In particularly, most of the warnings are about
+ * Item.Item->uDataType being uninitialized. QCBORDecode_GetNext()
+ * *always* sets this value and test case confirm
+ * this. -Wmaybe-uninitialized just can't tell.
+ *
+ * https://stackoverflow.com/questions/5080848/disable-gcc-may-be-used-uninitialized-on-a-particular-variable
+ */
+#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
+#endif
+
+
+/* Return true if the labels in Item1 and Item2 are the same.
+ Works only for integer and string labels. Returns false
+ for any other type. */
+static bool
+QCBORItem_MatchLabel(const QCBORItem Item1, const QCBORItem Item2)
+{
+ if(Item1.uLabelType == QCBOR_TYPE_INT64) {
+ if(Item2.uLabelType == QCBOR_TYPE_INT64 && Item1.label.int64 == Item2.label.int64) {
+ return true;
+ }
+#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
+ } else if(Item1.uLabelType == QCBOR_TYPE_TEXT_STRING) {
+ if(Item2.uLabelType == QCBOR_TYPE_TEXT_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
+ return true;
+ }
+ } else if(Item1.uLabelType == QCBOR_TYPE_BYTE_STRING) {
+ if(Item2.uLabelType == QCBOR_TYPE_BYTE_STRING && !UsefulBuf_Compare(Item1.label.string, Item2.label.string)) {
+ return true;
+ }
+ } else if(Item1.uLabelType == QCBOR_TYPE_UINT64) {
+ if(Item2.uLabelType == QCBOR_TYPE_UINT64 && Item1.label.uint64 == Item2.label.uint64) {
+ return true;
+ }
+#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+ }
+
+ /* Other label types are never matched */
+ return false;
+}
+
+
+
+/*
+ Returns true if Item1 and Item2 are the same type
+ or if either are of QCBOR_TYPE_ANY.
+ */
+static bool
+QCBORItem_MatchType(const QCBORItem Item1, const QCBORItem Item2)
+{
+ if(Item1.uDataType == Item2.uDataType) {
+ return true;
+ } else if(Item1.uDataType == QCBOR_TYPE_ANY) {
+ return true;
+ } else if(Item2.uDataType == QCBOR_TYPE_ANY) {
+ return true;
+ }
+ return false;
+}
+
+/**
+ * @brief Rewind cursor to start as if map or array were just entered.
+ *
+ * @param[in] pMe The decoding context
+ *
+ * This affects the nesting tracking and the UsefulInputBuf.
+ */
+static void
+QCBORDecode_Private_RewindMapOrArray(QCBORDecodeContext *pMe)
+{
+ /* Reset nesting tracking to the deepest bounded level */
+ DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
+
+ DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
+
+ /* Reposition traversal cursor to the start of the map/array */
+ UsefulInputBuf_Seek(&(pMe->InBuf),
+ DecodeNesting_GetMapOrArrayStart(&(pMe->nesting)));
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_Rewind(QCBORDecodeContext *pMe)
+{
+ if(pMe->nesting.pCurrentBounded != NULL) {
+ /* In a bounded map, array or bstr-wrapped CBOR */
+
+ if(DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
+ /* In bstr-wrapped CBOR. */
+
+ /* Reposition traversal cursor to start of wrapping byte string */
+ UsefulInputBuf_Seek(&(pMe->InBuf),
+ pMe->nesting.pCurrentBounded->u.bs.uBstrStartOffset);
+ DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
+
+ } else {
+ /* In a map or array */
+ QCBORDecode_Private_RewindMapOrArray(pMe);
+ }
+
+ } else {
+ /* Not in anything bounded */
+
+ /* Reposition traversal cursor to the start of input CBOR */
+ UsefulInputBuf_Seek(&(pMe->InBuf), 0ULL);
+
+ /* Reset nesting tracking to beginning of input. */
+ DecodeNesting_Init(&(pMe->nesting));
+ }
+
+ pMe->uLastError = QCBOR_SUCCESS;
+}
+
+
+
+
+/**
+ * @brief Search a map for a set of items.
+ *
+ * @param[in] pMe The decode context to search.
+ * @param[in,out] pItemArray The items to search for and the items found.
+ * @param[out] pInfo Several bits of meta-info returned by search.
+ * @param[in] pCallBack Callback object or @c NULL.
+ *
+ * @retval QCBOR_ERR_NOT_ENTERED Trying to search without entering a map.
+ *
+ * @retval QCBOR_ERR_DUPLICATE_LABEL Duplicate items (items with the same label)
+ * were found for one of the labels being
+ * search for. This duplicate detection is
+ * only performed for items in pItemArray,
+ * not every item in the map.
+ *
+ * @retval QCBOR_ERR_UNEXPECTED_TYPE A label was matched, but the type was
+ * wrong for the matchd label.
+ *
+ * @retval Also errors returned by QCBORDecode_GetNext().
+ *
+ * On input, @c pItemArray contains a list of labels and data types of
+ * items to be found.
+ *
+ * On output, the fully retrieved items are filled in with values and
+ * such. The label was matched, so it never changes.
+ *
+ * If an item was not found, its data type is set to @ref QCBOR_TYPE_NONE.
+ *
+ * This also finds the ends of maps and arrays when they are exited.
+ */
+QCBORError
+QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe,
+ QCBORItem *pItemArray,
+ MapSearchInfo *pInfo,
+ MapSearchCallBack *pCallBack)
+{
+ QCBORError uReturn;
+ uint64_t uFoundItemBitMap = 0;
+
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ uReturn = pMe->uLastError;
+ goto Done2;
+ }
+
+ if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_MAP) &&
+ pItemArray->uLabelType != QCBOR_TYPE_NONE) {
+ /* QCBOR_TYPE_NONE as first item indicates just looking
+ for the end of an array, so don't give error. */
+ uReturn = QCBOR_ERR_MAP_NOT_ENTERED;
+ goto Done2;
+ }
+
+ if(DecodeNesting_IsBoundedEmpty(&(pMe->nesting))) {
+ // It is an empty bounded array or map
+ if(pItemArray->uLabelType == QCBOR_TYPE_NONE) {
+ // Just trying to find the end of the map or array
+ pMe->uMapEndOffsetCache = DecodeNesting_GetMapOrArrayStart(&(pMe->nesting));
+ uReturn = QCBOR_SUCCESS;
+ } else {
+ // Nothing is ever found in an empty array or map. All items
+ // are marked as not found below.
+ uReturn = QCBOR_SUCCESS;
+ }
+ goto Done2;
+ }
+
+ QCBORDecodeNesting SaveNesting;
+ size_t uSavePos = UsefulInputBuf_Tell(&(pMe->InBuf));
+ DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
+
+ /* Reposition to search from the start of the map / array */
+ QCBORDecode_Private_RewindMapOrArray(pMe);
+
+ /*
+ Loop over all the items in the map or array. Each item
+ could be a map or array, but label matching is only at
+ the main level. This handles definite- and indefinite-
+ length maps and arrays. The only reason this is ever
+ called on arrays is to find their end position.
+
+ This will always run over all items in order to do
+ duplicate detection.
+
+ This will exit with failure if it encounters an
+ unrecoverable error, but continue on for recoverable
+ errors.
+
+ If a recoverable error occurs on a matched item, then
+ that error code is returned.
+ */
+ const uint8_t uMapNestLevel = DecodeNesting_GetBoundedModeLevel(&(pMe->nesting));
+ if(pInfo) {
+ pInfo->uItemCount = 0;
+ }
+ uint8_t uNextNestLevel;
+ do {
+ /* Remember offset of the item because sometimes it has to be returned */
+ const size_t uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
+
+ /* Get the item */
+ QCBORItem Item;
+ /* QCBORDecode_Private_GetNextTagContent() rather than GetNext()
+ * because a label match is performed on recoverable errors to
+ * be able to return the the error code for the found item. */
+ QCBORError uResult = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
+ if(QCBORDecode_IsUnrecoverableError(uResult)) {
+ /* The map/array can't be decoded when unrecoverable errors occur */
+ uReturn = uResult;
+ goto Done;
+ }
+ if(uResult == QCBOR_ERR_NO_MORE_ITEMS) {
+ /* Unexpected end of map or array. */
+ uReturn = uResult;
+ goto Done;
+ }
+
+ /* See if item has one of the labels that are of interest */
+ bool bMatched = false;
+ for(int nIndex = 0; pItemArray[nIndex].uLabelType != QCBOR_TYPE_NONE; nIndex++) {
+ if(QCBORItem_MatchLabel(Item, pItemArray[nIndex])) {
+ /* A label match has been found */
+ if(uFoundItemBitMap & (0x01ULL << nIndex)) {
+ uReturn = QCBOR_ERR_DUPLICATE_LABEL;
+ goto Done;
+ }
+ if(uResult != QCBOR_SUCCESS) {
+ /* The label matches, but the data item is in error.
+ * It is OK to have recoverable errors on items that
+ * are not matched. */
+ uReturn = uResult;
+ goto Done;
+ }
+ if(!QCBORItem_MatchType(Item, pItemArray[nIndex])) {
+ /* The data item is not of the type(s) requested */
+ uReturn = QCBOR_ERR_UNEXPECTED_TYPE;
+ goto Done;
+ }
+
+ /* Successful match. Return the item. */
+ pItemArray[nIndex] = Item;
+ uFoundItemBitMap |= 0x01ULL << nIndex;
+ if(pInfo) {
+ pInfo->uStartOffset = uOffset;
+ }
+ bMatched = true;
+ }
+ }
+
+
+ if(!bMatched && pCallBack != NULL) {
+ /*
+ Call the callback on unmatched labels.
+ (It is tempting to do duplicate detection here, but that would
+ require dynamic memory allocation because the number of labels
+ that might be encountered is unbounded.)
+ */
+ uReturn = (*(pCallBack->pfCallback))(pCallBack->pCBContext, &Item);
+ if(uReturn != QCBOR_SUCCESS) {
+ goto Done;
+ }
+ }
+
+ /*
+ Consume the item whether matched or not. This
+ does the work of traversing maps and array and
+ everything in them. In this loop only the
+ items at the current nesting level are examined
+ to match the labels.
+ */
+ uReturn = QCBORDecode_Private_ConsumeItem(pMe, &Item, NULL, &uNextNestLevel);
+ if(uReturn != QCBOR_SUCCESS) {
+ goto Done;
+ }
+
+ if(pInfo) {
+ pInfo->uItemCount++;
+ }
+
+ } while (uNextNestLevel >= uMapNestLevel);
+
+ uReturn = QCBOR_SUCCESS;
+
+ const size_t uEndOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
+
+ // Check here makes sure that this won't accidentally be
+ // QCBOR_MAP_OFFSET_CACHE_INVALID which is larger than
+ // QCBOR_MAX_DECODE_INPUT_SIZE.
+ // Cast to uint32_t to possibly address cases where SIZE_MAX < UINT32_MAX
+ if((uint32_t)uEndOffset >= QCBOR_MAX_DECODE_INPUT_SIZE) {
+ uReturn = QCBOR_ERR_INPUT_TOO_LARGE;
+ goto Done;
+ }
+ /* Cast OK because encoded CBOR is limited to UINT32_MAX */
+ pMe->uMapEndOffsetCache = (uint32_t)uEndOffset;
+
+ 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 */
+ for(int i = 0; pItemArray[i].uLabelType != 0; i++) {
+ if(!(uFoundItemBitMap & (0x01ULL << i))) {
+ pItemArray[i].uDataType = QCBOR_TYPE_NONE;
+ pItemArray[i].uLabelType = QCBOR_TYPE_NONE;
+ }
+ }
+
+ return uReturn;
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_SeekToLabelN(QCBORDecodeContext *pMe, int64_t nLabel)
+{
+ MapSearchInfo Info;
+ QCBORItem OneItemSeach[2];
+
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return;
+ }
+
+ OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
+ OneItemSeach[0].label.int64 = nLabel;
+ OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
+ OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
+
+ pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
+ if(pMe->uLastError == QCBOR_SUCCESS) {
+ UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
+ }
+}
+
+
+void
+QCBORDecode_SeekToLabelSZ(QCBORDecodeContext *pMe, const char *szLabel)
+{
+#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
+ MapSearchInfo Info;
+ QCBORItem OneItemSeach[2];
+
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return;
+ }
+
+ OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
+ OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
+ OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
+ OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
+
+ pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
+ if(pMe->uLastError == QCBOR_SUCCESS) {
+ UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
+ }
+#else
+ (void)pMe;
+ (void)szLabel;
+ pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
+#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+}
+
+
+void
+QCBORDecode_Private_GetItemInMapNoCheck(QCBORDecodeContext *pMe,
+ QCBORItem *OneItemSeach,
+ QCBORItem *pItem,
+ size_t *puOffset)
+{
+ QCBORError uErr;
+ MapSearchInfo SearchInfo;
+
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return;
+ }
+
+ uErr = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &SearchInfo, NULL);
+
+ if(uErr == QCBOR_SUCCESS && OneItemSeach[0].uDataType == QCBOR_TYPE_NONE) {
+ uErr = QCBOR_ERR_LABEL_NOT_FOUND;
+ }
+ *pItem = OneItemSeach[0];
+ *puOffset = SearchInfo.uStartOffset;
+
+ if(uErr == QCBOR_SUCCESS) {
+ QCBORDecode_Private_SaveTagNumbers(pMe, pItem);
+ }
+
+ pMe->uLastError = (uint8_t)uErr;
+}
+
+
+static void
+QCBORDecode_Private_GetItemInMap(QCBORDecodeContext *pMe, QCBORItem *OneItemSeach, QCBORItem *pItem)
+{
+ QCBORError uErr;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, &uOffset);
+
+ uErr = QCBORDecode_Private_GetItemChecks(pMe, pMe->uLastError, uOffset, pItem);
+ if(uErr != QCBOR_SUCCESS) {
+ goto Done;
+ }
+
+ QCBORDecode_Private_SaveTagNumbers(pMe, pItem);
+
+Done:
+ pMe->uLastError = (uint8_t)uErr;
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetItemInMapN(QCBORDecodeContext *pMe,
+ const int64_t nLabel,
+ const uint8_t uQcborType,
+ QCBORItem *pItem)
+{
+ QCBORItem OneItemSeach[2];
+
+ OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
+ OneItemSeach[0].label.int64 = nLabel;
+ OneItemSeach[0].uDataType = uQcborType;
+ OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
+
+ QCBORDecode_Private_GetItemInMap(pMe, OneItemSeach, pItem);
+}
+
+
+/**
+ * @brief Get an item by label by type.
+ *
+ * @param[in] pMe The decode context.
+ * @param[in] nLabel The label to search map for.
+ * @param[in] uQcborType The QCBOR type to look for.
+ * @param[out] pItem The item found.
+ * @param[out] puOffset The offset of item for tag consumption check.
+ *
+ * This finds the item with the given label in currently open
+ * map. This does not call QCBORDecode_Private_GetItemChecks()
+ * to check tag number consumption or decode conformance.
+ */
+void
+QCBORDecode_Private_GetItemInMapNoCheckN(QCBORDecodeContext *pMe,
+ const int64_t nLabel,
+ const uint8_t uQcborType,
+ QCBORItem *pItem,
+ size_t *puOffset)
+{
+ QCBORItem OneItemSeach[2];
+
+ OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
+ OneItemSeach[0].label.int64 = nLabel;
+ OneItemSeach[0].uDataType = uQcborType;
+ OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
+
+ QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, puOffset);
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetItemInMapSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ const uint8_t uQcborType,
+ QCBORItem *pItem)
+{
+#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
+ QCBORItem OneItemSeach[2];
+
+ OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
+ OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
+ OneItemSeach[0].uDataType = uQcborType;
+ OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
+
+ QCBORDecode_Private_GetItemInMap(pMe, OneItemSeach, pItem);
+
+#else
+ (void)pMe;
+ (void)szLabel;
+ (void)uQcborType;
+ (void)pItem;
+ pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
+#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+}
+
+/**
+ * @brief Get an item by string label of a particular type
+ *
+ * @param[in] pMe The decode context.
+ * @param[in] szLabel The label to search map for.
+ * @param[in] uQcborType The QCBOR type to look for.
+ * @param[out] pItem The item found.
+ * @param[out] puOffset The offset of item for tag consumption check.
+ *
+ * This finds the item with the given label in currently open
+ * map. This does not call QCBORDecode_Private_GetItemChecks()
+ * to check tag number consumption or decode conformance.
+ */
+void
+QCBORDecode_Private_GetItemInMapNoCheckSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ const uint8_t uQcborType,
+ QCBORItem *pItem,
+ size_t *puOffset)
+{
+#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
+ QCBORItem OneItemSeach[2];
+
+ OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
+ OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
+ OneItemSeach[0].uDataType = uQcborType;
+ OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
+
+ QCBORDecode_Private_GetItemInMapNoCheck(pMe, OneItemSeach, pItem, puOffset);
+
+#else
+ (void)pMe;
+ (void)szLabel;
+ (void)uQcborType;
+ (void)pItem;
+ (void)puOffset;
+ pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
+#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+}
+
+
+
+
+
+
+/**
+ * @brief Semi-private. Get pointer, length and item count of an array or map.
+ *
+ * @param[in] pMe The decode context.
+ * @param[in] pTarget The label and type of the array or map to retrieve.
+ * @param[out] pItem The item for the array/map.
+ * @param[out] pEncodedCBOR Pointer and length of the encoded map or array.
+ *
+ * The next item to be decoded must be a map or array as specified by @c uType.
+ *
+ * When this is complete, the traversal cursor is unchanged.
+ */void
+QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe,
+ QCBORItem *pTarget,
+ QCBORItem *pItem,
+ UsefulBufC *pEncodedCBOR)
+{
+ MapSearchInfo Info;
+ QCBORDecodeNesting SaveNesting;
+ size_t uSaveCursor;
+
+ pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pTarget, &Info, NULL);
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return;
+ }
+ pMe->uLastError = (uint8_t)QCBORDecode_Private_GetItemChecks(pMe, pMe->uLastError, Info.uStartOffset, pItem);
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return;
+ }
+
+ /* Save the whole position of things so they can be restored.
+ * so the cursor position is unchanged by this operation, like
+ * all the other GetXxxxInMap() operations. */
+ DecodeNesting_PrepareForMapSearch(&(pMe->nesting), &SaveNesting);
+ uSaveCursor = UsefulInputBuf_Tell(&(pMe->InBuf));
+
+ DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
+ UsefulInputBuf_Seek(&(pMe->InBuf), Info.uStartOffset);
+ QCBORDecode_Private_GetArrayOrMap(pMe, pTarget[0].uDataType, pItem, pEncodedCBOR);
+
+ UsefulInputBuf_Seek(&(pMe->InBuf), uSaveCursor);
+ DecodeNesting_RestoreFromMapSearch(&(pMe->nesting), &SaveNesting);
+}
+
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetItemsInMap(QCBORDecodeContext *pMe, QCBORItem *pItemList)
+{
+ pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, NULL);
+}
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe,
+ QCBORItem *pItemList,
+ void *pCallbackCtx,
+ QCBORItemCallback pfCB)
+{
+ MapSearchCallBack CallBack;
+
+ CallBack.pCBContext = pCallbackCtx;
+ CallBack.pfCallback = pfCB;
+
+ pMe->uLastError = (uint8_t)QCBORDecode_Private_MapSearch(pMe, pItemList, NULL, &CallBack);
+}
+
+
+
+
+/**
+ * @brief Search for a map/array by label and enter it
+ *
+ * @param[in] pMe The decode context.
+ * @param[in] pSearch The map/array to search for.
+ *
+ * @c pSearch is expected to contain one item of type map or array
+ * with the label specified. The current bounded map will be searched for
+ * this and if found will be entered.
+ *
+ * If the label is not found, or the item found is not a map or array,
+ * the error state is set.
+ */
+static void
+QCBORDecode_Private_SearchAndEnter(QCBORDecodeContext *pMe, QCBORItem pSearch[])
+{
+ QCBORError uErr;
+ MapSearchInfo SearchInfo;
+
+ // The first item in pSearch is the one that is to be
+ // entered. It should be the only one filled in. Any other
+ // will be ignored unless it causes an error.
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return;
+ }
+
+ uErr = QCBORDecode_Private_MapSearch(pMe, pSearch, &SearchInfo, NULL);
+
+ pMe->uLastError = (uint8_t)QCBORDecode_Private_GetItemChecks(pMe, uErr, SearchInfo.uStartOffset, pSearch);
+
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return;
+ }
+
+ if(pSearch->uDataType == QCBOR_TYPE_NONE) {
+ pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
+ return;
+ }
+
+
+ /* The map or array was found. Now enter it.
+ *
+ * QCBORDecode_EnterBoundedMapOrArray() used here, requires the
+ * next item for the pre-order traversal cursor to be the map/array
+ * found by MapSearch(). The next few lines of code force the
+ * cursor to that.
+ *
+ * There is no need to retain the old cursor because
+ * QCBORDecode_EnterBoundedMapOrArray() will set it to the
+ * beginning of the map/array being entered.
+ *
+ * The cursor is forced by: 1) setting the input buffer position to
+ * the item offset found by MapSearch(), 2) setting the map/array
+ * counter to the total in the map/array, 3) setting the nesting
+ * level. Setting the map/array counter to the total is not
+ * strictly correct, but this is OK because this cursor only needs
+ * to be used to get one item and MapSearch() has already found it
+ * confirming it exists.
+ */
+ UsefulInputBuf_Seek(&(pMe->InBuf), SearchInfo.uStartOffset);
+
+ DecodeNesting_ResetMapOrArrayCount(&(pMe->nesting));
+
+ DecodeNesting_SetCurrentToBoundedLevel(&(pMe->nesting));
+
+ QCBORDecode_Private_EnterBoundedMapOrArray(pMe, pSearch->uDataType, NULL);
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_EnterMapFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
+{
+ QCBORItem OneItemSeach[2];
+ OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
+ OneItemSeach[0].label.int64 = nLabel;
+ OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
+ OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
+
+ /* The map to enter was found, now finish off entering it. */
+ QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_EnterMapFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
+{
+#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
+ QCBORItem OneItemSeach[2];
+ OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
+ OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
+ OneItemSeach[0].uDataType = QCBOR_TYPE_MAP;
+ OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
+
+ QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
+#else
+ (void)szLabel;
+ pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
+#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+}
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_EnterArrayFromMapN(QCBORDecodeContext *pMe, int64_t nLabel)
+{
+ QCBORItem OneItemSeach[2];
+ OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
+ OneItemSeach[0].label.int64 = nLabel;
+ OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
+ OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
+
+ QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
+}
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_EnterArrayFromMapSZ(QCBORDecodeContext *pMe, const char *szLabel)
+{
+#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
+ QCBORItem OneItemSeach[2];
+ OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
+ OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
+ OneItemSeach[0].uDataType = QCBOR_TYPE_ARRAY;
+ OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE;
+
+ QCBORDecode_Private_SearchAndEnter(pMe, OneItemSeach);
+#else
+ (void)szLabel;
+ pMe->uLastError = QCBOR_ERR_LABEL_NOT_FOUND;
+#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+}
+
+
+/**
+ * @brief Semi-private to do the the work for EnterMap() and EnterArray().
+ *
+ * @param[in] pMe The decode context
+ * @param[in] uType QCBOR_TYPE_MAP or QCBOR_TYPE_ARRAY.
+ * @param[out] pItem The data item for the map or array entered.
+ *
+ * The next item in the traversal must be a map or array. This
+ * consumes that item and does the book keeping to enter the map or
+ * array.
+ */
+void
+QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe,
+ const uint8_t uType,
+ QCBORItem *pItem)
+{
+ QCBORError uErr;
+
+ /* Must only be called on maps and arrays. */
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ // Already in error state; do nothing.
+ return;
+ }
+
+ /* Get the data item that is the map or array being entered. */
+ QCBORItem Item;
+ uErr = QCBORDecode_GetNext(pMe, &Item);
+ if(uErr != QCBOR_SUCCESS) {
+ goto Done;
+ }
+
+ uint8_t uItemDataType = Item.uDataType;
+
+#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
+ if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY ) {
+ uItemDataType = QCBOR_TYPE_ARRAY;
+ }
+#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+
+ if(uItemDataType != uType) {
+ uErr = QCBOR_ERR_UNEXPECTED_TYPE;
+ goto Done;
+ }
+
+ QCBORDecode_Private_SaveTagNumbers(pMe, &Item);
+
+
+ const bool bIsEmpty = (Item.uNextNestLevel <= Item.uNestingLevel);
+ if(bIsEmpty) {
+ if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
+ // Undo decrement done by QCBORDecode_GetNext() so the the
+ // the decrement when exiting the map/array works correctly
+ pMe->nesting.pCurrent->u.ma.uCountCursor++;
+ }
+ // Special case to increment nesting level for zero-length maps
+ // and arrays entered in bounded mode.
+ DecodeNesting_Descend(&(pMe->nesting), uType);
+ }
+
+ pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
+
+ uErr = DecodeNesting_EnterBoundedMapOrArray(&(pMe->nesting), bIsEmpty,
+ UsefulInputBuf_Tell(&(pMe->InBuf)));
+
+ if(pItem != NULL) {
+ *pItem = Item;
+ }
+
+Done:
+ pMe->uLastError = (uint8_t)uErr;
+}
+
+
+/**
+ * @brief Exit a bounded map, array or bstr (semi-private).
+ *
+ * @param[in] pMe Decode context.
+ * @param[in] uEndOffset The input buffer offset of the end of item exited.
+ *
+ * @returns QCBOR_SUCCESS or an error code.
+ *
+ * This is the common work for exiting a level that is a bounded map,
+ * array or bstr wrapped CBOR.
+ *
+ * One chunk of work is to set up the pre-order traversal so it is at
+ * the item just after the bounded map, array or bstr that is being
+ * exited. This is somewhat complex.
+ *
+ * The other work is to level-up the bounded mode to next higest
+ * bounded mode or the top level if there isn't one.
+ */
+QCBORError
+QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe,
+ const uint32_t uEndOffset)
+{
+ QCBORError uErr;
+
+ /*
+ * First the pre-order-traversal byte offset is positioned to the
+ * item just after the bounded mode item that was just consumed.
+ */
+ UsefulInputBuf_Seek(&(pMe->InBuf), uEndOffset);
+
+ /*
+ * Next, set the current nesting level to one above the bounded
+ * level that was just exited.
+ *
+ * DecodeNesting_CheckBoundedType() is always called before this
+ * and makes sure pCurrentBounded is valid.
+ */
+ DecodeNesting_LevelUpCurrent(&(pMe->nesting));
+
+ /*
+ * This does the complex work of leveling up the pre-order
+ * traversal when the end of a map or array or another bounded
+ * level is reached. It may do nothing, or ascend all the way to
+ * the top level.
+ */
+ uErr = QCBORDecode_Private_NestLevelAscender(pMe, NULL, false);
+ if(uErr != QCBOR_SUCCESS) {
+ goto Done;
+ }
+
+ /*
+ * This makes the next highest bounded level the current bounded
+ * level. If there is no next highest level, then no bounded mode
+ * is in effect.
+ */
+ DecodeNesting_LevelUpBounded(&(pMe->nesting));
+
+ pMe->uMapEndOffsetCache = QCBOR_MAP_OFFSET_CACHE_INVALID;
+
+Done:
+ return uErr;
+}
+
+
+/**
+ * @brief Get started exiting a map or array (semi-private)
+ *
+ * @param[in] pMe The decode context
+ * @param[in] uType QCBOR_TYPE_ARRAY or QCBOR_TYPE_MAP
+ *
+ * This does some work for map and array exiting (but not
+ * bstr exiting). Then QCBORDecode_Private_ExitBoundedLevel()
+ * is called to do the rest.
+ */
+void
+QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe,
+ const uint8_t uType)
+{
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ /* Already in error state; do nothing. */
+ return;
+ }
+
+ QCBORError uErr;
+
+ if(!DecodeNesting_IsBoundedType(&(pMe->nesting), uType)) {
+ uErr = QCBOR_ERR_EXIT_MISMATCH;
+ goto Done;
+ }
+
+ /*
+ Have to set the offset to the end of the map/array
+ that is being exited. If there is no cached value,
+ from previous map search, then do a dummy search.
+ */
+ if(pMe->uMapEndOffsetCache == QCBOR_MAP_OFFSET_CACHE_INVALID) {
+ QCBORItem Dummy;
+ Dummy.uLabelType = QCBOR_TYPE_NONE;
+ uErr = QCBORDecode_Private_MapSearch(pMe, &Dummy, NULL, NULL);
+ if(uErr != QCBOR_SUCCESS) {
+ goto Done;
+ }
+ }
+
+ uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, pMe->uMapEndOffsetCache);
+
+Done:
+ pMe->uLastError = (uint8_t)uErr;
+}
+
+
+
+
+
+/**
+ * @brief Process simple type true and false, a boolean
+ *
+ * @param[in] pMe The decode context.
+ * @param[in] pItem The item with either true or false.
+ * @param[out] pBool The boolean value output.
+ *
+ * Sets the internal error if the item isn't a true or a false. Also
+ * records any tag numbers as the tag numbers of the last item.
+ */
+static void
+QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe,
+ const QCBORItem *pItem,
+ bool *pBool)
+{
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ /* Already in error state, do nothing */
+ return;
+ }
+
+ switch(pItem->uDataType) {
+ case QCBOR_TYPE_TRUE:
+ *pBool = true;
+ break;
+
+ case QCBOR_TYPE_FALSE:
+ *pBool = false;
+ break;
+
+ default:
+ pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
+ break;
+ }
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetBool(QCBORDecodeContext *pMe, bool *pValue)
+{
+ QCBORItem Item;
+ QCBORDecode_VGetNext(pMe, &Item);
+ QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetBoolInMapN(QCBORDecodeContext *pMe,
+ const int64_t nLabel,
+ bool *pValue)
+{
+ QCBORItem Item;
+ QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
+ QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetBoolInMapSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ bool *pValue)
+{
+ QCBORItem Item;
+ QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
+ QCBORDecode_Private_ProcessBool(pMe, &Item, pValue);
+}
+
+
+/**
+ * @brief Process simple values.
+ *
+ * @param[in] pMe The decode context.
+ * @param[in] pItem The item with the simple value.
+ * @param[out] puSimple The simple value output.
+ *
+ * Sets the internal error if the item isn't a true or a false. Also
+ * records any tag numbers as the tag numbers of the last item.
+ */
+static void
+QCBORDecode_Private_ProcessSimple(QCBORDecodeContext *pMe,
+ const QCBORItem *pItem,
+ uint8_t *puSimple)
+{
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return;
+ }
+
+ /* It's kind of lame to remap true...undef back to simple values, but
+ * this function isn't used much and to not do it would require
+ * changing GetNext() behavior in an incompatible way.
+ */
+ switch(pItem->uDataType) {
+ case QCBOR_TYPE_UKNOWN_SIMPLE:
+ *puSimple = pItem->val.uSimple;
+ break;
+
+ case QCBOR_TYPE_TRUE:
+ *puSimple = CBOR_SIMPLEV_TRUE;
+ break;
+
+ case QCBOR_TYPE_FALSE:
+ *puSimple = CBOR_SIMPLEV_FALSE;
+ break;
+
+ case QCBOR_TYPE_NULL:
+ *puSimple = CBOR_SIMPLEV_NULL;
+ break;
+
+ case QCBOR_TYPE_UNDEF:
+ *puSimple = CBOR_SIMPLEV_UNDEF;
+ break;
+
+ default:
+ pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
+ return;
+ }
+}
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetSimple(QCBORDecodeContext *pMe, uint8_t *puSimple)
+{
+ QCBORItem Item;
+ QCBORDecode_VGetNext(pMe, &Item);
+ QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimple);
+}
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetSimpleInMapN(QCBORDecodeContext *pMe,
+ int64_t nLabel,
+ uint8_t *puSimpleValue)
+{
+ QCBORItem Item;
+ QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, &Item);
+ QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
+}
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+void
+QCBORDecode_GetSimpleInMapSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ uint8_t *puSimpleValue)
+{
+ QCBORItem Item;
+ QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item);
+ QCBORDecode_Private_ProcessSimple(pMe, &Item, puSimpleValue);
+}
+
+
+
+
+
+
+// Improvement: add methods for wrapped CBOR, a simple alternate
+// to EnterBstrWrapped
+
diff --git a/src/qcbor_tag_decode.c b/src/qcbor_tag_decode.c
index 31f9c03..2627962 100644
--- a/src/qcbor_tag_decode.c
+++ b/src/qcbor_tag_decode.c
@@ -10,13 +10,1029 @@
* Created on 9/5/24 from qcbode_decode.c
* ========================================================================== */
-// TODO: qcbor_tag_decode.c or tag_decode.c
-
#include "qcbor/qcbor_tag_decode.h"
+#include "decode_private.h"
+#include "decode_nesting.h"
#include <math.h> /* For isnan() */
+
+#ifndef QCBOR_DISABLE_TAGS
+
+/* Public function; see qcbor_tag_decode.h */
+QCBORError
+QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pMe, uint64_t *puTagNumber)
+{
+ QCBORItem Item;
+ size_t uOffset;
+ QCBORError uErr;
+
+ const QCBORDecodeNesting SaveNesting = pMe->nesting;
+ const UsefulInputBuf Save = pMe->InBuf;
+
+ uOffset = UsefulInputBuf_Tell(&(pMe->InBuf));
+ if(uOffset == pMe->uTagNumberCheckOffset) {
+ pMe->uTagNumberIndex++;
+ } else {
+ pMe->uTagNumberIndex = 0;
+ }
+
+ *puTagNumber = CBOR_TAG_INVALID64;
+ uErr = QCBORDecode_Private_GetNextTagContent(pMe, &Item);
+ if(uErr) {
+ return uErr;
+ }
+
+ *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &Item, pMe->uTagNumberIndex);
+ if(*puTagNumber == CBOR_TAG_INVALID64 ||
+ QCBORDecode_GetNthTagNumber(pMe, &Item, pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
+ pMe->uTagNumberIndex = QCBOR_ALL_TAGS_PROCESSED;
+ }
+ pMe->uTagNumberCheckOffset = uOffset;
+
+ pMe->nesting = SaveNesting;
+ pMe->InBuf = Save;
+
+ return QCBOR_SUCCESS;
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_VGetNextTagNumber(QCBORDecodeContext *pMe, uint64_t *puTagNumber)
+{
+ pMe->uLastError = (uint8_t)QCBORDecode_GetNextTagNumber(pMe, puTagNumber);
+}
+
+/*
+ * Public function, see header qcbor/qcbor_tag_decode.h file
+ */
+QCBORError
+QCBORDecode_GetNextTagNumberInMapN(QCBORDecodeContext *pMe, const int64_t nLabel, uint64_t *puTagNumber)
+{
+ size_t uOffset;
+ MapSearchInfo Info;
+ QCBORItem OneItemSeach[2];
+ QCBORError uReturn;
+
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return pMe->uLastError;
+ }
+
+ OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64;
+ OneItemSeach[0].label.int64 = nLabel;
+ OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
+ OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
+
+ uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
+
+ uOffset = Info.uStartOffset;
+ if(uOffset == pMe->uTagNumberCheckOffset) {
+ pMe->uTagNumberIndex++;
+ } else {
+ pMe->uTagNumberIndex = 0;
+ }
+
+ *puTagNumber = CBOR_TAG_INVALID64;
+
+ *puTagNumber = QCBORDecode_GetNthTagNumber(pMe,
+ &OneItemSeach[0],
+ pMe->uTagNumberIndex);
+ if(*puTagNumber == CBOR_TAG_INVALID64 ||
+ QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
+ pMe->uTagNumberIndex = QCBOR_ALL_TAGS_PROCESSED;
+ }
+ pMe->uTagNumberCheckOffset = uOffset;
+
+ return uReturn;
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+QCBORError
+QCBORDecode_GetNextTagNumberInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint64_t *puTagNumber)
+{
+#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS
+ size_t uOffset;
+ MapSearchInfo Info;
+ QCBORItem OneItemSeach[2];
+
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return pMe->uLastError;
+ }
+
+ OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING;
+ OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel);
+ OneItemSeach[0].uDataType = QCBOR_TYPE_ANY;
+ OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array
+
+ QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL);
+
+
+ uOffset = Info.uStartOffset;
+ if(uOffset == pMe->uTagNumberCheckOffset) {
+ pMe->uTagNumberIndex++;
+ } else {
+ pMe->uTagNumberIndex = 0;
+ }
+
+ *puTagNumber = CBOR_TAG_INVALID64;
+
+ *puTagNumber = QCBORDecode_GetNthTagNumber(pMe,
+ &OneItemSeach[0],
+ pMe->uTagNumberIndex);
+ if(*puTagNumber == CBOR_TAG_INVALID64 ||
+ QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) {
+ pMe->uTagNumberIndex = 255; /* All tags clear for this item */
+ }
+ pMe->uTagNumberCheckOffset = uOffset;
+
+ return uReturn;
+#else /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+ (void)pMe;
+ (void)szLabel;
+ (void)puTagNumber;
+ return QCBOR_ERR_LABEL_NOT_FOUND;
+#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+uint64_t
+QCBORDecode_GetNthTagNumber(const QCBORDecodeContext *pMe,
+ const QCBORItem *pItem,
+ uint8_t uIndex)
+{
+ if(pItem->uDataType == QCBOR_TYPE_NONE) {
+ return CBOR_TAG_INVALID64;
+ }
+ if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
+ return CBOR_TAG_INVALID64;
+ }
+
+ return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->auTagNumbers[uIndex]);
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+uint64_t
+QCBORDecode_GetNthTagNumberOfLast(QCBORDecodeContext *pMe, uint8_t uIndex)
+{
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return CBOR_TAG_INVALID64;
+ }
+ if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
+ return CBOR_TAG_INVALID64;
+ }
+
+ return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->auLastTags[uIndex]);
+}
+
+
+static uint64_t
+QCBORDecode_Private_GetNthTagNumberReverse(const QCBORDecodeContext *pMe,
+ const uint16_t puTagNumbers[],
+ const uint32_t uIndex)
+{
+ uint32_t uArrayIndex;
+
+ /* Find number of tag numbers */
+ for(uArrayIndex = QCBOR_MAX_TAGS_PER_ITEM-1; uArrayIndex > 0; uArrayIndex--) {
+ if(puTagNumbers[uArrayIndex] != CBOR_TAG_INVALID16) {
+ break;
+ }
+ }
+ if(uIndex > uArrayIndex) {
+ return CBOR_TAG_INVALID64;
+ }
+
+ return QCBORDecode_Private_UnMapTagNumber(pMe, puTagNumbers[uArrayIndex - uIndex]);
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+uint64_t
+QCBORDecode_GetNthTag(QCBORDecodeContext *pMe,
+ const QCBORItem *pItem,
+ const uint32_t uIndex)
+{
+ if(pItem->uDataType == QCBOR_TYPE_NONE) {
+ return CBOR_TAG_INVALID64;
+ }
+
+ return QCBORDecode_Private_GetNthTagNumberReverse(pMe,
+ pItem->auTagNumbers,
+ uIndex);
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+uint64_t
+QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe, uint32_t uIndex)
+{
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return CBOR_TAG_INVALID64;
+ }
+ if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) {
+ return CBOR_TAG_INVALID64;
+ }
+
+ return QCBORDecode_Private_GetNthTagNumberReverse(pMe,
+ pMe->auLastTags,
+ uIndex);
+}
+
+
+
+// TODO: uTagNumber might be better a list than calling this multiple times
+static QCBORError
+QCBORDecode_Private_Check1TagNumber(const QCBORDecodeContext *pMe,
+ const QCBORItem *pItem,
+ const uint64_t uTagNumber,
+ const size_t uOffset)
+{
+ if(pItem->auTagNumbers[0] == CBOR_TAG_INVALID16) {
+ /* There are no tag numbers at all, so no unprocessed */
+ return QCBOR_SUCCESS;
+ }
+
+ /* There are some tag numbers, so keep checking. This check passes
+ * if there is one and only one tag number that matches uTagNumber
+ */
+
+ // TODO: behave different in v1 and v2?
+
+ const uint64_t uInnerTag = QCBORDecode_GetNthTagNumber(pMe, pItem, 0);
+
+ if(uInnerTag == uTagNumber && pItem->auTagNumbers[1] == CBOR_TAG_INVALID16) {
+ /* The only tag number is the one we are processing so no unprocessed */
+ return QCBOR_SUCCESS;
+ }
+
+ if(uOffset != pMe->uTagNumberCheckOffset) {
+ /* processed tag numbers are for some other item, not us */
+ return QCBOR_ERR_UNPROCESSED_TAG_NUMBER;
+ }
+
+ if(pMe->uTagNumberIndex != 1) {
+ return QCBOR_ERR_UNPROCESSED_TAG_NUMBER;
+ }
+
+ return QCBOR_SUCCESS;
+}
+#endif /* ! QCBOR_DISABLE_TAGS */
+
+
+static QCBORError
+QCBORDecode_Private_CheckTagNType(QCBORDecodeContext *pMe,
+ const QCBORItem *pItem,
+ const size_t uOffset,
+ const uint8_t *uQCBORTypes,
+ const uint64_t *uTagNumbers,
+ const uint8_t uTagRequirement,
+ bool *bTypeMatched)
+{
+ const uint64_t *pQType;
+ const uint64_t *pTNum;
+ const uint8_t *pTypeNum;
+
+ const int nTagReq = uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS;
+
+ *bTypeMatched = false;
+ for(pTypeNum = uQCBORTypes; *pTypeNum != QCBOR_TYPE_NONE; pTypeNum++) {
+ if(pItem->uDataType == *pTypeNum) {
+ *bTypeMatched = true;
+ break;
+ }
+ }
+
+#ifndef QCBOR_DISABLE_TAGS
+ bool bTagNumberMatched;
+ QCBORError uErr;
+ const uint64_t uInnerTag = QCBORDecode_GetNthTagNumber(pMe, pItem, 0);
+
+ bTagNumberMatched = false;
+ for(pQType = uTagNumbers; *pQType != CBOR_TAG_INVALID64; pQType++) {
+ if(uInnerTag == *pQType) {
+ bTagNumberMatched = true;
+ break;
+ }
+ }
+
+
+ if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) {
+ /* There must be a tag number */
+ if(!bTagNumberMatched && !*bTypeMatched) {
+ return QCBOR_ERR_UNEXPECTED_TYPE; // TODO: error code
+ }
+
+ } else if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) {
+ if(bTagNumberMatched || *bTypeMatched) {
+ return QCBOR_ERR_UNEXPECTED_TYPE; // TODO: error code
+ }
+
+ } else if(nTagReq == QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG) {
+ /* No check necessary */
+ }
+
+ /* Now check if there are extra tags and if there's an error in them */
+ if(!(uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS)) {
+ /* The flag to ignore extra is not set, so keep checking */
+ for(pTNum = uTagNumbers; *pTNum != CBOR_TAG_INVALID64; pTNum++) {
+ uErr = QCBORDecode_Private_Check1TagNumber(pMe, pItem, *pTNum, uOffset);
+ if(uErr != QCBOR_SUCCESS) {
+ return uErr;
+ }
+ }
+ }
+
+ return QCBOR_SUCCESS;
+#else /* ! QCBOR_DISABLE_TAGS */
+ (void)pMe;
+ (void)uOffset;
+ (void)uTagNumbers;
+
+ if(nTagReq != QCBOR_TAG_REQUIREMENT_TAG && bTypeMatched) {
+ return QCBOR_SUCCESS;
+ } else {
+ return QCBOR_ERR_UNEXPECTED_TYPE;
+ }
+
+#endif /* ! QCBOR_DISABLE_TAGS */
+
+}
+
+
+void
+QCBORDecode_Private_ProcessTagItemMulti(QCBORDecodeContext *pMe,
+ QCBORItem *pItem,
+ const uint8_t uTagRequirement,
+ const uint8_t uQCBORTypes[],
+ const uint64_t uTagNumbers[],
+ QCBORTagContentCallBack *pfCB,
+ size_t uOffset)
+{
+ QCBORError uErr;
+ bool bTypeMatched;
+
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return;
+ }
+
+ uErr = QCBORDecode_Private_CheckTagNType(pMe,
+ pItem,
+ uOffset,
+ uQCBORTypes,
+ uTagNumbers,
+ uTagRequirement,
+ &bTypeMatched);
+ if(uErr != QCBOR_SUCCESS) {
+ goto Done;
+ }
+
+ if(!bTypeMatched) {
+ /* Tag content wasn't previously processed, do it now */
+ uErr = (*pfCB)(pMe, NULL, uTagNumbers[0], pItem);
+ if(uErr != QCBOR_SUCCESS) {
+ goto Done;
+ }
+ }
+
+Done:
+ pMe->uLastError = (uint8_t)uErr;
+}
+
+
+/*
+ **/
+void
+QCBORDecode_Private_ProcessTagItem(QCBORDecodeContext *pMe,
+ QCBORItem *pItem,
+ const uint8_t uTagRequirement,
+ const uint8_t uQCBORTypes[],
+ const uint64_t uTagNumber,
+ QCBORTagContentCallBack *pfCB,
+ size_t uOffset)
+{
+ uint64_t auTagNumbers[2];
+
+ auTagNumbers[0] = uTagNumber;
+ auTagNumbers[1] = CBOR_TAG_INVALID64;
+
+ QCBORDecode_Private_ProcessTagItemMulti(pMe,
+ pItem,
+ uTagRequirement,
+ uQCBORTypes,
+ auTagNumbers,
+ pfCB,
+ uOffset);
+}
+
+
+static void
+QCBORDecode_Private_ProcessTagOne(QCBORDecodeContext *pMe,
+ QCBORItem *pItem,
+ const uint8_t uTagRequirement,
+ const uint8_t uQCBORType,
+ const uint64_t uTagNumber,
+ QCBORTagContentCallBack *pfCB,
+ const size_t uOffset)
+{
+ uint8_t auQCBORType[2];
+
+ auQCBORType[0] = uQCBORType;
+ auQCBORType[1] = QCBOR_TYPE_NONE;
+
+ QCBORDecode_Private_ProcessTagItem(pMe,
+ pItem,
+ uTagRequirement,
+ auQCBORType,
+ uTagNumber,
+ pfCB,
+ uOffset);
+}
+
+
+void
+QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe,
+ const uint8_t uTagRequirement,
+ const uint8_t uQCBOR_Type,
+ const uint64_t uTagNumber,
+ UsefulBufC *pStr)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+ QCBORDecode_Private_ProcessTagOne(pMe,
+ &Item,
+ uTagRequirement,
+ uQCBOR_Type,
+ uTagNumber,
+ QCBORDecode_StringsTagCB,
+ uOffset);
+
+ if(pMe->uLastError == QCBOR_SUCCESS) {
+ *pStr = Item.val.string;
+ } else {
+ *pStr = NULLUsefulBufC;
+ }
+}
+
+
+/**
+ * @brief Semi-private to get an string by label to match a tag specification.
+ *
+ * @param[in] pMe The decode context.
+ * @param[in] nLabel Label to search map for.
+ * @param[in] uTagRequirement Whether or not tag number is required.
+ * See @ref QCBOR_TAG_REQUIREMENT_TAG.
+ * @param[in] uQCBOR_Type QCBOR type to search for.
+ * @param[in] uTagNumber Tag number to match.
+ * @param[out] pString The string found.
+ *
+ * This finds the string with the given label in currently open
+ * map. Then checks that its tag number and types matches the tag
+ * specification. If not, an error is set in the decode context.
+ */
+void
+QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe,
+ const int64_t nLabel,
+ const uint8_t uTagRequirement,
+ const uint8_t uQCBOR_Type,
+ const uint64_t uTagNumber,
+ UsefulBufC *pString)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetItemInMapNoCheckN(pMe,
+ nLabel,
+ QCBOR_TYPE_ANY,
+ &Item,
+ &uOffset);
+ QCBORDecode_Private_ProcessTagOne(pMe,
+ &Item,
+ uTagRequirement,
+ uQCBOR_Type,
+ uTagNumber,
+ QCBORDecode_StringsTagCB,
+ uOffset);
+
+ if(pMe->uLastError == QCBOR_SUCCESS) {
+ *pString = Item.val.string;
+ }
+}
+
+
+/**
+ * @brief Semi-private to get an string by label to match a tag specification.
+ *
+ * @param[in] pMe The decode context.
+ * @param[in] szLabel Label to search map for.
+ * @param[in] uTagRequirement Whether or not tag number is required.
+ * See @ref QCBOR_TAG_REQUIREMENT_TAG.
+ * @param[in] uQCBOR_Type QCBOR type to search for.
+ * @param[in] uTagNumber Tag number to match.
+ * @param[out] pString The string found.
+ *
+ * This finds the string with the given label in currently open
+ * map. Then checks that its tag number and types matches the tag
+ * specification. If not, an error is set in the decode context.
+ */
+void
+QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ uint8_t uTagRequirement,
+ uint8_t uQCBOR_Type,
+ uint64_t uTagNumber,
+ UsefulBufC *pString)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe,
+ szLabel,
+ QCBOR_TYPE_ANY,
+ &Item,
+ &uOffset);
+ QCBORDecode_Private_ProcessTagOne(pMe,
+ &Item,
+ uTagRequirement,
+ uQCBOR_Type,
+ uTagNumber,
+ QCBORDecode_StringsTagCB,
+ uOffset);
+
+
+ if(pMe->uLastError == QCBOR_SUCCESS) {
+ *pString = Item.val.string;
+ }
+}
+
+
+
+
+/**
+ * @brief The main work of entering some byte-string wrapped CBOR.
+ *
+ * @param[in] pMe The decode context.
+ * @param[in] pItem The byte string item.
+ * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX
+ * @param[out] pBstr Pointer and length of byte string entered.
+ *
+ * This is called once the byte string item has been decoded to do all
+ * the book keeping work for descending a nesting level into the
+ * nested CBOR.
+ *
+ * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement.
+ */
+static QCBORError
+QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe,
+ const QCBORItem *pItem,
+ const uint8_t uTagRequirement,
+ const size_t uOffset,
+ UsefulBufC *pBstr)
+{
+ bool bTypeMatched;
+ QCBORError uError;
+
+ const uint8_t uTypes[] = {QBCOR_TYPE_WRAPPED_CBOR,
+ QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE,
+ QCBOR_TYPE_NONE};
+ const uint64_t uTagNumbers[] = {CBOR_TAG_CBOR,
+ CBOR_TAG_CBOR_SEQUENCE,
+ CBOR_TAG_INVALID64};
+
+
+ if(pBstr) {
+ *pBstr = NULLUsefulBufC;
+ }
+
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ return pMe->uLastError;
+ }
+
+ if(pItem->uDataAlloc) {
+ return QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING;
+ }
+
+ uError = QCBORDecode_Private_CheckTagNType(pMe,
+ pItem,
+ uOffset,
+ uTypes,//TODO: maybe empty?
+ uTagNumbers,
+ uTagRequirement,
+ &bTypeMatched);
+
+ if(pItem->uDataType != QCBOR_TYPE_BYTE_STRING) {
+ uError = QCBOR_ERR_BAD_TAG_CONTENT; // TODO: error
+ }
+
+
+ if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) {
+ /* Reverse the decrement done by GetNext() for the bstr so the
+ * increment in QCBORDecode_NestLevelAscender() called by
+ * ExitBoundedLevel() will work right.
+ */
+ DecodeNesting_ReverseDecrement(&(pMe->nesting));
+ }
+
+ if(pBstr) {
+ *pBstr = pItem->val.string;
+ }
+
+ /* This saves the current length of the UsefulInputBuf and then
+ * narrows the UsefulInputBuf to start and length of the wrapped
+ * CBOR that is being entered.
+ *
+ * Most of these calls are simple inline accessors so this doesn't
+ * amount to much code.
+ */
+
+ const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
+ /* This check makes the cast of uPreviousLength to uint32_t below safe. */
+ if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) {
+ uError = QCBOR_ERR_INPUT_TOO_LARGE;
+ goto Done;
+ }
+
+ const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf),
+ pItem->val.string.ptr);
+ /* This check makes the cast of uStartOfBstr to uint32_t below safe. */
+ if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) {
+ /* This should never happen because pItem->val.string.ptr should
+ * always be valid since it was just returned.
+ */
+ uError = QCBOR_ERR_INPUT_TOO_LARGE;
+ goto Done;
+ }
+
+ const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len;
+
+ UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr);
+ UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr);
+
+ uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting),
+ (uint32_t)uPreviousLength,
+ (uint32_t)uStartOfBstr);
+Done:
+ return uError;
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pBstr)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+ pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
+ &Item,
+ uTagRequirement,
+ uOffset,
+ pBstr);
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe,
+ const int64_t nLabel,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pBstr)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetItemInMapNoCheckN(pMe,
+ nLabel,
+ QCBOR_TYPE_BYTE_STRING,
+ &Item,
+ &uOffset);
+ pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
+ &Item,
+ uTagRequirement,
+ uOffset,
+ pBstr);
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pBstr)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe,
+ szLabel,
+ QCBOR_TYPE_BYTE_STRING,
+ &Item,
+ &uOffset);
+ pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe,
+ &Item,
+ uTagRequirement,
+ uOffset,
+ pBstr);
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe)
+{
+ if(pMe->uLastError != QCBOR_SUCCESS) {
+ // Already in error state; do nothing.
+ return;
+ }
+
+ if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) {
+ pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH;
+ return;
+ }
+
+ const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf));
+
+ /*
+ Reset the length of the UsefulInputBuf to what it was before
+ the bstr wrapped CBOR was entered.
+ */
+ UsefulInputBuf_SetBufferLength(&(pMe->InBuf),
+ DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting)));
+
+
+ QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr);
+ pMe->uLastError = (uint8_t)uErr;
+}
+
+
+
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe,
+ uint8_t uTagRequirement,
+ int64_t *pnTime)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+ QCBORDecode_Private_ProcessTagOne(pMe,
+ &Item,
+ uTagRequirement,
+ QCBOR_TYPE_DATE_EPOCH,
+ CBOR_TAG_DATE_EPOCH,
+ QCBORDecode_DateEpochTagCB,
+ uOffset);
+ *pnTime = Item.val.epochDate.nSeconds;
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe,
+ int64_t nLabel,
+ uint8_t uTagRequirement,
+ int64_t *pnTime)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetItemInMapNoCheckN(pMe,
+ nLabel,
+ QCBOR_TYPE_ANY,
+ &Item,
+ &uOffset);
+ QCBORDecode_Private_ProcessTagOne(pMe,
+ &Item,
+ uTagRequirement,
+ QCBOR_TYPE_DATE_EPOCH,
+ CBOR_TAG_DATE_EPOCH,
+ QCBORDecode_DateEpochTagCB,
+ uOffset);
+ *pnTime = Item.val.epochDate.nSeconds;
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ uint8_t uTagRequirement,
+ int64_t *pnTime)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe,
+ szLabel,
+ QCBOR_TYPE_ANY,
+ &Item,
+ &uOffset);
+ QCBORDecode_Private_ProcessTagOne(pMe,
+ &Item,
+ uTagRequirement,
+ QCBOR_TYPE_DATE_EPOCH,
+ CBOR_TAG_DATE_EPOCH,
+ QCBORDecode_DateEpochTagCB,
+ uOffset);
+ *pnTime = Item.val.epochDate.nSeconds;
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe,
+ uint8_t uTagRequirement,
+ int64_t *pnDays)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+ QCBORDecode_Private_ProcessTagOne(pMe,
+ &Item,
+ uTagRequirement,
+ QCBOR_TYPE_DAYS_EPOCH,
+ CBOR_TAG_DAYS_EPOCH,
+ QCBORDecode_DaysEpochTagCB,
+ uOffset);
+ *pnDays = Item.val.epochDays;
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe,
+ int64_t nLabel,
+ uint8_t uTagRequirement,
+ int64_t *pnDays)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetItemInMapNoCheckN(pMe,
+ nLabel,
+ QCBOR_TYPE_ANY,
+ &Item,
+ &uOffset);
+ QCBORDecode_Private_ProcessTagOne(pMe,
+ &Item,
+ uTagRequirement,
+ QCBOR_TYPE_DAYS_EPOCH,
+ CBOR_TAG_DAYS_EPOCH,
+ QCBORDecode_DaysEpochTagCB,
+ uOffset);
+ *pnDays = Item.val.epochDays;
+}
+
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ uint8_t uTagRequirement,
+ int64_t *pnDays)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe,
+ szLabel,
+ QCBOR_TYPE_ANY,
+ &Item,
+ &uOffset);
+ QCBORDecode_Private_ProcessTagOne(pMe,
+ &Item,
+ uTagRequirement,
+ QCBOR_TYPE_DAYS_EPOCH,
+ CBOR_TAG_DAYS_EPOCH,
+ QCBORDecode_DaysEpochTagCB,
+ uOffset);
+ *pnDays = Item.val.epochDays;
+}
+
+
+
+
+static void
+QCBORDecode_Private_GetMIME(QCBORDecodeContext *pMe,
+ const uint8_t uTagRequirement,
+ QCBORItem *pItem,
+ UsefulBufC *pValue,
+ bool *pbIsTag257,
+ size_t uOffset)
+{
+ QCBORError uErr;
+
+ const uint8_t puTypes[] = {QCBOR_TYPE_MIME, QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE};
+
+ const uint64_t puTNs[] = {CBOR_TAG_MIME, CBOR_TAG_BINARY_MIME, CBOR_TAG_INVALID64};
+
+ QCBORDecode_Private_ProcessTagItemMulti(pMe,
+ pItem,
+ uTagRequirement,
+ puTypes,
+ puTNs,
+ QCBORDecode_MIMETagCB,
+ uOffset);
+ if(pMe->uLastError) {
+ return;
+ }
+
+ if(pItem->uDataType == QCBOR_TYPE_MIME) {
+ *pbIsTag257 = false;
+ } else if(pItem->uDataType == QCBOR_TYPE_BINARY_MIME) {
+ *pbIsTag257 = true;
+ }
+ *pValue = pItem->val.string;
+
+
+ uErr = QCBOR_SUCCESS;
+
+ pMe->uLastError = (uint8_t)uErr;
+}
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pMe,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pMessage,
+ bool *pbIsTag257)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
+ QCBORDecode_Private_GetMIME(pMe,
+ uTagRequirement,
+ &Item,
+ pMessage,
+ pbIsTag257,
+ uOffset);
+}
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pMe,
+ const int64_t nLabel,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pMessage,
+ bool *pbIsTag257)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetItemInMapNoCheckN(pMe,
+ nLabel,
+ QCBOR_TYPE_ANY,
+ &Item,
+ &uOffset);
+ QCBORDecode_Private_GetMIME(pMe,
+ uTagRequirement,
+ &Item,
+ pMessage,
+ pbIsTag257,
+ uOffset);
+}
+
+/* Public function; see qcbor_tag_decode.h */
+void
+QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pMe,
+ const char *szLabel,
+ const uint8_t uTagRequirement,
+ UsefulBufC *pMessage,
+ bool *pbIsTag257)
+{
+ QCBORItem Item;
+ size_t uOffset;
+
+ QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe,
+ szLabel,
+ QCBOR_TYPE_ANY,
+ &Item,
+ &uOffset);
+ QCBORDecode_Private_GetMIME(pMe,
+ uTagRequirement,
+ &Item,
+ pMessage,
+ pbIsTag257,
+ uOffset);
+}
+
+
+
+
/* Public function; see qcbor_tag_decode.h */
QCBORError
QCBORDecode_DateEpochTagCB(QCBORDecodeContext *pDecodeCtx,
@@ -166,7 +1182,8 @@
* @ref CBOR_TAG_BIG_FLOAT.
* @param[in] pDecodedItem Item being decoded.
*
- * @returns One of the ten values related to @ref QCBOR_TYPE_DECIMAL_FRACTION and @ref QCBOR_TYPE_BIGFLOAT
+ * @returns One of the ten values related to @ref QCBOR_TYPE_DECIMAL_FRACTION
+ * and @ref QCBOR_TYPE_BIGFLOAT
*
* Does mapping between a CBOR tag number and a QCBOR type with a
* little logic and arithmetic.