Add compile option to disable floating point usage (#114)

This commit adds the option to disable floating point processing in
QCBOR. To disable, the USEFULBUF_DISABLE_ALL_FLOAT preprocessor macro
needs to be defined.

e.g.:

 $ make CMD_LINE="-DUSEFULBUF_DISABLE_ALL_FLOAT"

This removes the capability (and the code) of decoding floating point
types. The type is still recognised, so a meaningful
QCBOR_ERR_ALL_FLOAT_DISABLED error is returned when a floating point value
is encountered in a decoded qcbor. From the encoding interface the
floating point encoding functions are removed.

Change-Id: I371769246f7d83354607de9bce1e7998b8c536a1
Signed-off-by: Mate Toth-Pal <mate.toth-pal@arm.com>
diff --git a/inc/qcbor/UsefulBuf.h b/inc/qcbor/UsefulBuf.h
index c271a31..fb3c12b 100644
--- a/inc/qcbor/UsefulBuf.h
+++ b/inc/qcbor/UsefulBuf.h
@@ -1,6 +1,7 @@
 /*============================================================================
  Copyright (c) 2016-2018, The Linux Foundation.
  Copyright (c) 2018-2021, Laurence Lundblade.
+ Copyright (c) 2021, Arm Limited. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are
@@ -138,6 +139,12 @@
  *     handle big and little-endian with system option.
  *   USEFULBUF_CONFIG_BSWAP -- With USEFULBUF_CONFIG_LITTLE_ENDIAN,
  *     use __builtin_bswapXX().
+ *
+ * It is possible to run this code in environments where using floating point is
+ * not allowed. Defining USEFULBUF_DISABLE_ALL_FLOAT will disable all the code
+ * that is related to handling floating point types, along with related
+ * interfaces. This makes it possible to compile the code with the compile
+ * option -mgeneral-regs-only.
  */
 
 #if defined(USEFULBUF_CONFIG_BIG_ENDIAN) && defined(USEFULBUF_CONFIG_LITTLE_ENDIAN)
@@ -679,6 +686,7 @@
 
 
 
+#ifndef USEFULBUF_DISABLE_ALL_FLOAT
 /**
  * @brief Copy a @c float to a @c uint32_t.
  *
@@ -733,6 +741,7 @@
  * is a crusty corner of C.
  */
 static inline double UsefulBufUtil_CopyUint64ToDouble(uint64_t u64);
+#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
 
 
 
@@ -1032,6 +1041,7 @@
                                              size_t uPos);
 
 
+#ifndef USEFULBUF_DISABLE_ALL_FLOAT
 /**
  * @brief Insert a @c float into the @ref UsefulOutBuf.
  *
@@ -1064,6 +1074,7 @@
 static inline void UsefulOutBuf_InsertDouble(UsefulOutBuf *pUOutBuf,
                                              double d,
                                              size_t uPos);
+#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
 
 
 /**
@@ -1162,6 +1173,7 @@
                                              uint64_t uInteger64);
 
 
+#ifndef USEFULBUF_DISABLE_ALL_FLOAT
 /**
  * @brief Append a @c float to the @ref UsefulOutBuf
  *
@@ -1190,6 +1202,7 @@
  */
 static inline void UsefulOutBuf_AppendDouble(UsefulOutBuf *pUOutBuf,
                                              double d);
+#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
 
 
 /**
@@ -1519,6 +1532,7 @@
 static uint64_t UsefulInputBuf_GetUint64(UsefulInputBuf *pUInBuf);
 
 
+#ifndef USEFULBUF_DISABLE_ALL_FLOAT
 /**
  * @brief Get a float out of the input buffer.
  *
@@ -1547,6 +1561,7 @@
  * The input bytes are interpreted in network order (big endian).
  */
 static double UsefulInputBuf_GetDouble(UsefulInputBuf *pUInBuf);
+#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
 
 
 /**
@@ -1778,6 +1793,7 @@
 }
 
 
+#ifndef USEFULBUF_DISABLE_ALL_FLOAT
 static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f)
 {
    uint32_t u32;
@@ -1805,6 +1821,7 @@
    memcpy(&f, &u32, sizeof(uint32_t));
    return f;
 }
+#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
 
 
 
@@ -1984,6 +2001,7 @@
 }
 
 
+#ifndef USEFULBUF_DISABLE_ALL_FLOAT
 static inline void UsefulOutBuf_InsertFloat(UsefulOutBuf *pMe,
                                             float f,
                                             size_t uPos)
@@ -1998,6 +2016,7 @@
 {
    UsefulOutBuf_InsertUint64(pMe, UsefulBufUtil_CopyDoubleToUint64(d), uPos);
 }
+#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
 
 
 static inline void UsefulOutBuf_AppendUsefulBuf(UsefulOutBuf *pMe,
@@ -2055,6 +2074,7 @@
 }
 
 
+#ifndef USEFULBUF_DISABLE_ALL_FLOAT
 static inline void UsefulOutBuf_AppendFloat(UsefulOutBuf *pMe,
                                             float f)
 {
@@ -2067,6 +2087,7 @@
 {
    UsefulOutBuf_InsertDouble(pMe, d, UsefulOutBuf_GetEndPosition(pMe));
 }
+#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
 
 
 static inline int UsefulOutBuf_GetError(UsefulOutBuf *pMe)
@@ -2325,6 +2346,7 @@
 }
 
 
+#ifndef USEFULBUF_DISABLE_ALL_FLOAT
 static inline float UsefulInputBuf_GetFloat(UsefulInputBuf *pMe)
 {
    uint32_t uResult = UsefulInputBuf_GetUint32(pMe);
@@ -2339,6 +2361,7 @@
 
    return uResult ? UsefulBufUtil_CopyUint64ToDouble(uResult) : 0;
 }
+#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
 
 
 static inline int UsefulInputBuf_GetError(UsefulInputBuf *pMe)
diff --git a/inc/qcbor/qcbor_common.h b/inc/qcbor/qcbor_common.h
index 7fc48de..e1ff43a 100644
--- a/inc/qcbor/qcbor_common.h
+++ b/inc/qcbor/qcbor_common.h
@@ -1,6 +1,7 @@
 /*==============================================================================
  Copyright (c) 2016-2018, The Linux Foundation.
  Copyright (c) 2018-2021, Laurence Lundblade.
+ Copyright (c) 2021, Arm Limited.
  All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -58,6 +59,17 @@
 #define QCBOR_DISABLE_EXP_AND_MANTISSA
 #endif
 
+/* If USEFULBUF_DISABLE_ALL_FLOATis defined then define
+ * QCBOR_DISABLE_FLOAT_HW_USE and QCBOR_DISABLE_PREFERRED_FLOAT
+ */
+#ifdef USEFULBUF_DISABLE_ALL_FLOAT
+#ifndef QCBOR_DISABLE_FLOAT_HW_USE
+#define QCBOR_DISABLE_FLOAT_HW_USE
+#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+#define QCBOR_DISABLE_PREFERRED_FLOAT
+#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
+#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
 
 /* Standard CBOR Major type for positive integers of various lengths */
 #define CBOR_MAJOR_TYPE_POSITIVE_INT 0
@@ -504,7 +516,11 @@
 
    /** Trying to cancel a byte string wrapping after items have been
        added to it. */
-   QCBOR_ERR_CANNOT_CANCEL = 45
+   QCBOR_ERR_CANNOT_CANCEL = 45,
+
+   /** Floating point support is completely turned off, encoding/decoding
+       floating point numbers is not possible. */
+   QCBOR_ERR_ALL_FLOAT_DISABLED = 46
 
    /* This is stored in uint8_t; never add values > 255 */
 } QCBORError;
