1 /*
2  * This source file is part of MyGUI. For the latest info, see http://mygui.info/
3  * Distributed under the MIT License
4  * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT)
5  */
6 
7 #ifndef MYGUI_XML_DOCUMENT_H_
8 #define MYGUI_XML_DOCUMENT_H_
9 
10 #include "MyGUI_Prerequest.h"
11 #include "MyGUI_UString.h"
12 #include "MyGUI_Diagnostic.h"
13 #include "MyGUI_DataStream.h"
14 
15 #include <vector>
16 #include <string>
17 #include <iostream>
18 #include <fstream>
19 #include <sstream>
20 #include <cassert>
21 
22 namespace MyGUI
23 {
24 	namespace xml
25 	{
26 
27 		struct ElementType
28 		{
29 			enum Enum
30 			{
31 				Comment,
32 				Declaration,
33 				Normal,
34 				MAX
35 			};
36 
mValueElementType37 			ElementType(Enum _value = MAX) : mValue(_value) { }
38 			friend bool operator == (ElementType const& a, ElementType const& b)
39 			{
40 				return a.mValue == b.mValue;
41 			}
42 			friend bool operator != (ElementType const& a, ElementType const& b)
43 			{
44 				return a.mValue != b.mValue;
45 			}
46 
getValueElementType47 			int getValue() const
48 			{
49 				return mValue;
50 			}
51 
52 		private:
53 			Enum mValue;
54 		};
55 
56 		struct ErrorType
57 		{
58 			enum Enum
59 			{
60 				OpenFileFail,
61 				CreateFileFail,
62 				IncorrectContent,
63 				NotClosedElements,
64 				NoXMLDeclaration,
65 				CloseNotOpenedElement,
66 				InconsistentOpenCloseElements,
67 				MoreThanOneXMLDeclaration,
68 				MoreThanOneRootElement,
69 				IncorrectAttribute,
70 				MAX
71 			};
72 
mValueErrorType73 			ErrorType(Enum _value = MAX) : mValue(_value) { }
74 
printErrorType75 			std::string print() const
76 			{
77 				return getValueName(mValue);
78 			}
79 
80 		private:
getValueNameErrorType81 			const char* getValueName(int _index) const
82 			{
83 				static const char* values[MAX + 1] =
84 				{
85 					"Failed to open XML file",
86 					"Failed to ceate XML file",
87 					"XML file contain incorrect content",
88 					"XML file contain not closed elements",
89 					"XML file without declaration",
90 					"XML file contain closed but not opened element",
91 					"XML file contain inconsistent elements",
92 					"XML file contain more than one declaration",
93 					"XML file contain more than one root element",
94 					"XML file contain incorrect attribute",
95 					""
96 				};
97 				return values[(_index < MAX && _index >= 0) ? _index : MAX];
98 			}
99 		private:
100 			Enum mValue;
101 		};
102 
103 		class Element;
104 		class Document;
105 
106 		using ElementPtr = Element*;
107 		typedef std::pair<std::string, std::string> PairAttribute;
108 		using VectorAttributes = std::vector<PairAttribute>;
109 		using VectorElement = std::vector<ElementPtr>;
110 
111 		//----------------------------------------------------------------------//
112 		// class ElementEnumerator
113 		//----------------------------------------------------------------------//
114 		class MYGUI_EXPORT ElementEnumerator
115 		{
116 			friend class Element;
117 
118 		private:
119 			ElementEnumerator(VectorElement::iterator _begin, VectorElement::iterator _end);
120 
121 		public:
122 			bool next();
123 			bool next(const std::string& _name);
124 
125 			ElementPtr operator->() const;
126 			ElementPtr current();
127 
128 			/*obsolete:*/
129 #ifndef MYGUI_DONT_USE_OBSOLETE
130 
131 			MYGUI_OBSOLETE("use : bool ElementEnumerator::next()")
nextNode()132 			bool nextNode()
133 			{
134 				return next();
135 			}
136 			MYGUI_OBSOLETE("use : bool ElementEnumerator::next(const std::string& _name)")
nextNode(const std::string & _name)137 			bool nextNode(const std::string& _name)
138 			{
139 				return next(_name);
140 			}
141 			MYGUI_OBSOLETE("use : ElementPtr ElementEnumerator::current()")
currentNode()142 			ElementPtr currentNode()
143 			{
144 				return current();
145 			}
146 
147 #endif // MYGUI_DONT_USE_OBSOLETE
148 
149 		private:
150 			bool m_first;
151 			VectorElement::iterator m_current, m_end;
152 		};
153 
154 
155 		//----------------------------------------------------------------------//
156 		// class Element
157 		//----------------------------------------------------------------------//
158 		class MYGUI_EXPORT Element
159 		{
160 			friend class Document;
161 
162 		public:
163 			~Element();
164 
165 		private:
166 			Element(const std::string& _name, ElementPtr _parent, ElementType _type = ElementType::Normal, const std::string& _content = "");
167 			void save(std::ostream& _stream, size_t _level);
168 
169 		public:
170 			ElementPtr createChild(const std::string& _name, const std::string& _content = "", ElementType _type = ElementType::Normal);
171 			void removeChild(ElementPtr _child);
172 
173 			template <typename T>
addAttribute(const std::string & _key,const T & _value)174 			void addAttribute(const std::string& _key, const T& _value)
175 			{
176 				addAttribute(_key, utility::toString(_value));
177 			}
178 
179 			void addAttribute(const std::string& _key, const std::string& _value);
180 
181 			void removeAttribute(const std::string& _key);
182 
183 			void setAttribute(const std::string& _key, const std::string& _value);
184 
185 			template <typename T>
addContent(const T & _content)186 			void addContent(const T& _content)
187 			{
188 				addContent(utility::toString(_content));
189 			}
190 
191 			void addContent(const std::string& _content);
192 
193 			template <typename T>
setContent(const T & _content)194 			void setContent(const T& _content)
195 			{
196 				setContent(utility::toString(_content));
197 			}
198 
199 			void setContent(const std::string& _content);
200 
201 			void clear();
202 
203 			bool findAttribute(const std::string& _name, std::string& _value);
204 			std::string findAttribute(const std::string& _name);
205 
206 			const std::string& getName() const;
207 
208 			const std::string& getContent() const;
209 
210 			const VectorAttributes& getAttributes() const;
211 
212 			ElementPtr getParent() const;
213 
214 			ElementEnumerator getElementEnumerator();
215 
216 			ElementType getType() const;
217 
218 			ElementPtr createCopy();
219 
220 			/*obsolete:*/
221 #ifndef MYGUI_DONT_USE_OBSOLETE
222 
223 			template <typename T>
224 			MYGUI_OBSOLETE("use : template <typename T> void Element::addAttribute(const std::string &_key, const T& _value)")
addAttributes(const std::string & _key,const T & _value)225 			void addAttributes(const std::string& _key, const T& _value)
226 			{
227 				addAttribute<T>(_key, _value);
228 			}
229 			MYGUI_OBSOLETE("use : void Element::addAttribute(const std::string& _key, const std::string& _value)")
addAttributes(const std::string & _key,const std::string & _value)230 			void addAttributes(const std::string& _key, const std::string& _value)
231 			{
232 				addAttribute(_key, _value);
233 			}
234 
235 			template <typename T>
236 			MYGUI_OBSOLETE("use : template <typename T> void Element::addContent(const T& _content)")
addBody(const T & _content)237 			void addBody(const T& _content)
238 			{
239 				addContent<T>(_content);
240 			}
241 			MYGUI_OBSOLETE("use : void Element::addContent(const std::string& _content)")
addBody(const std::string & _content)242 			void addBody(const std::string& _content)
243 			{
244 				addContent(_content);
245 			}
246 			template <typename T>
247 			MYGUI_OBSOLETE("use : template <typename T> void Element::setContent(const T& _content)")
setBody(const T & _content)248 			void setBody(const T& _content)
249 			{
250 				setContent<T>(_content);
251 			}
252 			MYGUI_OBSOLETE("use : void Element::setContent(const std::string& _content)")
setBody(const std::string & _content)253 			void setBody(const std::string& _content)
254 			{
255 				setContent(_content);
256 			}
257 
258 			MYGUI_OBSOLETE("use : const std::string& Element::getContent()")
getBody()259 			const std::string& getBody() const
260 			{
261 				return getContent();
262 			}
263 			MYGUI_OBSOLETE("use : ElementEnumerator Element::getElementEnumerator()")
getNodeIterator()264 			ElementEnumerator getNodeIterator()
265 			{
266 				return getElementEnumerator();
267 			}
268 
269 #endif // MYGUI_DONT_USE_OBSOLETE
270 
271 		private:
272 			std::string mName;
273 			std::string mContent;
274 			VectorAttributes mAttributes;
275 			VectorElement mChilds;
276 			ElementPtr mParent;
277 			ElementType mType;
278 		};
279 
280 		//----------------------------------------------------------------------//
281 		// class Document
282 		//----------------------------------------------------------------------//
283 		class MYGUI_EXPORT Document
284 		{
285 		public:
286 			Document();
287 			~Document();
288 
289 			// открывает обычным файлом, имя файла в utf8
290 			bool open(const std::string& _filename);
291 
292 			// открывает обычным файлом, имя файла в utf16 или utf32
293 			bool open(const std::wstring& _filename);
294 
295 			// открывает обычным потоком
296 			bool open(std::istream& _stream);
297 
298 			bool open(const UString& _filename);
299 
300 			bool open(IDataStream* _data);
301 
302 			// сохраняет файл
303 			bool save(const std::string& _filename);
304 
305 			// сохраняет файл
306 			bool save(const std::wstring& _filename);
307 
308 			bool save(std::ostream& _stream);
309 
310 			bool save(const UString& _filename);
311 
312 			void clear();
313 
314 			std::string getLastError();
315 
316 			void clearLastError();
317 
318 			ElementPtr createDeclaration(const std::string& _version = "1.0", const std::string& _encoding = "UTF-8");
319 			ElementPtr createRoot(const std::string& _name);
320 
321 			ElementPtr getRoot() const;
322 
323 			/*obsolete:*/
324 #ifndef MYGUI_DONT_USE_OBSOLETE
325 
326 			MYGUI_OBSOLETE("use : ElementPtr Document::createDeclaration(const std::string& _version, const std::string& _encoding)")
327 			ElementPtr createInfo(const std::string& _version = "1.0", const std::string& _encoding = "UTF-8")
328 			{
329 				return createDeclaration(_version, _encoding);
330 			}
331 
332 #endif // MYGUI_DONT_USE_OBSOLETE
333 
334 		private:
335 			void setLastFileError(const std::string& _filename);
336 			void setLastFileError(const std::wstring& _filename);
337 
338 			bool parseTag(ElementPtr& _currentNode, std::string _content);
339 
340 			bool checkPair(std::string& _key, std::string& _value);
341 
342 			bool parseLine(std::string& _line, ElementPtr& _element);
343 
344 			// ищет символ без учета ковычек
345 			size_t find(const std::string& _text, char _char, size_t _start = 0);
346 
347 			void clearDeclaration();
348 			void clearRoot();
349 
350 		private:
351 			ElementPtr mRoot;
352 			ElementPtr mDeclaration;
353 			ErrorType mLastError;
354 			std::string mLastErrorFile;
355 			size_t mLine;
356 			size_t mCol;
357 
358 		}; // class Document
359 
360 		MYGUI_OBSOLETE("use : class MyGUI::xml::ElementEnumerator")
361 		typedef ElementEnumerator xmlNodeIterator;
362 		MYGUI_OBSOLETE("use : class MyGUI::xml::ElementPtr")
363 		typedef ElementPtr xmlNodePtr;
364 		MYGUI_OBSOLETE("use : class MyGUI::xml::Document")
365 		typedef Document xmlDocument;
366 
367 	} // namespace xml
368 
369 } // namespace MyGUI
370 
371 #endif // MYGUI_XML_DOCUMENT_H_
372