Getting started on indefinite lengths
diff --git a/cmd_line_main.c b/cmd_line_main.c
index 309b98b..cf6f1af 100644
--- a/cmd_line_main.c
+++ b/cmd_line_main.c
@@ -31,6 +31,10 @@
#include "basic_test.h"
int main(int argc, const char * argv[]) {
+ indefinite_length_decode_test();
+
+
+
printf("Test Result %d\n", basic_test_one());
diff --git a/inc/qcbor.h b/inc/qcbor.h
index b555873..48275af 100644
--- a/inc/qcbor.h
+++ b/inc/qcbor.h
@@ -183,6 +183,12 @@
uint8_t uDecodeMode;
QCBORDecodeNesting nesting;
+
+ // This is NULL or points to a QCBORStringAllocator. It is void
+ // here because _QCBORDecodeContext is defined early n the
+ // private part of this file and QCBORStringAllocat is defined
+ // later in the public part of this file.
+ void *pStringAllocator;
};
@@ -627,9 +633,10 @@
/** Type for the simple value undef; nothing more; nothing in val union. */
#define QCBOR_TYPE_UNDEF 23
+#define QCBOR_TYPE_BREAK 31 // Used internally; never returned
#define QCBOR_TYPE_OPTTAG 254 // Used internally; never returned
-#define QCBOR_TYPE_BREAK 255 // Used internally; never returned
+//#define QCBOR_TYPE_BREAK 255 // Used internally; never returned
@@ -679,6 +686,18 @@
} QCBORItem;
+/*
+ Optional to set up an allocator for bstr and tstr types.
+ Required to process indefinite length bstr and tstr types.
+ (indefinite length maps can be processed without this).
+ */
+typedef struct {
+ void *pAllocaterContext;
+ void * (*AllocatorFunction)(void *pMem, size_t uNewSize);
+ bool bAlwaysAlloc;
+} QCBORStringAllocator;
+
+
/** See the descriptions for CBOR_SIMPLEV_FALSE, CBOR_TAG_DATE_EPOCH... for
the meaning of the individual tags. The values here are bit flags
associated with each tag. These flags are set in uTagsBits in QCBORItem */
@@ -1436,6 +1455,13 @@
void QCBORDecode_Init(QCBORDecodeContext *pCtx, UsefulBufC EncodedCBOR, int8_t nMode);
+/*
+
+ */
+void QCBOR_Decode_SetUpAllocator(QCBORDecodeContext *pCtx, const QCBORStringAllocator *pAllocator);
+
+
+
/**
Gets the next item (integer, byte string, array...) in pre order traversal of CBOR tree
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 1d6fd58..68fe20a 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -92,26 +92,44 @@
return pNesting->pCurrent != &(pNesting->pMapsAndArrays[0]);
}
+inline static int IsIndefiniteLength(const QCBORDecodeNesting *pNesting)
+{
+ if(!DecodeNesting_IsNested(pNesting)) {
+ return 0;
+ }
+
+ return pNesting->pCurrent->uCount == UINT16_MAX;
+}
+
inline static int DecodeNesting_TypeIsMap(const QCBORDecodeNesting *pNesting)
{
- if(!DecodeNesting_IsNested(pNesting))
+ if(!DecodeNesting_IsNested(pNesting)) {
return 0;
+ }
return CBOR_MAJOR_TYPE_MAP == pNesting->pCurrent->uMajorType;
}
-inline static void DecodeNesting_Decrement(QCBORDecodeNesting *pNesting, uint8_t uDataType)
+inline static void DecodeNesting_Decrement(QCBORDecodeNesting *pNesting)
{
if(!DecodeNesting_IsNested(pNesting)) {
return; // at top level where there is no tracking
}
- // Decrement
- pNesting->pCurrent->uCount--;
-
- // Pop up nesting levels if the counts at the levels is zero
- while(0 == pNesting->pCurrent->uCount && DecodeNesting_IsNested(pNesting)) {
+ if(IsIndefiniteLength(pNesting)) {
+ // Decrement only gets called once. Only at the end of the array/map
+ // when the break is encountered. There is no tracking of the number
+ // of items in the array/map.
pNesting->pCurrent--;
+
+ } else {
+ // Decrement
+ pNesting->pCurrent->uCount--;
+
+ // Pop up nesting levels if the counts at the levels is zero
+ while(0 == pNesting->pCurrent->uCount && DecodeNesting_IsNested(pNesting)) {
+ pNesting->pCurrent--;
+ }
}
}
@@ -166,6 +184,15 @@
/*
+ Public function, see header file
+ */
+void QCBOR_Decode_SetUpAllocator(QCBORDecodeContext *pCtx, const QCBORStringAllocator *pAllocator)
+{
+ pCtx->pStringAllocator = (void *)pAllocator;
+}
+
+
+/*
This decodes the fundamental part of a CBOR data item, the type and number
This is the Counterpart to InsertEncodedTypeAndNumber().
@@ -211,10 +238,11 @@
case ADDINFO_RESERVED1: // reserved by CBOR spec
case ADDINFO_RESERVED2: // reserved by CBOR spec
case ADDINFO_RESERVED3: // reserved by CBOR spec
- case LEN_IS_INDEFINITE: // indefinite types not supported (yet)
nReturn = QCBOR_ERR_UNSUPPORTED;
goto Done;
-
+
+ case LEN_IS_INDEFINITE:
+ // Fall through OK to see what happens: TODO: check this.
default:
uTmpValue = uAdditionalInfo;
break;
@@ -299,6 +327,10 @@
#error QCBOR_TYPE_UNDEF macro value wrong
#endif
+#if QCBOR_TYPE_BREAK != CBOR_SIMPLE_BREAK
+#error QCBOR_TYPE_BREAK macro value wrong
+#endif
+
#if QCBOR_TYPE_DOUBLE != DOUBLE_PREC_FLOAT
#error QCBOR_TYPE_DOUBLE macro value wrong
#endif
@@ -323,7 +355,6 @@
case ADDINFO_RESERVED1: // 28
case ADDINFO_RESERVED2: // 29
case ADDINFO_RESERVED3: // 30
- case CBOR_SIMPLE_BREAK: // 31
nReturn = QCBOR_ERR_UNSUPPORTED;
break;
@@ -331,6 +362,7 @@
case CBOR_SIMPLEV_TRUE: // 21
case CBOR_SIMPLEV_NULL: // 22
case CBOR_SIMPLEV_UNDEF: // 23
+ case CBOR_SIMPLE_BREAK: // 31
break; // nothing to do
case CBOR_SIMPLEV_ONEBYTE: // 24
@@ -591,7 +623,11 @@
nReturn = QCBOR_ERR_ARRAY_TOO_LONG;
goto Done;
}
- pDecodedItem->val.uCount = uNumber; // type conversion OK because of check above
+ if(uAdditionalInfo == LEN_IS_INDEFINITE) {
+ pDecodedItem->val.uCount = UINT16_MAX;
+ } else {
+ pDecodedItem->val.uCount = (uint16_t)uNumber; // type conversion OK because of check above
+ }
pDecodedItem->uDataType = uMajorType; // C preproc #if above makes sure constants align
break;
@@ -678,9 +714,19 @@
if(IsMapOrArray(pDecodedItem->uDataType) && pDecodedItem->val.uCount) {
nReturn = DecodeNesting_Descend(&(me->nesting), pDecodedItem->uDataType, pDecodedItem->val.uCount);
} else {
- // Track number of items in maps and arrays and ascend nesting if all are consumed
- // Note that an empty array or map is like a integer or string in effect here
- DecodeNesting_Decrement(&(me->nesting), pDecodedItem->uDataType);
+ if(!IsIndefiniteLength(&(me->nesting))) {
+ // Is a definite length array or map
+ // Track number of items in maps and arrays and ascend nesting if all are consumed
+ // Note that an empty array or map is like a integer or string in effect here
+ DecodeNesting_Decrement(&(me->nesting));
+ } else {
+ // Is an indefinite length array or map
+ if(pDecodedItem->uDataType == QCBOR_TYPE_BREAK) {
+ // Only decrement when the end is encountered.
+ DecodeNesting_Decrement(&(me->nesting));
+ // TODO: get another item here....
+ }
+ }
}
Done:
diff --git a/test/basic_test.c b/test/basic_test.c
index 1f179ed..ac55a67 100644
--- a/test/basic_test.c
+++ b/test/basic_test.c
@@ -137,3 +137,60 @@
return 0;
}
+
+
+static const uint8_t pIndefiniteLenString[] = {0x7f, 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x67, 0xff};
+
+static const uint8_t pIndefiniteArray[] = {0x9f, 0x01, 0x82, 0x02, 0x03, 0xff};
+
+//0x9f018202039f0405ffff
+
+int indefinite_length_decode_test() {
+ UsefulBufC IndefLen = UsefulBuf_FromByteArrayLiteral(pIndefiniteArray);
+
+
+ // Decode it and see if it is OK
+ QCBORDecodeContext DC;
+ QCBORItem Item;
+ QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL);
+
+ QCBORDecode_GetNext(&DC, &Item);
+ if(Item.uDataType != QCBOR_TYPE_ARRAY) {
+ return -1;
+ }
+
+ QCBORDecode_GetNext(&DC, &Item);
+ if(Item.uDataType != QCBOR_TYPE_INT64) {
+ return -1;
+ }
+
+ QCBORDecode_GetNext(&DC, &Item);
+ if(Item.uDataType != QCBOR_TYPE_ARRAY) {
+ return -1;
+ }
+
+ QCBORDecode_GetNext(&DC, &Item);
+ if(Item.uDataType != QCBOR_TYPE_INT64) {
+ return -1;
+ }
+
+ QCBORDecode_GetNext(&DC, &Item);
+ if(Item.uDataType != QCBOR_TYPE_INT64) {
+ return -1;
+ }
+
+ QCBORDecode_GetNext(&DC, &Item);
+ if(Item.uDataType != QCBOR_TYPE_INT64) {
+ return -1;
+ }
+
+
+ return 0;
+}
+
+
+
+
+
+
+
diff --git a/test/basic_test.h b/test/basic_test.h
index da5849f..2a91c14 100644
--- a/test/basic_test.h
+++ b/test/basic_test.h
@@ -31,4 +31,6 @@
int basic_test_one(void);
+int indefinite_length_decode_test(void);
+
#endif /* basic_test_h */