diff --git a/changelog/current.md b/changelog/current.md index e54c65020..153b5279e 100644 --- a/changelog/current.md +++ b/changelog/current.md @@ -19,3 +19,15 @@ =VAL :foo =VAL :bar ``` +- Fix [#253](https://github.com/biojppm/rapidyaml/issues/253): double-quoted emitter should encode carriage-return `\r` to preserve roundtrip equivalence: + ```yaml + Tree tree; + NodeRef root = tree.rootref(); + root |= MAP; + root["s"] = "t\rt"; + root["s"] |= _WIP_VAL_DQUO; + std::string s = emitrs(tree); + EXPECT_EQ(s, "s: \"t\\rt\"\n"); + Tree tree2 = parse_in_arena(to_csubstr(s)); + EXPECT_EQ(tree2["s"].val(), tree["s"].val()); + ``` diff --git a/src/c4/yml/emit.def.hpp b/src/c4/yml/emit.def.hpp index 01b58618a..2898eaca1 100644 --- a/src/c4/yml/emit.def.hpp +++ b/src/c4/yml/emit.def.hpp @@ -767,6 +767,13 @@ void Emitter::_write_scalar_dquo(csubstr s, size_t ilevel) pos = i; } } + else if(C4_UNLIKELY(curr == '\r')) + { + csubstr sub = s.range(pos, i); + this->Writer::_do_write(sub); // write everything up to (excluding) this char + this->Writer::_do_write("\\r"); // write the escaped char + pos = i+1; + } } // write missing characters at the end of the string if(pos < s.len) diff --git a/test/test_double_quoted.cpp b/test/test_double_quoted.cpp index 5ee7d5cf6..9820c7fd3 100644 --- a/test/test_double_quoted.cpp +++ b/test/test_double_quoted.cpp @@ -399,6 +399,41 @@ TEST(double_quoted, error_on_bad_utf_codepoints) verify_error_is_reported("bad value \\U" , R"(foo: "\Ukokokoko")"); } +TEST(double_quoted, github253) +{ + { + Tree tree; + NodeRef root = tree.rootref(); + root |= MAP; + root["t"] = "t't\\nt"; + root["t"] |= _WIP_VAL_DQUO; + std::string s = emitrs(tree); + Tree tree2 = parse_in_arena(to_csubstr(s)); + EXPECT_EQ(tree2["t"].val(), tree["t"].val()); + } + { + Tree tree; + NodeRef root = tree.rootref(); + root |= MAP; + root["t"] = "t't\\nt"; + root["t"] |= _WIP_VAL_SQUO; + std::string s = emitrs(tree); + Tree tree2 = parse_in_arena(to_csubstr(s)); + EXPECT_EQ(tree2["t"].val(), tree["t"].val()); + } + { + Tree tree; + NodeRef root = tree.rootref(); + root |= MAP; + root["s"] = "t\rt"; + root["s"] |= _WIP_VAL_DQUO; + std::string s = emitrs(tree); + EXPECT_EQ(s, "s: \"t\\rt\"\n"); + Tree tree2 = parse_in_arena(to_csubstr(s)); + EXPECT_EQ(tree2["s"].val(), tree["s"].val()); + } +} + //----------------------------------------------------------------------------- //-----------------------------------------------------------------------------