diff --git a/inc/qcbor/qcbor_decode.h b/inc/qcbor/qcbor_decode.h
index 1b7d148..6616033 100644
--- a/inc/qcbor/qcbor_decode.h
+++ b/inc/qcbor/qcbor_decode.h
@@ -1,6 +1,7 @@
 /*==============================================================================
  Copyright (c) 2016-2018, The Linux Foundation.
  Copyright (c) 2018-2021, Laurence Lundblade.
+ Copyright (c) 2021, Arm Limited.
  All rights reserved.
 
  Redistribution and use in source and binary forms, with or without
@@ -394,16 +395,20 @@
        *  with @c uNestLevel and @c uNextNestLevel so as to work for
        *  both definite and indefinite length maps and arrays. */
       uint16_t    uCount;
+#ifndef USEFULBUF_DISABLE_ALL_FLOAT
       /** The value for @c uDataType @ref QCBOR_TYPE_DOUBLE. */
       double      dfnum;
       /** The value for @c uDataType @ref QCBOR_TYPE_FLOAT. */
       float       fnum;
+#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
       /** The value for @c uDataType @ref QCBOR_TYPE_DATE_EPOCH.
        *  Floating-point dates that are NaN, +Inifinity or -Inifinity
        *  result in the @ref QCBOR_ERR_DATE_OVERFLOW error. */
       struct {
          int64_t  nSeconds;
+#ifndef USEFULBUF_DISABLE_ALL_FLOAT
          double   fSecondsFraction;
+#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
       } epochDate;
 
       /** The value for @c uDataType @ref QCBOR_TYPE_DAYS_EPOCH -- the
@@ -889,6 +894,7 @@
  * | @ref QCBOR_ERR_INDEF_LEN_ARRAYS_DISABLED  | Library compiled with indefinite maps and arrays  disabled and indefinite map or array encountered |
  * | @ref QCBOR_ERR_INDEF_LEN_STRINGS_DISABLED | Library compiled with indefinite strings disabled and indefinite string encountered |
  * | @ref QCBOR_ERR_FLOAT_DATE_DISABLED        | Library compiled with floating-point disabled and floating-point date encountered |
+ * | @ref QCBOR_ERR_ALL_FLOAT_DISABLED             | Library compiled with floating-point support turned off. |
  * | __Resource exhaustion errors__  ||
  * | @ref QCBOR_ERR_STRING_ALLOCATE | The string allocator is unable to allocate more memory |
  */
