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 += "<";
164 break;
165
166 case '>':
167 res += ">";
168 break;
169
170 case '&':
171 res += "&";
172 break;
173
174 case '\'':
175 res += "'";
176 break;
177
178 case '"':
179 res += """;
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 += "<";
201 break;
202
203 case '>':
204 res += ">";
205 break;
206
207 case '&':
208 res += "&";
209 break;
210
211 case '\'':
212 res += "'";
213 break;
214
215 case '"':
216 res += """;
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