From 69b329fc87e7a10f84a0bd012e74e3af7549526d Mon Sep 17 00:00:00 2001 From: Vladimir Glavnyy <31897320+vglavnyy@users.noreply.github.com> Date: Tue, 16 Mar 2021 01:44:42 +0700 Subject: [PATCH] [flexbuffers, json] Parse `nan` and `inf` (#6512) --- include/flatbuffers/idl.h | 2 ++ src/idl_parser.cpp | 24 ++++++++++++++++++++++++ tests/test.cpp | 26 ++++++++++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h index d9ef95b..ab77893 100644 --- a/include/flatbuffers/idl.h +++ b/include/flatbuffers/idl.h @@ -956,6 +956,8 @@ class Parser : public ParserState { FLATBUFFERS_CHECKED_ERROR ParseProtoCurliesOrIdent(); FLATBUFFERS_CHECKED_ERROR ParseTypeFromProtoType(Type *type); FLATBUFFERS_CHECKED_ERROR SkipAnyJsonValue(); + FLATBUFFERS_CHECKED_ERROR ParseFlexBufferNumericConstant( + flexbuffers::Builder *builder); FLATBUFFERS_CHECKED_ERROR ParseFlexBufferValue(flexbuffers::Builder *builder); FLATBUFFERS_CHECKED_ERROR StartParseFile(const char *source, const char *source_filename); diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index 6faee4d..f20b6f9 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -3009,6 +3009,15 @@ CheckedError Parser::SkipAnyJsonValue() { return NoError(); } +CheckedError Parser::ParseFlexBufferNumericConstant( + flexbuffers::Builder *builder) { + double d; + if (!StringToNumber(attribute_.c_str(), &d)) + return Error("unexpected floating-point constant: " + attribute_); + builder->Double(d); + return NoError(); +} + CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) { ParseDepthGuard depth_guard(this); ECHECK(depth_guard.Check()); @@ -3056,6 +3065,18 @@ CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) { EXPECT(kTokenFloatConstant); break; } + case '-': + case '+': { + // `[-+]?(nan|inf|infinity)`, see ParseSingleValue(). + const auto sign = static_cast(token_); + NEXT(); + if (token_ != kTokenIdentifier) + return Error("floating-point constant expected"); + attribute_.insert(0, 1, sign); + ECHECK(ParseFlexBufferNumericConstant(builder)); + NEXT(); + break; + } default: if (IsIdent("true")) { builder->Bool(true); @@ -3066,6 +3087,9 @@ CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) { } else if (IsIdent("null")) { builder->Null(); NEXT(); + } else if (IsIdent("inf") || IsIdent("infinity") || IsIdent("nan")) { + ECHECK(ParseFlexBufferNumericConstant(builder)); + NEXT(); } else return TokenError(); } diff --git a/tests/test.cpp b/tests/test.cpp index ffd293d..87568c2 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -3020,6 +3020,31 @@ void FlexBuffersTest() { TEST_EQ(slb.GetSize(), 664); } +void FlexBuffersFloatingPointTest() { +#if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0) + flexbuffers::Builder slb(512, + flexbuffers::BUILDER_FLAG_SHARE_KEYS_AND_STRINGS); + // Parse floating-point values from JSON: + flatbuffers::Parser parser; + slb.Clear(); + auto jsontest = + "{ a: [1.0, nan, inf, infinity, -inf, +inf, -infinity, 8.0] }"; + TEST_EQ(parser.ParseFlexBuffer(jsontest, nullptr, &slb), true); + auto jroot = flexbuffers::GetRoot(slb.GetBuffer()); + auto jmap = jroot.AsMap(); + auto jvec = jmap["a"].AsVector(); + TEST_EQ(8, jvec.size()); + TEST_EQ(1.0, jvec[0].AsDouble()); + TEST_ASSERT(is_quiet_nan(jvec[1].AsDouble())); + TEST_EQ(infinity_d, jvec[2].AsDouble()); + TEST_EQ(infinity_d, jvec[3].AsDouble()); + TEST_EQ(-infinity_d, jvec[4].AsDouble()); + TEST_EQ(+infinity_d, jvec[5].AsDouble()); + TEST_EQ(-infinity_d, jvec[6].AsDouble()); + TEST_EQ(8.0, jvec[7].AsDouble()); +#endif +} + void FlexBuffersDeprecatedTest() { // FlexBuffers as originally designed had a flaw involving the // FBT_VECTOR_STRING datatype, and this test documents/tests the fix for it. @@ -3909,6 +3934,7 @@ int FlatBufferTests() { FieldIdentifierTest(); StringVectorDefaultsTest(); ParseIncorrectMonsterJsonTest(); + FlexBuffersFloatingPointTest(); return 0; } -- 2.7.4