diff --git a/inc/qcbor/qcbor_encode.h b/inc/qcbor/qcbor_encode.h
index 969deee..202a98f 100644
--- a/inc/qcbor/qcbor_encode.h
+++ b/inc/qcbor/qcbor_encode.h
@@ -1,6 +1,7 @@
 /*==============================================================================
  Copyright (c) 2016-2018, The Linux Foundation.
  Copyright (c) 2018-2021, Laurence Lundblade.
+ Copyright (c) 2021, Arm Limited.
  All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
@@ -341,6 +342,11 @@
  float type as 32-bits and a C double type as 64-bits. Floating-point
  epoch dates will be unsupported.
 
+ If USEFULBUF_DISABLE_ALL_FLOATis defined, then floating point support is
+ completely disabled. Decoding functions return @ref QCBOR_ERR_ALL_FLOAT_DISABLED
+ if a floating point value is encountered during decoding. Functions that are
+ encoding floating point values are not available.
+
  ## Limitations
 
  Summary Limits of this implementation:
@@ -588,6 +594,7 @@
 static void QCBOREncode_AddSZStringToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, const char *szString);
 
 
+#ifndef USEFULBUF_DISABLE_ALL_FLOAT
 /**
  @brief Add a double-precision floating-point number to the encoded output.
 
@@ -690,6 +697,7 @@
 static void QCBOREncode_AddFloatNoPreferredToMap(QCBOREncodeContext *pCtx, const char *szLabel, float fNum);
 
 static void QCBOREncode_AddFloatNoPreferredToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, float fNum);
+#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
 
 
 /**
@@ -2215,6 +2223,7 @@
 }
 
 
+#ifndef USEFULBUF_DISABLE_ALL_FLOAT
 static inline void
 QCBOREncode_AddDoubleToMap(QCBOREncodeContext *pMe, const char *szLabel, double dNum)
 {
@@ -2270,6 +2279,7 @@
    QCBOREncode_AddInt64(pMe, nLabel);
    QCBOREncode_AddFloatNoPreferred(pMe, dNum);
 }
+#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
 
 
 
diff --git a/inc/qcbor/qcbor_private.h b/inc/qcbor/qcbor_private.h
index abd6ba2..9f189e6 100644
--- a/inc/qcbor/qcbor_private.h
+++ b/inc/qcbor/qcbor_private.h
@@ -1,6 +1,7 @@
 /*==============================================================================
  Copyright (c) 2016-2018, The Linux Foundation.
  Copyright (c) 2018-2021, Laurence Lundblade.
+ Copyright (c) 2021, Arm Limited.
  All rights reserved.
 
  Redistribution and use in source and binary forms, with or without
@@ -73,6 +74,55 @@
 /* The number of tags (of any size) recorded for an individual item. */
 #define QCBOR_MAX_TAGS_PER_ITEM1 4
 
+/*
+ Convenience macro for selecting the proper return value in case floating
+ point feature(s) are disabled.
+
+ The macros:
+
+   FLOAT_ERR_CODE_NO_FLOAT(x) Can be used when disabled floating point should
+                              result error, and all other cases should return
+                              'x'.
+
+   The below macros always return QCBOR_ERR_ALL_FLOAT_DISABLED when all floating
+   point is disabled.
+
+   FLOAT_ERR_CODE_NO_HALF_PREC(x) Can be used when disabled preferred float
+                                  results in error, and all other cases should
+                                  return 'x'.
+   FLOAT_ERR_CODE_NO_FLOAT_HW(x) Can be used when disabled hardware floating
+                                 point results in error, and all other cases
+                                 should return 'x'.
+   FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) Can be used when either disabled
+                                              preferred float or disabling
+                                              hardware floating point results in
+                                              error, and all other cases should
+                                              return 'x'.
+ */
+#ifdef USEFULBUF_DISABLE_ALL_FLOAT
+   #define FLOAT_ERR_CODE_NO_FLOAT(x)                 QCBOR_ERR_ALL_FLOAT_DISABLED
+   #define FLOAT_ERR_CODE_NO_HALF_PREC(x)             QCBOR_ERR_ALL_FLOAT_DISABLED
+   #define FLOAT_ERR_CODE_NO_FLOAT_HW(x)              QCBOR_ERR_ALL_FLOAT_DISABLED
+   #define FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) QCBOR_ERR_ALL_FLOAT_DISABLED
+#else /* USEFULBUF_DISABLE_ALL_FLOAT*/
+   #define FLOAT_ERR_CODE_NO_FLOAT(x)     x
+   #ifdef QCBOR_DISABLE_PREFERRED_FLOAT
+      #define FLOAT_ERR_CODE_NO_HALF_PREC(x) QCBOR_ERR_HALF_PRECISION_DISABLED
+      #define FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) QCBOR_ERR_HALF_PRECISION_DISABLED
+   #else /* QCBOR_DISABLE_PREFERRED_FLOAT */
+      #define FLOAT_ERR_CODE_NO_HALF_PREC(x) x
+      #ifdef QCBOR_DISABLE_FLOAT_HW_USE
+         #define FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) QCBOR_ERR_HW_FLOAT_DISABLED
+      #else
+         #define FLOAT_ERR_CODE_NO_HALF_PREC_NO_FLOAT_HW(x) x
+      #endif
+   #endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
+   #ifdef QCBOR_DISABLE_FLOAT_HW_USE
+      #define FLOAT_ERR_CODE_NO_FLOAT_HW(x)  QCBOR_ERR_HW_FLOAT_DISABLED
+   #else /* QCBOR_DISABLE_FLOAT_HW_USE */
+      #define FLOAT_ERR_CODE_NO_FLOAT_HW(x)  x
+   #endif /* QCBOR_DISABLE_FLOAT_HW_USE */
+#endif /*USEFULBUF_DISABLE_ALL_FLOAT*/
 
 
 /*
diff --git a/inc/qcbor/qcbor_spiffy_decode.h b/inc/qcbor/qcbor_spiffy_decode.h
index dcf09a8..c924cdc 100644
--- a/inc/qcbor/qcbor_spiffy_decode.h
+++ b/inc/qcbor/qcbor_spiffy_decode.h
@@ -2,6 +2,7 @@
   qcbor_spiffy_decode.h -- higher-level easier-to-use CBOR decoding.
 
   Copyright (c) 2020-2021, Laurence Lundblade. All rights reserved.
+  Copyright (c) 2021, Arm Limited. All rights reserved.
 
   SPDX-License-Identifier: BSD-3-Clause
 
@@ -244,6 +245,9 @@
  this will set QCBOR_ERR_HALF_PRECISION_DISABLED if
  a half-precision number is encountered.
 
+ If floating-point usage is disabled this will set @ref QCBOR_ERR_ALL_FLOAT_DISABLED
+ if a floating point value is encountered.
+
  See also QCBORDecode_GetInt64ConvertAll() which will perform the same
  conversions as this and a lot more at the cost of adding more object
  code to your executable.
@@ -352,6 +356,9 @@
  this will set QCBOR_ERR_HALF_PRECISION_DISABLED if
  a half-precision number is encountered.
 
+ If floating-point usage is disabled this will set @ref QCBOR_ERR_ALL_FLOAT_DISABLED
+ if a floating point value is encountered.
+
  See also QCBORDecode_GetUInt64Convert() and
  QCBORDecode_GetUInt64ConvertAll().
 */
