1 /***********************************************************************
2     created:    Thue May 16 2006
3     author:     Olivier Delannoy
4 *************************************************************************/
5 /***************************************************************************
6  *   Copyright (C) 2004 - 2006 Paul D Turner & The CEGUI Development Team
7  *
8  *   Permission is hereby granted, free of charge, to any person obtaining
9  *   a copy of this software and associated documentation files (the
10  *   "Software"), to deal in the Software without restriction, including
11  *   without limitation the rights to use, copy, modify, merge, publish,
12  *   distribute, sublicense, and/or sell copies of the Software, and to
13  *   permit persons to whom the Software is furnished to do so, subject to
14  *   the following conditions:
15  *
16  *   The above copyright notice and this permission notice shall be
17  *   included in all copies or substantial portions of the Software.
18  *
19  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22  *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23  *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24  *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25  *   OTHER DEALINGS IN THE SOFTWARE.
26  ***************************************************************************/
27 #include "CEGUI/XMLSerializer.h"
28 #include <iostream>
29 // Start of CEGUI namespace section
30 namespace CEGUI
31 {
XMLSerializer(OutStream & out,size_t indentSpace)32 XMLSerializer::XMLSerializer(OutStream& out, size_t indentSpace)
33     : d_error(false), d_tagCount(0), d_depth(0), d_indentSpace(indentSpace),
34       d_needClose(false), d_lastIsText(false), d_stream(out)
35 {
36     d_stream << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
37     d_error = ! d_stream;
38 }
39 
40 
~XMLSerializer(void)41 XMLSerializer::~XMLSerializer(void)
42 {
43     if (!d_error || !d_tagStack.empty())
44     {
45         d_stream << std::endl;
46     }
47 }
48 
49 
50 
openTag(const String & name)51 XMLSerializer& XMLSerializer::openTag(const String& name)
52 {
53     if (! d_error)
54     {
55         ++d_tagCount;
56         if (d_needClose)
57         {
58             d_stream << '>';
59         }
60         if (!d_lastIsText)
61         {
62             d_stream << std::endl;
63             indentLine();
64         }
65         d_stream << '<' << name.c_str() << ' ';
66         d_tagStack.push_back(name);
67         ++d_depth;
68         d_needClose = true;
69         d_lastIsText = false;
70         d_error = ! d_stream;
71     }
72     return *this;
73 }
74 
closeTag(void)75 XMLSerializer& XMLSerializer::closeTag(void)
76 {
77     String back =  d_tagStack.back();
78     if (! d_error)
79     {
80         --d_depth;
81         if (d_needClose)
82         {
83             d_stream << "/>";
84         }
85         else if (! d_lastIsText)
86         {
87             d_stream << std::endl;
88             indentLine();
89             d_stream << "</" << back.c_str() << '>';
90         }
91         else
92         {
93             d_stream << "</" << back.c_str() << '>';
94         }
95         d_lastIsText = false;
96         d_needClose = false;
97         d_tagStack.pop_back();
98         d_error = ! d_stream;
99     }
100     return *this;
101 }
102 
103 
attribute(const String & name,const String & value)104 XMLSerializer& XMLSerializer::attribute(const String& name, const String& value)
105 {
106     if (!d_needClose)
107     {
108         d_error = true;
109     }
110     if (!d_error)
111     {
112         d_stream << name.c_str() << "=\""
113             << convertEntityInAttribute(value).c_str()
114             << "\" ";
115         d_lastIsText = false;
116         d_error = ! d_stream;
117     }
118     return *this;
119 }
120 
121 
text(const String & text)122 XMLSerializer& XMLSerializer::text(const String& text)
123 {
124     if (! d_error)
125     {
126         if (d_needClose)
127         {
128             d_stream << '>';
129             d_needClose = false;
130         }
131         d_stream << convertEntityInText(text).c_str();
132         d_lastIsText = true;
133         d_error = ! d_stream;
134     }
135     return *this;
136 }
137 
getTagCount() const138 unsigned int XMLSerializer::getTagCount() const
139 {
140     return d_tagCount;
141 }
142 
indentLine(void)143 void XMLSerializer::indentLine(void)
144 {
145     size_t spaceCount = d_depth * d_indentSpace;
146     // There's for sure a best way to do this but it works
147     for (size_t i = 0 ; i < spaceCount ; ++i)
148     {
149         d_stream << ' ';
150     }
151 }
152 
convertEntityInText(const String & text)153 String XMLSerializer::convertEntityInText(const String& text)
154 {
155     String res;
156     res.reserve(text.size()*2);
157     const String::const_iterator iterEnd = text.end();
158     for (String::const_iterator iter = text.begin(); iter != iterEnd ; ++iter)
159     {
160         switch(*iter)
161         {
162             case '<':
163                 res += "&lt;";
164                 break;
165 
166             case '>':
167                 res += "&gt;";
168                 break;
169 
170             case '&':
171                 res += "&amp;";
172                 break;
173 
174             case '\'':
175                 res += "&apos;";
176                 break;
177 
178             case '"':
179                 res += "&quot;";
180                 break;
181 
182             default:
183                 res += *iter;
184         }
185     }
186     return res;
187 }
188 
convertEntityInAttribute(const String & attributeValue)189 String XMLSerializer::convertEntityInAttribute(const String& attributeValue)
190 {
191     // Reserve a lot of space
192     String res;
193     res.reserve(attributeValue.size()*2);
194     const String::const_iterator iterEnd = attributeValue.end();
195     for (String::const_iterator iter = attributeValue.begin(); iter != iterEnd ; ++iter)
196     {
197         switch(*iter)
198         {
199             case '<':
200                 res += "&lt;";
201                 break;
202 
203             case '>':
204                 res += "&gt;";
205                 break;
206 
207             case '&':
208                 res += "&amp;";
209                 break;
210 
211             case '\'':
212                 res += "&apos;";
213                 break;
214 
215             case '"':
216                 res += "&quot;";
217                 break;
218 
219             case '\n':
220                 res += "\\n";
221                 break;
222 
223             default:
224                 res += *iter;
225         }
226     }
227 
228     return res;
229 }
230 
231 } // End of CEGUI Namespace
232