From de1011152ece31362bb735ea5dd03ff34ad04f0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Matte?= Date: Fri, 6 Nov 2015 00:24:17 -0500 Subject: [PATCH] Fixed an issue with the preservation of whitespaces for strings. The validation may be invalid when one of the previous calls to the saveValue was done and the value was taking more characters. A test is now added in order to reproduce this error. --- include/cereal/archives/xml.hpp | 13 ++++++---- unittests/basic_string.cpp | 44 +++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/include/cereal/archives/xml.hpp b/include/cereal/archives/xml.hpp index c9733e36..9a628c40 100644 --- a/include/cereal/archives/xml.hpp +++ b/include/cereal/archives/xml.hpp @@ -232,19 +232,22 @@ namespace cereal itsOS.clear(); itsOS.seekp( 0, std::ios::beg ); itsOS << value << std::ends; - const auto strValue = itsOS.str(); + auto strValue = itsOS.str(); + + // itsOS.str() may contains data from previous calls after the first '\0' that was just inserted + // and this data is counted in the length call. We make sure to remove that section so that the + // whitespace validation is done properly + strValue.resize(std::strlen(strValue.c_str())); // If the first or last character is a whitespace, add xml:space attribute - // the string always contains a '\0' added by std::ends, so the last character is at len-2 and an 'empty' - // string has a length of 1 or lower const auto len = strValue.length(); - if ( len > 1 && ( xml_detail::isWhitespace( strValue[0] ) || xml_detail::isWhitespace( strValue[len - 2] ) ) ) + if ( len > 0 && ( xml_detail::isWhitespace( strValue[0] ) || xml_detail::isWhitespace( strValue[len - 1] ) ) ) { itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "xml:space", "preserve" ) ); } // allocate strings for all of the data in the XML object - auto dataPtr = itsXML.allocate_string( itsOS.str().c_str(), itsOS.str().length() + 1 ); + auto dataPtr = itsXML.allocate_string(strValue.c_str(), strValue.length() + 1 ); // insert into the XML itsNodes.top().node->append_node( itsXML.allocate_node( rapidxml::node_data, nullptr, dataPtr ) ); diff --git a/unittests/basic_string.cpp b/unittests/basic_string.cpp index ede18525..65cfffb0 100644 --- a/unittests/basic_string.cpp +++ b/unittests/basic_string.cpp @@ -225,3 +225,47 @@ BOOST_AUTO_TEST_CASE( xml_char_issue109 ) test_ws_in_out( char( chars[i] ) ); } } + +template +void test_ws_in_out_array(Out const (&o_a_value_with_ws)[Nb]) +{ + std::ostringstream os; + { + OArchive oar(os); + for (const auto& o_value_with_ws : o_a_value_with_ws) + { + oar(o_value_with_ws); + } + } + + In i_a_value_with_ws[Nb]; + + std::istringstream is(os.str()); + { + IArchive iar(is); + for (In& i_value_with_ws : i_a_value_with_ws) + { + iar(i_value_with_ws); + } + } + + for (size_t uiIndex = 0; uiIndex < Nb; ++uiIndex) + { + BOOST_CHECK_EQUAL(i_a_value_with_ws[uiIndex], o_a_value_with_ws[uiIndex]); + } +} + +BOOST_AUTO_TEST_CASE(xml_string_issue_consecutive_calls) +{ + std::string strings[] = { + "some text", + " some text", + " some text ", + "Long text without ws at the end", + "some text ", + " some text", + " some text ", + }; + + test_ws_in_out_array(strings); +}