Reduce encode code size; new function QCBOREncode_AddSimple

Reduces object code size for minimal encode use case by about 50 bytes through some re factoring of the encoder. Size is reduced for maximal use cases too.

QCBOREncode_AddSimple() is made public.


* Readme and copyright updates

* Core encoder optimizations

* Tidy up and rearrange

* Documentation fixes

* Make AddSimple public

* Test fan out is working

---------

Co-authored-by: Laurence Lundblade <lgl@securitytheory.com>
diff --git a/inc/qcbor/qcbor_encode.h b/inc/qcbor/qcbor_encode.h
index 774f272..e86108b 100644
--- a/inc/qcbor/qcbor_encode.h
+++ b/inc/qcbor/qcbor_encode.h
@@ -535,7 +535,7 @@
  *
  * Error handling is the same as for QCBOREncode_AddInt64().
  */
-void
+static void
 QCBOREncode_AddUInt64(QCBOREncodeContext *pCtx, uint64_t uNum);
 
 static void
@@ -695,7 +695,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
@@ -719,7 +719,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
@@ -753,7 +753,7 @@
  * tags. See QCBORDecode_GetNext() for discussion of decoding custom
  * tags.
  */
-void
+static void
 QCBOREncode_AddTag(QCBOREncodeContext *pCtx, uint64_t uTag);
 
 
@@ -1748,7 +1748,6 @@
 QCBOREncode_AddBoolToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, bool b);
 
 
-
 /**
  * @brief  Add a NULL to the encoded output.
  *
@@ -1796,6 +1795,33 @@
 
 
 /**
+ * @brief Add a simple value.
+ *
+ * @param[in] pMe    The encode context.
+ * @param[in] uNum   The simple value.
+ *
+ * Use QCBOREncode_AddBool(), QCBOREncode_AddUndef()... instead of this.
+ *
+ * Use this to add simple values beyond those in defined RFC
+ * 8949. Simple values must be registered with IANA. There is no range
+ * of values for proprietary use.
+ * https://www.iana.org/assignments/cbor-simple-values/cbor-simple-values.xhtml
+ */
+static void
+QCBOREncode_AddSimple(QCBOREncodeContext *pMe, const uint64_t uNum);
+
+static void
+QCBOREncode_AddSimpleToMap(QCBOREncodeContext *pMe,
+                           const char         *szLabel,
+                           const uint8_t       uSimple);
+
+static void
+QCBOREncode_AddSimpleToMapN(QCBOREncodeContext *pMe,
+                            const int64_t       nLabel,
+                            const uint8_t       uSimple);
+
+
+/**
  * @brief  Indicates that the next items added are in an array.
  *
  * @param[in] pCtx The encoding context to open the array in.
@@ -2122,7 +2148,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
@@ -2287,8 +2313,6 @@
  * 100,010 byte buffer and encode it normally. Alternatively, you can
  * encode the head in a 10 byte buffer with this function, hash that and
  * then hash the 100,000 bytes using the same hash context.
- *
- * See also QCBOREncode_AddBytesLenOnly();
  */
 UsefulBufC
 QCBOREncode_EncodeHead(UsefulBuf Buffer,
@@ -2304,6 +2328,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,
@@ -2336,13 +2367,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,
@@ -2350,6 +2374,31 @@
                                    int64_t             nMantissa,
                                    int64_t             nExponent);
 
+
+/**
+ * @brief  Semi-private method to add simple items and floating-point.
+ *
+ * @param[in] pMe        The encoding context.
+ * @param[in] uMinLen    Minimum encoding size for uNum. Usually 0.
+ * @param[in] uArgument  The value to add.
+ *
+ * This is used to add simple types like true and false and float-point
+ * values, both of which are type 7.
+ *
+ * Call QCBOREncode_AddBool(), QCBOREncode_AddNULL(),
+ * QCBOREncode_AddUndef() QCBOREncode_AddDouble() instead of this.
+ *
+ * Error handling is the same as QCBOREncode_AddInt64().
+ */
+static inline void
+QCBOREncode_Private_AddType7(QCBOREncodeContext *pMe,
+                             const uint8_t       uMinLen,
+                             const uint64_t      uArgument)
+{
+   QCBOREncode_Private_AppendCBORHead(pMe, CBOR_MAJOR_TYPE_SIMPLE, uArgument, uMinLen);
+}
+
+
 /**
  * @brief Semi-private method to add only the type and length of a byte string.
  *
@@ -2370,7 +2419,7 @@
  * output buffer, rather than two, roughly cutting memory use in half.
  *
  * This is only used for this odd case, but this is a supported
- * tested function.
+ * tested function for QCBOR 1.0.
  *
  * See also QCBOREncode_EncodeHead().
  */
