mirror of
				https://github.com/catchorg/Catch2.git
				synced 2025-11-04 09:01:50 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			191 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			191 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
 *  Created by Phil on 19/07/2017.
 | 
						|
 *
 | 
						|
 *  Distributed under the Boost Software License, Version 1.0. (See accompanying
 | 
						|
 *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 | 
						|
 */
 | 
						|
 | 
						|
#include "catch_xmlwriter.hpp"
 | 
						|
 | 
						|
#include <iomanip>
 | 
						|
 | 
						|
namespace Catch {
 | 
						|
 | 
						|
    XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat )
 | 
						|
    :   m_str( str ),
 | 
						|
        m_forWhat( forWhat )
 | 
						|
    {}
 | 
						|
 | 
						|
    void XmlEncode::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 and
 | 
						|
                    // by @mrpi PR #588
 | 
						|
                    if ( ( c >= 0 && c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) {
 | 
						|
                        // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
 | 
						|
                        os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2)
 | 
						|
                           << static_cast<int>( c );
 | 
						|
                    }
 | 
						|
                    else
 | 
						|
                        os << c;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {
 | 
						|
        xmlEncode.encodeTo( os );
 | 
						|
        return os;
 | 
						|
    }
 | 
						|
 | 
						|
    XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer )
 | 
						|
    :   m_writer( writer )
 | 
						|
    {}
 | 
						|
 | 
						|
    XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept
 | 
						|
    :   m_writer( other.m_writer ){
 | 
						|
        other.m_writer = nullptr;
 | 
						|
    }
 | 
						|
    XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept {
 | 
						|
        if ( m_writer ) {
 | 
						|
            m_writer->endElement();
 | 
						|
        }
 | 
						|
        m_writer = other.m_writer;
 | 
						|
        other.m_writer = nullptr;
 | 
						|
        return *this;
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    XmlWriter::ScopedElement::~ScopedElement() {
 | 
						|
        if( m_writer )
 | 
						|
            m_writer->endElement();
 | 
						|
    }
 | 
						|
 | 
						|
    XmlWriter::ScopedElement& XmlWriter::ScopedElement::writeText( std::string const& text, bool indent ) {
 | 
						|
        m_writer->writeText( text, indent );
 | 
						|
        return *this;
 | 
						|
    }
 | 
						|
 | 
						|
    XmlWriter::XmlWriter( std::ostream& os ) : m_os( os )
 | 
						|
    {
 | 
						|
        writeDeclaration();
 | 
						|
    }
 | 
						|
 | 
						|
    XmlWriter::~XmlWriter() {
 | 
						|
        while( !m_tags.empty() )
 | 
						|
            endElement();
 | 
						|
    }
 | 
						|
 | 
						|
    XmlWriter& XmlWriter::startElement( std::string const& name ) {
 | 
						|
        ensureTagClosed();
 | 
						|
        newlineIfNecessary();
 | 
						|
        m_os << m_indent << '<' << name;
 | 
						|
        m_tags.push_back( name );
 | 
						|
        m_indent += "  ";
 | 
						|
        m_tagIsOpen = true;
 | 
						|
        return *this;
 | 
						|
    }
 | 
						|
 | 
						|
    XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name ) {
 | 
						|
        ScopedElement scoped( this );
 | 
						|
        startElement( name );
 | 
						|
        return scoped;
 | 
						|
    }
 | 
						|
 | 
						|
    XmlWriter& XmlWriter::endElement() {
 | 
						|
        newlineIfNecessary();
 | 
						|
        m_indent = m_indent.substr( 0, m_indent.size()-2 );
 | 
						|
        if( m_tagIsOpen ) {
 | 
						|
            m_os << "/>";
 | 
						|
            m_tagIsOpen = false;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            m_os << m_indent << "</" << m_tags.back() << ">";
 | 
						|
        }
 | 
						|
        m_os << std::endl;
 | 
						|
        m_tags.pop_back();
 | 
						|
        return *this;
 | 
						|
    }
 | 
						|
 | 
						|
    XmlWriter& XmlWriter::writeAttribute( std::string const& name, std::string const& attribute ) {
 | 
						|
        if( !name.empty() && !attribute.empty() )
 | 
						|
            m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"';
 | 
						|
        return *this;
 | 
						|
    }
 | 
						|
 | 
						|
    XmlWriter& XmlWriter::writeAttribute( std::string const& name, bool attribute ) {
 | 
						|
        m_os << ' ' << name << "=\"" << ( attribute ? "true" : "false" ) << '"';
 | 
						|
        return *this;
 | 
						|
    }
 | 
						|
 | 
						|
    XmlWriter& XmlWriter::writeText( std::string const& text, bool indent ) {
 | 
						|
        if( !text.empty() ){
 | 
						|
            bool tagWasOpen = m_tagIsOpen;
 | 
						|
            ensureTagClosed();
 | 
						|
            if( tagWasOpen && indent )
 | 
						|
                m_os << m_indent;
 | 
						|
            m_os << XmlEncode( text );
 | 
						|
            m_needsNewline = true;
 | 
						|
        }
 | 
						|
        return *this;
 | 
						|
    }
 | 
						|
 | 
						|
    XmlWriter& XmlWriter::writeComment( std::string const& text ) {
 | 
						|
        ensureTagClosed();
 | 
						|
        m_os << m_indent << "<!--" << text << "-->";
 | 
						|
        m_needsNewline = true;
 | 
						|
        return *this;
 | 
						|
    }
 | 
						|
 | 
						|
    void XmlWriter::writeStylesheetRef( std::string const& url ) {
 | 
						|
        m_os << "<?xml-stylesheet type=\"text/xsl\" href=\"" << url << "\"?>\n";
 | 
						|
    }
 | 
						|
 | 
						|
    XmlWriter& XmlWriter::writeBlankLine() {
 | 
						|
        ensureTagClosed();
 | 
						|
        m_os << '\n';
 | 
						|
        return *this;
 | 
						|
    }
 | 
						|
 | 
						|
    void XmlWriter::ensureTagClosed() {
 | 
						|
        if( m_tagIsOpen ) {
 | 
						|
            m_os << ">" << std::endl;
 | 
						|
            m_tagIsOpen = false;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    void XmlWriter::writeDeclaration() {
 | 
						|
        m_os << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
 | 
						|
    }
 | 
						|
 | 
						|
    void XmlWriter::newlineIfNecessary() {
 | 
						|
        if( m_needsNewline ) {
 | 
						|
            m_os << std::endl;
 | 
						|
            m_needsNewline = false;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |