060deb6346bedb4403518b0ba01b6b4ee1ebe366
[reactos.git] / reactos / subsys / system / explorer / utility / xmlstorage.h
1
2 //
3 // XML storage classes
4 //
5 // xmlstorage.h
6 //
7 // Copyright (c) 2004, 2005 Martin Fuchs <martin-fuchs@gmx.net>
8 //
9
10
11 /*
12
13 All rights reserved.
14
15 Redistribution and use in source and binary forms, with or without
16 modification, are permitted provided that the following conditions are met:
17
18 * Redistributions of source code must retain the above copyright
19 notice, this list of conditions and the following disclaimer.
20 * Redistributions in binary form must reproduce the above copyright
21 notice, this list of conditions and the following disclaimer in
22 the documentation and/or other materials provided with the
23 distribution.
24
25 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 POSSIBILITY OF SUCH DAMAGE.
36
37 */
38
39 #ifndef _XMLSTORAGE_H
40
41 #include <expat/expat.h>
42
43 #ifdef _MSC_VER
44 #pragma comment(lib, "libexpat.lib")
45 #pragma warning(disable: 4786)
46 #endif
47
48
49 #include <windows.h> // for LPCTSTR
50
51 #ifdef UNICODE
52 #define _UNICODE
53 #endif
54
55 #include <tchar.h>
56 #include <malloc.h>
57
58 #include <fstream>
59 #include <sstream>
60 #include <string>
61 #include <stack>
62 #include <list>
63 #include <map>
64
65
66 #ifndef BUFFER_LEN
67 #define BUFFER_LEN 2048
68 #endif
69
70
71 namespace XMLStorage {
72
73
74 #ifndef XS_String
75
76 #ifdef XS_STRING_UTF8
77 #define XS_CHAR char
78 #define XS_TEXT(x) x
79 #define LPXSSTR LPSTR
80 #define LPCXSSTR LPCSTR
81 #define XS_icmp stricmp
82 #define XS_nicmp strnicmp
83 #define XS_toi atoi
84 #define XS_len strlen
85 #define XS_snprintf snprintf
86 #define XS_vsnprintf vsnprintf
87 #else
88 #define XS_CHAR TCHAR
89 #define XS_TEXT(x) TEXT(x)
90 #define LPXSSTR LPTSTR
91 #define LPCXSSTR LPCTSTR
92 #define XS_icmp _tcsicmp
93 #define XS_nicmp _tcsnicmp
94 #define XS_toi _ttoi
95 #define XS_len _tcslen
96 #define XS_snprintf _sntprintf
97 #define XS_vsnprintf _vsntprintf
98 #endif
99
100 #ifndef COUNTOF
101 #define COUNTOF(b) (sizeof(b)/sizeof(b[0]))
102 #endif
103
104 #if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8)
105
106 #define XS_String String
107
108 #else // _STRING_DEFINED, !XS_STRING_UTF8
109
110 /// string class for TCHAR strings
111
112 struct XS_String
113 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
114 : public std::wstring
115 #else
116 : public std::string
117 #endif
118 {
119 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
120 typedef std::wstring super;
121 #else
122 typedef std::string super;
123 #endif
124
125 XS_String() {}
126
127 XS_String(LPCXSSTR s) {if (s) super::assign(s);}
128 XS_String(LPCXSSTR s, size_t l) : super(s, l) {}
129
130 XS_String(const super& other) : super(other) {}
131 XS_String(const XS_String& other) : super(other) {}
132
133 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
134 XS_String(LPCSTR s) {assign(s);}
135 XS_String(LPCSTR s, size_t l) {assign(s, l);}
136 XS_String(const std::string& other) {assign(other.c_str());}
137 XS_String& operator=(LPCSTR s) {assign(s); return *this;}
138 void assign(LPCSTR s) {if (s) {size_t bl=strlen(s); LPWSTR b=(LPWSTR)alloca(sizeof(WCHAR)*bl); super::assign(b, MultiByteToWideChar(CP_ACP, 0, s, bl, b, bl));} else erase();}
139 void assign(LPCSTR s, size_t l) {if (s) {size_t bl=l; LPWSTR b=(LPWSTR)alloca(sizeof(WCHAR)*bl); super::assign(b, MultiByteToWideChar(CP_ACP, 0, s, l, b, bl));} else erase();}
140 #else
141 XS_String(LPCWSTR s) {assign(s);}
142 XS_String(LPCWSTR s, size_t l) {assign(s, l);}
143 XS_String(const std::wstring& other) {assign(other.c_str());}
144 XS_String& operator=(LPCWSTR s) {assign(s); return *this;}
145 #ifdef XS_STRING_UTF8
146 void assign(const XS_String& s) {assign(s.c_str());}
147 void assign(LPCWSTR s) {if (s) {size_t bl=wcslen(s); LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_UTF8, 0, s, (int)bl, b, (int)bl, 0, 0));} else erase();}
148 void assign(LPCWSTR s, size_t l) {size_t bl=l; if (s) {LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_UTF8, 0, s, (int)l, b, (int)bl, 0, 0));} else erase();}
149 #else // if !UNICODE && !XS_STRING_UTF8
150 void assign(LPCWSTR s) {if (s) {size_t bl=wcslen(s); LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_ACP, 0, s, (int)bl, b, (int)bl, 0, 0));} else erase();}
151 void assign(LPCWSTR s, size_t l) {size_t bl=l; if (s) {LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_ACP, 0, s, (int)l, b, (int)bl, 0, 0));} else erase();}
152 #endif
153 #endif
154
155 XS_String& operator=(LPCXSSTR s) {if (s) super::assign(s); else erase(); return *this;}
156 XS_String& operator=(const super& s) {super::assign(s); return *this;}
157 void assign(LPCXSSTR s) {super::assign(s);}
158 void assign(LPCXSSTR s, size_t l) {super::assign(s, l);}
159
160 operator LPCXSSTR() const {return c_str();}
161
162 #ifdef XS_STRING_UTF8
163 operator std::wstring() const {size_t bl=length(); LPWSTR b=(LPWSTR)alloca(sizeof(WCHAR)*bl); return std::wstring(b, MultiByteToWideChar(CP_UTF8, 0, c_str(), bl, b, bl));}
164 #elif defined(UNICODE)
165 operator std::string() const {size_t bl=length(); LPSTR b=(LPSTR)alloca(bl); return std::string(b, WideCharToMultiByte(CP_ACP, 0, c_str(), bl, b, bl, 0, 0));}
166 #else
167 operator std::wstring() const {size_t bl=length(); LPWSTR b=(LPWSTR)alloca(sizeof(WCHAR)*bl); return std::wstring(b, MultiByteToWideChar(CP_ACP, 0, c_str(), (int)bl, b, (int)bl));}
168 #endif
169
170 XS_String& printf(LPCXSSTR fmt, ...)
171 {
172 va_list l;
173 XS_CHAR b[BUFFER_LEN];
174
175 va_start(l, fmt);
176 super::assign(b, XS_vsnprintf(b, COUNTOF(b), fmt, l));
177 va_end(l);
178
179 return *this;
180 }
181
182 XS_String& vprintf(LPCXSSTR fmt, va_list l)
183 {
184 XS_CHAR b[BUFFER_LEN];
185
186 super::assign(b, XS_vsnprintf(b, COUNTOF(b), fmt, l));
187
188 return *this;
189 }
190
191 XS_String& appendf(LPCXSSTR fmt, ...)
192 {
193 va_list l;
194 XS_CHAR b[BUFFER_LEN];
195
196 va_start(l, fmt);
197 super::append(b, XS_vsnprintf(b, COUNTOF(b), fmt, l));
198 va_end(l);
199
200 return *this;
201 }
202
203 XS_String& vappendf(LPCXSSTR fmt, va_list l)
204 {
205 XS_CHAR b[BUFFER_LEN];
206
207 super::append(b, XS_vsnprintf(b, COUNTOF(b), fmt, l));
208
209 return *this;
210 }
211 };
212
213 #endif // _STRING_DEFINED, !XS_STRING_UTF8
214
215 #endif // XS_String
216
217
218 #ifndef XS_STRING_UTF8
219
220 inline void assign_utf8(XS_String& s, const char* str)
221 {
222 int lutf8 = (int)strlen(str);
223
224 #ifdef UNICODE
225 LPTSTR buffer = (LPTSTR)alloca(sizeof(TCHAR)*lutf8);
226 int l = MultiByteToWideChar(CP_UTF8, 0, str, lutf8, buffer, lutf8);
227 #else
228 LPWSTR wbuffer = (LPWSTR)alloca(sizeof(WCHAR)*lutf8);
229 int l = MultiByteToWideChar(CP_UTF8, 0, str, lutf8, wbuffer, lutf8);
230
231 int bl=2*l; LPSTR buffer = (LPSTR)alloca(bl);
232 l = WideCharToMultiByte(CP_ACP, 0, wbuffer, l, buffer, bl, 0, 0);
233 #endif
234
235 s.assign(buffer, l);
236 }
237
238 inline std::string get_utf8(LPCTSTR s, size_t l)
239 {
240 #ifdef UNICODE
241 size_t bl=2*l; LPSTR buffer = (LPSTR)alloca(bl);
242 l = WideCharToMultiByte(CP_UTF8, 0, s, (int)l, buffer, (int)bl, 0, 0);
243 #else
244 LPWSTR wbuffer = (LPWSTR)alloca(sizeof(WCHAR)*l);
245 l = MultiByteToWideChar(CP_ACP, 0, s, (int)l, wbuffer, (int)l);
246
247 size_t bl=2*l; LPSTR buffer = (LPSTR)alloca(bl);
248 l = WideCharToMultiByte(CP_UTF8, 0, wbuffer, (int)l, buffer, (int)bl, 0, 0);
249 #endif
250
251 return std::string(buffer, l);
252 }
253
254 inline std::string get_utf8(const XS_String& s)
255 {
256 return get_utf8(s.c_str(), s.length());
257 }
258
259 #endif // XS_STRING_UTF8
260
261 extern std::string EncodeXMLString(const XS_String& str);
262 extern XS_String DecodeXMLString(const XS_String& str);
263
264
265 #ifdef __GNUC__
266 #include <ext/stdio_filebuf.h>
267 typedef __gnu_cxx::stdio_filebuf<char> STDIO_FILEBUF;
268 #else
269 typedef std::filebuf STDIO_FILEBUF;
270 #endif
271
272 /// input file stream with ANSI/UNICODE file names
273 struct tifstream : public std::istream
274 {
275 typedef std::istream super;
276
277 tifstream(LPCTSTR path)
278 : super(&_buf),
279 _pfile(_tfopen(path, TEXT("r"))),
280 #ifdef __GNUC__
281 _buf(_pfile, ios::in)
282 #else
283 _buf(_pfile)
284 #endif
285 {
286 }
287
288 ~tifstream()
289 {
290 if (_pfile)
291 fclose(_pfile);
292 }
293
294 protected:
295 FILE* _pfile;
296 STDIO_FILEBUF _buf;
297 };
298
299 /// output file stream with ANSI/UNICODE file names
300 struct tofstream : public std::ostream
301 {
302 typedef std::ostream super;
303
304 tofstream(LPCTSTR path)
305 : super(&_buf),
306 _pfile(_tfopen(path, TEXT("w"))),
307 #ifdef __GNUC__
308 _buf(_pfile, ios::out)
309 #else
310 _buf(_pfile)
311 #endif
312 {
313 }
314
315 ~tofstream()
316 {
317 flush();
318
319 if (_pfile)
320 fclose(_pfile);
321 }
322
323 protected:
324 FILE* _pfile;
325 STDIO_FILEBUF _buf;
326 };
327
328
329 // write XML files with 2 spaces indenting
330 #define XML_INDENT_SPACE " "
331
332
333 #ifdef XML_UNICODE // Are XML_Char strings UTF-16 encoded?
334
335 typedef XS_String String_from_XML_Char;
336
337 #elif defined(XS_STRING_UTF8)
338
339 typedef XS_String String_from_XML_Char;
340
341 #else
342
343 /// converter from Expat strings to XMLStorage internal strings
344 struct String_from_XML_Char : public XS_String
345 {
346 String_from_XML_Char(const XML_Char* str)
347 {
348 assign_utf8(*this, str);
349 }
350 };
351
352 #endif
353
354
355 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
356
357 // optimization for faster UNICODE/ASCII string comparison without temporary A/U conversion
358 inline bool operator==(const XS_String& s1, const char* s2)
359 {
360 LPCWSTR p = s1;
361 const unsigned char* q = (const unsigned char*)s2;
362
363 while(*p && *q)
364 if (*p++ != *q++)
365 return false;
366
367 return *p == *q;
368 };
369
370 #endif
371
372
373 /// in memory representation of an XML node
374 struct XMLNode : public XS_String
375 {
376 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
377 // optimized read access without temporary A/U conversion when using ASCII attribute names
378 struct AttributeMap : public std::map<XS_String, XS_String>
379 {
380 typedef std::map<XS_String, XS_String> super;
381
382 const_iterator find(const char* x) const
383 {
384 for(const_iterator it=begin(); it!=end(); ++it)
385 if (it->first == x)
386 return it;
387
388 return end();
389 }
390
391 const_iterator find(const key_type& x) const
392 {
393 return super::find(x);
394 }
395
396 iterator find(const key_type& x)
397 {
398 return super::find(x);
399 }
400 };
401 #else
402 typedef std::map<XS_String, XS_String> AttributeMap;
403 #endif
404
405 /// internal children node list
406 struct Children : public std::list<XMLNode*>
407 {
408 void assign(const Children& other)
409 {
410 clear();
411
412 for(Children::const_iterator it=other.begin(); it!=other.end(); ++it)
413 push_back(new XMLNode(**it));
414 }
415
416 void clear()
417 {
418 while(!empty()) {
419 XMLNode* node = back();
420 pop_back();
421
422 node->clear();
423 delete node;
424 }
425 }
426 };
427
428 // access to protected class members for XMLPos and XMLReader
429 friend struct XMLPos;
430 friend struct const_XMLPos;
431 friend struct XMLReaderBase;
432
433 XMLNode(const XS_String& name)
434 : XS_String(name)
435 {
436 }
437
438 XMLNode(const XS_String& name, const std::string& leading)
439 : XS_String(name),
440 _leading(leading)
441 {
442 }
443
444 XMLNode(const XMLNode& other)
445 : _attributes(other._attributes),
446 _leading(other._leading),
447 _content(other._content),
448 _end_leading(other._end_leading),
449 _trailing(other._trailing)
450 {
451 for(Children::const_iterator it=other._children.begin(); it!=other._children.end(); ++it)
452 _children.push_back(new XMLNode(**it));
453 }
454
455 ~XMLNode()
456 {
457 while(!_children.empty()) {
458 delete _children.back();
459 _children.pop_back();
460 }
461 }
462
463 void clear()
464 {
465 _leading.erase();
466 _content.erase();
467 _end_leading.erase();
468 _trailing.erase();
469
470 _attributes.clear();
471 _children.clear();
472
473 XS_String::erase();
474 }
475
476 XMLNode& operator=(const XMLNode& other)
477 {
478 _children.assign(other._children);
479
480 _attributes = other._attributes;
481
482 _leading = other._leading;
483 _content = other._content;
484 _end_leading = other._end_leading;
485 _trailing = other._trailing;
486
487 return *this;
488 }
489
490 /// add a new child node
491 void add_child(XMLNode* child)
492 {
493 _children.push_back(child);
494 }
495
496 /// write access to an attribute
497 void put(const XS_String& attr_name, const XS_String& value)
498 {
499 _attributes[attr_name] = value;
500 }
501
502 /// C++ write access to an attribute
503 XS_String& operator[](const XS_String& attr_name)
504 {
505 return _attributes[attr_name];
506 }
507
508 /// read only access to an attribute
509 template<typename T> XS_String get(const T& attr_name) const
510 {
511 AttributeMap::const_iterator found = _attributes.find(attr_name);
512
513 if (found != _attributes.end())
514 return found->second;
515 else
516 return XS_String();
517 }
518
519 /// convenient value access in children node
520 XS_String subvalue(const XS_String& name, const XS_String& attr_name, int n=0) const
521 {
522 const XMLNode* node = find(name, n);
523
524 if (node)
525 return node->get(attr_name);
526 else
527 return XS_String();
528 }
529
530 /// convenient storage of distinct values in children node
531 XS_String& subvalue(const XS_String& name, const XS_String& attr_name, int n=0)
532 {
533 XMLNode* node = find(name, n);
534
535 if (!node) {
536 node = new XMLNode(name);
537 add_child(node);
538 }
539
540 return (*node)[attr_name];
541 }
542
543 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
544 /// convenient value access in children node
545 XS_String subvalue(const char* name, const char* attr_name, int n=0) const
546 {
547 const XMLNode* node = find(name, n);
548
549 if (node)
550 return node->get(attr_name);
551 else
552 return XS_String();
553 }
554
555 /// convenient storage of distinct values in children node
556 XS_String& subvalue(const char* name, const XS_String& attr_name, int n=0)
557 {
558 XMLNode* node = find(name, n);
559
560 if (!node) {
561 node = new XMLNode(name);
562 add_child(node);
563 }
564
565 return (*node)[attr_name];
566 }
567 #endif
568
569 const Children& get_children() const
570 {
571 return _children;
572 }
573
574 Children& get_children()
575 {
576 return _children;
577 }
578
579 XS_String get_content() const
580 {
581 #ifdef XS_STRING_UTF8
582 const XS_String& ret = _content;
583 #else
584 XS_String ret;
585 assign_utf8(ret, _content.c_str());
586 #endif
587
588 return DecodeXMLString(ret.c_str());
589 }
590
591 void set_content(const XS_String& s)
592 {
593 _content.assign(EncodeXMLString(s.c_str()));
594 }
595
596 enum WRITE_MODE {
597 FORMAT_SMART = 0, /// preserve original white space and comments if present; pretty print otherwise
598 FORMAT_ORIGINAL = 1, /// write XML stream preserving original white space and comments
599 FORMAT_PRETTY = 2 /// pretty print node to stream without preserving original white space
600 };
601
602 /// write node with children tree to output stream
603 std::ostream& write(std::ostream& out, WRITE_MODE mode=FORMAT_SMART, int indent=0) const
604 {
605 switch(mode) {
606 case FORMAT_PRETTY:
607 pretty_write_worker(out, indent);
608 break;
609
610 case FORMAT_ORIGINAL:
611 write_worker(out, indent);
612 break;
613
614 default: // FORMAT_SMART
615 smart_write_worker(out, indent);
616 }
617
618 return out;
619 }
620
621 protected:
622 Children _children;
623 AttributeMap _attributes;
624
625 std::string _leading;
626 std::string _content;
627 std::string _end_leading;
628 std::string _trailing;
629
630 XMLNode* get_first_child() const
631 {
632 if (!_children.empty())
633 return _children.front();
634 else
635 return NULL;
636 }
637
638 XMLNode* find(const XS_String& name, int n=0) const
639 {
640 for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it)
641 if (**it == name)
642 if (!n--)
643 return *it;
644
645 return NULL;
646 }
647
648 XMLNode* find(const XS_String& name, const XS_String& attr_name, const XS_String& attr_value, int n=0) const
649 {
650 for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it) {
651 const XMLNode& node = **it;
652
653 if (node==name && node.get(attr_name)==attr_value)
654 if (!n--)
655 return *it;
656 }
657
658 return NULL;
659 }
660
661 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
662 XMLNode* find(const char* name, int n=0) const
663 {
664 for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it)
665 if (**it == name)
666 if (!n--)
667 return *it;
668
669 return NULL;
670 }
671
672 template<typename T, typename U>
673 XMLNode* find(const char* name, const T& attr_name, const U& attr_value, int n=0) const
674 {
675 for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it) {
676 const XMLNode& node = **it;
677
678 if (node==name && node.get(attr_name)==attr_value)
679 if (!n--)
680 return *it;
681 }
682
683 return NULL;
684 }
685 #endif
686
687 /// XPath find function (const)
688 const XMLNode* find_relative(const char* path) const;
689
690 /// XPath find function
691 XMLNode* find_relative(const char* path)
692 {return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->find_relative(path));}
693
694 /// relative XPath create function
695 XMLNode* create_relative(const char* path);
696
697 void write_worker(std::ostream& out, int indent) const;
698 void pretty_write_worker(std::ostream& out, int indent) const;
699 void smart_write_worker(std::ostream& out, int indent) const;
700 };
701
702
703 /// iterator access to children nodes with name filtering
704 struct XMLChildrenFilter
705 {
706 XMLChildrenFilter(XMLNode::Children& children, const XS_String& name)
707 : _begin(children.begin(), children.end(), name),
708 _end(children.end(), children.end(), name)
709 {
710 }
711
712 XMLChildrenFilter(XMLNode* node, const XS_String& name)
713 : _begin(node->get_children().begin(), node->get_children().end(), name),
714 _end(node->get_children().end(), node->get_children().end(), name)
715 {
716 }
717
718 /// internal iterator class
719 struct iterator
720 {
721 typedef XMLNode::Children::iterator BaseIterator;
722
723 iterator(BaseIterator begin, BaseIterator end, const XS_String& filter_name)
724 : _cur(begin),
725 _end(end),
726 _filter_name(filter_name)
727 {
728 search_next();
729 }
730
731 operator BaseIterator()
732 {
733 return _cur;
734 }
735
736 const XMLNode* operator*() const
737 {
738 return *_cur;
739 }
740
741 XMLNode* operator*()
742 {
743 return *_cur;
744 }
745
746 iterator& operator++()
747 {
748 ++_cur;
749 search_next();
750
751 return *this;
752 }
753
754 iterator operator++(int)
755 {
756 iterator ret = *this;
757
758 ++_cur;
759 search_next();
760
761 return ret;
762 }
763
764 bool operator==(const BaseIterator& other) const
765 {
766 return _cur == other;
767 }
768
769 bool operator!=(const BaseIterator& other) const
770 {
771 return _cur != other;
772 }
773
774 protected:
775 BaseIterator _cur;
776 BaseIterator _end;
777 XS_String _filter_name;
778
779 void search_next()
780 {
781 while(_cur!=_end && **_cur!=_filter_name)
782 ++_cur;
783 }
784 };
785
786 iterator begin()
787 {
788 return _begin;
789 }
790
791 iterator end()
792 {
793 return _end;
794 }
795
796 protected:
797 iterator _begin;
798 iterator _end;
799 };
800
801
802 /// read only iterator access to children nodes with name filtering
803 struct const_XMLChildrenFilter
804 {
805 const_XMLChildrenFilter(const XMLNode::Children& children, const XS_String& name)
806 : _begin(children.begin(), children.end(), name),
807 _end(children.end(), children.end(), name)
808 {
809 }
810
811 const_XMLChildrenFilter(const XMLNode* node, const XS_String& name)
812 : _begin(node->get_children().begin(), node->get_children().end(), name),
813 _end(node->get_children().end(), node->get_children().end(), name)
814 {
815 }
816
817 /// internal iterator class
818 struct const_iterator
819 {
820 typedef XMLNode::Children::const_iterator BaseIterator;
821
822 const_iterator(BaseIterator begin, BaseIterator end, const XS_String& filter_name)
823 : _cur(begin),
824 _end(end),
825 _filter_name(filter_name)
826 {
827 search_next();
828 }
829
830 operator BaseIterator()
831 {
832 return _cur;
833 }
834
835 const XMLNode* operator*() const
836 {
837 return *_cur;
838 }
839
840 const_iterator& operator++()
841 {
842 ++_cur;
843 search_next();
844
845 return *this;
846 }
847
848 const_iterator operator++(int)
849 {
850 const_iterator ret = *this;
851
852 ++_cur;
853 search_next();
854
855 return ret;
856 }
857
858 bool operator==(const BaseIterator& other) const
859 {
860 return _cur == other;
861 }
862
863 bool operator!=(const BaseIterator& other) const
864 {
865 return _cur != other;
866 }
867
868 protected:
869 BaseIterator _cur;
870 BaseIterator _end;
871 XS_String _filter_name;
872
873 void search_next()
874 {
875 while(_cur!=_end && **_cur!=_filter_name)
876 ++_cur;
877 }
878 };
879
880 const_iterator begin()
881 {
882 return _begin;
883 }
884
885 const_iterator end()
886 {
887 return _end;
888 }
889
890 protected:
891 const_iterator _begin;
892 const_iterator _end;
893 };
894
895
896 /// iterator for XML trees
897 struct XMLPos
898 {
899 XMLPos(XMLNode* root)
900 : _root(root),
901 _cur(root)
902 {
903 }
904
905 XMLPos(const XMLPos& other)
906 : _root(other._root),
907 _cur(other._cur)
908 { // don't copy _stack
909 }
910
911 XMLPos(XMLNode* node, const XS_String& name)
912 : _root(node),
913 _cur(node)
914 {
915 smart_create(name);
916 }
917
918 XMLPos(XMLNode* node, const XS_String& name, const XS_String& attr_name, const XS_String& attr_value)
919 : _root(node),
920 _cur(node)
921 {
922 smart_create(name, attr_name, attr_value);
923 }
924
925 XMLPos(const XMLPos& other, const XS_String& name)
926 : _root(other._root),
927 _cur(other._cur)
928 {
929 smart_create(name);
930 }
931
932 XMLPos(const XMLPos& other, const XS_String& name, const XS_String& attr_name, const XS_String& attr_value)
933 : _root(other._root),
934 _cur(other._cur)
935 {
936 smart_create(name, attr_name, attr_value);
937 }
938
939 /// access to current node
940 XMLNode& cur()
941 {
942 return *_cur;
943 }
944
945 const XMLNode& cur() const
946 {
947 return *_cur;
948 }
949
950 /// C++ access to current node
951 operator const XMLNode*() const {return _cur;}
952 operator XMLNode*() {return _cur;}
953
954 const XMLNode* operator->() const {return _cur;}
955 XMLNode* operator->() {return _cur;}
956
957 const XMLNode& operator*() const {return *_cur;}
958 XMLNode& operator*() {return *_cur;}
959
960 /// attribute access
961 XS_String get(const XS_String& attr_name) const
962 {
963 return _cur->get(attr_name);
964 }
965
966 /// attribute setting
967 void put(const XS_String& attr_name, const XS_String& value)
968 {
969 _cur->put(attr_name, value);
970 }
971
972 /// C++ attribute access
973 template<typename T> XS_String get(const T& attr_name) const {return (*_cur)[attr_name];}
974 XS_String& operator[](const XS_String& attr_name) {return (*_cur)[attr_name];}
975
976 /// insert children when building tree
977 void add_down(XMLNode* child)
978 {
979 _cur->add_child(child);
980 go_to(child);
981 }
982
983 /// go back to previous position
984 bool back()
985 {
986 if (!_stack.empty()) {
987 _cur = _stack.top();
988 _stack.pop();
989 return true;
990 } else
991 return false;
992 }
993
994 /// go down to first child
995 bool go_down()
996 {
997 XMLNode* node = _cur->get_first_child();
998
999 if (node) {
1000 go_to(node);
1001 return true;
1002 } else
1003 return false;
1004 }
1005
1006 /// search for child and go down
1007 bool go_down(const XS_String& name, int n=0)
1008 {
1009 XMLNode* node = _cur->find(name, n);
1010
1011 if (node) {
1012 go_to(node);
1013 return true;
1014 } else
1015 return false;
1016 }
1017
1018 /// move XPath like to position in XML tree
1019 bool go(const char* path);
1020
1021 /// create child nodes using XPath notation and move to the deepest child
1022 bool create_relative(const char* path)
1023 {
1024 XMLNode* node = _cur->create_relative(path);
1025 if (!node)
1026 return false; // invalid path specified
1027
1028 go_to(node);
1029 return true;
1030 }
1031
1032 /// create node and move to it
1033 void create(const XS_String& name)
1034 {
1035 add_down(new XMLNode(name));
1036 }
1037
1038 /// create node if not already existing and move to it
1039 void smart_create(const XS_String& name)
1040 {
1041 XMLNode* node = _cur->find(name);
1042
1043 if (node)
1044 go_to(node);
1045 else
1046 add_down(new XMLNode(name));
1047 }
1048
1049 /// search matching child node identified by key name and an attribute value
1050 void smart_create(const XS_String& name, const XS_String& attr_name, const XS_String& attr_value)
1051 {
1052 XMLNode* node = _cur->find(name, attr_name, attr_value);
1053
1054 if (node)
1055 go_to(node);
1056 else {
1057 node = new XMLNode(name);
1058 add_down(node);
1059 (*node)[attr_name] = attr_value;
1060 }
1061 }
1062
1063 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
1064 /// search for child and go down
1065 bool go_down(const char* name, int n=0)
1066 {
1067 XMLNode* node = _cur->find(name, n);
1068
1069 if (node) {
1070 go_to(node);
1071 return true;
1072 } else
1073 return false;
1074 }
1075
1076 /// create node and move to it
1077 void create(const char* name)
1078 {
1079 add_down(new XMLNode(name));
1080 }
1081
1082 /// create node if not already existing and move to it
1083 void smart_create(const char* name)
1084 {
1085 XMLNode* node = _cur->find(name);
1086
1087 if (node)
1088 go_to(node);
1089 else
1090 add_down(new XMLNode(name));
1091 }
1092
1093 /// search matching child node identified by key name and an attribute value
1094 template<typename T, typename U>
1095 void smart_create(const char* name, const T& attr_name, const U& attr_value)
1096 {
1097 XMLNode* node = _cur->find(name, attr_name, attr_value);
1098
1099 if (node)
1100 go_to(node);
1101 else {
1102 XMLNode* node = new XMLNode(name);
1103 add_down(node);
1104 (*node)[attr_name] = attr_value;
1105 }
1106 }
1107 #endif
1108
1109 XS_String& str() {return *_cur;}
1110 const XS_String& str() const {return *_cur;}
1111
1112 protected:
1113 XMLNode* _root;
1114 XMLNode* _cur;
1115 std::stack<XMLNode*> _stack;
1116
1117 /// go to specified node
1118 void go_to(XMLNode* child)
1119 {
1120 _stack.push(_cur);
1121 _cur = child;
1122 }
1123 };
1124
1125
1126 /// iterator for XML trees
1127 struct const_XMLPos
1128 {
1129 const_XMLPos(const XMLNode* root)
1130 : _root(root),
1131 _cur(root)
1132 {
1133 }
1134
1135 const_XMLPos(const const_XMLPos& other)
1136 : _root(other._root),
1137 _cur(other._cur)
1138 { // don't copy _stack
1139 }
1140
1141 /// access to current node
1142 const XMLNode& cur() const
1143 {
1144 return *_cur;
1145 }
1146
1147 /// C++ access to current node
1148 operator const XMLNode*() const {return _cur;}
1149
1150 const XMLNode* operator->() const {return _cur;}
1151
1152 const XMLNode& operator*() const {return *_cur;}
1153
1154 /// attribute access
1155 XS_String get(const XS_String& attr_name) const
1156 {
1157 return _cur->get(attr_name);
1158 }
1159
1160 /// C++ attribute access
1161 template<typename T> XS_String get(const T& attr_name) const {return _cur->get(attr_name);}
1162
1163 /// go back to previous position
1164 bool back()
1165 {
1166 if (!_stack.empty()) {
1167 _cur = _stack.top();
1168 _stack.pop();
1169 return true;
1170 } else
1171 return false;
1172 }
1173
1174 /// go down to first child
1175 bool go_down()
1176 {
1177 const XMLNode* node = _cur->get_first_child();
1178
1179 if (node) {
1180 go_to(node);
1181 return true;
1182 } else
1183 return false;
1184 }
1185
1186 /// search for child and go down
1187 bool go_down(const XS_String& name, int n=0)
1188 {
1189 XMLNode* node = _cur->find(name, n);
1190
1191 if (node) {
1192 go_to(node);
1193 return true;
1194 } else
1195 return false;
1196 }
1197
1198 /// move XPath like to position in XML tree
1199 bool go(const char* path);
1200
1201 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
1202 /// search for child and go down
1203 bool go_down(const char* name, int n=0)
1204 {
1205 XMLNode* node = _cur->find(name, n);
1206
1207 if (node) {
1208 go_to(node);
1209 return true;
1210 } else
1211 return false;
1212 }
1213 #endif
1214
1215 const XS_String& str() const {return *_cur;}
1216
1217 protected:
1218 const XMLNode* _root;
1219 const XMLNode* _cur;
1220 std::stack<const XMLNode*> _stack;
1221
1222 /// go to specified node
1223 void go_to(const XMLNode* child)
1224 {
1225 _stack.push(_cur);
1226 _cur = child;
1227 }
1228 };
1229
1230
1231 // work around GCC's wide string constant bug
1232 #ifdef __GNUC__
1233 extern const LPCXSSTR XS_TRUE;
1234 extern const LPCXSSTR XS_FALSE;
1235 extern const LPCXSSTR XS_NUMBERFMT;
1236 #else
1237 #define XS_TRUE XS_TEXT("true")
1238 #define XS_FALSE XS_TEXT("false")
1239 #define XS_NUMBERFMT XS_TEXT("%d")
1240 #endif
1241
1242
1243 /// type converter for boolean data
1244 struct XMLBool
1245 {
1246 XMLBool(bool value=false)
1247 : _value(value)
1248 {
1249 }
1250
1251 XMLBool(LPCXSSTR value, bool def=false)
1252 {
1253 if (value && *value)
1254 _value = !XS_icmp(value, XS_TRUE);
1255 else
1256 _value = def;
1257 }
1258
1259 XMLBool(const XMLNode* node, const XS_String& attr_name, bool def=false)
1260 {
1261 const XS_String& value = node->get(attr_name);
1262
1263 if (!value.empty())
1264 _value = !XS_icmp(value.c_str(), XS_TRUE);
1265 else
1266 _value = def;
1267 }
1268
1269 operator bool() const
1270 {
1271 return _value;
1272 }
1273
1274 bool operator!() const
1275 {
1276 return !_value;
1277 }
1278
1279 operator LPCXSSTR() const
1280 {
1281 return _value? XS_TRUE: XS_FALSE;
1282 }
1283
1284 protected:
1285 bool _value;
1286
1287 private:
1288 void operator=(const XMLBool&); // disallow assignment operations
1289 };
1290
1291 /// type converter for boolean data with write access
1292 struct XMLBoolRef
1293 {
1294 XMLBoolRef(XMLNode* node, const XS_String& attr_name, bool def=false)
1295 : _ref((*node)[attr_name])
1296 {
1297 if (_ref.empty())
1298 assign(def);
1299 }
1300
1301 operator bool() const
1302 {
1303 return !XS_icmp(_ref.c_str(), XS_TRUE);
1304 }
1305
1306 bool operator!() const
1307 {
1308 return XS_icmp(_ref.c_str(), XS_TRUE)? true: false;
1309 }
1310
1311 XMLBoolRef& operator=(bool value)
1312 {
1313 assign(value);
1314
1315 return *this;
1316 }
1317
1318 void assign(bool value)
1319 {
1320 _ref.assign(value? XS_TRUE: XS_FALSE);
1321 }
1322
1323 void toggle()
1324 {
1325 assign(!operator bool());
1326 }
1327
1328 protected:
1329 XS_String& _ref;
1330 };
1331
1332
1333 /// type converter for integer data
1334 struct XMLInt
1335 {
1336 XMLInt(int value)
1337 : _value(value)
1338 {
1339 }
1340
1341 XMLInt(LPCXSSTR value, int def=0)
1342 {
1343 if (value && *value)
1344 _value = XS_toi(value);
1345 else
1346 _value = def;
1347 }
1348
1349 XMLInt(const XMLNode* node, const XS_String& attr_name, int def=0)
1350 {
1351 const XS_String& value = node->get(attr_name);
1352
1353 if (!value.empty())
1354 _value = XS_toi(value.c_str());
1355 else
1356 _value = def;
1357 }
1358
1359 operator int() const
1360 {
1361 return _value;
1362 }
1363
1364 operator XS_String() const
1365 {
1366 XS_CHAR buffer[32];
1367 XS_snprintf(buffer, COUNTOF(buffer), XS_NUMBERFMT, _value);
1368 return buffer;
1369 }
1370
1371 protected:
1372 int _value;
1373
1374 private:
1375 void operator=(const XMLInt&); // disallow assignment operations
1376 };
1377
1378 /// type converter for integer data with write access
1379 struct XMLIntRef
1380 {
1381 XMLIntRef(XMLNode* node, const XS_String& attr_name, int def=0)
1382 : _ref((*node)[attr_name])
1383 {
1384 if (_ref.empty())
1385 assign(def);
1386 }
1387
1388 XMLIntRef& operator=(int value)
1389 {
1390 assign(value);
1391
1392 return *this;
1393 }
1394
1395 operator int() const
1396 {
1397 return XS_toi(_ref.c_str());
1398 }
1399
1400 void assign(int value)
1401 {
1402 XS_CHAR buffer[32];
1403 XS_snprintf(buffer, COUNTOF(buffer), XS_NUMBERFMT, value);
1404 _ref.assign(buffer);
1405 }
1406
1407 protected:
1408 XS_String& _ref;
1409 };
1410
1411
1412 /// type converter for string data
1413 struct XMLString
1414 {
1415 XMLString(const XS_String& value)
1416 : _value(value)
1417 {
1418 }
1419
1420 XMLString(LPCXSSTR value, LPCXSSTR def=XS_TEXT(""))
1421 {
1422 if (value && *value)
1423 _value = value;
1424 else
1425 _value = def;
1426 }
1427
1428 XMLString(const XMLNode* node, const XS_String& attr_name, LPCXSSTR def=XS_TEXT(""))
1429 {
1430 const XS_String& value = node->get(attr_name);
1431
1432 if (!value.empty())
1433 _value = value;
1434 else
1435 _value = def;
1436 }
1437
1438 operator const XS_String&() const
1439 {
1440 return _value;
1441 }
1442
1443 const XS_String& c_str() const
1444 {
1445 return _value;
1446 }
1447
1448 protected:
1449 XS_String _value;
1450
1451 private:
1452 void operator=(const XMLString&); // disallow assignment operations
1453 };
1454
1455 /// type converter for string data with write access
1456 struct XMStringRef
1457 {
1458 XMStringRef(XMLNode* node, const XS_String& attr_name, LPCXSSTR def=XS_TEXT(""))
1459 : _ref((*node)[attr_name])
1460 {
1461 if (_ref.empty())
1462 assign(def);
1463 }
1464
1465 XMStringRef(XMLNode* node, const XS_String& node_name, const XS_String& attr_name, LPCXSSTR def=XS_TEXT(""))
1466 : _ref(node->subvalue(node_name, attr_name))
1467 {
1468 if (_ref.empty())
1469 assign(def);
1470 }
1471
1472 XMStringRef& operator=(const XS_String& value)
1473 {
1474 assign(value);
1475
1476 return *this;
1477 }
1478
1479 operator const XS_String&() const
1480 {
1481 return _ref;
1482 }
1483
1484 void assign(const XS_String& value)
1485 {
1486 _ref.assign(value);
1487 }
1488
1489 protected:
1490 XS_String& _ref;
1491 };
1492
1493
1494 template<typename T>
1495 inline void read_option(T& var, const_XMLPos& cfg, LPCXSSTR key)
1496 {
1497 const XS_String& val = cfg.get(key);
1498
1499 if (!val.empty())
1500 var = val;
1501 }
1502
1503 template<>
1504 inline void read_option(int& var, const_XMLPos& cfg, LPCXSSTR key)
1505 {
1506 const XS_String& val = cfg.get(key);
1507
1508 if (!val.empty())
1509 var = XS_toi(val.c_str());
1510 }
1511
1512
1513 #ifdef _MSC_VER
1514 #pragma warning(disable: 4355)
1515 #endif
1516
1517 /// XML reader base class
1518 struct XMLReaderBase
1519 {
1520 XMLReaderBase(XMLNode* node)
1521 : _pos(node),
1522 _parser(XML_ParserCreate(NULL))
1523 {
1524 XML_SetUserData(_parser, this);
1525 XML_SetXmlDeclHandler(_parser, XML_XmlDeclHandler);
1526 XML_SetElementHandler(_parser, XML_StartElementHandler, XML_EndElementHandler);
1527 XML_SetDefaultHandler(_parser, XML_DefaultHandler);
1528
1529 _last_tag = TAG_NONE;
1530 }
1531
1532 virtual ~XMLReaderBase()
1533 {
1534 XML_ParserFree(_parser);
1535 }
1536
1537 XML_Status read();
1538
1539 virtual int read_buffer(char* buffer, int len) = 0;
1540
1541 std::string get_position() const
1542 {
1543 int line = XML_GetCurrentLineNumber(_parser);
1544 int column = XML_GetCurrentColumnNumber(_parser);
1545
1546 std::ostringstream out;
1547 out << "(" << line << ") : [column " << column << "]";
1548
1549 return out.str();
1550 }
1551
1552 std::string get_instructions() const {return _instructions;}
1553
1554 XML_Error get_error_code() {return XML_GetErrorCode(_parser);}
1555 std::string get_error_string() const;
1556
1557 protected:
1558 XMLPos _pos;
1559 XML_Parser _parser;
1560 std::string _xml_version;
1561 std::string _encoding;
1562 std::string _instructions;
1563
1564 std::string _content;
1565 enum {TAG_NONE, TAG_START, TAG_END} _last_tag;
1566
1567 static void XMLCALL XML_XmlDeclHandler(void* userData, const XML_Char* version, const XML_Char* encoding, int standalone);
1568 static void XMLCALL XML_StartElementHandler(void* userData, const XML_Char* name, const XML_Char** atts);
1569 static void XMLCALL XML_EndElementHandler(void* userData, const XML_Char* name);
1570 static void XMLCALL XML_DefaultHandler(void* userData, const XML_Char* s, int len);
1571 };
1572
1573
1574 /// XML file reader
1575 struct XMLReader : public XMLReaderBase
1576 {
1577 XMLReader(XMLNode* node, std::istream& in)
1578 : XMLReaderBase(node),
1579 _in(in)
1580 {
1581 }
1582
1583 /// read XML stream into XML tree below _pos
1584 int read_buffer(char* buffer, int len)
1585 {
1586 if (!_in.good())
1587 return -1;
1588
1589 _in.read(buffer, len);
1590
1591 return _in.gcount();
1592 }
1593
1594 protected:
1595 std::istream& _in;
1596 };
1597
1598
1599 /// management of XML file headers
1600 struct XMLHeader
1601 {
1602 XMLHeader(const std::string& xml_version="1.0", const std::string& encoding="UTF-8", const std::string& doctype="")
1603 : _version(xml_version),
1604 _encoding(encoding),
1605 _doctype(doctype)
1606 {
1607 }
1608
1609 void print(std::ostream& out, bool pretty=true) const
1610 {
1611 out << "<?xml version=\"" << _version << "\" encoding=\"" << _encoding << "\"?>";
1612
1613 if (pretty)
1614 out << std::endl;
1615
1616 if (!_doctype.empty())
1617 out << _doctype << '\n';
1618
1619 if (!_additional.empty())
1620 out << _additional << '\n';
1621 }
1622
1623 std::string _version;
1624 std::string _encoding;
1625 std::string _doctype;
1626 std::string _additional;
1627 };
1628
1629
1630 /// XML document holder
1631 struct XMLDoc : public XMLNode
1632 {
1633 XMLDoc()
1634 : XMLNode(""),
1635 _last_error(XML_ERROR_NONE)
1636 {
1637 }
1638
1639 XMLDoc(LPCTSTR path)
1640 : XMLNode(""),
1641 _last_error(XML_ERROR_NONE)
1642 {
1643 read(path);
1644 }
1645
1646 std::istream& read(std::istream& in)
1647 {
1648 XMLReader reader(this, in);
1649
1650 read(reader);
1651
1652 return in;
1653 }
1654
1655 bool read(LPCTSTR path)
1656 {
1657 tifstream in(path);
1658 XMLReader reader(this, in);
1659
1660 //#if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8)
1661 // return read(reader, std::string(ANS(path)));
1662 //#else
1663 return read(reader, XS_String(path));
1664 //#endif
1665 }
1666
1667 bool read(XMLReaderBase& reader)
1668 {
1669 XML_Status status = reader.read();
1670
1671 _header._additional = reader.get_instructions();
1672
1673 if (status == XML_STATUS_ERROR) {
1674 std::ostringstream out;
1675
1676 out << "input stream" << reader.get_position() << " " << reader.get_error_string();
1677
1678 _last_error = reader.get_error_code();
1679 _last_error_msg = out.str();
1680 }
1681
1682 return status != XML_STATUS_ERROR;
1683 }
1684
1685 bool read(XMLReaderBase& reader, const std::string& display_path)
1686 {
1687 XML_Status status = reader.read();
1688
1689 _header._additional = reader.get_instructions();
1690
1691 if (status == XML_STATUS_ERROR) {
1692 std::ostringstream out;
1693
1694 out << display_path << reader.get_position() << " " << reader.get_error_string();
1695
1696 _last_error = reader.get_error_code();
1697 _last_error_msg = out.str();
1698 }
1699
1700 return status != XML_STATUS_ERROR;
1701 }
1702
1703 /// write XML stream preserving previous white space and comments
1704 std::ostream& write(std::ostream& out, WRITE_MODE mode=FORMAT_SMART) const
1705 {
1706 _header.print(out);
1707
1708 if (!_children.empty())
1709 _children.front()->write(out);
1710
1711 return out;
1712 }
1713
1714 /// write XML stream with formating
1715 std::ostream& write_formating(std::ostream& out) const
1716 {
1717 return write(out, FORMAT_PRETTY);
1718 }
1719
1720 void write(LPCTSTR path, WRITE_MODE mode=FORMAT_SMART) const
1721 {
1722 tofstream out(path);
1723
1724 write(out, mode);
1725 }
1726
1727 void write_formating(LPCTSTR path) const
1728 {
1729 tofstream out(path);
1730
1731 write_formating(out);
1732 }
1733
1734 XMLHeader _header;
1735 XML_Error _last_error;
1736 std::string _last_error_msg;
1737 };
1738
1739
1740 /// XML message wrapper
1741 struct XMLMessage : public XMLDoc
1742 {
1743 XMLMessage(const char* name)
1744 : _pos(this)
1745 {
1746 _pos.create(name);
1747 }
1748
1749 XMLPos _pos;
1750 };
1751
1752
1753 enum PRETTY_FLAGS {
1754 PRETTY_PLAIN = 0,
1755 PRETTY_LINEFEED = 1,
1756 PRETTY_INDENT = 2
1757 };
1758
1759 struct XMLWriter
1760 {
1761 XMLWriter(std::ostream& out, PRETTY_FLAGS pretty=PRETTY_INDENT, const XMLHeader& header=XMLHeader())
1762 : _pofstream(NULL),
1763 _out(out),
1764 _pretty(pretty)
1765 {
1766 header.print(_out, false);
1767 }
1768
1769 XMLWriter(LPCTSTR path, PRETTY_FLAGS pretty=PRETTY_INDENT, const XMLHeader& header=XMLHeader())
1770 : _pofstream(new tofstream(path)),
1771 _out(*_pofstream),
1772 _pretty(pretty)
1773 {
1774 header.print(_out, false);
1775 }
1776
1777 ~XMLWriter()
1778 {
1779 _out << std::endl;
1780 delete _pofstream;
1781 }
1782
1783 /// create node and move to it
1784 void create(const XS_String& name)
1785 {
1786 if (!_stack.empty()) {
1787 StackEntry& last = _stack.top();
1788
1789 if (last._state < PRE_CLOSED) {
1790 write_attributes(last);
1791 close_pre(last);
1792 }
1793
1794 ++last._children;
1795 }
1796
1797 StackEntry entry;
1798 entry._node_name = name;
1799 _stack.push(entry);
1800
1801 write_pre(entry);
1802 }
1803
1804 /// go back to previous position
1805 bool back()
1806 {
1807 if (!_stack.empty()) {
1808 write_post(_stack.top());
1809
1810 _stack.pop();
1811 return true;
1812 } else
1813 return false;
1814 }
1815
1816 /// attribute setting
1817 void put(const XS_String& attr_name, const XS_String& value)
1818 {
1819 if (!_stack.empty())
1820 _stack.top()._attributes[attr_name] = value;
1821 }
1822
1823 /// C++ write access to an attribute
1824 XS_String& operator[](const XS_String& attr_name)
1825 {
1826 if (_stack.empty())
1827 return s_empty_attr;
1828
1829 return _stack.top()._attributes[attr_name];
1830 }
1831
1832 void set_content(const XS_String& s)
1833 {
1834 if (!_stack.empty())
1835 _stack.top()._content = s;
1836 }
1837
1838 // public for access in StackEntry
1839 enum WRITESTATE {
1840 NOTHING, /*PRE,*/ ATTRIBUTES, PRE_CLOSED, /*CONTENT,*/ POST
1841 };
1842
1843 protected:
1844 tofstream* _pofstream;
1845 std::ostream& _out;
1846 PRETTY_FLAGS _pretty;
1847
1848 typedef XMLNode::AttributeMap AttrMap;
1849
1850 struct StackEntry {
1851 XS_String _node_name;
1852 AttrMap _attributes;
1853 std::string _content;
1854 WRITESTATE _state;
1855 bool _children;
1856
1857 StackEntry() : _state(NOTHING), _children(false) {}
1858 };
1859
1860 std::stack<StackEntry> _stack;
1861
1862 static XS_String s_empty_attr;
1863
1864 void close_pre(StackEntry& entry)
1865 {
1866 _out << '>';
1867
1868 entry._state = PRE_CLOSED;
1869 }
1870
1871 void write_pre(StackEntry& entry)
1872 {
1873 if (_pretty >= PRETTY_LINEFEED)
1874 _out << std::endl;
1875
1876 if (_pretty == PRETTY_INDENT)
1877 for(int i=_stack.size(); --i>0; )
1878 _out << XML_INDENT_SPACE;
1879
1880 _out << '<' << EncodeXMLString(entry._node_name);
1881 //entry._state = PRE;
1882 }
1883
1884 void write_attributes(StackEntry& entry)
1885 {
1886 for(AttrMap::const_iterator it=entry._attributes.begin(); it!=entry._attributes.end(); ++it)
1887 _out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\"";
1888
1889 entry._state = ATTRIBUTES;
1890 }
1891
1892 void write_post(StackEntry& entry)
1893 {
1894 if (entry._state < ATTRIBUTES)
1895 write_attributes(entry);
1896
1897 if (entry._children || !entry._content.empty()) {
1898 if (entry._state < PRE_CLOSED)
1899 close_pre(entry);
1900
1901 _out << entry._content;
1902 //entry._state = CONTENT;
1903
1904 if (_pretty>=PRETTY_LINEFEED && entry._content.empty())
1905 _out << std::endl;
1906
1907 if (_pretty==PRETTY_INDENT && entry._content.empty())
1908 for(int i=_stack.size(); --i>0; )
1909 _out << XML_INDENT_SPACE;
1910
1911 _out << "</" << EncodeXMLString(entry._node_name) << ">";
1912 } else {
1913 _out << "/>";
1914 }
1915
1916 entry._state = POST;
1917 }
1918 };
1919
1920
1921 } // namespace XMLStorage
1922
1923 #define _XMLSTORAGE_H
1924 #endif // _XMLSTORAGE_H