@@ -2389,6 +2438,10 @@
                                  UsefulBufC           Bytes);
 
 
+/* Forward declaration */
+static void
+QCBOREncode_AddSZString(QCBOREncodeContext *pMe, const char *szString);
+
 
 
 
@@ -2397,10 +2450,7 @@
                           const char        *szLabel,
                           const int64_t      uNum)
 {
-   /* Use _AddBuffer() because _AddSZString() is defined below, not above */
-   QCBOREncode_Private_AddBuffer(pMe,
-                                 CBOR_MAJOR_TYPE_TEXT_STRING,
-                                 UsefulBuf_FromSZ(szLabel));
+   QCBOREncode_AddSZString(pMe, szLabel);
    QCBOREncode_AddInt64(pMe, uNum);
 }
 
@@ -2415,14 +2465,18 @@
 
 
 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)
 {
-   /* Use _AddBuffer() because _AddSZString() is defined below, not above */
-   QCBOREncode_Private_AddBuffer(pMe,
-                                 CBOR_MAJOR_TYPE_TEXT_STRING,
-                                 UsefulBuf_FromSZ(szLabel));
+   QCBOREncode_AddSZString(pMe, szLabel);
    QCBOREncode_AddUInt64(pMe, uNum);
 }
 
@@ -2486,7 +2540,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,
@@ -2562,6 +2646,8 @@
 
 
 
+
+
 static inline void
 QCBOREncode_AddTDateEpoch(QCBOREncodeContext *pMe,
                           const uint8_t       uTag,
@@ -2694,12 +2780,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,29 +3719,36 @@
 }
 
 
-
 static inline void
-QCBOREncode_Private_AddSimple(QCBOREncodeContext *pMe, const uint64_t uNum)
+QCBOREncode_AddSimple(QCBOREncodeContext *pMe, const uint64_t uNum)
 {
+   /* This check often is optimized out because uNum is known at compile time. */
+#ifndef QCBOR_DISABLE_ENCODE_USAGE_GUARDS
+   if(uNum >= CBOR_SIMPLEV_RESERVED_START && uNum <= CBOR_SIMPLEV_RESERVED_END) {
+      pMe->uError = QCBOR_ERR_ENCODE_UNSUPPORTED;
+      return;
+   }
+#endif /* !QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
+
    QCBOREncode_Private_AddType7(pMe, 0, uNum);
 }
 
 static inline void
-QCBOREncode_Private_AddSimpleToMap(QCBOREncodeContext *pMe,
+QCBOREncode_AddSimpleToMap(QCBOREncodeContext *pMe,
                                    const char         *szLabel,
                                    const uint8_t       uSimple)
 {
    QCBOREncode_AddSZString(pMe, szLabel);
-   QCBOREncode_Private_AddSimple(pMe, uSimple);
+   QCBOREncode_AddSimple(pMe, uSimple);
 }
 
 static inline void
-QCBOREncode_Private_AddSimpleToMapN(QCBOREncodeContext *pMe,
+QCBOREncode_AddSimpleToMapN(QCBOREncodeContext *pMe,
                                     const int64_t       nLabel,
                                     const uint8_t       uSimple)
 {
    QCBOREncode_AddInt64(pMe, nLabel);
-   QCBOREncode_Private_AddSimple(pMe, uSimple);
+   QCBOREncode_AddSimple(pMe, uSimple);
 }
 
 
@@ -3661,7 +3759,7 @@
    if(b) {
       uSimple = CBOR_SIMPLEV_TRUE;
    }
-   QCBOREncode_Private_AddSimple(pMe, uSimple);
+   QCBOREncode_AddSimple(pMe, uSimple);
 }
 
 static inline void
@@ -3682,7 +3780,7 @@
 static inline void
 QCBOREncode_AddNULL(QCBOREncodeContext *pMe)
 {
-   QCBOREncode_Private_AddSimple(pMe, CBOR_SIMPLEV_NULL);
+   QCBOREncode_AddSimple(pMe, CBOR_SIMPLEV_NULL);
 }
 
 static inline void
@@ -3703,7 +3801,7 @@
 static inline void
 QCBOREncode_AddUndef(QCBOREncodeContext *pMe)
 {
-   QCBOREncode_Private_AddSimple(pMe, CBOR_SIMPLEV_UNDEF);
+   QCBOREncode_AddSimple(pMe, CBOR_SIMPLEV_UNDEF);
 }
 
 static inline void
@@ -3859,11 +3957,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 35c60a7..a061809 100644
--- a/inc/qcbor/qcbor_private.h
+++ b/inc/qcbor/qcbor_private.h
@@ -377,9 +377,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