Commit cc743297 authored by Ingvar Stepanyan's avatar Ingvar Stepanyan

Simplify JSON number decoding

Simplifiy implementation and, as a bonus, allow overflowing floating numbers to convert to +/-Infinity like they do in JSON.parse.

Also update outdated comment about NaN and Infinity being encoded as `null`.
parent bf787a2d
......@@ -258,6 +258,8 @@ KJ_TEST("decode all types") {
CASE_NO_ROUNDTRIP(R"({"float32Field":"-infinity"})", root.getFloat32Field() == -kj::inf());
CASE_NO_ROUNDTRIP(R"({"float32Field":"INF"})", root.getFloat32Field() == kj::inf());
CASE_NO_ROUNDTRIP(R"({"float32Field":"-INF"})", root.getFloat32Field() == -kj::inf());
CASE_NO_ROUNDTRIP(R"({"float32Field":1e39})", root.getFloat32Field() == kj::inf());
CASE_NO_ROUNDTRIP(R"({"float32Field":-1e39})", root.getFloat32Field() == -kj::inf());
CASE_NO_ROUNDTRIP(R"({"float64Field":0})", root.getFloat64Field() == 0);
CASE(R"({"float64Field":4.5})", root.getFloat64Field() == 4.5);
CASE_NO_ROUNDTRIP(R"({"float64Field":null})", kj::isNaN(root.getFloat64Field()));
......@@ -268,6 +270,8 @@ KJ_TEST("decode all types") {
CASE_NO_ROUNDTRIP(R"({"float64Field":"-infinity"})", root.getFloat64Field() == -kj::inf());
CASE_NO_ROUNDTRIP(R"({"float64Field":"INF"})", root.getFloat64Field() == kj::inf());
CASE_NO_ROUNDTRIP(R"({"float64Field":"-INF"})", root.getFloat64Field() == -kj::inf());
CASE_NO_ROUNDTRIP(R"({"float64Field":1e309})", root.getFloat64Field() == kj::inf());
CASE_NO_ROUNDTRIP(R"({"float64Field":-1e309})", root.getFloat64Field() == -kj::inf());
CASE(R"({"textField":"hello"})", kj::str("hello") == root.getTextField());
CASE(R"({"dataField":[7,0,122]})",
kj::heapArray<byte>({7,0,122}).asPtr() == root.getDataField());
......@@ -531,20 +535,6 @@ KJ_TEST("basic json decoding") {
KJ_EXPECT_THROW_MESSAGE("Unexpected", json.decodeRaw("+123", root));
}
{
MallocMessageBuilder message;
auto root = message.initRoot<JsonValue>();
KJ_EXPECT_THROW_MESSAGE("Overflow", json.decodeRaw("1e1024", root));
}
{
MallocMessageBuilder message;
auto root = message.initRoot<JsonValue>();
KJ_EXPECT_THROW_MESSAGE("Underflow", json.decodeRaw("1e-1023", root));
}
{
MallocMessageBuilder message;
auto root = message.initRoot<JsonValue>();
......
......@@ -658,19 +658,7 @@ public:
}
void parseNumber(JsonValue::Builder& output) {
auto numberStr = consumeNumber();
char *endPtr;
errno = 0;
double value = strtod(numberStr.begin(), &endPtr);
KJ_ASSERT(endPtr != numberStr.begin(), "strtod should not fail! Is consumeNumber wrong?");
KJ_REQUIRE((value != HUGE_VAL && value != -HUGE_VAL) || errno != ERANGE,
"Overflow in JSON number.");
KJ_REQUIRE(value != 0.0 || errno != ERANGE,
"Underflow in JSON number.");
output.setNumber(value);
output.setNumber(consumeNumber().parseAs<double>());
}
void parseString(JsonValue::Builder& output) {
......
......@@ -49,7 +49,7 @@ class JsonCodec {
// - 64-bit integers are encoded as strings, since JSON "numbers" are double-precision floating
// points which cannot store a 64-bit integer without losing data.
// - NaNs and infinite floating point numbers are not allowed by the JSON spec, and so are encoded
// as null. This matches the behavior of `JSON.stringify` in at least Firefox and Chrome.
// as strings.
// - Data is encoded as an array of numbers in the range [0,255]. You probably want to register
// a handler that does something better, like maybe base64 encoding, but there are a zillion
// different ways people do this.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment