Add indefinite length encoding for maps and arrays
diff --git a/inc/qcbor.h b/inc/qcbor.h
index 2df3eba..f7f0e5b 100644
--- a/inc/qcbor.h
+++ b/inc/qcbor.h
@@ -43,6 +43,7 @@
when who what, where, why
-------- ---- ---------------------------------------------------
+ 7/25/19 janjongboom Add indefinite length encoding for maps and arrays
05/26/19 llundblade Add QCBOREncode_GetErrorState() and _IsBufferNULL().
04/26/19 llundblade Big documentation & style update. No interface change.
02/16/19 llundblade Redesign MemPool to fix memory access alignment bug.
@@ -607,7 +608,6 @@
@ref QCBOR_MAX_ARRAY_NESTING (this is typically 15).
- Max items in an array or map when encoding / decoding is
@ref QCBOR_MAX_ITEMS_IN_ARRAY (typically 65,536).
- - Does not support encoding indefinite lengths (decoding is supported).
- Does not directly support some tagged types: decimal fractions, big floats
- Does not directly support labels in maps other than text strings and integers.
- Does not directly support integer labels greater than @c INT64_MAX.
@@ -2467,6 +2467,18 @@
/**
+ @brief Semi-private method to open a map, array or bstr wrapped CBOR with indefinite length
+
+ @param[in] pCtx The context to add to.
+ @param[in] uMajorType The major CBOR type to close
+
+ Call QCBOREncode_OpenArrayIndefiniteLength() or QCBOREncode_OpenMapIndefiniteLength()
+ instead of this.
+ */
+void QCBOREncode_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx, uint8_t uMajorType);
+
+
+/**
@brief Semi-private method to close a map, array or bstr wrapped CBOR
@param[in] pCtx The context to add to.
@@ -2478,6 +2490,17 @@
*/
void QCBOREncode_CloseMapOrArray(QCBOREncodeContext *pCtx, uint8_t uMajorType, UsefulBufC *pWrappedCBOR);
+/**
+ @brief Semi-private method to close a map, array or bstr wrapped CBOR with indefinite length
+
+ @param[in] pCtx The context to add to.
+ @param[in] uMajorType The major CBOR type to close.
+ @param[out] pWrappedCBOR Pointer to @ref UsefulBufC containing wrapped bytes.
+
+ Call QCBOREncode_CloseArrayIndefiniteLength() or QCBOREncode_CloseMapIndefiniteLength()
+ instead of this.
+ */
+void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *pCtx, uint8_t uMajorType, UsefulBufC *pWrappedCBOR);
/**
@brief Semi-private method to add simple types.
@@ -2973,6 +2996,50 @@
QCBOREncode_CloseMapOrArray(pCtx, CBOR_MAJOR_TYPE_MAP, NULL);
}
+static inline void QCBOREncode_OpenArrayIndefiniteLength(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_OpenMapOrArrayIndefiniteLength(pCtx, CBOR_MAJOR_TYPE_ARRAY);
+}
+
+static inline void QCBOREncode_OpenArrayIndefiniteLengthInMap(QCBOREncodeContext *pCtx, const char *szLabel)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_OpenArrayIndefiniteLength(pCtx);
+}
+
+static inline void QCBOREncode_OpenArrayIndefiniteLengthInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_OpenArrayIndefiniteLength(pCtx);
+}
+
+static inline void QCBOREncode_CloseArrayIndefiniteLength(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_CloseMapOrArrayIndefiniteLength(pCtx, CBOR_MAJOR_TYPE_ARRAY, NULL);
+}
+
+
+static inline void QCBOREncode_OpenMapIndefiniteLength(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_OpenMapOrArrayIndefiniteLength(pCtx, CBOR_MAJOR_TYPE_MAP);
+}
+
+static inline void QCBOREncode_OpenMapIndefiniteLengthInMap(QCBOREncodeContext *pCtx, const char *szLabel)
+{
+ QCBOREncode_AddSZString(pCtx, szLabel);
+ QCBOREncode_OpenMapIndefiniteLength(pCtx);
+}
+
+static inline void QCBOREncode_OpenMapIndefiniteLengthInMapN(QCBOREncodeContext *pCtx, int64_t nLabel)
+{
+ QCBOREncode_AddInt64(pCtx, nLabel);
+ QCBOREncode_OpenMapIndefiniteLength(pCtx);
+}
+
+static inline void QCBOREncode_CloseMapIndefiniteLength(QCBOREncodeContext *pCtx)
+{
+ QCBOREncode_CloseMapOrArrayIndefiniteLength(pCtx, CBOR_MAJOR_TYPE_MAP, NULL);
+}
static inline void QCBOREncode_BstrWrap(QCBOREncodeContext *pCtx)
{
@@ -3034,7 +3101,7 @@
// OK. Once the caller fixes this, they'll be unmasked.
}
- return pCtx->uError;
+ return (QCBORError)pCtx->uError;
}
@@ -3048,4 +3115,3 @@
#endif
#endif /* defined(__QCBOR__qcbor__) */
-
diff --git a/src/qcbor_encode.c b/src/qcbor_encode.c
index c6b2a6f..af87d60 100644
--- a/src/qcbor_encode.c
+++ b/src/qcbor_encode.c
@@ -42,6 +42,7 @@
when who what, where, why
-------- ---- ---------------------------------------------------
+ 7/25/19 janjongboom Add indefinite length encoding for maps and arrays
4/6/19 llundblade Wrapped bstr returned now includes the wrapping bstr
12/30/18 llundblade Small efficient clever encode of type & argument.
11/29/18 llundblade Rework to simpler handling of tags and labels.
@@ -303,6 +304,12 @@
if(uNumber < CBOR_TWENTY_FOUR && nMinLen == 0) {
// Simple case where argument is < 24
uAdditionalInfo = uNumber;
+ } else if (uNumber == LEN_IS_INDEFINITE) {
+ // If the length is indefinite we don't need to encode in multiple bytes
+ uAdditionalInfo = uNumber;
+ } else if (uMajorType == CBOR_MAJOR_TYPE_SIMPLE && uNumber == CBOR_SIMPLE_BREAK) {
+ // Break statement can be encoded in single byte too (0xff)
+ uAdditionalInfo = uNumber;
} else {
/*
Encode argument in 1,2,4 or 8 bytes. Outer loop
@@ -515,6 +522,19 @@
}
}
+/*
+ Semi-public function. It is exposed to user of the interface,
+ but they will usually call one of the inline wrappers rather than this.
+
+ See header qcbor.h
+*/
+void QCBOREncode_OpenMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t uMajorType)
+{
+ // insert the indefinite length marker (0x9f for arrays, 0xbf for maps)
+ InsertEncodedTypeAndNumber(me, uMajorType, 0, LEN_IS_INDEFINITE, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
+
+ QCBOREncode_OpenMapOrArray(me, uMajorType);
+}
/*
Public functions for closing arrays and maps. See header qcbor.h
@@ -568,6 +588,36 @@
}
}
+/*
+ Public functions for closing arrays and maps. See header qcbor.h
+ */
+void QCBOREncode_CloseMapOrArrayIndefiniteLength(QCBOREncodeContext *me, uint8_t uMajorType, UsefulBufC *pWrappedCBOR)
+{
+ if(me->uError == QCBOR_SUCCESS) {
+ if(!Nesting_IsInNest(&(me->nesting))) {
+ me->uError = QCBOR_ERR_TOO_MANY_CLOSES;
+ } else if(Nesting_GetMajorType(&(me->nesting)) != uMajorType) {
+ me->uError = QCBOR_ERR_CLOSE_MISMATCH;
+ } else {
+ // insert the break marker (0xff for both arrays and maps)
+ InsertEncodedTypeAndNumber(me, CBOR_MAJOR_TYPE_SIMPLE, 0, CBOR_SIMPLE_BREAK, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
+
+ // Return pointer and length to the enclosed encoded CBOR. The intended
+ // use is for it to be hashed (e.g., SHA-256) in a COSE implementation.
+ // This must be used right away, as the pointer and length go invalid
+ // on any subsequent calls to this function because there might be calls to
+ // InsertEncodedTypeAndNumber() that slides data to the right.
+ if(pWrappedCBOR) {
+ const UsefulBufC PartialResult = UsefulOutBuf_OutUBuf(&(me->OutBuf));
+ *pWrappedCBOR = UsefulBuf_Tail(PartialResult, UsefulOutBuf_GetEndPosition(&(me->OutBuf)));
+ }
+
+ // Decrease nesting level
+ Nesting_Decrease(&(me->nesting));
+ }
+ }
+}
+
/*
Public functions to finish and get the encoded result. See header qcbor.h
@@ -650,4 +700,3 @@
instance can be removed, saving some code.
*/
-