mirror of
https://github.com/open-source-parsers/jsoncpp.git
synced 2025-04-27 18:30:50 +02:00
Replaced the complex implementation of valueToString(double).
The previous one was confusing and prone to buffer overflows, and didn't work correctly with 16-decimal-digit numbers. The new one simply uses snprintf with a standard format string. The major change is that we don't always print a decimal point now. Fortunately, JSON doesn't distinguish between integers and reals.
This commit is contained in:
parent
bb53cd0899
commit
32ffb931e7
@ -73,40 +73,19 @@ std::string valueToString( UInt value )
|
|||||||
|
|
||||||
std::string valueToString( double value )
|
std::string valueToString( double value )
|
||||||
{
|
{
|
||||||
|
// Allocate a buffer that is more than large enough to store the 16 digits of
|
||||||
|
// precision requested below.
|
||||||
char buffer[32];
|
char buffer[32];
|
||||||
|
|
||||||
|
// Print into the buffer. We need not request the alternative representation
|
||||||
|
// that always has a decimal point because JSON doesn't distingish the
|
||||||
|
// concepts of reals and integers.
|
||||||
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning.
|
#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning.
|
||||||
sprintf_s(buffer, sizeof(buffer), "%#.16g", value);
|
sprintf_s(buffer, sizeof(buffer), "%.16g", value);
|
||||||
#else
|
#else
|
||||||
snprintf(buffer, sizeof(buffer), "%#.16g", value);
|
snprintf(buffer, sizeof(buffer), "%.16g", value);
|
||||||
#endif
|
#endif
|
||||||
char* ch = buffer + strlen(buffer) - 1;
|
|
||||||
if (*ch != '0') return buffer; // nothing to truncate, so save time
|
|
||||||
while(ch > buffer && *ch == '0'){
|
|
||||||
--ch;
|
|
||||||
}
|
|
||||||
char* last_nonzero = ch;
|
|
||||||
while(ch >= buffer){
|
|
||||||
switch(*ch){
|
|
||||||
case '0':
|
|
||||||
case '1':
|
|
||||||
case '2':
|
|
||||||
case '3':
|
|
||||||
case '4':
|
|
||||||
case '5':
|
|
||||||
case '6':
|
|
||||||
case '7':
|
|
||||||
case '8':
|
|
||||||
case '9':
|
|
||||||
--ch;
|
|
||||||
continue;
|
|
||||||
case '.':
|
|
||||||
// Truncate zeroes to save bytes in output, but keep one.
|
|
||||||
*(last_nonzero+2) = '\0';
|
|
||||||
return buffer;
|
|
||||||
default:
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -462,7 +462,7 @@ JSONTEST_FIXTURE( ValueTest, integers )
|
|||||||
JSONTEST_ASSERT_EQUAL(0.0, val.asDouble());
|
JSONTEST_ASSERT_EQUAL(0.0, val.asDouble());
|
||||||
JSONTEST_ASSERT_EQUAL(0.0, val.asFloat());
|
JSONTEST_ASSERT_EQUAL(0.0, val.asFloat());
|
||||||
JSONTEST_ASSERT_EQUAL(false, val.asBool());
|
JSONTEST_ASSERT_EQUAL(false, val.asBool());
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("0.0", val.asString());
|
JSONTEST_ASSERT_STRING_EQUAL("0", val.asString());
|
||||||
|
|
||||||
// Zero (signed constructor arg)
|
// Zero (signed constructor arg)
|
||||||
val = Json::Value(0);
|
val = Json::Value(0);
|
||||||
@ -546,7 +546,7 @@ JSONTEST_FIXTURE( ValueTest, integers )
|
|||||||
JSONTEST_ASSERT_EQUAL(0.0, val.asDouble());
|
JSONTEST_ASSERT_EQUAL(0.0, val.asDouble());
|
||||||
JSONTEST_ASSERT_EQUAL(0.0, val.asFloat());
|
JSONTEST_ASSERT_EQUAL(0.0, val.asFloat());
|
||||||
JSONTEST_ASSERT_EQUAL(false, val.asBool());
|
JSONTEST_ASSERT_EQUAL(false, val.asBool());
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("0.0", val.asString());
|
JSONTEST_ASSERT_STRING_EQUAL("0", val.asString());
|
||||||
|
|
||||||
// 2^20 (signed constructor arg)
|
// 2^20 (signed constructor arg)
|
||||||
val = Json::Value(1 << 20);
|
val = Json::Value(1 << 20);
|
||||||
@ -629,7 +629,7 @@ JSONTEST_FIXTURE( ValueTest, integers )
|
|||||||
JSONTEST_ASSERT_EQUAL((1 << 20), val.asDouble());
|
JSONTEST_ASSERT_EQUAL((1 << 20), val.asDouble());
|
||||||
JSONTEST_ASSERT_EQUAL((1 << 20), val.asFloat());
|
JSONTEST_ASSERT_EQUAL((1 << 20), val.asFloat());
|
||||||
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("1048576.0", normalizeFloatingPointStr(val.asString()));
|
JSONTEST_ASSERT_STRING_EQUAL("1048576", normalizeFloatingPointStr(val.asString()));
|
||||||
|
|
||||||
// -2^20
|
// -2^20
|
||||||
val = Json::Value(-(1 << 20));
|
val = Json::Value(-(1 << 20));
|
||||||
@ -869,7 +869,7 @@ JSONTEST_FIXTURE( ValueTest, integers )
|
|||||||
JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asDouble());
|
JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asDouble());
|
||||||
JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asFloat());
|
JSONTEST_ASSERT_EQUAL((Json::Int64(1) << 40), val.asFloat());
|
||||||
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("1099511627776.0", normalizeFloatingPointStr(val.asString()));
|
JSONTEST_ASSERT_STRING_EQUAL("1099511627776", normalizeFloatingPointStr(val.asString()));
|
||||||
|
|
||||||
// -2^40
|
// -2^40
|
||||||
val = Json::Value(-(Json::Int64(1) << 40));
|
val = Json::Value(-(Json::Int64(1) << 40));
|
||||||
@ -1035,7 +1035,7 @@ JSONTEST_FIXTURE( ValueTest, integers )
|
|||||||
JSONTEST_ASSERT_EQUAL(1e19, val.asDouble());
|
JSONTEST_ASSERT_EQUAL(1e19, val.asDouble());
|
||||||
JSONTEST_ASSERT_EQUAL(1e19, val.asFloat());
|
JSONTEST_ASSERT_EQUAL(1e19, val.asFloat());
|
||||||
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("1.000000000000000e+19", normalizeFloatingPointStr(val.asString()));
|
JSONTEST_ASSERT_STRING_EQUAL("1e+19", normalizeFloatingPointStr(val.asString()));
|
||||||
|
|
||||||
// uint64 max
|
// uint64 max
|
||||||
val = Json::Value(Json::UInt64(kuint64max));
|
val = Json::Value(Json::UInt64(kuint64max));
|
||||||
@ -1114,7 +1114,7 @@ JSONTEST_FIXTURE( ValueTest, nonIntegers )
|
|||||||
JSONTEST_ASSERT_EQUAL(1, val.asUInt());
|
JSONTEST_ASSERT_EQUAL(1, val.asUInt());
|
||||||
JSONTEST_ASSERT_EQUAL(1, val.asLargestUInt());
|
JSONTEST_ASSERT_EQUAL(1, val.asLargestUInt());
|
||||||
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
||||||
JSONTEST_ASSERT_EQUAL("1.50", val.asString());
|
JSONTEST_ASSERT_EQUAL("1.5", val.asString());
|
||||||
|
|
||||||
// Small negative number
|
// Small negative number
|
||||||
val = Json::Value(-1.5);
|
val = Json::Value(-1.5);
|
||||||
@ -1140,7 +1140,7 @@ JSONTEST_FIXTURE( ValueTest, nonIntegers )
|
|||||||
JSONTEST_ASSERT_EQUAL(-1, val.asInt());
|
JSONTEST_ASSERT_EQUAL(-1, val.asInt());
|
||||||
JSONTEST_ASSERT_EQUAL(-1, val.asLargestInt());
|
JSONTEST_ASSERT_EQUAL(-1, val.asLargestInt());
|
||||||
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
||||||
JSONTEST_ASSERT_EQUAL("-1.50", val.asString());
|
JSONTEST_ASSERT_EQUAL("-1.5", val.asString());
|
||||||
|
|
||||||
// A bit over int32 max
|
// A bit over int32 max
|
||||||
val = Json::Value(kint32max + 0.5);
|
val = Json::Value(kint32max + 0.5);
|
||||||
@ -1169,7 +1169,7 @@ JSONTEST_FIXTURE( ValueTest, nonIntegers )
|
|||||||
JSONTEST_ASSERT_EQUAL(2147483647U, val.asLargestUInt());
|
JSONTEST_ASSERT_EQUAL(2147483647U, val.asLargestUInt());
|
||||||
#endif
|
#endif
|
||||||
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
||||||
JSONTEST_ASSERT_EQUAL("2147483647.50", normalizeFloatingPointStr(val.asString()));
|
JSONTEST_ASSERT_EQUAL("2147483647.5", normalizeFloatingPointStr(val.asString()));
|
||||||
|
|
||||||
// A bit under int32 min
|
// A bit under int32 min
|
||||||
val = Json::Value(kint32min - 0.5);
|
val = Json::Value(kint32min - 0.5);
|
||||||
@ -1196,7 +1196,7 @@ JSONTEST_FIXTURE( ValueTest, nonIntegers )
|
|||||||
JSONTEST_ASSERT_EQUAL(-Json::Int64(1)<< 31, val.asLargestInt());
|
JSONTEST_ASSERT_EQUAL(-Json::Int64(1)<< 31, val.asLargestInt());
|
||||||
#endif
|
#endif
|
||||||
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
||||||
JSONTEST_ASSERT_EQUAL("-2147483648.50", normalizeFloatingPointStr(val.asString()));
|
JSONTEST_ASSERT_EQUAL("-2147483648.5", normalizeFloatingPointStr(val.asString()));
|
||||||
|
|
||||||
// A bit over uint32 max
|
// A bit over uint32 max
|
||||||
val = Json::Value(kuint32max + 0.5);
|
val = Json::Value(kuint32max + 0.5);
|
||||||
@ -1224,15 +1224,15 @@ JSONTEST_FIXTURE( ValueTest, nonIntegers )
|
|||||||
JSONTEST_ASSERT_EQUAL((Json::UInt64(1) << 32)-Json::UInt64(1), val.asLargestUInt());
|
JSONTEST_ASSERT_EQUAL((Json::UInt64(1) << 32)-Json::UInt64(1), val.asLargestUInt());
|
||||||
#endif
|
#endif
|
||||||
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
JSONTEST_ASSERT_EQUAL(true, val.asBool());
|
||||||
JSONTEST_ASSERT_EQUAL("4294967295.50", normalizeFloatingPointStr(val.asString()));
|
JSONTEST_ASSERT_EQUAL("4294967295.5", normalizeFloatingPointStr(val.asString()));
|
||||||
|
|
||||||
val = Json::Value(1.2345678901234);
|
val = Json::Value(1.2345678901234);
|
||||||
JSONTEST_ASSERT_STRING_EQUAL( "1.23456789012340", normalizeFloatingPointStr(val.asString()));
|
JSONTEST_ASSERT_STRING_EQUAL( "1.2345678901234", normalizeFloatingPointStr(val.asString()));
|
||||||
|
|
||||||
// A 16-digit floating point number.
|
// A 16-digit floating point number.
|
||||||
val = Json::Value(2199023255552000.0f);
|
val = Json::Value(2199023255552000.0f);
|
||||||
JSONTEST_ASSERT_EQUAL(float(2199023255552000), val.asFloat());
|
JSONTEST_ASSERT_EQUAL(float(2199023255552000), val.asFloat());
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("2199023255552000.", normalizeFloatingPointStr(val.asString()));
|
JSONTEST_ASSERT_STRING_EQUAL("2199023255552000", normalizeFloatingPointStr(val.asString()));
|
||||||
|
|
||||||
// A very large floating point number.
|
// A very large floating point number.
|
||||||
val = Json::Value(3.402823466385289e38);
|
val = Json::Value(3.402823466385289e38);
|
||||||
@ -1242,7 +1242,7 @@ JSONTEST_FIXTURE( ValueTest, nonIntegers )
|
|||||||
// An even larger floating point number.
|
// An even larger floating point number.
|
||||||
val = Json::Value(1.2345678e300);
|
val = Json::Value(1.2345678e300);
|
||||||
JSONTEST_ASSERT_EQUAL(double(1.2345678e300), val.asDouble());
|
JSONTEST_ASSERT_EQUAL(double(1.2345678e300), val.asDouble());
|
||||||
JSONTEST_ASSERT_STRING_EQUAL("1.234567800000000e+300", normalizeFloatingPointStr(val.asString()));
|
JSONTEST_ASSERT_STRING_EQUAL("1.2345678e+300", normalizeFloatingPointStr(val.asString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user