Core encoder optimizations
diff --git a/inc/qcbor/qcbor_encode.h b/inc/qcbor/qcbor_encode.h
index 3981e9b..c63f05e 100644
--- a/inc/qcbor/qcbor_encode.h
+++ b/inc/qcbor/qcbor_encode.h
@@ -364,6 +364,7 @@
* - The maximum tag nesting is @c QCBOR_MAX_TAGS_PER_ITEM (typically 4).
* - Works only on 32- and 64-bit CPUs (modifications could make it work
* on 16-bit CPUs).
+ * - QCBORDecode_EnterBstrWrapped() doesn't work on indefinite-length strings.
*
* The public interface uses @c size_t for all lengths. Internally the
* implementation uses 32-bit lengths by design to use less memory and
@@ -533,7 +534,7 @@
*
* Error handling is the same as for QCBOREncode_AddInt64().
*/
-void
+static void
QCBOREncode_AddUInt64(QCBOREncodeContext *pCtx, uint64_t uNum);
static void
@@ -693,7 +694,7 @@
* See also QCBOREncode_AddDouble(), QCBOREncode_AddFloat(), and
* QCBOREncode_AddFloatNoPreferred() and @ref Floating-Point.
*/
-void
+static void
QCBOREncode_AddDoubleNoPreferred(QCBOREncodeContext *pCtx, double dNum);
static void
@@ -717,7 +718,7 @@
* See also QCBOREncode_AddDouble(), QCBOREncode_AddFloat(), and
* QCBOREncode_AddDoubleNoPreferred() and @ref Floating-Point.
*/
-void
+static void
QCBOREncode_AddFloatNoPreferred(QCBOREncodeContext *pCtx, float fNum);
static void
@@ -751,7 +752,7 @@
* tags. See QCBORDecode_GetNext() for discussion of decoding custom
* tags.
*/
-void
+static void
QCBOREncode_AddTag(QCBOREncodeContext *pCtx, uint64_t uTag);
@@ -2120,7 +2121,7 @@
* must be enclosed in a map or array. At the top level the raw
* CBOR must be a single data item.
*/
-static void
+void
QCBOREncode_AddEncoded(QCBOREncodeContext *pCtx, UsefulBufC Encoded);
static void
@@ -2302,6 +2303,13 @@
========================================================================= */
/* Semi-private funcion used by public inline functions. See qcbor_encode.c */
+void QCBOREncode_Private_AppendCBORHead(QCBOREncodeContext *pMe,
+ const uint8_t uMajorType,
+ const uint64_t uArgument,
+ const uint8_t uMinLen);
+
+
+/* Semi-private funcion used by public inline functions. See qcbor_encode.c */
void
QCBOREncode_Private_AddBuffer(QCBOREncodeContext *pCtx,
uint8_t uMajorType,
@@ -2334,13 +2342,6 @@
/* Semi-private funcion used by public inline functions. See qcbor_encode.c */
void
-QCBOREncode_Private_AddType7(QCBOREncodeContext *pCtx,
- uint8_t uMinLen,
- uint64_t uNum);
-
-
-/* Semi-private funcion used by public inline functions. See qcbor_encode.c */
-void
QCBOREncode_Private_AddExpMantissa(QCBOREncodeContext *pCtx,
uint64_t uTag,
UsefulBufC BigNumMantissa,
@@ -2348,30 +2349,44 @@
int64_t nMantissa,
int64_t nExponent);
+
+
/**
- * @brief Semi-private method to add only the type and length of a byte string.
+ * @brief Semi-private method to add simple types.
*
- * @param[in] pCtx The context to initialize.
- * @param[in] Bytes Pointer and length of the input data.
+ * @param[in] pMe The encoding context to add the simple value to.
+ * @param[in] uMinLen Minimum encoding size for uNum. Usually 0.
+ * @param[in] uNum One of CBOR_SIMPLEV_FALSE through _UNDEF or other.
*
- * This will be removed in QCBOR 2.0. It was never a public function.
+ * This is used to add simple types like true and false.
*
- * This is the same as QCBOREncode_AddBytes() except it only adds the
- * CBOR encoding for the type and the length. It doesn't actually add
- * the bytes. You can't actually produce correct CBOR with this and
- * the rest of this API. It is only used for a special case where the
- * valid CBOR is created manually by putting this type and length in
- * and then adding the actual bytes. In particular, when only a hash
- * of the encoded CBOR is needed, where the type and header are hashed
- * separately and then the bytes is hashed. This makes it possible to
- * implement COSE Sign1 with only one copy of the payload in the
- * output buffer, rather than two, roughly cutting memory use in half.
+ * Call QCBOREncode_AddBool(), QCBOREncode_AddNULL(),
+ * QCBOREncode_AddUndef() instead of this.
*
- * This is only used for this odd case, but this is a supported
- * tested function.
+ * This function can add simple values that are not defined by CBOR
+ * yet. This expansion point in CBOR should not be used unless they are
+ * standardized.
*
- * See also QCBOREncode_EncodeHead().
+ * Error handling is the same as QCBOREncode_AddInt64().
*/
+static inline void
+QCBOREncode_Private_AddType7(QCBOREncodeContext *pMe,
+ const uint8_t uMinLen,
+ const uint64_t uNum)
+{
+#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
+ if(uNum >= CBOR_SIMPLEV_RESERVED_START && uNum <= CBOR_SIMPLEV_RESERVED_END) {
+ /* This check often is optimized out because uNum is known at compile time. */
+ pMe->uError = QCBOR_ERR_ENCODE_UNSUPPORTED;
+ return;
+ }
+#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
+
+ /* AppendCBORHead() does endian swapping for the float / double */
+ QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_SIMPLE, uNum, uMinLen);
+}
+
+
static void
QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pCtx,
UsefulBufC Bytes);
@@ -2389,7 +2404,6 @@
-
static inline void
QCBOREncode_AddInt64ToMap(QCBOREncodeContext *pMe,
const char *szLabel,
@@ -2413,6 +2427,13 @@
static inline void
+QCBOREncode_AddUInt64(QCBOREncodeContext *pMe, const uint64_t uValue)
+{
+ QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_POSITIVE_INT, uValue, 0);
+}
+
+
+static inline void
QCBOREncode_AddUInt64ToMap(QCBOREncodeContext *pMe,
const char *szLabel,
const uint64_t uNum)
@@ -2484,7 +2505,37 @@
}
+
+/*
+ * Public functions for adding a tag. See qcbor/qcbor_encode.h
+ */
+static inline void
+QCBOREncode_AddTag(QCBOREncodeContext *pMe, const uint64_t uTag)
+{
+ QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_TAG, uTag, 0);
+}
+
+
+
#ifndef USEFULBUF_DISABLE_ALL_FLOAT
+
+static inline void
+QCBOREncode_AddDoubleNoPreferred(QCBOREncodeContext *pMe, const double dNum)
+{
+ QCBOREncode_Private_AddType7(pMe,
+ sizeof(uint64_t),
+ UsefulBufUtil_CopyDoubleToUint64(dNum));
+}
+
+static inline void
+QCBOREncode_AddFloatNoPreferred(QCBOREncodeContext *pMe, const float fNum)
+{
+ QCBOREncode_Private_AddType7(pMe,
+ sizeof(uint32_t),
+ UsefulBufUtil_CopyFloatToUint32(fNum));
+}
+
+
static inline void
QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pMe,
const char *szLabel,
@@ -2560,6 +2611,8 @@
+
+
static inline void
QCBOREncode_AddTDateEpoch(QCBOREncodeContext *pMe,
const uint8_t uTag,
@@ -2692,12 +2745,17 @@
QCBOREncode_OpenBytes(pMe, pPlace);
}
+
+/*
+ * Public functions for adding only a byte string length. See qcbor/qcbor_encode.h
+ */
static inline void
QCBOREncode_AddBytesLenOnly(QCBOREncodeContext *pMe, const UsefulBufC Bytes)
{
- QCBOREncode_Private_AddBuffer(pMe, CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY, Bytes);
+ QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_BYTE_STRING, Bytes.len, 0);
}
+
static inline void
QCBOREncode_AddBytesLenOnlyToMap(QCBOREncodeContext *pMe,
const char *szLabel,
@@ -3628,12 +3686,25 @@
static inline void
-QCBOREncode_Private_AddSimple(QCBOREncodeContext *pMe, const uint64_t uNum)
+XQCBOREncode_Private_AddSimple(QCBOREncodeContext *pMe, const uint64_t uNum)
{
QCBOREncode_Private_AddType7(pMe, 0, uNum);
}
static inline void
+QCBOREncode_Private_AddSimple(QCBOREncodeContext *pMe, const uint64_t uNum)
+{
+ if(pMe->uError == QCBOR_SUCCESS) {
+ if(uNum >= CBOR_SIMPLEV_RESERVED_START && uNum <= CBOR_SIMPLEV_RESERVED_END) {
+ pMe->uError = QCBOR_ERR_ENCODE_UNSUPPORTED;
+ return;
+ }
+ }
+ QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_SIMPLE, uNum, 0);
+}
+
+
+static inline void
QCBOREncode_Private_AddSimpleToMap(QCBOREncodeContext *pMe,
const char *szLabel,
const uint8_t uSimple)
@@ -3659,6 +3730,7 @@
if(b) {
uSimple = CBOR_SIMPLEV_TRUE;
}
+
QCBOREncode_Private_AddSimple(pMe, uSimple);
}
@@ -3857,11 +3929,6 @@
}
-static inline void
-QCBOREncode_AddEncoded(QCBOREncodeContext *pMe, const UsefulBufC Encoded)
-{
- QCBOREncode_Private_AddBuffer(pMe, CBOR_MAJOR_NONE_TYPE_RAW, Encoded);
-}
static inline void
QCBOREncode_AddEncodedToMap(QCBOREncodeContext *pMe,
diff --git a/inc/qcbor/qcbor_private.h b/inc/qcbor/qcbor_private.h
index 84c4cbe..f3ef185 100644
--- a/inc/qcbor/qcbor_private.h
+++ b/inc/qcbor/qcbor_private.h
@@ -375,9 +375,7 @@
/* Used internally in the impementation here Must not conflict with
* any of the official CBOR types
*/
-#define CBOR_MAJOR_NONE_TYPE_RAW 9
#define CBOR_MAJOR_NONE_TAG_LABEL_REORDER 10
-#define CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY 11
#define CBOR_MAJOR_NONE_TYPE_OPEN_BSTR 12
diff --git a/src/qcbor_encode.c b/src/qcbor_encode.c
index fa3486e..db36bd9 100644
--- a/src/qcbor_encode.c
+++ b/src/qcbor_encode.c
@@ -114,7 +114,7 @@
if(1 >= QCBOR_MAX_ITEMS_IN_ARRAY - pNesting->pCurrentNesting->uCount) {
return QCBOR_ERR_ARRAY_TOO_LONG;
}
-#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
+#endif /* !QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
pNesting->pCurrentNesting->uCount++;
@@ -426,6 +426,7 @@
/* The 5 bits in the initial byte that are not the major type */
int nAdditionalInfo;
+#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS
if(uMajorType > QCBOR_INDEFINITE_LEN_TYPE_MODIFIER) {
/* Special case for start & end of indefinite length */
uMajorType = uMajorType - QCBOR_INDEFINITE_LEN_TYPE_MODIFIER;
@@ -438,7 +439,9 @@
#endif
nAdditionalInfo = CBOR_SIMPLE_BREAK;
- } else if (uArgument < CBOR_TWENTY_FOUR && uMinLen == 0) {
+ } else
+#endif /* !QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */
+ if (uArgument < CBOR_TWENTY_FOUR && uMinLen == 0) {
/* Simple case where argument is < 24 */
nAdditionalInfo = (int)uArgument;
@@ -500,41 +503,6 @@
/**
- * @brief Append the CBOR head, the major type and argument
- *
- * @param pMe Encoder context.
- * @param uMajorType Major type to insert.
- * @param uArgument The argument (an integer value or a length).
- * @param uMinLen The minimum number of bytes for encoding the CBOR argument.
- *
- * This formats the CBOR "head" and appends it to the output.
- */
-static void
-QCBOREncode_Private_AppendCBORHead(QCBOREncodeContext *pMe,
- const uint8_t uMajorType,
- const uint64_t uArgument,
- const uint8_t uMinLen)
-{
- /* A stack buffer large enough for a CBOR head */
- UsefulBuf_MAKE_STACK_UB (pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE);
-
- UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead,
- uMajorType,
- uMinLen,
- uArgument);
-
- /* No check for EncodedHead == NULLUsefulBufC is performed here to
- * save object code. It is very clear that pBufferForEncodedHead is
- * the correct size. If EncodedHead == NULLUsefulBufC then
- * UsefulOutBuf_AppendUsefulBuf() will do nothing so there is no
- * security hole introduced.
- */
-
- UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), EncodedHead);
-}
-
-
-/**
* @brief Check for errors when decreasing nesting.
*
* @param pMe QCBOR encoding context.
@@ -566,7 +534,7 @@
return true;
}
-#else
+#else /* !QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
/* None of these checks are performed if the encode guards are
* turned off as they all relate to correct calling.
*
@@ -576,7 +544,7 @@
(void)uMajorType;
(void)pMe;
-#endif
+#endif /* !QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
return false;
}
@@ -649,18 +617,48 @@
}
-/*
- * Public functions for adding unsigned integers. See qcbor/qcbor_encode.h
+/**
+ * @brief Append the CBOR head, the major type and argument
+ *
+ * @param pMe Encoder context.
+ * @param uMajorType Major type to insert.
+ * @param uArgument The argument (an integer value or a length).
+ * @param uMinLen The minimum number of bytes for encoding the CBOR argument.
+ *
+ * This formats the CBOR "head" and appends it to the output.
+ *
+ * This also increments the array/map item counter in most cases.
*/
void
-QCBOREncode_AddUInt64(QCBOREncodeContext *pMe, const uint64_t uValue)
+QCBOREncode_Private_AppendCBORHead(QCBOREncodeContext *pMe,
+ const uint8_t uMajorType,
+ const uint64_t uArgument,
+ const uint8_t uMinLen)
{
- QCBOREncode_Private_AppendCBORHead(pMe,
- CBOR_MAJOR_TYPE_POSITIVE_INT,
- uValue,
- 0);
+ /* A stack buffer large enough for a CBOR head */
+ UsefulBuf_MAKE_STACK_UB (pBufferForEncodedHead, QCBOR_HEAD_BUFFER_SIZE);
- QCBOREncode_Private_IncrementMapOrArrayCount(pMe);
+ UsefulBufC EncodedHead = QCBOREncode_EncodeHead(pBufferForEncodedHead,
+ uMajorType,
+ uMinLen,
+ uArgument);
+
+ /* No check for EncodedHead == NULLUsefulBufC is performed here to
+ * save object code. It is very clear that pBufferForEncodedHead is
+ * the correct size. If EncodedHead == NULLUsefulBufC then
+ * UsefulOutBuf_AppendUsefulBuf() will do nothing so there is no
+ * security hole introduced.
+ */
+
+ UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), EncodedHead);
+ if(!(uMajorType & QCBOR_INDEFINITE_LEN_TYPE_MODIFIER || uMajorType == CBOR_MAJOR_TYPE_TAG)) {
+ /* Don't increment the map count for tag or break because that is
+ * not needed. Don't do it for indefinite-length arrays and maps
+ * because it is done elsewhere. This is never called for definite-length
+ * arrays and maps.
+ */
+ QCBOREncode_Private_IncrementMapOrArrayCount(pMe);
+ }
}
@@ -687,111 +685,39 @@
uMajorType = CBOR_MAJOR_TYPE_POSITIVE_INT;
}
QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, uValue, 0);
-
- QCBOREncode_Private_IncrementMapOrArrayCount(pMe);
}
/**
* @brief Semi-private method to add a buffer full of bytes to encoded output.
*
- * @param[in] pMe The encoding context to add the integer to.
+ * @param[in] pMe The encoding context to add the string to.
* @param[in] uMajorType The CBOR major type of the bytes.
* @param[in] Bytes The bytes to add.
*
- * Use QCBOREncode_AddText() or QCBOREncode_AddBytes() or
- * QCBOREncode_AddEncoded() instead. They are inline functions that
- * call this and supply the correct major type. This function is
- * public to make the inline functions work to keep the overall code
- * size down and because the C language has no way to make it private.
+ * Called by inline functions to add text and byte strings.
*
- * If this is called the major type should be @c CBOR_MAJOR_TYPE_TEXT_STRING,
- * @c CBOR_MAJOR_TYPE_BYTE_STRING or @c CBOR_MAJOR_NONE_TYPE_RAW. The
- * last one is special for adding already-encoded CBOR.
- *
- * This does the work of adding actual strings bytes to the CBOR
- * output (as opposed to adding numbers and opening / closing
- * aggregate types).
-
- * There are four use cases:
- * CBOR_MAJOR_TYPE_BYTE_STRING -- Byte strings
- * CBOR_MAJOR_TYPE_TEXT_STRING -- Text strings
- * CBOR_MAJOR_NONE_TYPE_RAW -- Already-encoded CBOR
- * CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY -- Special case
- *
- * The first two add the head plus the actual bytes. The third just
- * adds the bytes as the heas is presumed to be in the bytes. The
- * fourth just adds the head for the very special case of
- * QCBOREncode_AddBytesLenOnly().
+ * (This used to support QCBOREncode_AddEncoded() and QCBOREncode_AddBytesLenOnly(),
+ * but that was pulled out to make this smaller. This is one of the most used methods
+ * and they are some of the least used).
*/
void
QCBOREncode_Private_AddBuffer(QCBOREncodeContext *pMe,
const uint8_t uMajorType,
const UsefulBufC Bytes)
{
- /* If it is not Raw CBOR, add the type and the length */
- if(uMajorType != CBOR_MAJOR_NONE_TYPE_RAW) {
- uint8_t uRealMajorType = uMajorType;
- if(uRealMajorType == CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY) {
- uRealMajorType = CBOR_MAJOR_TYPE_BYTE_STRING;
- }
- QCBOREncode_Private_AppendCBORHead(pMe, uRealMajorType, Bytes.len, 0);
- }
-
- if(uMajorType != CBOR_MAJOR_NONE_TYPE_BSTR_LEN_ONLY) {
- /* Actually add the bytes */
- UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), Bytes);
- }
-
- QCBOREncode_Private_IncrementMapOrArrayCount(pMe);
+ QCBOREncode_Private_AppendCBORHead(pMe, uMajorType, Bytes.len, 0);
+ UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), Bytes);
}
/*
- * Public functions for adding a tag. See qcbor/qcbor_encode.h
+ * Public functions for adding raw encoded CBOR. See qcbor/qcbor_encode.h
*/
void
-QCBOREncode_AddTag(QCBOREncodeContext *pMe, const uint64_t uTag)
+QCBOREncode_AddEncoded(QCBOREncodeContext *pMe, const UsefulBufC Encoded)
{
- QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_TAG, uTag, 0);
-}
-
-
-/**
- * @brief Semi-private method to add simple types.
- *
- * @param[in] pMe The encoding context to add the simple value to.
- * @param[in] uMinLen Minimum encoding size for uNum. Usually 0.
- * @param[in] uNum One of CBOR_SIMPLEV_FALSE through _UNDEF or other.
- *
- * This is used to add simple types like true and false.
- *
- * Call QCBOREncode_AddBool(), QCBOREncode_AddNULL(),
- * QCBOREncode_AddUndef() instead of this.
- *
- * This function can add simple values that are not defined by CBOR
- * yet. This expansion point in CBOR should not be used unless they are
- * standardized.
- *
- * Error handling is the same as QCBOREncode_AddInt64().
- */
-void
-QCBOREncode_Private_AddType7(QCBOREncodeContext *pMe,
- const uint8_t uMinLen,
- const uint64_t uNum)
-{
-#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
- if(pMe->uError == QCBOR_SUCCESS) {
- if(uNum >= CBOR_SIMPLEV_RESERVED_START && uNum <= CBOR_SIMPLEV_RESERVED_END) {
- pMe->uError = QCBOR_ERR_ENCODE_UNSUPPORTED;
- return;
- }
- }
-#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
-
- /* AppendCBORHead() does endian swapping for the float / double */
- QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_SIMPLE, uNum, uMinLen);
-
+ UsefulOutBuf_AppendUsefulBuf(&(pMe->OutBuf), Encoded);
QCBOREncode_Private_IncrementMapOrArrayCount(pMe);
}
@@ -801,18 +727,6 @@
* Public functions for adding a double. See qcbor/qcbor_encode.h
*/
void
-QCBOREncode_AddDoubleNoPreferred(QCBOREncodeContext *pMe, const double dNum)
-{
- QCBOREncode_Private_AddType7(pMe,
- sizeof(uint64_t),
- UsefulBufUtil_CopyDoubleToUint64(dNum));
-}
-
-
-/*
- * Public functions for adding a double. See qcbor/qcbor_encode.h
- */
-void
QCBOREncode_AddDouble(QCBOREncodeContext *pMe, const double dNum)
{
#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
@@ -829,18 +743,6 @@
* Public functions for adding a float. See qcbor/qcbor_encode.h
*/
void
-QCBOREncode_AddFloatNoPreferred(QCBOREncodeContext *pMe, const float fNum)
-{
- QCBOREncode_Private_AddType7(pMe,
- sizeof(uint32_t),
- UsefulBufUtil_CopyFloatToUint32(fNum));
-}
-
-
-/*
- * Public functions for adding a float. See qcbor/qcbor_encode.h
- */
-void
QCBOREncode_AddFloat(QCBOREncodeContext *pMe, const float fNum)
{
#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
diff --git a/test/qcbor_encode_tests.h b/test/qcbor_encode_tests.h
index bac1085..8452009 100644
--- a/test/qcbor_encode_tests.h
+++ b/test/qcbor_encode_tests.h
@@ -80,9 +80,8 @@
/*
- This tests the QCBOREncode_AddRaw() function by adding two chunks or
- RAWCBOR to an array and comparing with expected values. This is an
- encoding test.
+ This tests the QCBOREncode_AddRaw() function by adding two chunks of
+ raw CBOR to an array and comparing with expected values.
*/
int32_t EncodeRawTest(void);