Add SetError(); VGetNext error bug fix
diff --git a/inc/qcbor/qcbor_common.h b/inc/qcbor/qcbor_common.h
index 0575fd5..e27de4d 100644
--- a/inc/qcbor/qcbor_common.h
+++ b/inc/qcbor/qcbor_common.h
@@ -521,7 +521,14 @@
* whole tag contents when it is not the correct tag content, this
* error can be returned. None of the built-in tag decoders do this
* (to save object code). */
- QCBOR_ERR_RECOVERABLE_BAD_TAG_CONTENT = 78
+ QCBOR_ERR_RECOVERABLE_BAD_TAG_CONTENT = 78,
+
+ /** A range of error codes that can be made use of by
+ * the caller. QCBOR internally does nothing with these
+ * except notice that they are not QCBOR_SUCCESS. See
+ * QCBORDecode_SetError(). */
+ QCBOR_ERR_FIRST_USER = 128,
+ QCBOR_ERR_LAST_USER = 255
/* This is stored in uint8_t; never add values > 255 */
} QCBORError;
diff --git a/inc/qcbor/qcbor_decode.h b/inc/qcbor/qcbor_decode.h
index 568739d..6cbb0ca 100644
--- a/inc/qcbor/qcbor_decode.h
+++ b/inc/qcbor/qcbor_decode.h
@@ -892,7 +892,7 @@
*
* See [Decode Error Overview](#Decode-Errors-Overview).
*
- * If a decoding error occurs, \c uDataType and \c uLabelType will be set
+ * If a decoding error occurs or previously occured, \c uDataType and \c uLabelType will be set
* to @ref QCBOR_TYPE_NONE. If there is no need to know the specific
* error, it is sufficient to check for @ref QCBOR_TYPE_NONE.
*
@@ -1204,7 +1204,7 @@
/**
* @brief Whether an error indicates non-well-formed CBOR.
*
- * @param[in] uErr The decoder context.
+ * @param[in] uErr The QCBOR error code.
* @return @c true if the error code indicates non-well-formed CBOR.
*/
static bool
@@ -1214,7 +1214,7 @@
/**
* @brief Whether a decoding error is recoverable.
*
- * @param[in] uErr The decoder context.
+ * @param[in] uErr The QCBOR error code.
* @return @c true if the error code indicates and uncrecoverable error.
*
* When an error is unrecoverable, no further decoding of the input is
@@ -1234,6 +1234,29 @@
QCBORDecode_IsUnrecoverableError(QCBORError uErr);
+/**
+ * @brief Manually set error condition, or set user-defined error.
+ *
+ * @param[in] pCtx The decoder context.
+ * @param[in] uError The error code to set.
+ *
+ * Once set, none of the QCBORDecode methods will do anything and
+ * the error code set will stay until cleared with
+ * QCBORDecode_GetAndResetError().
+ * The error can be set deep in some decoding layers to propagate
+ * an error up.
+ *
+ * When the error condition is set, QCBORDecode_VGetNext() will always return
+ * an item with data and label type \ref QCBOR_TYPE_NONE. It is safe
+ * to count on this behavior.
+ *
+ * The main intent of this is to set a user-defined error
+ * code in the range of \ref QCBOR_ERR_FIRST_USER to \ref QCBOR_ERR_LAST_USER, but it is OK to set
+ * QCBOR-defined error codes too.
+ */
+static void
+QCBORDecode_SetError(QCBORDecodeContext *pCtx, QCBORError uError);
+
/**
@@ -1522,6 +1545,14 @@
}
}
+
+static inline void
+QCBORDecode_SetError(QCBORDecodeContext *pMe, QCBORError uError)
+{
+ pMe->uLastError = (uint8_t)uError;
+}
+
+
/* A few cross checks on size constants and special value lengths */
#if QCBOR_MAP_OFFSET_CACHE_INVALID < QCBOR_MAX_DECODE_INPUT_SIZE
#error QCBOR_MAP_OFFSET_CACHE_INVALID is too large
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 72a81c6..2188211 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -2660,6 +2660,8 @@
QCBORDecode_VPeekNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
{
if(pMe->uLastError != QCBOR_SUCCESS) {
+ pDecodedItem->uDataType = QCBOR_TYPE_NONE;
+ pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
return;
}
@@ -2674,6 +2676,8 @@
QCBORDecode_VGetNext(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem)
{
if(pMe->uLastError != QCBOR_SUCCESS) {
+ pDecodedItem->uDataType = QCBOR_TYPE_NONE;
+ pDecodedItem->uLabelType = QCBOR_TYPE_NONE;
return;
}
diff --git a/test/qcbor_decode_tests.c b/test/qcbor_decode_tests.c
index 77514de..169ec4b 100644
--- a/test/qcbor_decode_tests.c
+++ b/test/qcbor_decode_tests.c
@@ -8829,3 +8829,87 @@
return 0;
}
+
+
+int32_t
+ErrorHandlingTests(void)
+{
+ QCBORDecodeContext DCtx;
+ QCBORItem Item;
+ QCBORError uError;
+ int64_t integer;
+
+ /* Test QCBORDecode_SetError() */
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded),
+ QCBOR_DECODE_MODE_NORMAL);
+
+ QCBORDecode_SetError(&DCtx, QCBOR_ERR_FIRST_USER);
+
+ QCBORDecode_VGetNext(&DCtx, &Item);
+
+ uError = QCBORDecode_GetError(&DCtx);
+
+ if(uError != QCBOR_ERR_FIRST_USER) {
+ return -1;
+ }
+
+ if(Item.uLabelType != QCBOR_TYPE_NONE ||
+ Item.uDataType != QCBOR_TYPE_NONE) {
+ return -2;
+ }
+
+
+ /* Test data type returned from previous error */
+ QCBORDecode_Init(&DCtx,
+ UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded),
+ QCBOR_DECODE_MODE_NORMAL);
+ QCBORDecode_GetInt64(&DCtx, &integer);
+ uError = QCBORDecode_GetError(&DCtx);
+ if(uError != QCBOR_ERR_UNEXPECTED_TYPE) {
+ return -3;
+ }
+
+
+ QCBORDecode_VGetNext(&DCtx, &Item);
+ if(Item.uLabelType != QCBOR_TYPE_NONE ||
+ Item.uDataType != QCBOR_TYPE_NONE) {
+ return -2;
+ }
+ uError = QCBORDecode_GetError(&DCtx);
+ if(uError != QCBOR_ERR_UNEXPECTED_TYPE) {
+ return -3;
+ }
+
+
+
+ if(!QCBORDecode_IsUnrecoverableError(QCBOR_ERR_INDEFINITE_STRING_CHUNK)) {
+ return -10;
+ }
+ if(QCBORDecode_IsUnrecoverableError(QCBOR_SUCCESS)) {
+ return -11;
+ }
+ if(!QCBORDecode_IsUnrecoverableError(QCBOR_ERR_INDEFINITE_STRING_CHUNK)) {
+ return -12;
+ }
+ if(QCBORDecode_IsUnrecoverableError(QCBOR_ERR_DUPLICATE_LABEL)) {
+ return -13;
+ }
+
+ if(!QCBORDecode_IsNotWellFormedError(QCBOR_ERR_BAD_TYPE_7)) {
+ return -20;
+ }
+ if(!QCBORDecode_IsNotWellFormedError(QCBOR_ERR_BAD_BREAK)) {
+ return -21;
+ }
+ if(QCBORDecode_IsNotWellFormedError(QCBOR_SUCCESS)) {
+ return -22;
+ }
+ if(QCBORDecode_IsNotWellFormedError(QCBOR_ERR_ARRAY_DECODE_TOO_LONG)) {
+ return -23;
+ }
+
+
+
+ return 0;
+}
diff --git a/test/qcbor_decode_tests.h b/test/qcbor_decode_tests.h
index 11fdc94..0cedf43 100644
--- a/test/qcbor_decode_tests.h
+++ b/test/qcbor_decode_tests.h
@@ -318,4 +318,9 @@
*/
int32_t CBORTestIssue134(void);
+
+
+int32_t ErrorHandlingTests(void);
+
+
#endif /* defined(__QCBOR__qcbort_decode_tests__) */
diff --git a/test/run_tests.c b/test/run_tests.c
index 9e747a6..988fd36 100644
--- a/test/run_tests.c
+++ b/test/run_tests.c
@@ -66,7 +66,8 @@
static test_entry s_tests[] = {
- TEST_ENTRY(OpenCloseBytesTest),
+ TEST_ENTRY(ErrorHandlingTests),
+ TEST_ENTRY(OpenCloseBytesTest),
TEST_ENTRY(EnterBstrTest),
TEST_ENTRY(IntegerConvertTest),
TEST_ENTRY(EnterMapTest),