@@ -455,6 +462,7 @@
 
 
 
+#ifndef USEFULBUF_DISABLE_ALL_FLOAT
 /**
  @brief Decode next item into a double floating-point value.
 
@@ -570,6 +578,7 @@
                                             const char         *szLabel,
                                             uint32_t            uConvertTypes,
                                             double             *pdValue);
+#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
 
 
 
@@ -1022,11 +1031,14 @@
 
  Floating-point dates that are plus infinity, minus infinity or NaN
  (not-a-number) will result in the @ref QCBOR_ERR_DATE_OVERFLOW
- error. If the QCBOR library is compiled with floating-point disabled,
+ error. If the QCBOR library is compiled with hardware floating-point disabled,
  @ref QCBOR_ERR_HW_FLOAT_DISABLED is set. If compiled with preferred
  float disabled, half-precision dates will result in the @ref
  QCBOR_ERR_HALF_PRECISION_DISABLED error.
 
+ If the QCBOR library is compiled with floating-point disabled,
+ @ref QCBOR_ERR_ALL_FLOAT_DISABLED is set.
+
  Please see @ref Decode-Errors-Overview "Decode Errors Overview".
 
  See @ref Tag-Usage for discussion on tag requirements.
@@ -1866,6 +1878,7 @@
 
 
 
+#ifndef USEFULBUF_DISABLE_ALL_FLOAT
 // Semi-private
 void
 QCBORDecode_GetDoubleConvertInternal(QCBORDecodeContext *pMe,
@@ -1954,6 +1967,7 @@
                                        QCBOR_CONVERT_TYPE_FLOAT,
                                        pdValue);
 }
+#endif /* USEFULBUF_DISABLE_ALL_FLOAT */