Allow partial decode of CBOR sequences (#77)
Add QCBORDecode_PartialFinish() to get the offset to which decoding has progressed. Also reports error status of partial decoding.
Co-authored-by: Laurence Lundblade <lgl@securitytheory.com>
diff --git a/inc/qcbor/qcbor_decode.h b/inc/qcbor/qcbor_decode.h
index ad8c354..63e94cb 100644
--- a/inc/qcbor/qcbor_decode.h
+++ b/inc/qcbor/qcbor_decode.h
@@ -902,6 +902,7 @@
QCBORDecode_PeekNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem);
+
/**
@brief Gets the next item including full list of tags for item.
@@ -1046,10 +1047,39 @@
input was well-formed and there are extra bytes at the end @ref
QCBOR_ERR_EXTRA_BYTES will be returned. This can be considered a
successful decode.
+
+ See also QCBORDecode_PartialFinish().
*/
QCBORError QCBORDecode_Finish(QCBORDecodeContext *pCtx);
+/**
+ @brief Return number of bytes consumed so far.
+
+ @param[in] pCtx The context to check.
+ @param[out] puConsumed The number of bytes consumed so far. May be @c NULL.
+
+ @returns The same as QCBORDecode_Finish();
+
+ This is primarily for partially decoding CBOR sequences. It is the
+ same as QCBORDecode_Finish() except it returns the number of bytes
+ consumed and doesn't call the destructor for the string allocator
+ (See @ref and QCBORDecode_SetMemPool()).
+
+ When this is called before all input bytes are consumed, @ref
+ QCBOR_ERR_EXTRA_BYTES will be returned as QCBORDecode_Finish()
+ does. For typical use of this, that particular error is disregarded.
+
+ Decoding with the same @ref QCBORDecodeContext can continue after
+ calling this and this may be called many times.
+
+ Another way to resume decoding is to call QCBORDecode_Init() on the
+ bytes not decoded, but this only works on CBOR sequences when the
+ decoding stopped with no open arrays, maps or byte strings.
+ */
+QCBORError
+QCBORDecode_PartialFinish(QCBORDecodeContext *pCtx, size_t *puConsumed);
+
/**
@brief Get the decoding error.
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 8989211..b46908d 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -2391,8 +2391,12 @@
/*
* Public function, see header qcbor/qcbor_decode.h file
*/
-QCBORError QCBORDecode_Finish(QCBORDecodeContext *pMe)
+QCBORError QCBORDecode_PartialFinish(QCBORDecodeContext *pMe, size_t *puConsumed)
{
+ if(puConsumed != NULL) {
+ *puConsumed = pMe->InBuf.cursor;
+ }
+
QCBORError uReturn = pMe->uLastError;
if(uReturn != QCBOR_SUCCESS) {
@@ -2411,6 +2415,15 @@
}
Done:
+ return uReturn;
+}
+
+
+/*
+ * Public function, see header qcbor/qcbor_decode.h file
+ */
+QCBORError QCBORDecode_Finish(QCBORDecodeContext *pMe)
+{
#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS
/* Call the destructor for the string allocator if there is one.
* Always called, even if there are errors; always have to clean up.
@@ -2418,7 +2431,7 @@
StringAllocator_Destruct(&(pMe->StringAllocator));
#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS */
- return uReturn;
+ return QCBORDecode_PartialFinish(pMe, NULL);
}
diff --git a/test/qcbor_decode_tests.c b/test/qcbor_decode_tests.c
index a7ef065..567f654 100644
--- a/test/qcbor_decode_tests.c
+++ b/test/qcbor_decode_tests.c
@@ -6138,8 +6138,9 @@
int32_t CBORSequenceDecodeTests(void)
{
QCBORDecodeContext DCtx;
- QCBORItem Item;
- QCBORError uCBORError;
+ QCBORItem Item;
+ QCBORError uCBORError;
+ size_t uConsumed;
// --- Test a sequence with extra bytes ---
@@ -6159,12 +6160,24 @@
return 2;
}
+ uCBORError = QCBORDecode_PartialFinish(&DCtx, &uConsumed);
+ if(uCBORError != QCBOR_ERR_EXTRA_BYTES ||
+ uConsumed != 12) {
+ return 102;
+ }
+
// Get a second item
uCBORError = QCBORDecode_GetNext(&DCtx, &Item);
if(uCBORError != QCBOR_ERR_BAD_OPT_TAG) {
return 66;
}
+ uCBORError = QCBORDecode_PartialFinish(&DCtx, &uConsumed);
+ if(uCBORError != QCBOR_ERR_EXTRA_BYTES ||
+ uConsumed != 14) {
+ return 102;
+ }
+
// Get a third item
uCBORError = QCBORDecode_GetNext(&DCtx, &Item);
if(uCBORError != QCBOR_SUCCESS) {