From ff5493188293eab30f1294241461abebe29e56fa Mon Sep 17 00:00:00 2001 From: Joao Paulo Magalhaes Date: Sun, 1 May 2022 16:59:50 +0100 Subject: [PATCH] [fix] double-quoted emitter should escape carriage return to ensure roundtrip equivalence re #253 --- changelog/current.md | 12 ++++++++++++ src/c4/yml/emit.def.hpp | 7 +++++++ test/test_double_quoted.cpp | 35 +++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+) diff --git a/changelog/current.md b/changelog/current.md index e54c6502..153b5279 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 01b58618..2898eaca 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 5ee7d5cf..9820c7fd 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()); + } +} + //----------------------------------------------------------------------------- //-----------------------------------------------------------------------------