blob: 571c1ba5334b3a470ccb6d373ff35ae3d4af4cd2 [file] [log] [blame]
/* ==========================================================================
* qcbor_number_decode.c -- Number decoding beyond the basic ints and floats
*
* Copyright (c) 2016-2018, The Linux Foundation.
* Copyright (c) 2018-2024, Laurence Lundblade.
* Copyright (c) 2021, Arm Limited.
* All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*
* See BSD-3-Clause license in README.md
*
* Forked from qcbor_decode.c on 11/14/24.
* ========================================================================== */
#include "qcbor/qcbor_number_decode.h"
#include "qcbor/qcbor_spiffy_decode.h"
#include "qcbor/qcbor_tag_decode.h"
#include "ieee754.h" /* Does not use math.h */
#ifndef QCBOR_DISABLE_FLOAT_HW_USE
#include <math.h> /* For isnan(), llround(), llroudf(), round(), roundf(),
* pow(), exp2()
*/
#include <fenv.h> /* feclearexcept(), fetestexcept() */
#endif /* ! QCBOR_DISABLE_FLOAT_HW_USE */
/* Order of stuff here is
* Simple conversions between ints and floats
* Complicated conversions involving big numbers, mantissa and exponent
* Big number decoding
* Mantissa and exponent decoding
*/
#if (defined(__GNUC__) && !defined(__clang__))
/*
* This is how the -Wmaybe-uninitialized compiler warning is
* handled. It can’t be ignored because some version of gcc enable it
* with -Wall which is a common and useful gcc warning option. It also
* can’t be ignored because it is the goal of QCBOR to compile clean
* out of the box in all environments.
*
* The big problem with -Wmaybe-uninitialized is that it generates
* false positives. It complains things are uninitialized when they
* are not. This is because it is not a thorough static analyzer. This
* is why “maybe” is in its name. The problem is it is just not
* thorough enough to understand all the code (and someone saw fit to
* put it in gcc and worse to enable it with -Wall).
*
* One solution would be to change the code so -Wmaybe-uninitialized
* doesn’t get confused, for example adding an unnecessary extra
* initialization to zero. (If variables were truly uninitialized, the
* correct path is to understand the code thoroughly and set them to
* the correct value at the correct time; in essence this is already
* done; -Wmaybe-uninitialized just can’t tell). This path is not
* taken because it makes the code bigger and is kind of the tail
* wagging the dog.
*
* The solution here is to just use a pragma to disable it for the
* whole file. Disabling it for each line makes the code fairly ugly
* requiring #pragma to push, pop and ignore. Another reason is the
* warnings issues vary by version of gcc and which optimization
* optimizations are selected. Another reason is that compilers other
* than gcc don’t have -Wmaybe-uninitialized.
*
* One may ask how to be sure these warnings are false positives and
* not real issues. 1) The code has been read carefully to check. 2)
* Testing is pretty thorough. 3) This code has been run through
* thorough high-quality static analyzers.
*
* In particularly, most of the warnings are about
* Item.Item->uDataType being uninitialized. QCBORDecode_GetNext()
* *always* sets this value and test case confirm
* this. -Wmaybe-uninitialized just can't tell.
*
* https://stackoverflow.com/questions/5080848/disable-gcc-may-be-used-uninitialized-on-a-particular-variable
*/
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
/**
* @brief Convert integers and floats to an int64_t.
*
* @param[in] pItem The item to convert.
* @param[in] uConvertTypes See @ref QCBORDecodeNumberConvert.
* @param[out] pnValue The resulting converted value.
*
* @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
* in uConvertTypes.
* @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
* @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
* or too small.
*/
static QCBORError
QCBOR_Private_ConvertInt64(const QCBORItem *pItem,
const enum QCBORDecodeNumberConvert uConvertTypes,
int64_t *pnValue)
{
switch(pItem->uDataType) {
case QCBOR_TYPE_FLOAT:
case QCBOR_TYPE_DOUBLE:
#ifndef QCBOR_DISABLE_FLOAT_HW_USE
if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
/* https://pubs.opengroup.org/onlinepubs/009695399/functions/llround.html
http://www.cplusplus.com/reference/cmath/llround/
*/
// Not interested in FE_INEXACT
feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
*pnValue = llround(pItem->val.dfnum);
} else {
*pnValue = lroundf(pItem->val.fnum);
}
if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
// llround() shouldn't result in divide by zero, but catch
// it here in case it unexpectedly does. Don't try to
// distinguish between the various exceptions because it seems
// they vary by CPU, compiler and OS.
return QCBOR_ERR_FLOAT_EXCEPTION;
}
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
#else /* ! QCBOR_DISABLE_FLOAT_HW_USE */
return QCBOR_ERR_HW_FLOAT_DISABLED;
#endif /* ! QCBOR_DISABLE_FLOAT_HW_USE */
break;
case QCBOR_TYPE_INT64:
if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
*pnValue = pItem->val.int64;
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
case QCBOR_TYPE_UINT64:
if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
if(pItem->val.uint64 < INT64_MAX) {
*pnValue = pItem->val.int64;
} else {
return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
}
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
case QCBOR_TYPE_65BIT_NEG_INT:
/* This type occurs if the value won't fit into int64_t
* so this is always an error. */
return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
break;
default:
return QCBOR_ERR_UNEXPECTED_TYPE;
}
return QCBOR_SUCCESS;
}
/**
* @brief Almost-public method to decode a number and convert to int64_t (semi-private).
*
* @param[in] pMe The decode context.
* @param[in] uConvertTypes See @ref QCBORDecodeNumberConvert.
* @param[out] pnValue Result of the conversion.
* @param[in,out] pItem Temporary space to store Item, returned item.
*
* See QCBORDecode_GetInt64Convert().
*/
void
QCBORDecode_Private_GetInt64Convert(QCBORDecodeContext *pMe,
const enum QCBORDecodeNumberConvert uConvertTypes,
int64_t *pnValue,
QCBORItem *pItem)
{
QCBORDecode_VGetNext(pMe, pItem);
if(pMe->uLastError) {
return;
}
pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
uConvertTypes,
pnValue);
}
/**
* @brief Almost-public method to decode a number and convert to int64_t (semi-private).
*
* @param[in] pMe The decode context.
* @param[in] nLabel Label to find in map.
* @param[in] uConvertTypes See @ref QCBORDecodeNumberConvert.
* @param[out] pnValue Result of the conversion.
* @param[in,out] pItem Temporary space to store Item, returned item.
*
* See QCBORDecode_GetInt64ConvertInMapN().
*/
void
QCBORDecode_Private_GetInt64ConvertInMapN(QCBORDecodeContext *pMe,
const int64_t nLabel,
const enum QCBORDecodeNumberConvert uConvertTypes,
int64_t *pnValue,
QCBORItem *pItem)
{
QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
if(pMe->uLastError != QCBOR_SUCCESS) {
return;
}
pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
uConvertTypes,
pnValue);
}
/**
* @brief Almost-public method to decode a number and convert to int64_t (semi-private).
*
* @param[in] pMe The decode context.
* @param[in] szLabel Label to find in map.
* @param[in] uConvertTypes See @ref QCBORDecodeNumberConvert.
* @param[out] pnValue Result of the conversion.
* @param[in,out] pItem Temporary space to store Item, returned item.
*
* See QCBORDecode_GetInt64ConvertInMapSZ().
*/
void
QCBORDecode_Private_GetInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
const char *szLabel,
const enum QCBORDecodeNumberConvert uConvertTypes,
int64_t *pnValue,
QCBORItem *pItem)
{
QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
if(pMe->uLastError != QCBOR_SUCCESS) {
return;
}
pMe->uLastError = (uint8_t)QCBOR_Private_ConvertInt64(pItem,
uConvertTypes,
pnValue);
}
/**
* @brief Convert many number types to an uint64_t.
*
* @param[in] pItem The item to convert.
* @param[in] uConvertTypes See @ref QCBORDecodeNumberConvert.
* @param[out] puValue The resulting converted value.
*
* @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
* in uConvertTypes.
* @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
* @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
* or too small.
*/
static QCBORError
QCBOR_Private_ConvertUInt64(const QCBORItem *pItem,
const enum QCBORDecodeNumberConvert uConvertTypes,
uint64_t *puValue)
{
switch(pItem->uDataType) {
case QCBOR_TYPE_DOUBLE:
case QCBOR_TYPE_FLOAT:
#ifndef QCBOR_DISABLE_FLOAT_HW_USE
if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
// Can't use llround here because it will not convert values
// greater than INT64_MAX and less than UINT64_MAX that
// need to be converted so it is more complicated.
feclearexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO);
if(pItem->uDataType == QCBOR_TYPE_DOUBLE) {
if(isnan(pItem->val.dfnum)) {
return QCBOR_ERR_FLOAT_EXCEPTION;
} else if(pItem->val.dfnum < 0) {
return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
} else {
double dRounded = round(pItem->val.dfnum);
// See discussion in DecodeDateEpoch() for
// explanation of - 0x7ff
if(dRounded > (double)(UINT64_MAX- 0x7ff)) {
return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
}
*puValue = (uint64_t)dRounded;
}
} else {
if(isnan(pItem->val.fnum)) {
return QCBOR_ERR_FLOAT_EXCEPTION;
} else if(pItem->val.fnum < 0) {
return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
} else {
float fRounded = roundf(pItem->val.fnum);
// See discussion in DecodeDateEpoch() for
// explanation of - 0x7ff
if(fRounded > (float)(UINT64_MAX- 0x7ff)) {
return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
}
*puValue = (uint64_t)fRounded;
}
}
if(fetestexcept(FE_INVALID|FE_OVERFLOW|FE_UNDERFLOW|FE_DIVBYZERO)) {
// round() and roundf() shouldn't result in exceptions here, but
// catch them to be robust and thorough. Don't try to
// distinguish between the various exceptions because it seems
// they vary by CPU, compiler and OS.
return QCBOR_ERR_FLOAT_EXCEPTION;
}
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
#else /* ! QCBOR_DISABLE_FLOAT_HW_USE */
return QCBOR_ERR_HW_FLOAT_DISABLED;
#endif /* ! QCBOR_DISABLE_FLOAT_HW_USE */
break;
case QCBOR_TYPE_INT64:
if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
if(pItem->val.int64 >= 0) {
*puValue = (uint64_t)pItem->val.int64;
} else {
return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
}
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
case QCBOR_TYPE_UINT64:
if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
*puValue = pItem->val.uint64;
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
case QCBOR_TYPE_65BIT_NEG_INT:
return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
default:
return QCBOR_ERR_UNEXPECTED_TYPE;
}
return QCBOR_SUCCESS;
}
/**
* @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
*
* @param[in] pMe The decode context.
* @param[in] uConvertTypes See @ref QCBORDecodeNumberConvert.
* @param[out] puValue Result of the conversion.
* @param[in,out] pItem Temporary space to store Item, returned item.
*
* See QCBORDecode_GetUInt64Convert().
*/
void
QCBORDecode_Private_GetUInt64Convert(QCBORDecodeContext *pMe,
const enum QCBORDecodeNumberConvert uConvertTypes,
uint64_t *puValue,
QCBORItem *pItem)
{
QCBORDecode_VGetNext(pMe, pItem);
if(pMe->uLastError) {
return;
}
pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
uConvertTypes,
puValue);
}
/**
* @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
*
* @param[in] pMe The decode context.
* @param[in] nLabel Label to find in map.
* @param[in] uConvertTypes See @ref QCBORDecodeNumberConvert.
* @param[out] puValue Result of the conversion.
* @param[in,out] pItem Temporary space to store Item, returned item.
*
* See QCBORDecode_GetUInt64ConvertInMapN().
*/
void
QCBORDecode_Private_GetUInt64ConvertInMapN(QCBORDecodeContext *pMe,
const int64_t nLabel,
const enum QCBORDecodeNumberConvert uConvertTypes,
uint64_t *puValue,
QCBORItem *pItem)
{
QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
if(pMe->uLastError != QCBOR_SUCCESS) {
return;
}
pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
uConvertTypes,
puValue);
}
/**
* @brief Almost-public method to decode a number and convert to uint64_t (semi-private).
*
* @param[in] pMe The decode context.
* @param[in] szLabel Label to find in map.
* @param[in] uConvertTypes See @ref QCBORDecodeNumberConvert.
* @param[out] puValue Result of the conversion.
* @param[in,out] pItem Temporary space to store Item, returned item.
*
* See QCBORDecode_GetUInt64ConvertInMapSZ().
*/
void
QCBORDecode_Private_GetUInt64ConvertInMapSZ(QCBORDecodeContext *pMe,
const char *szLabel,
const enum QCBORDecodeNumberConvert uConvertTypes,
uint64_t *puValue,
QCBORItem *pItem)
{
QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
if(pMe->uLastError != QCBOR_SUCCESS) {
return;
}
pMe->uLastError = (uint8_t)QCBOR_Private_ConvertUInt64(pItem,
uConvertTypes,
puValue);
}
#ifndef USEFULBUF_DISABLE_ALL_FLOAT
/**
* @brief Basic conversions to a double.
*
* @param[in] pItem The item to convert
* @param[in] uConvertTypes See @ref QCBORDecodeNumberConvert.
* @param[out] pdValue The value converted to a double
*
* This does the conversions that don't need much object code,
* the conversions from int, uint and float to double.
*
* See QCBOR_Private_DoubleConvertAll() for the full set
* of conversions.
*/
static QCBORError
QCBOR_Private_ConvertDouble(const QCBORItem *pItem,
const enum QCBORDecodeNumberConvert uConvertTypes,
double *pdValue)
{
switch(pItem->uDataType) {
case QCBOR_TYPE_FLOAT:
#ifndef QCBOR_DISABLE_FLOAT_HW_USE
if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
// Simple cast does the job.
*pdValue = (double)pItem->val.fnum;
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
}
#else /* ! QCBOR_DISABLE_FLOAT_HW_USE */
return QCBOR_ERR_HW_FLOAT_DISABLED;
#endif /* ! QCBOR_DISABLE_FLOAT_HW_USE */
break;
case QCBOR_TYPE_DOUBLE:
if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
if(uConvertTypes & QCBOR_CONVERT_TYPE_FLOAT) {
*pdValue = pItem->val.dfnum;
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
}
break;
case QCBOR_TYPE_INT64:
#ifndef QCBOR_DISABLE_FLOAT_HW_USE
if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
// A simple cast seems to do the job with no worry of exceptions.
// There will be precision loss for some values.
*pdValue = (double)pItem->val.int64;
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
#else /* ! QCBOR_DISABLE_FLOAT_HW_USE */
return QCBOR_ERR_HW_FLOAT_DISABLED;
#endif /* ! QCBOR_DISABLE_FLOAT_HW_USE */
break;
case QCBOR_TYPE_UINT64:
#ifndef QCBOR_DISABLE_FLOAT_HW_USE
if(uConvertTypes & QCBOR_CONVERT_TYPE_XINT64) {
// A simple cast seems to do the job with no worry of exceptions.
// There will be precision loss for some values.
*pdValue = (double)pItem->val.uint64;
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
#else /* ! QCBOR_DISABLE_FLOAT_HW_USE */
return QCBOR_ERR_HW_FLOAT_DISABLED;
#endif /* ! QCBOR_DISABLE_FLOAT_HW_USE */
case QCBOR_TYPE_65BIT_NEG_INT:
#ifndef QCBOR_DISABLE_FLOAT_HW_USE
// TODO: don't use float HW. We have the function to do it.
*pdValue = -(double)pItem->val.uint64 - 1;
break;
#else /* ! QCBOR_DISABLE_FLOAT_HW_USE */
return QCBOR_ERR_HW_FLOAT_DISABLED;
#endif /* ! QCBOR_DISABLE_FLOAT_HW_USE */
default:
return QCBOR_ERR_UNEXPECTED_TYPE;
}
return QCBOR_SUCCESS;
}
/**
* @brief Almost-public method to decode a number and convert to double (semi-private).
*
* @param[in] pMe The decode context.
* @param[in] uConvertTypes Bit mask list of conversion options
* @param[out] pdValue The output of the conversion.
* @param[in,out] pItem Temporary space to store Item, returned item.
*
* See QCBORDecode_GetDoubleConvert().
*/
void
QCBORDecode_Private_GetDoubleConvert(QCBORDecodeContext *pMe,
const enum QCBORDecodeNumberConvert uConvertTypes,
double *pdValue,
QCBORItem *pItem)
{
QCBORDecode_VGetNext(pMe, pItem);
if(pMe->uLastError) {
return;
}
pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
uConvertTypes,
pdValue);
}
/**
* @brief Almost-public method to decode a number and convert to double (semi-private).
*
* @param[in] pMe The decode context.
* @param[in] nLabel Label to find in map.
* @param[in] uConvertTypes See @ref QCBORDecodeNumberConvert.
* @param[out] pdValue The output of the conversion.
* @param[in,out] pItem Temporary space to store Item, returned item.
*
* See QCBORDecode_GetDoubleConvertInMapN().
*/
void
QCBORDecode_Private_GetDoubleConvertInMapN(QCBORDecodeContext *pMe,
const int64_t nLabel,
const enum QCBORDecodeNumberConvert uConvertTypes,
double *pdValue,
QCBORItem *pItem)
{
QCBORDecode_GetItemInMapN(pMe, nLabel, QCBOR_TYPE_ANY, pItem);
if(pMe->uLastError != QCBOR_SUCCESS) {
return;
}
pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
uConvertTypes,
pdValue);
}
/**
* @brief Almost-public method to decode a number and convert to double (semi-private).
*
* @param[in] pMe The decode context.
* @param[in] szLabel Label to find in map.
* @param[in] uConvertTypes See @ref QCBORDecodeNumberConvert.
* @param[out] pdValue The output of the conversion.
* @param[in,out] pItem Temporary space to store Item, returned item.
*
* See QCBORDecode_GetDoubleConvertInMapSZ().
*/
void
QCBORDecode_Private_GetDoubleConvertInMapSZ(QCBORDecodeContext *pMe,
const char *szLabel,
const enum QCBORDecodeNumberConvert uConvertTypes,
double *pdValue,
QCBORItem *pItem)
{
QCBORDecode_GetItemInMapSZ(pMe, szLabel, QCBOR_TYPE_ANY, pItem);
if(pMe->uLastError != QCBOR_SUCCESS) {
return;
}
pMe->uLastError = (uint8_t)QCBOR_Private_ConvertDouble(pItem,
uConvertTypes,
pdValue);
}
#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetNumberConvertPrecisely(QCBORDecodeContext *pMe,
QCBORItem *pNumber)
{
QCBORItem Item;
struct IEEE754_ToInt ToInt;
double dNum;
QCBORError uError;
if(pMe->uLastError != QCBOR_SUCCESS) {
return;
}
// TODO:VGetNext?
uError = QCBORDecode_GetNext(pMe, &Item);
if(uError != QCBOR_SUCCESS) {
*pNumber = Item;
pMe->uLastError = (uint8_t)uError;
return;
}
switch(Item.uDataType) {
case QCBOR_TYPE_INT64:
case QCBOR_TYPE_UINT64:
*pNumber = Item;
break;
case QCBOR_TYPE_DOUBLE:
ToInt = IEEE754_DoubleToInt(Item.val.dfnum);
if(ToInt.type == IEEE754_ToInt_IS_INT) {
pNumber->uDataType = QCBOR_TYPE_INT64;
pNumber->val.int64 = ToInt.integer.is_signed;
} else if(ToInt.type == IEEE754_ToInt_IS_UINT) {
if(ToInt.integer.un_signed <= INT64_MAX) {
/* Do the same as base QCBOR integer decoding */
pNumber->uDataType = QCBOR_TYPE_INT64;
pNumber->val.int64 = (int64_t)ToInt.integer.un_signed;
} else {
pNumber->uDataType = QCBOR_TYPE_UINT64;
pNumber->val.uint64 = ToInt.integer.un_signed;
}
} else {
*pNumber = Item;
}
break;
case QCBOR_TYPE_FLOAT:
ToInt = IEEE754_SingleToInt(Item.val.fnum);
if(ToInt.type == IEEE754_ToInt_IS_INT) {
pNumber->uDataType = QCBOR_TYPE_INT64;
pNumber->val.int64 = ToInt.integer.is_signed;
} else if(ToInt.type == IEEE754_ToInt_IS_UINT) {
if(ToInt.integer.un_signed <= INT64_MAX) {
/* Do the same as base QCBOR integer decoding */
pNumber->uDataType = QCBOR_TYPE_INT64;
pNumber->val.int64 = (int64_t)ToInt.integer.un_signed;
} else {
pNumber->uDataType = QCBOR_TYPE_UINT64;
pNumber->val.uint64 = ToInt.integer.un_signed;
}
} else {
*pNumber = Item;
}
break;
case QCBOR_TYPE_65BIT_NEG_INT:
if(Item.val.uint64 == UINT64_MAX) {
/* The value -18446744073709551616 is encoded as an
* unsigned 18446744073709551615. It's a whole number that
* needs to be returned as a double. It can't be handled
* by IEEE754_UintToDouble because 18446744073709551616
* doesn't fit into a uint64_t. You can't get it by adding
* 1 to 18446744073709551615.
*/
pNumber->val.dfnum = -18446744073709551616.0;
pNumber->uDataType = QCBOR_TYPE_DOUBLE;
} else {
dNum = IEEE754_UintToDouble(Item.val.uint64 + 1, 1);
if(dNum == IEEE754_UINT_TO_DOUBLE_OOB) {
*pNumber = Item;
} else {
pNumber->val.dfnum = dNum;
pNumber->uDataType = QCBOR_TYPE_DOUBLE;
}
}
break;
default:
pMe->uLastError = QCBOR_ERR_UNEXPECTED_TYPE;
pNumber->uDataType = QCBOR_TYPE_NONE;
break;
}
}
#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */
#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
/**
* @brief Prototype for conversion of exponent and mantissa to unsigned integer.
*
* @param[in] uMantissa The mantissa.
* @param[in] nExponent The exponent.
* @param[out] puResult The resulting integer.
*
* Concrete implementations of this are for exponent base 10 and 2 supporting
* decimal fractions and big floats.
*/
typedef QCBORError (*fExponentiator)(uint64_t uMantissa, int64_t nExponent, uint64_t *puResult);
/**
* @brief Base 10 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
*
* @param[in] uMantissa The unsigned integer mantissa.
* @param[in] nExponent The signed integer exponent.
* @param[out] puResult Place to return the unsigned integer result.
*
* This computes: mantissa * 10 ^^ exponent as for a decimal fraction. The output is a 64-bit
* unsigned integer.
*
* There are many inputs for which the result will not fit in the
* 64-bit integer and @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
* be returned.
*/
static QCBORError
QCBOR_Private_Exponentitate10(const uint64_t uMantissa,
int64_t nExponent,
uint64_t *puResult)
{
uint64_t uResult = uMantissa;
if(uResult != 0) {
/* This loop will run a maximum of 19 times because
* UINT64_MAX < 10 ^^ 19. More than that will cause
* exit with the overflow error
*/
for(; nExponent > 0; nExponent--) {
if(uResult > UINT64_MAX / 10) {
return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
}
uResult = uResult * 10;
}
for(; nExponent < 0; nExponent++) {
uResult = uResult / 10;
if(uResult == 0) {
return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
}
}
}
/* else, mantissa is zero so this returns zero */
*puResult = uResult;
return QCBOR_SUCCESS;
}
/**
* @brief Base 2 exponentiate a mantissa and exponent into an unsigned 64-bit integer.
*
* @param[in] uMantissa The unsigned integer mantissa.
* @param[in] nExponent The signed integer exponent.
* @param[out] puResult Place to return the unsigned integer result.
*
* This computes: mantissa * 2 ^^ exponent as for a big float. The
* output is a 64-bit unsigned integer.
*
* There are many inputs for which the result will not fit in the
* 64-bit integer and @ref QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW will
* be returned.
*/
static QCBORError
QCBOR_Private_Exponentitate2(const uint64_t uMantissa,
int64_t nExponent,
uint64_t *puResult)
{
uint64_t uResult;
uResult = uMantissa;
/* This loop will run a maximum of 64 times because INT64_MAX <
* 2^31. More than that will cause exit with the overflow error
*/
while(nExponent > 0) {
if(uResult > UINT64_MAX >> 1) {
return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
}
uResult = uResult << 1;
nExponent--;
}
while(nExponent < 0 ) {
if(uResult == 0) {
return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
}
uResult = uResult >> 1;
nExponent++;
}
*puResult = uResult;
return QCBOR_SUCCESS;
}
/**
* @brief Exponentiate a signed mantissa and signed exponent to produce a signed result.
*
* @param[in] nMantissa Signed integer mantissa.
* @param[in] nExponent Signed integer exponent.
* @param[out] pnResult Place to put the signed integer result.
* @param[in] pfExp Exponentiation function.
*
* @returns Error code
*
* @c pfExp performs exponentiation on and unsigned mantissa and
* produces an unsigned result. This converts the mantissa from signed
* and converts the result to signed. The exponentiation function is
* either for base 2 or base 10 (and could be other if needed).
*/
static QCBORError
QCBOR_Private_ExponentiateNN(const int64_t nMantissa,
const int64_t nExponent,
int64_t *pnResult,
fExponentiator pfExp)
{
uint64_t uResult;
uint64_t uMantissa;
/* Take the absolute value and put it into an unsigned. */
if(nMantissa >= 0) {
/* Positive case is straightforward */
uMantissa = (uint64_t)nMantissa;
} else if(nMantissa != INT64_MIN) {
/* The common negative case. See next. */
uMantissa = (uint64_t)-nMantissa;
} else {
/* int64_t and uint64_t are always two's complement per the
* C standard (and since QCBOR uses these it only works with
* two's complement, which is pretty much universal these
* days). The range of a negative two's complement integer is
* one more that than a positive, so the simple code above might
* not work all the time because you can't simply negate the
* value INT64_MIN because it can't be represented in an
* int64_t. -INT64_MIN can however be represented in a
* uint64_t. Some compilers seem to recognize this case for the
* above code and put the correct value in uMantissa, however
* they are not required to do this by the C standard. This next
* line does however work for all compilers.
*
* This does assume two's complement where -INT64_MIN ==
* INT64_MAX + 1 (which wouldn't be true for one's complement or
* sign and magnitude (but we know we're using two's complement
* because int64_t requires it)).
*
* See these, particularly the detailed commentary:
* https://stackoverflow.com/questions/54915742/does-c99-mandate-a-int64-t-type-be-available-always
* https://stackoverflow.com/questions/37301078/is-negating-int-min-undefined-behaviour
*/
uMantissa = (uint64_t)INT64_MAX+1;
}
/* Call the exponentiator passed for either base 2 or base 10.
* Here is where most of the overflow errors are caught. */
QCBORError uReturn = (*pfExp)(uMantissa, nExponent, &uResult);
if(uReturn) {
return uReturn;
}
/* Convert back to the sign of the original mantissa */
if(nMantissa >= 0) {
if(uResult > INT64_MAX) {
return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
}
*pnResult = (int64_t)uResult;
} else {
/* (uint64_t)INT64_MAX+1 is used to represent the absolute value
* of INT64_MIN. This assumes two's compliment representation
* where INT64_MIN is one increment farther from 0 than
* INT64_MAX. Trying to write -INT64_MIN doesn't work to get
* this because the compiler makes it an int64_t which can't
* represent -INT64_MIN. Also see above.
*/
if(uResult > (uint64_t)INT64_MAX+1) {
return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
}
*pnResult = -(int64_t)uResult;
}
return QCBOR_SUCCESS;
}
/**
* @brief Exponentiate an unsigned mantissa and signed exponent to produce an unsigned result.
*
* @param[in] nMantissa Signed integer mantissa.
* @param[in] nExponent Signed integer exponent.
* @param[out] puResult Place to put the signed integer result.
* @param[in] pfExp Exponentiation function.
*
* @returns Error code
*
* @c pfExp performs exponentiation on and unsigned mantissa and
* produces an unsigned result. This errors out if the mantissa
* is negative because the output is unsigned.
*/
static QCBORError
QCBOR_Private_ExponentitateNU(const int64_t nMantissa,
const int64_t nExponent,
uint64_t *puResult,
fExponentiator pfExp)
{
if(nMantissa < 0) {
return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
}
/* Cast to unsigned is OK because of check for negative.
* Cast to unsigned is OK because UINT64_MAX > INT64_MAX.
* Exponentiation is straight forward
*/
return (*pfExp)((uint64_t)nMantissa, nExponent, puResult);
}
/**
* @brief Exponentiate an usnigned mantissa and unsigned exponent to produce an unsigned result.
*
* @param[in] uMantissa Unsigned integer mantissa.
* @param[in] nExponent Unsigned integer exponent.
* @param[out] puResult Place to put the unsigned integer result.
* @param[in] pfExp Exponentiation function.
*
* @returns Error code
*
* @c pfExp performs exponentiation on and unsigned mantissa and
* produces an unsigned result so this is just a wrapper that does
* nothing (and is likely inlined).
*/
static QCBORError
QCBOR_Private_ExponentitateUU(const uint64_t uMantissa,
const int64_t nExponent,
uint64_t *puResult,
fExponentiator pfExp)
{
return (*pfExp)(uMantissa, nExponent, puResult);
}
#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
/**
* @brief Convert a CBOR big number to a uint64_t.
*
* @param[in] BigNumber Bytes of the big number to convert.
* @param[in] uMax Maximum value allowed for the result.
* @param[out] pResult Place to put the unsigned integer result.
*
* @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW When the bignumber is
* too large to fit
* @retval QCBOR_SUCCESS The conversion succeeded.
*
* Many values will overflow because a big number can represent a much
* larger range than uint64_t.
*/
static QCBORError
QCBORDecode_Private_BigNumberToUInt(const UsefulBufC BigNumber,
const uint64_t uMax,
uint64_t *pResult)
{
uint64_t uResult;
size_t uLen;
const uint8_t *pByte = BigNumber.ptr;
uResult = 0;
for(uLen = BigNumber.len; uLen > 0; uLen--) {
if(uResult > (uMax >> 8)) {
return QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
}
uResult = (uResult << 8) + *pByte++;
}
*pResult = uResult;
return QCBOR_SUCCESS;
}
/**
* @brief Convert a CBOR postive big number to a uint64_t.
*
* @param[in] BigNumber Bytes of the big number to convert.
* @param[out] pResult Place to put the unsigned integer result.
*
* @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW When the bignumber is
* too large to fit
* @retval QCBOR_SUCCESS The conversion succeeded.
*
* Many values will overflow because a big num can represent a much
* larger range than uint64_t.
*/
static QCBORError
QCBORDecode_Private_PositiveBigNumberToUInt(const UsefulBufC BigNumber,
uint64_t *pResult)
{
return QCBORDecode_Private_BigNumberToUInt(BigNumber, UINT64_MAX, pResult);
}
/**
* @brief Convert a CBOR positive big number to an int64_t.
*
* @param[in] BigNumber Bytes of the big number to convert.
* @param[out] pResult Place to put the signed integer result.
*
* @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW When the bignumber is
* too large to fit
* @retval QCBOR_SUCCESS The conversion succeeded.
*
* Many values will overflow because a big num can represent a much
* larger range than int64_t.
*/
static QCBORError
QCBORDecode_Private_PositiveBigNumberToInt(const UsefulBufC BigNumber,
int64_t *pResult)
{
uint64_t uResult;
QCBORError uError;
uError = QCBORDecode_Private_BigNumberToUInt(BigNumber, INT64_MAX, &uResult);
if(uError != QCBOR_SUCCESS) {
return uError;
}
/* Cast safe because QCBORDecode_Private_BigNumberToUInt() limits to INT64_MAX */
*pResult = (int64_t)uResult;
return QCBOR_SUCCESS;
}
/**
* @brief Convert a CBOR negative big number to an int64_t.
*
* @param[in] BigNumber Bytes of the big number to convert.
* @param[out] pnResult Place to put the signed integer result.
*
* @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW When the bignumber is
* too large to fit
* @retval QCBOR_SUCCESS The conversion succeeded.
*
* Many values will overflow because a big num can represent a much
* larger range than int64_t.
*/
static QCBORError
QCBORDecode_Private_NegativeBigNumberToInt(const UsefulBufC BigNumber,
int64_t *pnResult)
{
uint64_t uResult;
QCBORError uError;
/* The negative integer furthest from zero for a C int64_t is
* INT64_MIN which is expressed as -INT64_MAX - 1. The value of a
* negative number in CBOR is computed as -n - 1 where n is the
* encoded integer, where n is what is in the variable BigNum. When
* converting BigNum to a uint64_t, the maximum value is thus
* INT64_MAX, so that when it -n - 1 is applied to it the result
* will never be further from 0 than INT64_MIN.
*
* -n - 1 <= INT64_MIN.
* -n - 1 <= -INT64_MAX - 1
* n <= INT64_MAX.
*/
uError = QCBORDecode_Private_BigNumberToUInt(BigNumber, INT64_MAX, &uResult);
if(uError != QCBOR_SUCCESS) {
return uError;
}
/* Now apply -n - 1. The cast is safe because
* ConvertBigNumToUnsigned() is limited to INT64_MAX which does fit
* is the largest positive integer that an int64_t can
* represent. */
*pnResult = -(int64_t)uResult - 1;
return QCBOR_SUCCESS;
}
/**
* @brief Convert an integer to a big number.
*
* @param[in] uNum The integer to convert.
* @param[in] BigNumberBuf The buffer to output the big number to.
*
* @returns The big number or NULLUsefulBufC is the buffer is to small.
*
* This always succeeds unless the buffer is too small.
*/
static UsefulBufC
QCBORDecode_Private_UIntToBigNumber(uint64_t uNum, const UsefulBuf BigNumberBuf)
{
UsefulOutBuf UOB;
/* With a UsefulOutBuf, there's no pointer math */
UsefulOutBuf_Init(&UOB, BigNumberBuf);
/* Must copy one byte even if zero. The loop, mask and shift
* algorithm provides endian conversion.
*/
do {
UsefulOutBuf_InsertByte(&UOB, uNum & 0xff, 0);
uNum >>= 8;
} while(uNum);
return UsefulOutBuf_OutUBuf(&UOB);
}
#ifndef QCBOR_DISABLE_FLOAT_HW_USE
/**
* @brief Convert a big number to double-precision float.
*
* @param[in] BigNumber The big number to convert.
*
* @returns The double value.
*
* This will always succeed. It will lose precision for larger
* numbers. If the big number is too large to fit (more than
* 1.7976931348623157E+308) infinity will be returned. NaN is never
* returned.
*/
static double
QCBORDecode_Private_BigNumberToDouble(const UsefulBufC BigNumber)
{
double dResult;
size_t uLen;
const uint8_t *pByte = BigNumber.ptr;
dResult = 0.0;
/* This will overflow and become the float value INFINITY if the number
* is too large to fit. */
for(uLen = BigNumber.len; uLen > 0; uLen--){
dResult = (dResult * 256.0) + (double)*pByte++;
}
return dResult;
}
#endif /* ! QCBOR_DISABLE_FLOAT_HW_USE */
/**
* @brief Convert many number types to an int64_t.
*
* @param[in] pItem The item to convert.
* @param[in] uConvertTypes See @ref QCBORDecodeNumberConvert.
* @param[out] pnValue The resulting converted value.
*
* @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
* in uConvertTypes.
* @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
* @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
* or too small.
*/
static QCBORError
QCBOR_Private_Int64ConvertAll(const QCBORItem *pItem,
const enum QCBORDecodeNumberConvert uConvertTypes,
int64_t *pnValue)
{
switch(pItem->uDataType) {
case QCBOR_TYPE_POSBIGNUM:
if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
return QCBORDecode_Private_PositiveBigNumberToInt(pItem->val.bigNum, pnValue);
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
case QCBOR_TYPE_NEGBIGNUM:
if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
return QCBORDecode_Private_NegativeBigNumberToInt(pItem->val.bigNum, pnValue);
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
case QCBOR_TYPE_DECIMAL_FRACTION:
if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
pItem->val.expAndMantissa.nExponent,
pnValue,
&QCBOR_Private_Exponentitate10);
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
case QCBOR_TYPE_BIGFLOAT:
if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
return QCBOR_Private_ExponentiateNN(pItem->val.expAndMantissa.Mantissa.nInt,
pItem->val.expAndMantissa.nExponent,
pnValue,
QCBOR_Private_Exponentitate2);
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
int64_t nMantissa;
QCBORError uErr;
uErr = QCBORDecode_Private_PositiveBigNumberToInt(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
if(uErr) {
return uErr;
}
return QCBOR_Private_ExponentiateNN(nMantissa,
pItem->val.expAndMantissa.nExponent,
pnValue,
QCBOR_Private_Exponentitate10);
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
int64_t nMantissa;
QCBORError uErr;
uErr = QCBORDecode_Private_NegativeBigNumberToInt(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
if(uErr) {
return uErr;
}
return QCBOR_Private_ExponentiateNN(nMantissa,
pItem->val.expAndMantissa.nExponent,
pnValue,
QCBOR_Private_Exponentitate10);
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
case QCBOR_TYPE_BIGFLOAT_POS_BIGMANTISSA:
if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
int64_t nMantissa;
QCBORError uErr;
uErr = QCBORDecode_Private_PositiveBigNumberToInt(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
if(uErr) {
return uErr;
}
return QCBOR_Private_ExponentiateNN(nMantissa,
pItem->val.expAndMantissa.nExponent,
pnValue,
QCBOR_Private_Exponentitate2);
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
case QCBOR_TYPE_BIGFLOAT_NEG_BIGMANTISSA:
if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
int64_t nMantissa;
QCBORError uErr;
uErr = QCBORDecode_Private_NegativeBigNumberToInt(pItem->val.expAndMantissa.Mantissa.bigNum, &nMantissa);
if(uErr) {
return uErr;
}
return QCBOR_Private_ExponentiateNN(nMantissa,
pItem->val.expAndMantissa.nExponent,
pnValue,
QCBOR_Private_Exponentitate2);
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
default:
return QCBOR_ERR_UNEXPECTED_TYPE; }
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetInt64ConvertAll(QCBORDecodeContext *pMe,
const enum QCBORDecodeNumberConvert uConvertTypes,
int64_t *pnValue)
{
QCBORItem Item;
QCBORDecode_Private_GetInt64Convert(pMe, uConvertTypes, pnValue, &Item);
if(pMe->uLastError == QCBOR_SUCCESS) {
// The above conversion succeeded
return;
}
if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
// The above conversion failed in a way that code below can't correct
return;
}
pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
uConvertTypes,
pnValue);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
const int64_t nLabel,
const enum QCBORDecodeNumberConvert uConvertTypes,
int64_t *pnValue)
{
QCBORItem Item;
QCBORDecode_Private_GetInt64ConvertInMapN(pMe,
nLabel,
uConvertTypes,
pnValue,
&Item);
if(pMe->uLastError == QCBOR_SUCCESS) {
// The above conversion succeeded
return;
}
if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
// The above conversion failed in a way that code below can't correct
return;
}
pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
uConvertTypes,
pnValue);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
const char *szLabel,
const enum QCBORDecodeNumberConvert uConvertTypes,
int64_t *pnValue)
{
QCBORItem Item;
QCBORDecode_Private_GetInt64ConvertInMapSZ(pMe,
szLabel,
uConvertTypes,
pnValue,
&Item);
if(pMe->uLastError == QCBOR_SUCCESS) {
// The above conversion succeeded
return;
}
if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
// The above conversion failed in a way that code below can't correct
return;
}
pMe->uLastError = (uint8_t)QCBOR_Private_Int64ConvertAll(&Item,
uConvertTypes,
pnValue);
}
/**
* @brief Convert many number types to an unt64_t.
*
* @param[in] pItem The item to convert.
* @param[in] uConvertTypes See @ref QCBORDecodeNumberConvert.
* @param[out] puValue The resulting converted value.
*
* @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
* in uConvertTypes.
* @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
* @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
* or too small.
*/
static QCBORError
QCBOR_Private_UInt64ConvertAll(const QCBORItem *pItem,
const enum QCBORDecodeNumberConvert uConvertTypes,
uint64_t *puValue)
{
switch(pItem->uDataType) { /* -Wmaybe-uninitialized falsly warns here */
case QCBOR_TYPE_POSBIGNUM:
if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
return QCBORDecode_Private_PositiveBigNumberToUInt(pItem->val.bigNum, puValue);
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
case QCBOR_TYPE_NEGBIGNUM:
if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
case QCBOR_TYPE_DECIMAL_FRACTION:
if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
pItem->val.expAndMantissa.nExponent,
puValue,
QCBOR_Private_Exponentitate10);
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
case QCBOR_TYPE_BIGFLOAT:
if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
return QCBOR_Private_ExponentitateNU(pItem->val.expAndMantissa.Mantissa.nInt,
pItem->val.expAndMantissa.nExponent,
puValue,
QCBOR_Private_Exponentitate2);
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
uint64_t uMantissa;
QCBORError uErr;
uErr = QCBORDecode_Private_PositiveBigNumberToUInt(pItem->val.expAndMantissa.Mantissa.bigNum, &uMantissa);
if(uErr != QCBOR_SUCCESS) {
return uErr;
}
return QCBOR_Private_ExponentitateUU(uMantissa,
pItem->val.expAndMantissa.nExponent,
puValue,
QCBOR_Private_Exponentitate10);
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
case QCBOR_TYPE_BIGFLOAT_POS_BIGMANTISSA:
if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
uint64_t uMantissa;
QCBORError uErr;
uErr = QCBORDecode_Private_PositiveBigNumberToUInt(pItem->val.expAndMantissa.Mantissa.bigNum,
&uMantissa);
if(uErr != QCBOR_SUCCESS) {
return uErr;
}
return QCBOR_Private_ExponentitateUU(uMantissa,
pItem->val.expAndMantissa.nExponent,
puValue,
QCBOR_Private_Exponentitate2);
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
case QCBOR_TYPE_BIGFLOAT_NEG_BIGMANTISSA:
if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
return QCBOR_ERR_NUMBER_SIGN_CONVERSION;
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
default:
return QCBOR_ERR_UNEXPECTED_TYPE;
}
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetUInt64ConvertAll(QCBORDecodeContext *pMe,
const enum QCBORDecodeNumberConvert uConvertTypes,
uint64_t *puValue)
{
QCBORItem Item;
QCBORDecode_Private_GetUInt64Convert(pMe, uConvertTypes, puValue, &Item);
if(pMe->uLastError == QCBOR_SUCCESS) {
// The above conversion succeeded
return;
}
if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
// The above conversion failed in a way that code below can't correct
return;
}
pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
uConvertTypes,
puValue);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetUInt64ConvertAllInMapN(QCBORDecodeContext *pMe,
const int64_t nLabel,
const enum QCBORDecodeNumberConvert uConvertTypes,
uint64_t *puValue)
{
QCBORItem Item;
QCBORDecode_Private_GetUInt64ConvertInMapN(pMe,
nLabel,
uConvertTypes,
puValue,
&Item);
if(pMe->uLastError == QCBOR_SUCCESS) {
// The above conversion succeeded
return;
}
if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
// The above conversion failed in a way that code below can't correct
return;
}
pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
uConvertTypes,
puValue);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetUInt64ConvertAllInMapSZ(QCBORDecodeContext *pMe,
const char *szLabel,
const enum QCBORDecodeNumberConvert uConvertTypes,
uint64_t *puValue)
{
QCBORItem Item;
QCBORDecode_Private_GetUInt64ConvertInMapSZ(pMe,
szLabel,
uConvertTypes,
puValue,
&Item);
if(pMe->uLastError == QCBOR_SUCCESS) {
// The above conversion succeeded
return;
}
if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
// The above conversion failed in a way that code below can't correct
return;
}
pMe->uLastError = (uint8_t)QCBOR_Private_UInt64ConvertAll(&Item,
uConvertTypes,
puValue);
}
#ifndef USEFULBUF_DISABLE_ALL_FLOAT
/**
* @brief Convert many number types to a double.
*
* @param[in] pItem The item to convert.
* @param[in] uConvertTypes See @ref QCBORDecodeNumberConvert.
* @param[out] pdValue The resulting converted value.
*
* @retval QCBOR_ERR_UNEXPECTED_TYPE Conversion, possible, but not requested
* in uConvertTypes.
* @retval QCBOR_ERR_UNEXPECTED_TYPE Of a type that can't be converted
* @retval QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW Conversion result is too large
* or too small.
*/
static QCBORError
QCBOR_Private_DoubleConvertAll(const QCBORItem *pItem,
const enum QCBORDecodeNumberConvert uConvertTypes,
double *pdValue)
{
#ifndef QCBOR_DISABLE_FLOAT_HW_USE
/*
* What Every Computer Scientist Should Know About Floating-Point Arithmetic
* https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
*/
switch(pItem->uDataType) {
#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
case QCBOR_TYPE_DECIMAL_FRACTION:
if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
// Underflow gives 0, overflow gives infinity
*pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
pow(10.0, (double)pItem->val.expAndMantissa.nExponent);
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
case QCBOR_TYPE_BIGFLOAT:
if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT ) {
// Underflow gives 0, overflow gives infinity
*pdValue = (double)pItem->val.expAndMantissa.Mantissa.nInt *
exp2((double)pItem->val.expAndMantissa.nExponent);
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
case QCBOR_TYPE_POSBIGNUM:
if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
*pdValue = QCBORDecode_Private_BigNumberToDouble(pItem->val.bigNum);
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
case QCBOR_TYPE_NEGBIGNUM:
if(uConvertTypes & QCBOR_CONVERT_TYPE_BIG_NUM) {
*pdValue = -1-QCBORDecode_Private_BigNumberToDouble(pItem->val.bigNum);
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
double dMantissa = QCBORDecode_Private_BigNumberToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
*pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
if(uConvertTypes & QCBOR_CONVERT_TYPE_DECIMAL_FRACTION) {
/* Must subtract 1 for CBOR negative integer offset */
double dMantissa = -1-QCBORDecode_Private_BigNumberToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
*pdValue = dMantissa * pow(10, (double)pItem->val.expAndMantissa.nExponent);
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
case QCBOR_TYPE_BIGFLOAT_POS_BIGMANTISSA:
if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
double dMantissa = QCBORDecode_Private_BigNumberToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
*pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
case QCBOR_TYPE_BIGFLOAT_NEG_BIGMANTISSA:
if(uConvertTypes & QCBOR_CONVERT_TYPE_BIGFLOAT) {
double dMantissa = -1-QCBORDecode_Private_BigNumberToDouble(pItem->val.expAndMantissa.Mantissa.bigNum);
*pdValue = dMantissa * exp2((double)pItem->val.expAndMantissa.nExponent);
} else {
return QCBOR_ERR_UNEXPECTED_TYPE;
}
break;
#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */
default:
return QCBOR_ERR_UNEXPECTED_TYPE;
}
return QCBOR_SUCCESS;
#else /* ! QCBOR_DISABLE_FLOAT_HW_USE */
(void)pItem;
(void)uConvertTypes;
(void)pdValue;
return QCBOR_ERR_HW_FLOAT_DISABLED;
#endif /* ! QCBOR_DISABLE_FLOAT_HW_USE */
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetDoubleConvertAll(QCBORDecodeContext *pMe,
const enum QCBORDecodeNumberConvert uConvertTypes,
double *pdValue)
{
QCBORItem Item;
QCBORDecode_Private_GetDoubleConvert(pMe, uConvertTypes, pdValue, &Item);
if(pMe->uLastError == QCBOR_SUCCESS) {
// The above conversion succeeded
return;
}
if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
// The above conversion failed in a way that code below can't correct
return;
}
pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
uConvertTypes,
pdValue);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetDoubleConvertAllInMapN(QCBORDecodeContext *pMe,
const int64_t nLabel,
const enum QCBORDecodeNumberConvert uConvertTypes,
double *pdValue)
{
QCBORItem Item;
QCBORDecode_Private_GetDoubleConvertInMapN(pMe,
nLabel,
uConvertTypes,
pdValue,
&Item);
if(pMe->uLastError == QCBOR_SUCCESS) {
// The above conversion succeeded
return;
}
if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
// The above conversion failed in a way that code below can't correct
return;
}
pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
uConvertTypes,
pdValue);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetDoubleConvertAllInMapSZ(QCBORDecodeContext *pMe,
const char *szLabel,
const enum QCBORDecodeNumberConvert uConvertTypes,
double *pdValue)
{
QCBORItem Item;
QCBORDecode_Private_GetDoubleConvertInMapSZ(pMe,
szLabel,
uConvertTypes,
pdValue,
&Item);
if(pMe->uLastError == QCBOR_SUCCESS) {
// The above conversion succeeded
return;
}
if(pMe->uLastError != QCBOR_ERR_UNEXPECTED_TYPE) {
// The above conversion failed in a way that code below can't correct
return;
}
pMe->uLastError = (uint8_t)QCBOR_Private_DoubleConvertAll(&Item,
uConvertTypes,
pdValue);
}
#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */
/* Add one to the big number and put the result in a new UsefulBufC
* from storage in UsefulBuf.
*
* Leading zeros must be removed before calling this.
*
* Code Reviewers: THIS FUNCTION DOES POINTER MATH
*/
static UsefulBufC
QCBORDecode_BigNumberCopyPlusOne(UsefulBufC BigNumber, UsefulBuf BigNumberBuf)
{
uint8_t uCarry;
uint8_t uSourceValue;
const uint8_t *pSource;
uint8_t *pDest;
ptrdiff_t uDestBytesLeft;
/* Start adding at the LSB */
pSource = &((const uint8_t *)BigNumber.ptr)[BigNumber.len-1];
pDest = &((uint8_t *)BigNumberBuf.ptr)[BigNumberBuf.len-1];
uCarry = 1; /* Gets set back to zero if add the next line doesn't wrap */
*pDest = *pSource + 1;
while(1) {
/* Wrap around from 0xff to 0 is a defined operation for
* unsigned addition in C.*/
if(*pDest != 0) {
/* The add operation didn't wrap so no more carry. This
* funciton only adds one, so when there is no more carry,
* carrying is over to the end.
*/
uCarry = 0;
}
uDestBytesLeft = pDest - (uint8_t *)BigNumberBuf.ptr;
if(pSource <= (const uint8_t *)BigNumber.ptr && uCarry == 0) {
break; /* Successful exit */
}
if(pSource > (const uint8_t *)BigNumber.ptr) {
uSourceValue = *--pSource;
} else {
/* All source bytes processed, but not the last carry */
uSourceValue = 0;
}
pDest--;
if(uDestBytesLeft < 0) {
return NULLUsefulBufC; /* Not enough space in destination buffer */
}
*pDest = uSourceValue + uCarry;
}
return (UsefulBufC){pDest, BigNumberBuf.len - (size_t)uDestBytesLeft};
}
/* This returns 1 when uNum is 0 */
static size_t
QCBORDecode_Private_CountNonZeroBytes(uint64_t uNum)
{
size_t uCount = 0;
do {
uCount++;
uNum >>= 8;
} while(uNum);
return uCount;
}
/* Public function, see qcbor/qcbor_number_decode.h */
QCBORError
QCBORDecode_ProcessBigNumberNoPreferred(const QCBORItem Item,
const UsefulBuf BigNumberBuf,
UsefulBufC *pBigNumber,
bool *pbIsNegative)
{
size_t uLen;
UsefulBufC BigNumber;
int uType;
uType = Item.uDataType;
if(uType == QCBOR_TYPE_BYTE_STRING) {
uType = *pbIsNegative ? QCBOR_TYPE_NEGBIGNUM : QCBOR_TYPE_POSBIGNUM;
}
static const uint8_t Zero[] = {0x00};
BigNumber = UsefulBuf_SkipLeading(Item.val.bigNum, 0);
if(BigNumber.len == 0) {
BigNumber = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(Zero);
}
/* Compute required length so it can be returned if buffer is too small */
switch(uType) {
case QCBOR_TYPE_POSBIGNUM:
uLen = BigNumber.len;
break;
case QCBOR_TYPE_NEGBIGNUM:
uLen = BigNumber.len;
if(UsefulBuf_IsValue(UsefulBuf_SkipLeading(BigNumber, 0), 0xff) == SIZE_MAX) {
uLen++;
}
break;
default:
return QCBOR_ERR_UNEXPECTED_TYPE;
}
*pBigNumber = (UsefulBufC){NULL, uLen};
if(BigNumberBuf.len < uLen || uLen == 0 || BigNumberBuf.ptr == NULL) {
return BigNumberBuf.ptr == NULL ? QCBOR_SUCCESS : QCBOR_ERR_BUFFER_TOO_SMALL;
/* Buffer is too short or type is wrong */
}
if(uType == QCBOR_TYPE_POSBIGNUM) {
*pBigNumber = UsefulBuf_Copy(BigNumberBuf, BigNumber);
*pbIsNegative = false;
} else if(uType == QCBOR_TYPE_NEGBIGNUM) {
/* The messy one. Take the stuff in the buffer and copy it to
* the new buffer, adding one to it. This might be one byte
* bigger than the original because of the carry from adding
* one.*/
*pbIsNegative = true;
*pBigNumber = QCBORDecode_BigNumberCopyPlusOne(BigNumber, BigNumberBuf);
}
return QCBOR_SUCCESS;
}
/* Public function, see qcbor/qcbor_number_decode.h */
QCBORError
QCBORDecode_ProcessBigNumber(const QCBORItem Item,
UsefulBuf BigNumberBuf,
UsefulBufC *pBigNumber,
bool *pbIsNegative)
{
QCBORError uResult;
size_t uLen;
int uType;
uType = Item.uDataType;
switch(uType) {
case QCBOR_TYPE_POSBIGNUM:
case QCBOR_TYPE_NEGBIGNUM:
case QCBOR_TYPE_BYTE_STRING:
return QCBORDecode_ProcessBigNumberNoPreferred(Item, BigNumberBuf, pBigNumber, pbIsNegative);
break;
case QCBOR_TYPE_INT64:
uLen = QCBORDecode_Private_CountNonZeroBytes((uint64_t)ABSOLUTE_VALUE(Item.val.int64));
break;
case QCBOR_TYPE_UINT64:
uLen = QCBORDecode_Private_CountNonZeroBytes(Item.val.uint64);
break;
case QCBOR_TYPE_65BIT_NEG_INT:
uLen = Item.val.uint64 == UINT64_MAX ? 9 : QCBORDecode_Private_CountNonZeroBytes(Item.val.uint64);
break;
default:
return QCBOR_ERR_UNEXPECTED_TYPE;
}
*pBigNumber = (UsefulBufC){NULL, uLen};
if(BigNumberBuf.len < uLen || uLen == 0 || BigNumberBuf.ptr == NULL) {
return BigNumberBuf.ptr == NULL ? QCBOR_SUCCESS : QCBOR_ERR_BUFFER_TOO_SMALL;
/* Buffer is too short or type is wrong */
}
uResult = QCBOR_SUCCESS;
if(uType == QCBOR_TYPE_UINT64) {
*pBigNumber = QCBORDecode_Private_UIntToBigNumber(Item.val.uint64, BigNumberBuf);
*pbIsNegative = false;
} else if(uType == QCBOR_TYPE_INT64) {
/* Offset of 1 for negative numbers already performed */
*pbIsNegative = Item.val.int64 < 0;
const uint64_t uIntTmp = (uint64_t)(*pbIsNegative ? -Item.val.int64 : Item.val.int64);
*pBigNumber = QCBORDecode_Private_UIntToBigNumber(uIntTmp, BigNumberBuf);
} else if(uType == QCBOR_TYPE_65BIT_NEG_INT) {
/* Offset of 1 for negative numbers NOT already performed */
*pbIsNegative = true;
if(Item.val.uint64 == UINT64_MAX) {
/* The one value that can't be done with a computation
* because it would overflow a uint64_t */
static const uint8_t TwoToThe64[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
*pBigNumber = UsefulBuf_Copy(BigNumberBuf, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(TwoToThe64));
} else {
/* +1 because negative big numbers are encoded one less than actual */
*pBigNumber = QCBORDecode_Private_UIntToBigNumber(Item.val.uint64 + 1, BigNumberBuf);
}
}
return uResult;
}
static const uint64_t QCBORDecode_Private_BigNumberTagNumbers[] = {
CBOR_TAG_POS_BIGNUM,
CBOR_TAG_NEG_BIGNUM,
CBOR_TAG_INVALID64};
static const uint8_t QCBORDecode_Private_BigNumberTypes[] = {
QCBOR_TYPE_INT64,
QCBOR_TYPE_UINT64,
QCBOR_TYPE_65BIT_NEG_INT,
QCBOR_TYPE_POSBIGNUM,
QCBOR_TYPE_NEGBIGNUM,
QCBOR_TYPE_NONE};
#define QCBORDecode_Private_BigNumberTypesNoPreferred &QCBORDecode_Private_BigNumberTypes[3]
/**
* @brief Common processing for a big number tag.
*
* @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX.
* @param[in] pItem The item with the date.
* @param[out] pBignumber The returned big number
* @param[out] pbIsNegative The returned sign of the big number.
*
* Common processing for the big number tag. Mostly make sure
* the tag content is correct and copy forward any further other tag
* numbers.
*/
static void
QCBORDecode_Private_BigNumberRawMain(QCBORDecodeContext *pMe,
const enum QCBORDecodeTagReq uTagRequirement,
QCBORItem *pItem,
UsefulBufC *pBignumber,
bool *pbIsNegative,
size_t uOffset)
{
QCBORDecode_Private_ProcessTagItemMulti(pMe,
pItem,
uTagRequirement,
QCBORDecode_Private_BigNumberTypesNoPreferred,
QCBORDecode_Private_BigNumberTagNumbers,
QCBORDecode_StringsTagCB,
uOffset);
if(pMe->uLastError) {
return;
}
if(pItem->uDataType == QCBOR_TYPE_POSBIGNUM) {
*pbIsNegative = false;
} else if(pItem->uDataType == QCBOR_TYPE_NEGBIGNUM) {
*pbIsNegative = true;
}
*pBignumber = pItem->val.bigNum;
}
static void
QCBORDecode_Private_BigNumberNoPreferredMain(QCBORDecodeContext *pMe,
const enum QCBORDecodeTagReq uTagRequirement,
QCBORItem *pItem,
const size_t uOffset,
UsefulBuf BigNumberBuf,
UsefulBufC *pBigNumber,
bool *pbIsNegative)
{
QCBORDecode_Private_ProcessTagItemMulti(pMe,
pItem,
uTagRequirement,
QCBORDecode_Private_BigNumberTypesNoPreferred,
QCBORDecode_Private_BigNumberTagNumbers,
QCBORDecode_StringsTagCB,
uOffset);
if(pMe->uLastError) {
return;
}
pMe->uLastError = (uint8_t)QCBORDecode_ProcessBigNumberNoPreferred(*pItem, BigNumberBuf, pBigNumber, pbIsNegative);
}
static void
QCBORDecode_Private_BigNumberMain(QCBORDecodeContext *pMe,
const enum QCBORDecodeTagReq uTagRequirement,
QCBORItem *pItem,
const size_t uOffset,
UsefulBuf BigNumberBuf,
UsefulBufC *pBigNumber,
bool *pbIsNegative)
{
QCBORDecode_Private_ProcessTagItemMulti(pMe,
pItem,
uTagRequirement,
QCBORDecode_Private_BigNumberTypes,
QCBORDecode_Private_BigNumberTagNumbers,
QCBORDecode_StringsTagCB,
uOffset);
if(pMe->uLastError) {
return;
}
pMe->uLastError = (uint8_t)QCBORDecode_ProcessBigNumber(*pItem, BigNumberBuf, pBigNumber, pbIsNegative);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTBigNumber(QCBORDecodeContext *pMe,
const enum QCBORDecodeTagReq uTagRequirement,
UsefulBuf BigNumberBuf,
UsefulBufC *pBigNumber,
bool *pbIsNegative)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
QCBORDecode_Private_BigNumberMain(pMe, uTagRequirement, &Item, uOffset, BigNumberBuf, pBigNumber, pbIsNegative);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTBigNumberInMapN(QCBORDecodeContext *pMe,
const int64_t nLabel,
const enum QCBORDecodeTagReq uTagRequirement,
UsefulBuf BigNumberBuf,
UsefulBufC *pBigNumber,
bool *pbIsNegative)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
QCBORDecode_Private_BigNumberMain(pMe,
uTagRequirement,
&Item,
uOffset,
BigNumberBuf,
pBigNumber,
pbIsNegative);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTBigNumberInMapSZ(QCBORDecodeContext *pMe,
const char *szLabel,
const enum QCBORDecodeTagReq uTagRequirement,
UsefulBuf BigNumberBuf,
UsefulBufC *pBigNumber,
bool *pbIsNegative)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
QCBORDecode_Private_BigNumberMain(pMe,
uTagRequirement,
&Item,
uOffset,
BigNumberBuf,
pBigNumber,
pbIsNegative);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTBigNumberNoPreferred(QCBORDecodeContext *pMe,
const enum QCBORDecodeTagReq uTagRequirement,
UsefulBuf BigNumberBuf,
UsefulBufC *pBigNumber,
bool *pbIsNegative)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
QCBORDecode_Private_BigNumberNoPreferredMain(pMe,
uTagRequirement,
&Item,
uOffset,
BigNumberBuf,
pBigNumber,
pbIsNegative);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTBigNumberNoPreferredInMapN(QCBORDecodeContext *pMe,
const int64_t nLabel,
const enum QCBORDecodeTagReq uTagRequirement,
UsefulBuf BigNumberBuf,
UsefulBufC *pBigNumber,
bool *pbIsNegative)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
QCBORDecode_Private_BigNumberNoPreferredMain(pMe,
uTagRequirement,
&Item,
uOffset,
BigNumberBuf,
pBigNumber,
pbIsNegative);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTBigNumberNoPreferredInMapSZ(QCBORDecodeContext *pMe,
const char *szLabel,
const enum QCBORDecodeTagReq uTagRequirement,
UsefulBuf BigNumberBuf,
UsefulBufC *pBigNumber,
bool *pbIsNegative)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
QCBORDecode_Private_BigNumberNoPreferredMain(pMe,
uTagRequirement,
&Item,
uOffset,
BigNumberBuf,
pBigNumber,
pbIsNegative);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTBigNumberRaw(QCBORDecodeContext *pMe,
const enum QCBORDecodeTagReq uTagRequirement,
UsefulBufC *pBignumber,
bool *pbIsNegative)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
QCBORDecode_Private_BigNumberRawMain(pMe,
uTagRequirement,
&Item,
pBignumber,
pbIsNegative,
uOffset);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTBigNumberRawInMapN(QCBORDecodeContext *pMe,
const int64_t nLabel,
const enum QCBORDecodeTagReq uTagRequirement,
UsefulBufC *pBigNumber,
bool *pbIsNegative)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
QCBORDecode_Private_BigNumberRawMain(pMe,
uTagRequirement,
&Item,
pBigNumber,
pbIsNegative,
uOffset);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTBigNumberRawInMapSZ(QCBORDecodeContext *pMe,
const char *szLabel,
const enum QCBORDecodeTagReq uTagRequirement,
UsefulBufC *pBigNumber,
bool *pbIsNegative)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
QCBORDecode_Private_BigNumberRawMain(pMe,
uTagRequirement,
&Item,
pBigNumber,
pbIsNegative,
uOffset);
}
#ifndef QCBOR_DISABLE_EXP_AND_MANTISSA
static const uint8_t QCBORDecode_Private_DecimalFractionTypes[] = {
QCBOR_TYPE_DECIMAL_FRACTION,
QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM,
QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM,
QCBOR_TYPE_DECIMAL_FRACTION_POS_U64,
QCBOR_TYPE_DECIMAL_FRACTION_NEG_U64,
QCBOR_TYPE_NONE};
static const uint8_t QCBORDecode_Private_BigFloatTypes[] = {
QCBOR_TYPE_BIGFLOAT,
QCBOR_TYPE_BIGFLOAT_POS_BIGMANTISSA,
QCBOR_TYPE_BIGFLOAT_NEG_BIGMANTISSA,
QCBOR_TYPE_BIGFLOAT_POS_U64MANTISSA,
QCBOR_TYPE_BIGFLOAT_NEG_U64MANTISSA,
QCBOR_TYPE_NONE};
/**
* @brief Common processor for exponent and int64_t mantissa.
*
* @param[in] pMe The decode context.
* @param[in] uTagRequirement Whether tag number must be present or not.
* @param[in] uTagNumber The tag number for which content is expected.
* @param[in] uOffset Cursor offset for tag number consumption checking.
* @param[in] pItem The data item to process.
* @param[out] pnMantissa The returned mantissa as an int64_t.
* @param[out] pnExponent The returned exponent as an int64_t.
*
* This handles exponent and mantissa for base 2 and 10. This
* is limited to a mantissa that is an int64_t. See also
* QCBORDecode_Private_ProcessExpMantissaBig().
*
* On output, the item is always a fully decoded decimal fraction or
* big float.
*
* This errors out if the input tag and type aren't as required.
*
* This always provides the correctly offset mantissa, even when the
* input CBOR is a negative big number. This works the
* same in QCBOR v1 and v2.
*/
static void
QCBORDecode_Private_ExpIntMantissaMain(QCBORDecodeContext *pMe,
const enum QCBORDecodeTagReq uTagReq,
const uint64_t uTagNumber,
const size_t uOffset,
QCBORItem *pItem,
int64_t *pnMantissa,
int64_t *pnExponent)
{
QCBORError uErr;
const uint8_t *qTypes;
if(pMe->uLastError) {
return;
}
if(uTagNumber == CBOR_TAG_BIGFLOAT) {
qTypes = QCBORDecode_Private_BigFloatTypes;
} else {
qTypes = QCBORDecode_Private_DecimalFractionTypes;
}
QCBORDecode_Private_ProcessTagItem(pMe,
pItem,
uTagReq,
qTypes,
uTagNumber,
QCBORDecode_ExpMantissaTagCB,
uOffset);
if(pMe->uLastError != QCBOR_SUCCESS) {
return;
}
uErr = QCBOR_SUCCESS;
switch (pItem->uDataType) {
case QCBOR_TYPE_DECIMAL_FRACTION:
case QCBOR_TYPE_BIGFLOAT:
*pnExponent = pItem->val.expAndMantissa.nExponent;
*pnMantissa = pItem->val.expAndMantissa.Mantissa.nInt;
break;
#ifndef QCBOR_DISABLE_TAGS
/* If tags are disabled, mantissas can never be big nums */
case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
case QCBOR_TYPE_BIGFLOAT_POS_BIGMANTISSA:
*pnExponent = pItem->val.expAndMantissa.nExponent;
uErr = QCBORDecode_Private_PositiveBigNumberToInt(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
break;
case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
case QCBOR_TYPE_BIGFLOAT_NEG_BIGMANTISSA:
*pnExponent = pItem->val.expAndMantissa.nExponent;
uErr = QCBORDecode_Private_NegativeBigNumberToInt(pItem->val.expAndMantissa.Mantissa.bigNum, pnMantissa);
break;
#endif /* ! QCBOR_DISABLE_TAGS */
case QCBOR_TYPE_BIGFLOAT_NEG_U64MANTISSA:
case QCBOR_TYPE_DECIMAL_FRACTION_NEG_U64:
case QCBOR_TYPE_BIGFLOAT_POS_U64MANTISSA:
case QCBOR_TYPE_DECIMAL_FRACTION_POS_U64:
uErr = QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW;
break;
default:
uErr = QCBOR_ERR_UNEXPECTED_TYPE;
}
pMe->uLastError = (uint8_t)uErr;
}
static void
QCBORDecode_Private_ExpBigMantissaRawMain(QCBORDecodeContext *pMe,
const enum QCBORDecodeTagReq uTagReq,
const uint64_t uTagNumber,
const size_t uOffset,
QCBORItem *pItem,
const UsefulBuf BufferForMantissa,
UsefulBufC *pMantissa,
bool *pbIsNegative,
int64_t *pnExponent)
{
QCBORError uErr;
uint64_t uMantissa;
const uint8_t *qTypes;
if(pMe->uLastError) {
return;
}
if(uTagNumber == CBOR_TAG_BIGFLOAT) {
qTypes = QCBORDecode_Private_BigFloatTypes;
} else {
qTypes = QCBORDecode_Private_DecimalFractionTypes;
}
QCBORDecode_Private_ProcessTagItem(pMe,
pItem,
uTagReq,
qTypes,
uTagNumber,
QCBORDecode_ExpMantissaTagCB,
uOffset);
if(pMe->uLastError != QCBOR_SUCCESS) {
return;
}
uErr = QCBOR_SUCCESS;
switch (pItem->uDataType) {
case QCBOR_TYPE_DECIMAL_FRACTION:
case QCBOR_TYPE_BIGFLOAT:
if(pItem->val.expAndMantissa.Mantissa.nInt >= 0) {
uMantissa = (uint64_t)pItem->val.expAndMantissa.Mantissa.nInt;
*pbIsNegative = false;
} else {
if(pItem->val.expAndMantissa.Mantissa.nInt != INT64_MIN) {
uMantissa = (uint64_t)-pItem->val.expAndMantissa.Mantissa.nInt;
} else {
/* Can't negate like above when int64_t is INT64_MIN because it
* will overflow. See ExponentNN() */
uMantissa = (uint64_t)INT64_MAX+1;
}
*pbIsNegative = true;
}
/* 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. This is a bug fix for QCBOR v1.5.
*/
uMantissa--;
*pMantissa = QCBORDecode_Private_UIntToBigNumber(uMantissa, BufferForMantissa);
*pnExponent = pItem->val.expAndMantissa.nExponent;
break;
#ifndef QCBOR_DISABLE_TAGS
/* If tags are disabled, mantissas can never be big nums */
case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
case QCBOR_TYPE_BIGFLOAT_POS_BIGMANTISSA:
*pnExponent = pItem->val.expAndMantissa.nExponent;
*pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
*pbIsNegative = false;
break;
case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
case QCBOR_TYPE_BIGFLOAT_NEG_BIGMANTISSA:
*pnExponent = pItem->val.expAndMantissa.nExponent;
*pMantissa = pItem->val.expAndMantissa.Mantissa.bigNum;
*pbIsNegative = true;
break;
#endif /* ! QCBOR_DISABLE_TAGS */
default:
uErr = QCBOR_ERR_UNEXPECTED_TYPE;
}
pMe->uLastError = (uint8_t)uErr;
}
/**
* @brief Decode exponent and mantissa into a big number with negative offset of 1.
*
* @param[in] pMe The decode context.
* @param[in] uTagRequirement Whether a tag number must be present or not.
* @param[in] pItem Item to decode and convert.
* @param[in] BufferForMantissa Buffer to output mantissa into.
* @param[out] pMantissa The output mantissa.
* @param[out] pbIsNegative The sign of the output.
* @param[out] pnExponent The mantissa of the output.
*
* This is the common processing of a decimal fraction or a big float
* into a big number. This will decode and consume all the CBOR items
* that make up the decimal fraction or big float.
*
* This performs the subtraction of 1 from the negative value so the
* caller doesn't need to. This links more object code than QCBORDecode_Private_ProcessExpMantissaBig().
*/
static void
QCBORDecode_Private_ExpBigMantissaMain(QCBORDecodeContext *pMe,
const enum QCBORDecodeTagReq uTagReq,
const uint64_t uTagNumber,
const size_t uOffset,
QCBORItem *pItem,
const UsefulBuf BufferForMantissa,
UsefulBufC *pMantissa,
bool *pbIsNegative,
int64_t *pnExponent)
{
QCBORError uErr;
QCBORItem TempMantissa;
const uint8_t *qTypes;
if(pMe->uLastError) {
return;
}
if(uTagNumber == CBOR_TAG_BIGFLOAT) {
qTypes = QCBORDecode_Private_BigFloatTypes;
} else {
qTypes = QCBORDecode_Private_DecimalFractionTypes;
}
QCBORDecode_Private_ProcessTagItem(pMe,
pItem,
uTagReq,
qTypes,
uTagNumber,
QCBORDecode_ExpMantissaTagCB,
uOffset);
if(pMe->uLastError != QCBOR_SUCCESS) {
return;
}
memset(&TempMantissa, 0, sizeof(TempMantissa));
switch (pItem->uDataType) {
case QCBOR_TYPE_DECIMAL_FRACTION:
case QCBOR_TYPE_BIGFLOAT:
TempMantissa.uDataType = QCBOR_TYPE_INT64;
TempMantissa.val.int64 = pItem->val.expAndMantissa.Mantissa.nInt;
break;
case QCBOR_TYPE_DECIMAL_FRACTION_POS_U64:
case QCBOR_TYPE_BIGFLOAT_POS_U64MANTISSA:
TempMantissa.uDataType = QCBOR_TYPE_UINT64;
TempMantissa.val.uint64 = pItem->val.expAndMantissa.Mantissa.uInt;
break;
case QCBOR_TYPE_DECIMAL_FRACTION_NEG_U64:
case QCBOR_TYPE_BIGFLOAT_NEG_U64MANTISSA:
TempMantissa.uDataType = QCBOR_TYPE_65BIT_NEG_INT;
TempMantissa.val.uint64 = pItem->val.expAndMantissa.Mantissa.uInt;
break;
#ifndef QCBOR_DISABLE_TAGS
/* If tags are disabled, mantissas can never be big nums */
case QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM:
case QCBOR_TYPE_BIGFLOAT_POS_BIGMANTISSA:
TempMantissa.uDataType = QCBOR_TYPE_BYTE_STRING;
TempMantissa.val.bigNum = pItem->val.expAndMantissa.Mantissa.bigNum;
*pbIsNegative = false;
break;
case QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM:
case QCBOR_TYPE_BIGFLOAT_NEG_BIGMANTISSA:
TempMantissa.uDataType = QCBOR_TYPE_BYTE_STRING;
TempMantissa.val.bigNum = pItem->val.expAndMantissa.Mantissa.bigNum;
*pbIsNegative = true;
break;
#endif /* ! QCBOR_DISABLE_TAGS */
}
*pnExponent = pItem->val.expAndMantissa.nExponent;
uErr = QCBORDecode_ProcessBigNumber(TempMantissa, BufferForMantissa, pMantissa, pbIsNegative);
pMe->uLastError = (uint8_t)uErr;
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTDecimalFraction(QCBORDecodeContext *pMe,
const enum QCBORDecodeTagReq uTagRequirement,
int64_t *pnMantissa,
int64_t *pnExponent)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
QCBORDecode_Private_ExpIntMantissaMain(pMe,
uTagRequirement,
CBOR_TAG_DECIMAL_FRACTION,
uOffset,
&Item,
pnMantissa,
pnExponent);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTDecimalFractionInMapN(QCBORDecodeContext *pMe,
const int64_t nLabel,
const enum QCBORDecodeTagReq uTagReq,
int64_t *pnMantissa,
int64_t *pnExponent)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
QCBORDecode_Private_ExpIntMantissaMain(pMe,
uTagReq,
CBOR_TAG_DECIMAL_FRACTION,
uOffset,
&Item,
pnMantissa,
pnExponent);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTDecimalFractionInMapSZ(QCBORDecodeContext *pMe,
const char *szLabel,
const enum QCBORDecodeTagReq uTagReq,
int64_t *pnMantissa,
int64_t *pnExponent)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
QCBORDecode_Private_ExpIntMantissaMain(pMe,
uTagReq,
CBOR_TAG_DECIMAL_FRACTION,
uOffset,
&Item,
pnMantissa,
pnExponent);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTDecimalFractionBigMantissa(QCBORDecodeContext *pMe,
const enum QCBORDecodeTagReq uTagReq,
const UsefulBuf MantissaBuffer,
UsefulBufC *pMantissa,
bool *pbMantissaIsNegative,
int64_t *pnExponent)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
QCBORDecode_Private_ExpBigMantissaMain(pMe,
uTagReq,
CBOR_TAG_DECIMAL_FRACTION,
uOffset,
&Item,
MantissaBuffer,
pMantissa,
pbMantissaIsNegative,
pnExponent);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTDecimalFractionBigMantissaInMapN(QCBORDecodeContext *pMe,
const int64_t nLabel,
const enum QCBORDecodeTagReq uTagReq,
const UsefulBuf BufferForMantissa,
UsefulBufC *pMantissa,
bool *pbIsNegative,
int64_t *pnExponent)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
QCBORDecode_Private_ExpBigMantissaMain(pMe,
uTagReq,
CBOR_TAG_DECIMAL_FRACTION,
uOffset,
&Item,
BufferForMantissa,
pMantissa,
pbIsNegative,
pnExponent);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTDecimalFractionBigMantissaInMapSZ(QCBORDecodeContext *pMe,
const char *szLabel,
const enum QCBORDecodeTagReq uTagReq,
const UsefulBuf BufferForMantissa,
UsefulBufC *pMantissa,
bool *pbIsNegative,
int64_t *pnExponent)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
QCBORDecode_Private_ExpBigMantissaMain(pMe,
uTagReq,
CBOR_TAG_DECIMAL_FRACTION,
uOffset,
&Item,
BufferForMantissa,
pMantissa,
pbIsNegative,
pnExponent);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTDecimalFractionBigMantissaRaw(QCBORDecodeContext *pMe,
const enum QCBORDecodeTagReq uTagReq,
const UsefulBuf MantissaBuffer,
UsefulBufC *pMantissa,
bool *pbMantissaIsNegative,
int64_t *pnExponent)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
QCBORDecode_Private_ExpBigMantissaRawMain(pMe,
uTagReq,
CBOR_TAG_DECIMAL_FRACTION,
uOffset,
&Item,
MantissaBuffer,
pMantissa,
pbMantissaIsNegative,
pnExponent);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTDecimalFractionBigMantissaRawInMapN(QCBORDecodeContext *pMe,
const int64_t nLabel,
const enum QCBORDecodeTagReq uTagReq,
const UsefulBuf BufferForMantissa,
UsefulBufC *pMantissa,
bool *pbIsNegative,
int64_t *pnExponent)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
QCBORDecode_Private_ExpBigMantissaRawMain(pMe,
uTagReq,
CBOR_TAG_DECIMAL_FRACTION,
uOffset,
&Item,
BufferForMantissa,
pMantissa,
pbIsNegative,
pnExponent);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTDecimalFractionBigMantissaRawInMapSZ(QCBORDecodeContext *pMe,
const char *szLabel,
const enum QCBORDecodeTagReq uTagReq,
const UsefulBuf BufferForMantissa,
UsefulBufC *pMantissa,
bool *pbIsNegative,
int64_t *pnExponent)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
QCBORDecode_Private_ExpBigMantissaRawMain(pMe,
uTagReq,
CBOR_TAG_DECIMAL_FRACTION,
uOffset,
&Item,
BufferForMantissa,
pMantissa,
pbIsNegative,
pnExponent);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTBigFloat(QCBORDecodeContext *pMe,
const enum QCBORDecodeTagReq uTagRequirement,
int64_t *pnMantissa,
int64_t *pnExponent)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
QCBORDecode_Private_ExpIntMantissaMain(pMe,
uTagRequirement,
CBOR_TAG_BIGFLOAT,
uOffset,
&Item,
pnMantissa,
pnExponent);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTBigFloatInMapN(QCBORDecodeContext *pMe,
const int64_t nLabel,
const enum QCBORDecodeTagReq uTagRequirement,
int64_t *pnMantissa,
int64_t *pnExponent)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
QCBORDecode_Private_ExpIntMantissaMain(pMe,
uTagRequirement,
CBOR_TAG_BIGFLOAT,
uOffset,
&Item,
pnMantissa,
pnExponent);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTBigFloatInMapSZ(QCBORDecodeContext *pMe,
const char *szLabel,
const enum QCBORDecodeTagReq uTagRequirement,
int64_t *pnMantissa,
int64_t *pnExponent)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
QCBORDecode_Private_ExpIntMantissaMain(pMe,
uTagRequirement,
CBOR_TAG_BIGFLOAT,
uOffset,
&Item,
pnMantissa,
pnExponent);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTBigFloatBigMantissa(QCBORDecodeContext *pMe,
const enum QCBORDecodeTagReq uTagReq,
const UsefulBuf MantissaBuffer,
UsefulBufC *pMantissa,
bool *pbMantissaIsNegative,
int64_t *pnExponent)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
QCBORDecode_Private_ExpBigMantissaMain(pMe,
uTagReq,
CBOR_TAG_BIGFLOAT,
uOffset,
&Item,
MantissaBuffer,
pMantissa,
pbMantissaIsNegative,
pnExponent);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTBigFloatBigMantissaInMapN(QCBORDecodeContext *pMe,
const int64_t nLabel,
const enum QCBORDecodeTagReq uTagReq,
const UsefulBuf BufferForMantissa,
UsefulBufC *pMantissa,
bool *pbIsNegative,
int64_t *pnExponent)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
QCBORDecode_Private_ExpBigMantissaMain(pMe,
uTagReq,
CBOR_TAG_BIGFLOAT,
uOffset,
&Item,
BufferForMantissa,
pMantissa,
pbIsNegative,
pnExponent);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTBigFloatBigMantissaInMapSZ(QCBORDecodeContext *pMe,
const char *szLabel,
const enum QCBORDecodeTagReq uTagReq,
const UsefulBuf BufferForMantissa,
UsefulBufC *pMantissa,
bool *pbIsNegative,
int64_t *pnExponent)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
QCBORDecode_Private_ExpBigMantissaMain(pMe,
uTagReq,
CBOR_TAG_BIGFLOAT,
uOffset,
&Item,
BufferForMantissa,
pMantissa,
pbIsNegative,
pnExponent);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTBigFloatBigMantissaRaw(QCBORDecodeContext *pMe,
const enum QCBORDecodeTagReq uTagReq,
const UsefulBuf MantissaBuffer,
UsefulBufC *pMantissa,
bool *pbMantissaIsNegative,
int64_t *pnExponent)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset);
QCBORDecode_Private_ExpBigMantissaRawMain(pMe,
uTagReq,
CBOR_TAG_BIGFLOAT,
uOffset,
&Item,
MantissaBuffer,
pMantissa,
pbMantissaIsNegative,
pnExponent);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTBigFloatBigMantissaRawInMapN(QCBORDecodeContext *pMe,
const int64_t nLabel,
const enum QCBORDecodeTagReq uTagReq,
const UsefulBuf BufferForMantissa,
UsefulBufC *pMantissa,
bool *pbIsNegative,
int64_t *pnExponent)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
QCBORDecode_Private_ExpBigMantissaRawMain(pMe,
uTagReq,
CBOR_TAG_BIGFLOAT,
uOffset,
&Item,
BufferForMantissa,
pMantissa,
pbIsNegative,
pnExponent);
}
/* Public function, see qcbor/qcbor_number_decode.h */
void
QCBORDecode_GetTBigFloatBigMantissaRawInMapSZ(QCBORDecodeContext *pMe,
const char *szLabel,
const enum QCBORDecodeTagReq uTagReq,
const UsefulBuf BufferForMantissa,
UsefulBufC *pMantissa,
bool *pbIsNegative,
int64_t *pnExponent)
{
QCBORItem Item;
size_t uOffset;
QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset);
QCBORDecode_Private_ExpBigMantissaRawMain(pMe,
uTagReq,
CBOR_TAG_BIGFLOAT,
uOffset,
&Item,
BufferForMantissa,
pMantissa,
pbIsNegative,
pnExponent);
}
#endif /* ! QCBOR_DISABLE_EXP_AND_MANTISSA */