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); +}