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