diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index 4b2d72322..a28219df3 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -1972,6 +1972,8 @@ class GenericValue { return handler.EndArray(data_.a.size); case kStringType: + if (data_.f.flags & kRawNumberFlag) + return handler.RawNumber(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0); return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0); default: @@ -1999,6 +2001,7 @@ class GenericValue { kStringFlag = 0x0400, kCopyFlag = 0x0800, kInlineStrFlag = 0x1000, + kRawNumberFlag = 0x2000, // Initial flags of different types. kNullFlag = kNullType, @@ -2831,6 +2834,7 @@ class GenericDocument : public GenericValue { new (stack_.template Push()) ValueType(str, length, GetAllocator()); else new (stack_.template Push()) ValueType(str, length); + stack_.template Top()->data_.f.flags |= ValueType::kRawNumberFlag; return true; } diff --git a/include/rapidjson/prettywriter.h b/include/rapidjson/prettywriter.h index 29dffb42e..e61181b2d 100644 --- a/include/rapidjson/prettywriter.h +++ b/include/rapidjson/prettywriter.h @@ -121,7 +121,7 @@ class PrettyWriter : public Writer(json); + EXPECT_FALSE(d.HasParseError()); + + // Verify values are stored as strings internally + EXPECT_TRUE(d["age"].IsString()); + EXPECT_STREQ("27", d["age"].GetString()); + EXPECT_TRUE(d["pi"].IsString()); + EXPECT_STREQ("3.14159", d["pi"].GetString()); + EXPECT_TRUE(d["name"].IsString()); + EXPECT_STREQ("test", d["name"].GetString()); + + // Serialize back via Writer + StringBuffer buffer; + Writer writer(buffer); + d.Accept(writer); + + // Numbers should NOT be quoted, but actual strings should be + EXPECT_STREQ("{\"age\":27,\"pi\":3.14159,\"name\":\"test\"}", buffer.GetString()); +} + +TEST(Document, RawNumberRoundtrip_Array) { + const char* json = "[1, 2.5, \"hello\", 100]"; + + Document d; + d.Parse(json); + EXPECT_FALSE(d.HasParseError()); + + StringBuffer buffer; + Writer writer(buffer); + d.Accept(writer); + + EXPECT_STREQ("[1,2.5,\"hello\",100]", buffer.GetString()); +} + +TEST(Document, RawNumberRoundtrip_PrettyWriter) { + const char* json = "{\"value\":42}"; + + Document d; + d.Parse(json); + EXPECT_FALSE(d.HasParseError()); + + StringBuffer buffer; + PrettyWriter writer(buffer); + d.Accept(writer); + + // Should contain unquoted 42 + const char* s = buffer.GetString(); + EXPECT_TRUE(strstr(s, ": 42") != NULL); + // Should NOT contain "42" + EXPECT_TRUE(strstr(s, ": \"42\"") == NULL); +} + #ifdef __clang__ RAPIDJSON_DIAG_POP #endif diff --git a/test/unittest/prettywritertest.cpp b/test/unittest/prettywritertest.cpp index 0b7feef3b..39ac40cb5 100644 --- a/test/unittest/prettywritertest.cpp +++ b/test/unittest/prettywritertest.cpp @@ -368,6 +368,25 @@ TEST(PrettyWriter, Issue_1336) { EXPECT_TRUE(writer.IsComplete()); } +TEST(PrettyWriter, RawNumber_NoQuotes) { + StringBuffer buffer; + PrettyWriter writer(buffer); + writer.StartObject(); + writer.Key("pi"); + writer.RawNumber("3.14159", 7); + writer.Key("answer"); + writer.RawNumber("42", 2); + writer.Key("label"); + writer.String("test"); + writer.EndObject(); + EXPECT_TRUE(writer.IsComplete()); + // Verify numbers are not quoted + const char* s = buffer.GetString(); + EXPECT_TRUE(strstr(s, ": 3.14159") != NULL); + EXPECT_TRUE(strstr(s, ": 42") != NULL); + EXPECT_TRUE(strstr(s, ": \"test\"") != NULL); +} + #ifdef __clang__ RAPIDJSON_DIAG_POP #endif diff --git a/test/unittest/writertest.cpp b/test/unittest/writertest.cpp index 4c2412109..69416c420 100644 --- a/test/unittest/writertest.cpp +++ b/test/unittest/writertest.cpp @@ -568,6 +568,31 @@ TEST(Writer, RawValue) { EXPECT_STREQ("{\"a\":1,\"raw\":[\"Hello\\nWorld\", 123.456]}", buffer.GetString()); } +TEST(Writer, RawNumber_NoQuotes) { + StringBuffer buffer; + Writer writer(buffer); + writer.StartArray(); + const char number[] = "3.14159"; + writer.RawNumber(number, 4); + writer.RawNumber(number, static_cast(strlen(number))); + writer.EndArray(); + EXPECT_TRUE(writer.IsComplete()); + EXPECT_STREQ("[3.14,3.14159]", buffer.GetString()); +} + +TEST(Writer, RawNumber_InObject) { + StringBuffer buffer; + Writer writer(buffer); + writer.StartObject(); + writer.Key("value"); + writer.RawNumber("42", 2); + writer.Key("name"); + writer.String("test"); + writer.EndObject(); + EXPECT_TRUE(writer.IsComplete()); + EXPECT_STREQ("{\"value\":42,\"name\":\"test\"}", buffer.GetString()); +} + TEST(Write, RawValue_Issue1152) { { GenericStringBuffer > sb;