a bit of Makefile and string constants cleanup
[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 #define XS_TRUE_STR XS_TEXT("true")
1232 #define XS_FALSE_STR XS_TEXT("false")
1233 #define XS_NUMBERFMT_STR XS_TEXT("%d")
1234
1235 // work around GCC's wide string constant bug
1236 #ifdef __GNUC__
1237 extern const LPCXSSTR XS_TRUE;
1238 extern const LPCXSSTR XS_FALSE;
1239 extern const LPCXSSTR XS_NUMBERFMT;
1240 #else
1241 #define XS_TRUE XS_TRUE_STR
1242 #define XS_FALSE XS_FALSE_STR
1243 #define XS_NUMBERFMT XS_NUMBERFMT_STR
1244 #endif
1245
1246
1247 /// type converter for boolean data
1248 struct XMLBool
1249 {
1250 XMLBool(bool value=false)
1251 : _value(value)
1252 {
1253 }
1254
1255 XMLBool(LPCXSSTR value, bool def=false)
1256 {
1257 if (value && *value)
1258 _value = !XS_icmp(value, XS_TRUE);
1259 else
1260 _value = def;
1261 }
1262
1263 XMLBool(const XMLNode* node, const XS_String& attr_name, bool def=false)
1264 {
1265 const XS_String& value = node->get(attr_name);
1266
1267 if (!value.empty())
1268 _value = !XS_icmp(value.c_str(), XS_TRUE);
1269 else
1270 _value = def;
1271 }
1272
1273 operator bool() const
1274 {
1275 return _value;
1276 }
1277
1278 bool operator!() const
1279 {
1280 return !_value;
1281 }
1282
1283 operator LPCXSSTR() const
1284 {
1285 return _value? XS_TRUE: XS_FALSE;
1286 }
1287
1288 protected:
1289 bool _value;
1290
1291 private:
1292 void operator=(const XMLBool&); // disallow assignment operations
1293 };
1294
1295 /// type converter for boolean data with write access
1296 struct XMLBoolRef
1297 {
1298 XMLBoolRef(XMLNode* node, const XS_String& attr_name, bool def=false)
1299 : _ref((*node)[attr_name])
1300 {
1301 if (_ref.empty())
1302 assign(def);
1303 }
1304
1305 operator bool() const
1306 {
1307 return !XS_icmp(_ref.c_str(), XS_TRUE);
1308 }
1309
1310 bool operator!() const
1311 {
1312 return XS_icmp(_ref.c_str(), XS_TRUE)? true: false;
1313 }
1314
1315 XMLBoolRef& operator=(bool value)
1316 {
1317 assign(value);
1318
1319 return *this;
1320 }
1321
1322 void assign(bool value)
1323 {
1324 _ref.assign(value? XS_TRUE: XS_FALSE);
1325 }
1326
1327 void toggle()
1328 {
1329 assign(!operator bool());
1330 }
1331
1332 protected:
1333 XS_String& _ref;
1334 };
1335
1336
1337 /// type converter for integer data
1338 struct XMLInt
1339 {
1340 XMLInt(int value)
1341 : _value(value)
1342 {
1343 }
1344
1345 XMLInt(LPCXSSTR value, int def=0)
1346 {
1347 if (value && *value)
1348 _value = XS_toi(value);
1349 else
1350 _value = def;
1351 }
1352
1353 XMLInt(const XMLNode* node, const XS_String& attr_name, int def=0)
1354 {
1355 const XS_String& value = node->get(attr_name);
1356
1357 if (!value.empty())
1358 _value = XS_toi(value.c_str());
1359 else
1360 _value = def;
1361 }
1362
1363 operator int() const
1364 {
1365 return _value;
1366 }
1367
1368 operator XS_String() const
1369 {
1370 XS_CHAR buffer[32];
1371 XS_snprintf(buffer, COUNTOF(buffer), XS_NUMBERFMT, _value);
1372 return buffer;
1373 }
1374
1375 protected:
1376 int _value;
1377
1378 private:
1379 void operator=(const XMLInt&); // disallow assignment operations
1380 };
1381
1382 /// type converter for integer data with write access
1383 struct XMLIntRef
1384 {
1385 XMLIntRef(XMLNode* node, const XS_String& attr_name, int def=0)
1386 : _ref((*node)[attr_name])
1387 {
1388 if (_ref.empty())
1389 assign(def);
1390 }
1391
1392 XMLIntRef& operator=(int value)
1393 {
1394 assign(value);
1395
1396 return *this;
1397 }
1398
1399 operator int() const
1400 {
1401 return XS_toi(_ref.c_str());
1402 }
1403
1404 void assign(int value)
1405 {
1406 XS_CHAR buffer[32];
1407 XS_snprintf(buffer, COUNTOF(buffer), XS_NUMBERFMT, value);
1408 _ref.assign(buffer);
1409 }
1410
1411 protected:
1412 XS_String& _ref;
1413 };
1414
1415
1416 /// type converter for string data
1417 struct XMLString
1418 {
1419 XMLString(const XS_String& value)
1420 : _value(value)
1421 {
1422 }
1423
1424 XMLString(LPCXSSTR value, LPCXSSTR def=XS_TEXT(""))
1425 {
1426 if (value && *value)
1427 _value = value;
1428 else
1429 _value = def;
1430 }
1431
1432 XMLString(const XMLNode* node, const XS_String& attr_name, LPCXSSTR def=XS_TEXT(""))
1433 {
1434 const XS_String& value = node->get(attr_name);
1435
1436 if (!value.empty())
1437 _value = value;
1438 else
1439 _value = def;
1440 }
1441
1442 operator const XS_String&() const
1443 {
1444 return _value;
1445 }
1446
1447 const XS_String& c_str() const
1448 {
1449 return _value;
1450 }
1451
1452 protected:
1453 XS_String _value;
1454
1455 private:
1456 void operator=(const XMLString&); // disallow assignment operations
1457 };
1458
1459 /// type converter for string data with write access
1460 struct XMStringRef
1461 {
1462 XMStringRef(XMLNode* node, const XS_String& attr_name, LPCXSSTR def=XS_TEXT(""))
1463 : _ref((*node)[attr_name])
1464 {
1465 if (_ref.empty())
1466 assign(def);
1467 }
1468
1469 XMStringRef(XMLNode* node, const XS_String& node_name, const XS_String& attr_name, LPCXSSTR def=XS_TEXT(""))
1470 : _ref(node->subvalue(node_name, attr_name))
1471 {
1472 if (_ref.empty())
1473 assign(def);
1474 }
1475
1476 XMStringRef& operator=(const XS_String& value)
1477 {
1478 assign(value);
1479
1480 return *this;
1481 }
1482
1483 operator const XS_String&() const
1484 {
1485 return _ref;
1486 }
1487
1488 void assign(const XS_String& value)
1489 {
1490 _ref.assign(value);
1491 }
1492
1493 protected:
1494 XS_String& _ref;
1495 };
1496
1497
1498 template<typename T>
1499 inline void read_option(T& var, const_XMLPos& cfg, LPCXSSTR key)
1500 {
1501 const XS_String& val = cfg.get(key);
1502
1503 if (!val.empty())
1504 var = val;
1505 }
1506
1507 template<>
1508 inline void read_option(int& var, const_XMLPos& cfg, LPCXSSTR key)
1509 {
1510 const XS_String& val = cfg.get(key);
1511
1512 if (!val.empty())
1513 var = XS_toi(val.c_str());
1514 }
1515
1516
1517 #ifdef _MSC_VER
1518 #pragma warning(disable: 4355)
1519 #endif
1520
1521 /// XML reader base class
1522 struct XMLReaderBase
1523 {
1524 XMLReaderBase(XMLNode* node)
1525 : _pos(node),
1526 _parser(XML_ParserCreate(NULL))
1527 {
1528 XML_SetUserData(_parser, this);
1529 XML_SetXmlDeclHandler(_parser, XML_XmlDeclHandler);
1530 XML_SetElementHandler(_parser, XML_StartElementHandler, XML_EndElementHandler);
1531 XML_SetDefaultHandler(_parser, XML_DefaultHandler);
1532
1533 _last_tag = TAG_NONE;
1534 }
1535
1536 virtual ~XMLReaderBase()
1537 {
1538 XML_ParserFree(_parser);
1539 }
1540
1541 XML_Status read();
1542
1543 virtual int read_buffer(char* buffer, int len) = 0;
1544
1545 std::string get_position() const
1546 {
1547 int line = XML_GetCurrentLineNumber(_parser);
1548 int column = XML_GetCurrentColumnNumber(_parser);
1549
1550 std::ostringstream out;
1551 out << "(" << line << ") : [column " << column << "]";
1552
1553 return out.str();
1554 }
1555
1556 std::string get_instructions() const {return _instructions;}
1557
1558 XML_Error get_error_code() {return XML_GetErrorCode(_parser);}
1559 std::string get_error_string() const;
1560
1561 protected:
1562 XMLPos _pos;
1563 XML_Parser _parser;
1564 std::string _xml_version;
1565 std::string _encoding;
1566 std::string _instructions;
1567
1568 std::string _content;
1569 enum {TAG_NONE, TAG_START, TAG_END} _last_tag;
1570
1571 static void XMLCALL XML_XmlDeclHandler(void* userData, const XML_Char* version, const XML_Char* encoding, int standalone);
1572 static void XMLCALL XML_StartElementHandler(void* userData, const XML_Char* name, const XML_Char** atts);
1573 static void XMLCALL XML_EndElementHandler(void* userData, const XML_Char* name);
1574 static void XMLCALL XML_DefaultHandler(void* userData, const XML_Char* s, int len);
1575 };
1576
1577
1578 /// XML file reader
1579 struct XMLReader : public XMLReaderBase
1580 {
1581 XMLReader(XMLNode* node, std::istream& in)
1582 : XMLReaderBase(node),
1583 _in(in)
1584 {
1585 }
1586
1587 /// read XML stream into XML tree below _pos
1588 int read_buffer(char* buffer, int len)
1589 {
1590 if (!_in.good())
1591 return -1;
1592
1593 _in.read(buffer, len);
1594
1595 return _in.gcount();
1596 }
1597
1598 protected:
1599 std::istream& _in;
1600 };
1601
1602
1603 /// management of XML file headers
1604 struct XMLHeader
1605 {
1606 XMLHeader(const std::string& xml_version="1.0", const std::string& encoding="UTF-8", const std::string& doctype="")
1607 : _version(xml_version),
1608 _encoding(encoding),
1609 _doctype(doctype)
1610 {
1611 }
1612
1613 void print(std::ostream& out, bool pretty=true) const
1614 {
1615 out << "<?xml version=\"" << _version << "\" encoding=\"" << _encoding << "\"?>";
1616
1617 if (pretty)
1618 out << std::endl;
1619
1620 if (!_doctype.empty())
1621 out << _doctype << '\n';
1622
1623 if (!_additional.empty())
1624 out << _additional << '\n';
1625 }
1626
1627 std::string _version;
1628 std::string _encoding;
1629 std::string _doctype;
1630 std::string _additional;
1631 };
1632
1633
1634 /// XML document holder
1635 struct XMLDoc : public XMLNode
1636 {
1637 XMLDoc()
1638 : XMLNode(""),
1639 _last_error(XML_ERROR_NONE)
1640 {
1641 }
1642
1643 XMLDoc(LPCTSTR path)
1644 : XMLNode(""),
1645 _last_error(XML_ERROR_NONE)
1646 {
1647 read(path);
1648 }
1649
1650 std::istream& read(std::istream& in)
1651 {
1652 XMLReader reader(this, in);
1653
1654 read(reader);
1655
1656 return in;
1657 }
1658
1659 bool read(LPCTSTR path)
1660 {
1661 tifstream in(path);
1662 XMLReader reader(this, in);
1663
1664 //#if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8)
1665 // return read(reader, std::string(ANS(path)));
1666 //#else
1667 return read(reader, XS_String(path));
1668 //#endif
1669 }
1670
1671 bool read(XMLReaderBase& reader)
1672 {
1673 XML_Status status = reader.read();
1674
1675 _header._additional = reader.get_instructions();
1676
1677 if (status == XML_STATUS_ERROR) {
1678 std::ostringstream out;
1679
1680 out << "input stream" << reader.get_position() << " " << reader.get_error_string();
1681
1682 _last_error = reader.get_error_code();
1683 _last_error_msg = out.str();
1684 }
1685
1686 return status != XML_STATUS_ERROR;
1687 }
1688
1689 bool read(XMLReaderBase& reader, const std::string& display_path)
1690 {
1691 XML_Status status = reader.read();
1692
1693 _header._additional = reader.get_instructions();
1694
1695 if (status == XML_STATUS_ERROR) {
1696 std::ostringstream out;
1697
1698 out << display_path << reader.get_position() << " " << reader.get_error_string();
1699
1700 _last_error = reader.get_error_code();
1701 _last_error_msg = out.str();
1702 }
1703
1704 return status != XML_STATUS_ERROR;
1705 }
1706
1707 /// write XML stream preserving previous white space and comments
1708 std::ostream& write(std::ostream& out, WRITE_MODE mode=FORMAT_SMART) const
1709 {
1710 _header.print(out);
1711
1712 if (!_children.empty())
1713 _children.front()->write(out);
1714
1715 return out;
1716 }
1717
1718 /// write XML stream with formating
1719 std::ostream& write_formating(std::ostream& out) const
1720 {
1721 return write(out, FORMAT_PRETTY);
1722 }
1723
1724 void write(LPCTSTR path, WRITE_MODE mode=FORMAT_SMART) const
1725 {
1726 tofstream out(path);
1727
1728 write(out, mode);
1729 }
1730
1731 void write_formating(LPCTSTR path) const
1732 {
1733 tofstream out(path);
1734
1735 write_formating(out);
1736 }
1737
1738 XMLHeader _header;
1739 XML_Error _last_error;
1740 std::string _last_error_msg;
1741 };
1742
1743
1744 /// XML message wrapper
1745 struct XMLMessage : public XMLDoc
1746 {
1747 XMLMessage(const char* name)
1748 : _pos(this)
1749 {
1750 _pos.create(name);
1751 }
1752
1753 XMLPos _pos;
1754 };
1755
1756
1757 enum PRETTY_FLAGS {
1758 PRETTY_PLAIN = 0,
1759 PRETTY_LINEFEED = 1,
1760 PRETTY_INDENT = 2
1761 };
1762
1763 struct XMLWriter
1764 {
1765 XMLWriter(std::ostream& out, PRETTY_FLAGS pretty=PRETTY_INDENT, const XMLHeader& header=XMLHeader())
1766 : _pofstream(NULL),
1767 _out(out),
1768 _pretty(pretty)
1769 {
1770 header.print(_out, false);
1771 }
1772
1773 XMLWriter(LPCTSTR path, PRETTY_FLAGS pretty=PRETTY_INDENT, const XMLHeader& header=XMLHeader())
1774 : _pofstream(new tofstream(path)),
1775 _out(*_pofstream),
1776 _pretty(pretty)
1777 {
1778 header.print(_out, false);
1779 }
1780
1781 ~XMLWriter()
1782 {
1783 _out << std::endl;
1784 delete _pofstream;
1785 }
1786
1787 /// create node and move to it
1788 void create(const XS_String& name)
1789 {
1790 if (!_stack.empty()) {
1791 StackEntry& last = _stack.top();
1792
1793 if (last._state < PRE_CLOSED) {
1794 write_attributes(last);
1795 close_pre(last);
1796 }
1797
1798 ++last._children;
1799 }
1800
1801 StackEntry entry;
1802 entry._node_name = name;
1803 _stack.push(entry);
1804
1805 write_pre(entry);
1806 }
1807
1808 /// go back to previous position
1809 bool back()
1810 {
1811 if (!_stack.empty()) {
1812 write_post(_stack.top());
1813
1814 _stack.pop();
1815 return true;
1816 } else
1817 return false;
1818 }
1819
1820 /// attribute setting
1821 void put(const XS_String& attr_name, const XS_String& value)
1822 {
1823 if (!_stack.empty())
1824 _stack.top()._attributes[attr_name] = value;
1825 }
1826
1827 /// C++ write access to an attribute
1828 XS_String& operator[](const XS_String& attr_name)
1829 {
1830 if (_stack.empty())
1831 return s_empty_attr;
1832
1833 return _stack.top()._attributes[attr_name];
1834 }
1835
1836 void set_content(const XS_String& s)
1837 {
1838 if (!_stack.empty())
1839 _stack.top()._content = s;
1840 }
1841
1842 // public for access in StackEntry
1843 enum WRITESTATE {
1844 NOTHING, /*PRE,*/ ATTRIBUTES, PRE_CLOSED, /*CONTENT,*/ POST
1845 };
1846
1847 protected:
1848 tofstream* _pofstream;
1849 std::ostream& _out;
1850 PRETTY_FLAGS _pretty;
1851
1852 typedef XMLNode::AttributeMap AttrMap;
1853
1854 struct StackEntry {
1855 XS_String _node_name;
1856 AttrMap _attributes;
1857 std::string _content;
1858 WRITESTATE _state;
1859 bool _children;
1860
1861 StackEntry() : _state(NOTHING), _children(false) {}
1862 };
1863
1864 std::stack<StackEntry> _stack;
1865
1866 static XS_String s_empty_attr;
1867
1868 void close_pre(StackEntry& entry)
1869 {
1870 _out << '>';
1871
1872 entry._state = PRE_CLOSED;
1873 }
1874
1875 void write_pre(StackEntry& entry)
1876 {
1877 if (_pretty >= PRETTY_LINEFEED)
1878 _out << std::endl;
1879
1880 if (_pretty == PRETTY_INDENT)
1881 for(int i=_stack.size(); --i>0; )
1882 _out << XML_INDENT_SPACE;
1883
1884 _out << '<' << EncodeXMLString(entry._node_name);
1885 //entry._state = PRE;
1886 }
1887
1888 void write_attributes(StackEntry& entry)
1889 {
1890 for(AttrMap::const_iterator it=entry._attributes.begin(); it!=entry._attributes.end(); ++it)
1891 _out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\"";
1892
1893 entry._state = ATTRIBUTES;
1894 }
1895
1896 void write_post(StackEntry& entry)
1897 {
1898 if (entry._state < ATTRIBUTES)
1899 write_attributes(entry);
1900
1901 if (entry._children || !entry._content.empty()) {
1902 if (entry._state < PRE_CLOSED)
1903 close_pre(entry);
1904
1905 _out << entry._content;
1906 //entry._state = CONTENT;
1907
1908 if (_pretty>=PRETTY_LINEFEED && entry._content.empty())
1909 _out << std::endl;
1910
1911 if (_pretty==PRETTY_INDENT && entry._content.empty())
1912 for(int i=_stack.size(); --i>0; )
1913 _out << XML_INDENT_SPACE;
1914
1915 _out << "</" << EncodeXMLString(entry._node_name) << ">";
1916 } else {
1917 _out << "/>";
1918 }
1919
1920 entry._state = POST;
1921 }
1922 };
1923
1924
1925 } // namespace XMLStorage
1926
1927 #define _XMLSTORAGE_H
1928 #endif // _XMLSTORAGE_H