q3map2/light_bounce: prevent infinite loop on obscure bias compute
[xonotic/netradiant.git] / libs / xml / xmlwriter.h
1 /*
2    Copyright (C) 2001-2006, William Joseph.
3    All Rights Reserved.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 #if !defined( INCLUDED_XML_XMLWRITER_H )
23 #define INCLUDED_XML_XMLWRITER_H
24
25 #include "convert.h"
26 #include <vector>
27 #include "xml/ixml.h"
28
29 class XMLEntityOutputStream
30 {
31 SingleCharacterOutputStream m_ostream;
32 public:
33 XMLEntityOutputStream( TextOutputStream& ostream )
34         : m_ostream( ostream ){
35 }
36 void write( const char c ){
37         m_ostream.write( c );
38 }
39 void writeEscaped( const char c ){
40         switch ( c )
41         {
42         case '<':
43                 write( '&' );
44                 write( 'l' );
45                 write( 't' );
46                 write( ';' );
47                 break;
48         case '>':
49                 write( '&' );
50                 write( 'g' );
51                 write( 't' );
52                 write( ';' );
53                 break;
54         case '"':
55                 write( '&' );
56                 write( 'q' );
57                 write( 'u' );
58                 write( 'o' );
59                 write( 't' );
60                 write( ';' );
61                 break;
62         case '&':
63                 write( '&' );
64                 write( 'a' );
65                 write( 'm' );
66                 write( 'p' );
67                 write( ';' );
68                 break;
69         default:
70                 write( c );
71                 break;
72         }
73 }
74 std::size_t write( const char* buffer, std::size_t length ){
75         const char*const end = buffer + length;
76         for ( const char* p = buffer; p != end; ++p )
77         {
78                 writeEscaped( *p );
79         }
80         return length;
81 }
82 };
83
84 template<typename T>
85 inline XMLEntityOutputStream& operator<<( XMLEntityOutputStream& ostream, const T& t ){
86         return ostream_write( ostream, t );
87 }
88
89
90 class XMLStreamWriter : public XMLImporter, public XMLAttrVisitor
91 {
92 class state_t
93 {
94 public:
95 enum EState
96 {
97         eStartElement,
98         eContent,
99 };
100 state_t()
101         : m_state( eStartElement )
102 {}
103 EState m_state;
104 };
105
106 XMLEntityOutputStream m_ostream;
107 std::vector<state_t> m_elements;
108
109 void write_cdata( const char* buffer, std::size_t length ){
110         m_ostream << StringRange( buffer, buffer + length );
111 }
112 void write_string( const char* string ){
113         m_ostream << string;
114 }
115 void write_quoted_string( const char* string ){
116         m_ostream.write( '"' );
117         m_ostream << string;
118         m_ostream.write( '"' );
119 }
120 public:
121 XMLStreamWriter( TextOutputStream& ostream )
122         : m_ostream( ostream ){
123         m_elements.push_back( state_t() );
124         m_elements.back().m_state = state_t::eContent;
125         m_ostream.write( '<' );
126         m_ostream.write( '?' );
127         write_string( "xml" );
128         visit( "version", "1.0" );
129         m_ostream.write( '?' );
130         m_ostream.write( '>' );
131 }
132
133 void pushElement( const XMLElement& element ){
134         if ( m_elements.back().m_state == state_t::eStartElement ) {
135                 m_elements.back().m_state = state_t::eContent;
136                 m_ostream.write( '>' );
137         }
138
139         m_elements.push_back( state_t() );
140
141         m_ostream.write( '<' );
142         write_string( element.name() );
143         element.forEachAttribute( *this );
144 }
145 void popElement( const char* name ){
146         if ( m_elements.back().m_state == state_t::eStartElement ) {
147                 m_ostream.write( '/' );
148                 m_ostream.write( '>' );
149                 m_elements.pop_back();
150         }
151         else
152         {
153                 m_ostream.write( '<' );
154                 m_ostream.write( '/' );
155                 write_string( name );
156                 m_ostream.write( '>' );
157                 m_elements.pop_back();
158         }
159 }
160 std::size_t write( const char* data, std::size_t length ){
161         if ( m_elements.back().m_state == state_t::eStartElement ) {
162                 m_elements.back().m_state = state_t::eContent;
163                 m_ostream.write( '>' );
164         }
165         write_cdata( data, length );
166         return length;
167 }
168
169 void visit( const char* name, const char* value ){
170         m_ostream.write( ' ' );
171         write_string( name );
172         m_ostream.write( '=' );
173         write_quoted_string( value );
174 }
175 };
176
177
178 #endif