blob: e101494ee1b799cab8a0de1ad0daca296b4a7b22 [file] [edit]
#include "bej_common.h"
#include <float.h>
#include <inttypes.h>
#include <stdio.h>
uint64_t bejGetUnsignedInteger(const uint8_t* bytes, uint8_t numOfBytes)
{
uint64_t num = 0;
for (uint8_t i = 0; i < numOfBytes; ++i)
{
num |= (uint64_t)(*(bytes + i)) << (i * 8);
}
return num;
}
uint64_t bejGetNnint(const uint8_t* nnint)
{
// In nnint, first byte indicate how many bytes are there. Remaining bytes
// represent the value in little-endian format.
const uint8_t size = *nnint;
return bejGetUnsignedInteger(nnint + sizeof(uint8_t), size);
}
uint8_t bejGetNnintSize(const uint8_t* nnint)
{
// In nnint, first byte indicate how many bytes are there.
return *nnint + sizeof(uint8_t);
}
uint8_t bejIntLengthOfValue(int64_t val)
{
// Only need to encode 0x00 or 0xFF
if (val == 0 || val == -1)
{
return 1;
}
// Starts at the MSB. LSB index is 0.
uint8_t byteIndex = sizeof(uint64_t) - 1;
const uint8_t bitsPerByte = 8;
// The current byte being looked at. Starts at MSB.
uint8_t currentByte = (val >> (bitsPerByte * byteIndex)) & 0xFF;
uint8_t byteLength = sizeof(int64_t);
while ((val > 0 && currentByte == 0) || (val < 0 && currentByte == 0xFF))
{
byteLength--;
byteIndex--;
currentByte = (val >> (bitsPerByte * byteIndex)) & 0xFF;
}
// If the value is positive and encoded MSBbit is 1 we need to add 0x00 to
// the encoded value as padding.
if (val > 0 && (currentByte & 0x80))
{
byteLength++;
}
// If the value is negative and encoded MSBbit is 0 we need to add 0xFF to
// the encoded value as padding.
if (val < 0 && !(currentByte & 0x80))
{
byteLength++;
}
return byteLength;
}
uint8_t bejNnintEncodingSizeOfUInt(uint64_t val)
{
uint8_t bytes = 0;
do
{
// Even if the value is 0, we need a byte for that.
++bytes;
val = val >> 8;
} while (val != 0);
// Need 1 byte to add the nnint length.
return bytes + 1;
}
uint8_t bejNnintLengthFieldOfUInt(uint64_t val)
{
// From the size of the encoded value, we need 1 byte for the length field.
return bejNnintEncodingSizeOfUInt(val) - 1;
}
double bejFabs(double x)
{
return (x < 0) ? -x : x;
}
double bejModf(double x, double* integer)
{
// x expected to be within int64_t max value.
int64_t i = (int64_t)x;
*integer = (double)i;
return x - *integer;
}
int bejGetDoubleFromBejReal(const struct BejReal* value, double* output)
{
// Maximum supported zero count in BejReal type. The value selected will prevent
// overflow of divisor(uin64_t). We could support larger zero count but that
// will require more computational logic and we probably do not need that level
// of precision.
#define BEJ_REAL_MAX_SUPPORTED_ZERO_COUNT 19
// Maximum value possible for the uint64_t divisor used.
#define BEJ_UINT64_DIVISOR_MAX ((uint64_t)10000000000000000000ULL)
if (value->zeroCount > BEJ_REAL_MAX_SUPPORTED_ZERO_COUNT)
{
fprintf(stderr,
"Provided zero count: %" PRIu64 " exceeds supported: %u\n",
value->zeroCount, BEJ_REAL_MAX_SUPPORTED_ZERO_COUNT);
return -1;
}
// Initialize the multiplication or division factor based on exponent
double exp_factor = 1.00;
for (int64_t exp = bejFabs(value->exp); exp > 0; --exp)
{
// Check if the multiplication factor is larger than what can be
// supported.
if (exp_factor > (DBL_MAX / 10.0))
{
fprintf(stderr, "Multiplication factor derived from exp is larger "
"than a double\n");
return -1;
}
exp_factor *= 10;
}
// The double value will be formed as follows:
// value.whole = 1
// value.zeroCount = 3
// value.fract = 525
// output = whole.[zero_count][fractional_part] ==> 1.000525.
// Then the exponent will be applied.
// output /* 10^(exp)
// Get the whole value.
*output = value->whole;
// Calculating the divisor needed to divide the fract. Check for divisor
// overflow.
uint64_t divisor = 1;
while (divisor <= value->fract && (divisor < BEJ_UINT64_DIVISOR_MAX))
{
divisor *= 10;
}
double fraction = (double)value->fract / divisor;
// In case divisor was going to overflow, we need to divide fraction by an
// additional 10.
if (divisor == BEJ_UINT64_DIVISOR_MAX)
{
fraction /= 10;
}
// Then we need to divide the fractional part by the number of zeros.
// Calculating the divisor for that. Divisor will not overflow since we have
// limit the zero count.
divisor = 1;
for (uint64_t zeroCount = value->zeroCount; zeroCount > 0; --zeroCount)
{
divisor *= 10;
}
fraction /= divisor;
// "fract" part doesn't include the sign. We need to use the sign of the
// "whole". The current representation doesn't support negative values less
// than 0 and greater then -1. That means if the whole part is 0, then sign
// will be always +.
fraction *= ((value->whole < 0) ? -1 : 1);
*output += fraction;
if (value->exp > 0)
{
// Check if the result is larger than a double
if (*output > (DBL_MAX / exp_factor))
{
fprintf(stderr, "Result is larger than a double\n");
return -1;
}
*output *= exp_factor;
}
// Using else if to avoid unnecessary division if exp == 0.
else if (value->exp < 0)
{
*output /= exp_factor;
}
return 0;
}