all the indefinite stuff seems to be working; needs lots more testing
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 4679ec0..7189c20 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -635,8 +635,8 @@
/*
- This layer deals with indefinite length strings
-
+ This layer deals with indefinite length strings. It pulls all the
+ individual segment items together into one QCBORItem
*/
static int GetNext_FullItem(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
{
@@ -654,26 +654,25 @@
// To reduce code size by removing support for indefinite length strings, the
// code in this function from here down can be eliminated. Run tests to be sure
// all is OK if you remove this.
- if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
- nReturn = QCBOR_ERR_BAD_BREAK;
- goto Done;
- }
+ // Only do indefinite length processing on strings
if(pDecodedItem->uDataType != QCBOR_TYPE_BYTE_STRING && pDecodedItem->uDataType != QCBOR_TYPE_TEXT_STRING) {
goto Done; // no need to do any work here on non-string types
}
+ // Is this a string with an indefinite length?
if(pDecodedItem->val.string.len != SIZE_MAX) { // TODO: is this right? Is there a better way to mark this?
- goto Done; // length is not indefinite, so no work to do
+ goto Done; // length is not indefinite, so no work to do here
}
+ // can't do indefinite length strings without a string allocator
if(pAlloc == NULL) {
- // can't do indefinite length strings without an allocator
nReturn = QCBOR_ERR_NO_STRING_ALLOCATOR;
goto Done;
}
// There is an indefinite length string to work on...
+ // Track which type of string it is
const uint8_t uStringType = pDecodedItem->uDataType;
// Loop getting segments of indefinite string
@@ -688,7 +687,7 @@
// See if it is marker at end of indefinite length string
if(Item.uDataType == QCBOR_TYPE_BREAK) {
- // SUCCESS!!!
+ // String is complete
pDecodedItem->val.string = FullString;
pDecodedItem->uAllocated = 1;
break;
@@ -819,7 +818,7 @@
/*
- This layer takes care of map entries. It combines the label and data items into one item.
+ This layer takes care of map entries. It combines the label and data items into one QCBORItem.
*/
static inline int GetNext_MapEntry(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
{
@@ -867,6 +866,32 @@
}
+/* Loops processing breaks until a non-break is encountered
+ or an error is encountered
+ */
+static int LoopOverBreaks(QCBORDecodeContext *me, QCBORItem *pDecodedItem)
+{
+ int nReturn = QCBOR_SUCCESS;
+
+ do {
+ nReturn = GetNext_MapEntry(me, pDecodedItem);
+ if(nReturn) {
+ goto Done;
+ }
+
+ if(pDecodedItem->uDataType != QCBOR_TYPE_BREAK) {
+ break;
+ }
+
+ nReturn = DecodeNesting_BreakAscend(&(me->nesting));
+ if(nReturn) {
+ goto Done;
+ }
+ } while (DecodeNesting_IsNested(&(me->nesting)));
+Done:
+ return nReturn;
+}
+
/*
Public function, see header qcbor.h file
*/
@@ -887,22 +912,9 @@
int nReturn;
// Loop getting items until one that is not a break is fetched
- for(;;) {
- nReturn = GetNext_MapEntry(me, pDecodedItem);
- if(nReturn) {
- goto Done;
- }
-
- if(pDecodedItem->uDataType != QCBOR_TYPE_BREAK) {
- break;
- }
-
- // Item is a break. That means we have to try to reduce
- // nesting level.
- nReturn = DecodeNesting_BreakAscend(&(me->nesting));
- if(nReturn) {
- goto Done;
- }
+ nReturn = LoopOverBreaks(me, pDecodedItem);
+ if(nReturn) {
+ goto Done;
}
// Now have the next item that is not a break, the one that is going to be returned
@@ -932,27 +944,31 @@
{
int nReturn = QCBOR_SUCCESS;
- // Consume any breaks ending indefinite length arrays or maps here
+ // Consume any last breaks ending indefinite length arrays or maps here
// Definite length arrays and maps get closed off above when they
// the last item in them is consumed; they are not handled here.
- // TODO: put in a function and make common with above similar code
- while(DecodeNesting_GetLevel(&(me->nesting))) {
+ if(DecodeNesting_IsNested(&(me->nesting))) {
QCBORItem Item;
- int nReturn = GetNext_Item(&(me->InBuf), &Item, NULL);
+ nReturn = LoopOverBreaks(me, &Item);
if(nReturn) {
- break;
- }
- if(Item.uDataType != QCBOR_TYPE_BREAK) {
- nReturn = QCBOR_ERR_EXTRA_BYTES;
- break;
- }
- nReturn = DecodeNesting_BreakAscend(&(me->nesting));
- if(nReturn) {
- break;
+ goto Done;
}
}
- // Call the desctructor for the string allocator if there is one
+ // Error out if all the maps/arrays are not closed out
+ if(DecodeNesting_IsNested(&(me->nesting))) {
+ nReturn = QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN;
+ goto Done;
+ }
+
+ // Error out if not all the bytes are consumed
+ if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) {
+ nReturn = QCBOR_ERR_EXTRA_BYTES;
+ }
+
+Done:
+ // Call the destructor for the string allocator if there is one
+ // Always called, even if there are errors; always have to clean up
if(me->pStringAllocator) {
QCBORStringAllocator *pAllocator = (QCBORStringAllocator *)me->pStringAllocator;
if(pAllocator->fDestructor) {
@@ -960,10 +976,6 @@
}
}
- if(UsefulInputBuf_BytesUnconsumed(&(me->InBuf))) {
- nReturn = QCBOR_ERR_EXTRA_BYTES;
- }
-
return nReturn;
}