Fix neg big num off by 1 for decimal fraction conversion to float
diff --git a/inc/qcbor/qcbor_common.h b/inc/qcbor/qcbor_common.h
index 0b630ac..8fafba8 100644
--- a/inc/qcbor/qcbor_common.h
+++ b/inc/qcbor/qcbor_common.h
@@ -30,6 +30,7 @@
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ========================================================================= */
+
#ifndef qcbor_common_h
#define qcbor_common_h
diff --git a/inc/qcbor/qcbor_decode.h b/inc/qcbor/qcbor_decode.h
index f6f8650..f832fd1 100644
--- a/inc/qcbor/qcbor_decode.h
+++ b/inc/qcbor/qcbor_decode.h
@@ -382,34 +382,36 @@
/**
* @anchor expAndMantissa
*
- * This holds the value for big floats and decimal fractions. For big
- * floats, the base for exponentiation is 2. For decimal fractions it
- * is 10. Whether this is a big float or decimal fraction is known by
- * context, usually by @c uDataType in @ref QCBORItem which might be
- * @ref QCBOR_TYPE_DECIMAL_FRACTION, @ref QCBOR_TYPE_BIGFLOAT, ...
+ * This holds the value for big floats and decimal fractions, as an
+ * exponent and mantissa. For big floats the base for exponentiation
+ * is 2. For decimal fractions it is 10. Whether an instance is a big
+ * float or decimal fraction is known by context, usually by @c uDataType
+ * in @ref QCBORItem which might be @ref QCBOR_TYPE_DECIMAL_FRACTION,
+ * @ref QCBOR_TYPE_BIGFLOAT, ...
*
- * The mantissa may be an int64_t or a big number. This is again
+ * The mantissa may be an @c int64_t or a big number. This is again
* determined by context, usually @c uDataType in @ref QCBORItem which
- * might be @ref QCBOR_TYPE_DECIMAL_FRACTION, @ref
- * QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, ... This context indicates
- * the sign of the big number too.
+ * might be @ref QCBOR_TYPE_DECIMAL_FRACTION,
+ * @ref QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM, ... The sign of the
+ * big number also comes from the context
+ * (@ref QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
+ * @ref QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM,...).
*
- * @c bigNum is big endian, network byte order, with the most significant
- * bytes first.
+ * @c bigNum is big endian or network byte order. The most significant
+ * byte is first.
*
- * When @c Mantissa is an @c int64_t, it represents the true value of
- * the mantissa with the offset of 1 for CBOR negative values
- * applied. When it is a negative big number (@ref
- * QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM or @ref
- * QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM , the offset of 1 has NOT been
- * applied (it requires somewhat complex big number arithmetic and may
- * increase the length of the big number). To get the correct value
- * bigNum must be incremented by one before use.
+ * When @c Mantissa is @c int64_t, it represents the true value of the
+ * mantissa with the offset of 1 for CBOR negative values
+ * applied. When it is a negative big number
+ * (@ref QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM or
+ * @ref QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM), the offset of 1 has NOT been
+ * applied (doing so requires somewhat complex big number arithmetic
+ * and may increase the length of the big number). To get the correct
+ * value @c bigNum must be incremented by one before use.
*
* Also see QCBOREncode_AddTDecimalFraction(),
- * QCBOREncode_AddTBigFloat(),
- * QCBOREncode_AddTDecimalFractionBigNum() and
- * QCBOREncode_AddTBigFloatBigNum().
+ * QCBOREncode_AddTBigFloat(), QCBOREncode_AddTDecimalFractionBigNum()
+ * and QCBOREncode_AddTBigFloatBigNum().
*/
typedef struct {
int64_t nExponent;
@@ -514,7 +516,7 @@
uint8_t uSimple;
#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
QCBORExpAndMantissa expAndMantissa;
-#endif /* QCBOR_DISABLE_EXP_AND_MANTISSA */
+#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
uint64_t uTagV; /* Used internally during decoding */
} val;
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 8e3b038..9edcfa3 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -6499,7 +6499,8 @@
case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
- double dMantissa = -QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
+ /* Must subtract 1 for CBOR negative integer offset */
+ double dMantissa = -1-QCBOR_Private_ConvertBigNumToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
*pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
@@ -6859,6 +6860,7 @@
int64_t *pnExponent)
{
QCBORError uErr;
+ uint64_t uMantissa;
if(pMe->uLastError != QCBOR_SUCCESS) {
return;
@@ -6869,8 +6871,6 @@
goto Done;
}
- uint64_t uMantissa;
-
switch (pItem->uDataType) {
case QCBOR_TYPE_DECIMAL_FRACTION:
@@ -6890,7 +6890,7 @@
}
/* Reverse the offset by 1 for type 1 negative value to be consistent
* with big num case below which don't offset because it requires
- * big number arithmetic.
+ * big number arithmetic. This is a bug fix for QCBOR v1.5.
*/
uMantissa--;
*pMantissa = QCBOR_Private_ConvertIntToBigNum(uMantissa, BufferForMantissa);
diff --git a/test/qcbor_decode_tests.c b/test/qcbor_decode_tests.c
index 6cc3db8..429ba3f 100644
--- a/test/qcbor_decode_tests.c
+++ b/test/qcbor_decode_tests.c
@@ -7555,6 +7555,26 @@
FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS))
},
{
+ "Decimal fraction -3/10",
+ {(uint8_t[]){0xC4, 0x82, 0x20, 0x22}, 4},
+ 0,
+ EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW),
+ 0,
+ EXP_AND_MANTISSA_ERROR(QCBOR_ERR_NUMBER_SIGN_CONVERSION),
+ -0.30000000000000004,
+ FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS))
+ },
+ {
+ "Decimal fraction -3/10, neg bignum mantissa",
+ {(uint8_t[]){0xC4, 0x82, 0x20, 0xc3, 0x41, 0x02}, 6},
+ 0,
+ EXP_AND_MANTISSA_ERROR(QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW),
+ 0,
+ EXP_AND_MANTISSA_ERROR(QCBOR_ERR_NUMBER_SIGN_CONVERSION),
+ -0.30000000000000004,
+ FLOAT_ERR_CODE_NO_FLOAT_HW(EXP_AND_MANTISSA_ERROR(QCBOR_SUCCESS))
+ },
+ {
"extreme pos bignum",
{(uint8_t[]){0xc2, 0x59, 0x01, 0x90,
// 50 rows of 8 is 400 digits.
@@ -7790,7 +7810,6 @@
INFINITY,
FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
},
-
};
@@ -7818,6 +7837,10 @@
for(int nIndex = 0; nIndex < nNumTests; nIndex++) {
const struct NumberConversion *pF = &NumberConversions[nIndex];
+ //if(nIndex == 14) {
+ // nIndex = 12;
+ //}
+
// Set up the decoding context including a memory pool so that
// indefinite length items can be checked
QCBORDecodeContext DCtx;