Extended the fix for issue #109 and added a test.

This commit is contained in:
Volo Zyko 2014-07-31 15:45:05 +03:00
parent b0d45bd565
commit 16bf75dedf
2 changed files with 112 additions and 3 deletions

View File

@ -238,8 +238,11 @@ namespace cereal
itsOS.clear(); itsOS.seekp( 0, std::ios::beg );
itsOS << value << std::ends;
// workaround rapidxml restriction on whitespace handling.
auto encoded = encode_cdata( itsOS.str() );
// allocate strings for all of the data in the XML object
auto dataPtr = itsXML.allocate_string( itsOS.str().c_str() );
auto dataPtr = itsXML.allocate_string( encoded.c_str() );
// allocate cdata and set its value
auto cdata = itsXML.allocate_node( rapidxml::node_cdata );
@ -317,6 +320,34 @@ namespace cereal
}
}; // NodeInfo
//! Encode only & and > in cdata text
/* Normally CDATA when saved to XML should not be changed in any way
but since rapidxml doesn't handle xml:space attribute in XML elements then
we use CDATA and do escaping of non-allowed characters manually. */
std::string encode_cdata( std::string const & text )
{
std::string res;
res.reserve( text.size() );
for( auto c : text )
{
if( c == '&' )
{
res.append( "&amp;" );
}
else if( c == '>' )
{
res.append( "&gt;" );
}
else
{
res.append( 1, c );
}
}
return res;
}
//! @}
private:
@ -594,8 +625,8 @@ namespace cereal
std::basic_istringstream<CharT, Traits> is( first_node->value() );
str.assign( std::istreambuf_iterator<CharT, Traits>( is ),
std::istreambuf_iterator<CharT, Traits>() );
str = decode_cdata<CharT, Traits, Alloc>( std::istreambuf_iterator<CharT, Traits>( is ),
std::istreambuf_iterator<CharT, Traits>() );
}
//! Loads the size of the current top node
@ -676,6 +707,44 @@ namespace cereal
const char * name; //!< The NVP name for next next child node
}; // NodeInfo
//! Decode & and > characters in cdata
/* For details see explanation for XMLOutputArchive::encode_cdata(). */
template<class CharT, class Traits, class Alloc>
std::basic_string<CharT, Traits, Alloc> decode_cdata( std::istreambuf_iterator<CharT, Traits> start,
const std::istreambuf_iterator<CharT, Traits>& end )
{
std::basic_string<CharT, Traits, Alloc> res;
for( ; start != end; ++start )
{
if( *start == '&' )
{
const auto first = *( ++start );
const auto second = *( ++start );
const auto third = *( ++start );
if( first == 'g' && second == 't' && third == ';' )
{
res.append( 1, '>' );
}
else if( first == 'a' && second == 'm' && third == 'p' && *( ++start ) == ';' )
{
res.append( 1, '&' );
}
else
{
throw Exception("Cannot decode cdata value");
}
}
else
{
res.append( 1, *start );
}
}
return res;
}
//! @}
private:

View File

@ -125,3 +125,43 @@ BOOST_AUTO_TEST_CASE( json_string_basic )
test_string_basic<cereal::JSONInputArchive, cereal::JSONOutputArchive>();
}
template <class IArchive, class OArchive, class T, size_t N, size_t M>
void test_string_for_array(T (&strings)[N][M])
{
for(size_t i=0; i<N; ++i)
{
std::basic_string<T> o_string = strings[i];
std::ostringstream os;
{
OArchive oar(os);
oar(o_string);
}
std::basic_string<T> i_string;
std::istringstream is(os.str());
{
IArchive iar(is);
iar(i_string);
}
BOOST_CHECK_EQUAL(i_string, o_string);
}
}
BOOST_AUTO_TEST_CASE( xml_string_issue109 )
{
char strings[][20] = {
"some text",
" some text ",
" ",
" text ",
" ]]> ",
" &gt; > ]]> ",
" < <]>] &lt; ",
" &amp; & "
};
test_string_for_array<cereal::XMLInputArchive, cereal::XMLOutputArchive>(strings);
}