/* Copyright (C) 2001-2006, William Joseph. All Rights Reserved. This file is part of GtkRadiant. GtkRadiant is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GtkRadiant is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #if !defined( INCLUDED_XML_XMLWRITER_H ) #define INCLUDED_XML_XMLWRITER_H #include "convert.h" #include #include "xml/ixml.h" class XMLEntityOutputStream { SingleCharacterOutputStream m_ostream; public: XMLEntityOutputStream( TextOutputStream& ostream ) : m_ostream( ostream ){ } void write( const char c ){ m_ostream.write( c ); } void writeEscaped( const char c ){ switch ( c ) { case '<': write( '&' ); write( 'l' ); write( 't' ); write( ';' ); break; case '>': write( '&' ); write( 'g' ); write( 't' ); write( ';' ); break; case '"': write( '&' ); write( 'q' ); write( 'u' ); write( 'o' ); write( 't' ); write( ';' ); break; case '&': write( '&' ); write( 'a' ); write( 'm' ); write( 'p' ); write( ';' ); break; default: write( c ); break; } } std::size_t write( const char* buffer, std::size_t length ){ const char*const end = buffer + length; for ( const char* p = buffer; p != end; ++p ) { writeEscaped( *p ); } return length; } }; template inline XMLEntityOutputStream& operator<<( XMLEntityOutputStream& ostream, const T& t ){ return ostream_write( ostream, t ); } class XMLStreamWriter : public XMLImporter, public XMLAttrVisitor { class state_t { public: enum EState { eStartElement, eContent, }; state_t() : m_state( eStartElement ) {} EState m_state; }; XMLEntityOutputStream m_ostream; std::vector m_elements; void write_cdata( const char* buffer, std::size_t length ){ m_ostream << StringRange( buffer, buffer + length ); } void write_string( const char* string ){ m_ostream << string; } void write_quoted_string( const char* string ){ m_ostream.write( '"' ); m_ostream << string; m_ostream.write( '"' ); } public: XMLStreamWriter( TextOutputStream& ostream ) : m_ostream( ostream ){ m_elements.push_back( state_t() ); m_elements.back().m_state = state_t::eContent; m_ostream.write( '<' ); m_ostream.write( '?' ); write_string( "xml" ); visit( "version", "1.0" ); m_ostream.write( '?' ); m_ostream.write( '>' ); } void pushElement( const XMLElement& element ){ if ( m_elements.back().m_state == state_t::eStartElement ) { m_elements.back().m_state = state_t::eContent; m_ostream.write( '>' ); } m_elements.push_back( state_t() ); m_ostream.write( '<' ); write_string( element.name() ); element.forEachAttribute( *this ); } void popElement( const char* name ){ if ( m_elements.back().m_state == state_t::eStartElement ) { m_ostream.write( '/' ); m_ostream.write( '>' ); m_elements.pop_back(); } else { m_ostream.write( '<' ); m_ostream.write( '/' ); write_string( name ); m_ostream.write( '>' ); m_elements.pop_back(); } } std::size_t write( const char* data, std::size_t length ){ if ( m_elements.back().m_state == state_t::eStartElement ) { m_elements.back().m_state = state_t::eContent; m_ostream.write( '>' ); } write_cdata( data, length ); return length; } void visit( const char* name, const char* value ){ m_ostream.write( ' ' ); write_string( name ); m_ostream.write( '=' ); write_quoted_string( value ); } }; #endif