diff options
| author | Phil Nash | 2015-12-04 10:19:08 +0000 |
|---|---|---|
| committer | Phil Nash | 2015-12-04 10:19:08 +0000 |
| commit | fdc42d0af47f58fa13a42b685bbeaf55a8347673 (patch) | |
| tree | 779ff3d692eeffd33353d89ad7697a592ab5201e /include/internal/catch_xmlwriter.hpp | |
| parent | d758428fe297655e558a86cc6a013fcb1bcc8c7d (diff) | |
| parent | d274fc571c3980b5ac04cbe1416cf2205e6c99f7 (diff) | |
| download | catch3-1.3.0.tar.gz | |
Merged from develop branchv1.3.0
- now v1.3.0
Diffstat (limited to 'include/internal/catch_xmlwriter.hpp')
| -rw-r--r-- | include/internal/catch_xmlwriter.hpp | 103 |
1 files changed, 68 insertions, 35 deletions
diff --git a/include/internal/catch_xmlwriter.hpp b/include/internal/catch_xmlwriter.hpp index 553c5a79..c59725b0 100644 --- a/include/internal/catch_xmlwriter.hpp +++ b/include/internal/catch_xmlwriter.hpp @@ -8,14 +8,72 @@ #ifndef TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED #define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED -#include "../internal/catch_stream.h" +#include "catch_stream.h" +#include "catch_compiler_capabilities.h" +#include "catch_suppress_warnings.h" #include <sstream> #include <string> #include <vector> +#include <iomanip> namespace Catch { + class XmlEncode { + public: + enum ForWhat { ForTextNodes, ForAttributes }; + + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ) + : m_str( str ), + m_forWhat( forWhat ) + {} + + void encodeTo( std::ostream& os ) const { + + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: http://www.w3.org/TR/xml/#syntax) + + for( std::size_t i = 0; i < m_str.size(); ++ i ) { + char c = m_str[i]; + switch( c ) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: http://www.w3.org/TR/xml/#syntax + if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) + os << ">"; + else + os << c; + break; + + case '\"': + if( m_forWhat == ForAttributes ) + os << """; + else + os << c; + break; + + default: + // Escape control chars - based on contribution by @espenalb in PR #465 + if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) + os << "&#x" << std::uppercase << std::hex << static_cast<int>( c ); + else + os << c; + } + } + } + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } + + private: + std::string m_str; + ForWhat m_forWhat; + }; + class XmlWriter { public: @@ -27,7 +85,7 @@ namespace Catch { ScopedElement( ScopedElement const& other ) : m_writer( other.m_writer ){ - other.m_writer = NULL; + other.m_writer = CATCH_NULL; } ~ScopedElement() { @@ -98,11 +156,8 @@ namespace Catch { } XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { - if( !name.empty() && !attribute.empty() ) { - stream() << " " << name << "=\""; - writeEncodedText( attribute ); - stream() << "\""; - } + if( !name.empty() && !attribute.empty() ) + stream() << " " << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << "\""; return *this; } @@ -113,9 +168,9 @@ namespace Catch { template<typename T> XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { - if( !name.empty() ) - stream() << " " << name << "=\"" << attribute << "\""; - return *this; + std::ostringstream oss; + oss << attribute; + return writeAttribute( name, oss.str() ); } XmlWriter& writeText( std::string const& text, bool indent = true ) { @@ -124,7 +179,7 @@ namespace Catch { ensureTagClosed(); if( tagWasOpen && indent ) stream() << m_indent; - writeEncodedText( text ); + stream() << XmlEncode( text ); m_needsNewline = true; } return *this; @@ -169,30 +224,6 @@ namespace Catch { } } - void writeEncodedText( std::string const& text ) { - static const char* charsToEncode = "<&\""; - std::string mtext = text; - std::string::size_type pos = mtext.find_first_of( charsToEncode ); - while( pos != std::string::npos ) { - stream() << mtext.substr( 0, pos ); - - switch( mtext[pos] ) { - case '<': - stream() << "<"; - break; - case '&': - stream() << "&"; - break; - case '\"': - stream() << """; - break; - } - mtext = mtext.substr( pos+1 ); - pos = mtext.find_first_of( charsToEncode ); - } - stream() << mtext; - } - bool m_tagIsOpen; bool m_needsNewline; std::vector<std::string> m_tags; @@ -201,4 +232,6 @@ namespace Catch { }; } +#include "catch_reenable_warnings.h" + #endif // TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED |