7 // Copyright (c) 2004, 2005 Martin Fuchs <martin-fuchs@gmx.net>
15 Redistribution and use in source and binary forms, with or without
16 modification, are permitted provided that the following conditions are met:
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
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.
41 #include <expat/expat.h>
44 #pragma comment(lib, "libexpat.lib")
45 #pragma warning(disable: 4786)
49 #include <windows.h> // for LPCTSTR
67 #define BUFFER_LEN 2048
71 namespace XMLStorage
{
80 #define LPCXSSTR LPCSTR
81 #define XS_icmp stricmp
82 #define XS_nicmp strnicmp
85 #define XS_sprintf sprintf
86 #define XS_vsprintf vsprintf
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
95 #define XS_len _tcslen
96 #define XS_sprintf _stprintf
97 #define XS_vsprintf _vstprintf
100 #if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8)
102 #define XS_String String
104 #else // _STRING_DEFINED, !XS_STRING_UTF8
106 /// string class for TCHAR strings
109 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
110 : public std::wstring
115 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
116 typedef std::wstring super
;
118 typedef std::string super
;
123 XS_String(LPCXSSTR s
) {if (s
) super::assign(s
);}
124 XS_String(LPCXSSTR s
, int l
) : super(s
, l
) {}
126 XS_String(const super
& other
) : super(other
) {}
127 XS_String(const XS_String
& other
) : super(other
) {}
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();}
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();}
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
);}
156 operator LPCXSSTR() const {return c_str();}
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));}
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
));}
166 XS_String
& printf(LPCXSSTR fmt
, ...)
169 XS_CHAR b
[BUFFER_LEN
];
172 super::assign(b
, XS_vsprintf(b
, fmt
, l
));
178 XS_String
& vprintf(LPCXSSTR fmt
, va_list l
)
180 XS_CHAR b
[BUFFER_LEN
];
182 super::assign(b
, XS_vsprintf(b
, fmt
, l
));
187 XS_String
& appendf(LPCXSSTR fmt
, ...)
190 XS_CHAR b
[BUFFER_LEN
];
193 super::append(b
, XS_vsprintf(b
, fmt
, l
));
199 XS_String
& vappendf(LPCXSSTR fmt
, va_list l
)
201 XS_CHAR b
[BUFFER_LEN
];
203 super::append(b
, XS_vsprintf(b
, fmt
, l
));
209 #endif // _STRING_DEFINED, !XS_STRING_UTF8
214 #ifndef XS_STRING_UTF8
216 inline void assign_utf8(XS_String
& s
, const char* str
)
218 int lutf8
= strlen(str
);
221 LPTSTR buffer
= (LPTSTR
)alloca(sizeof(TCHAR
)*lutf8
);
222 int l
= MultiByteToWideChar(CP_UTF8
, 0, str
, lutf8
, buffer
, lutf8
);
224 LPWSTR wbuffer
= (LPWSTR
)alloca(sizeof(WCHAR
)*lutf8
);
225 int l
= MultiByteToWideChar(CP_UTF8
, 0, str
, lutf8
, wbuffer
, lutf8
);
227 int bl
=2*l
; LPSTR buffer
= (LPSTR
)alloca(bl
);
228 l
= WideCharToMultiByte(CP_ACP
, 0, wbuffer
, l
, buffer
, bl
, 0, 0);
234 inline std::string
get_utf8(LPCTSTR s
, int l
)
237 int bl
=2*l
; LPSTR buffer
= (LPSTR
)alloca(bl
);
238 l
= WideCharToMultiByte(CP_UTF8
, 0, s
, l
, buffer
, bl
, 0, 0);
240 LPWSTR wbuffer
= (LPWSTR
)alloca(sizeof(WCHAR
)*l
);
241 l
= MultiByteToWideChar(CP_ACP
, 0, s
, l
, wbuffer
, l
);
243 int bl
=2*l
; LPSTR buffer
= (LPSTR
)alloca(bl
);
244 l
= WideCharToMultiByte(CP_UTF8
, 0, wbuffer
, l
, buffer
, bl
, 0, 0);
247 return std::string(buffer
, l
);
250 inline std::string
get_utf8(const XS_String
& s
)
252 return get_utf8(s
.c_str(), s
.length());
255 #endif // XS_STRING_UTF8
257 extern std::string
EncodeXMLString(const XS_String
& str
);
258 extern XS_String
DecodeXMLString(const XS_String
& str
);
262 #include <ext/stdio_filebuf.h>
263 typedef __gnu_cxx::stdio_filebuf
<char> STDIO_FILEBUF
;
265 typedef std::filebuf STDIO_FILEBUF
;
268 /// input file stream with ANSI/UNICODE file names
269 struct tifstream
: public std::istream
271 typedef std::istream super
;
273 tifstream(LPCTSTR path
)
275 _pfile(_tfopen(path
, TEXT("r"))),
277 _buf(_pfile
, ios::in
)
295 /// output file stream with ANSI/UNICODE file names
296 struct tofstream
: public std::ostream
298 typedef std::ostream super
;
300 tofstream(LPCTSTR path
)
302 _pfile(_tfopen(path
, TEXT("w"))),
304 _buf(_pfile
, ios::out
)
325 // write XML files with 2 spaces indenting
326 #define XML_INDENT_SPACE " "
329 #ifdef XML_UNICODE // Are XML_Char strings UTF-16 encoded?
331 typedef XS_String String_from_XML_Char
;
333 #elif defined(XS_STRING_UTF8)
335 typedef XS_String String_from_XML_Char
;
339 struct String_from_XML_Char
: public XS_String
341 String_from_XML_Char(const XML_Char
* str
)
343 assign_utf8(*this, str
);
350 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
352 // optimization for faster UNICODE/ASCII string comparison without temporary A/U conversion
353 inline bool operator==(const XS_String
& s1
, const char* s2
)
356 const unsigned char* q
= (const unsigned char*)s2
;
368 /// in memory representation of an XML node
369 struct XMLNode
: public XS_String
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
>
375 typedef std::map
<XS_String
, XS_String
> super
;
377 const_iterator
find(const char* x
) const
379 for(const_iterator it
=begin(); it
!=end(); ++it
)
386 const_iterator
find(const key_type
& x
) const
388 return super::find(x
);
391 iterator
find(const key_type
& x
)
393 return super::find(x
);
397 typedef std::map
<XS_String
, XS_String
> AttributeMap
;
400 struct Children
: public std::list
<XMLNode
*>
402 void assign(const Children
& other
)
406 for(Children::const_iterator it
=other
.begin(); it
!=other
.end(); ++it
)
407 push_back(new XMLNode(**it
));
413 XMLNode
* node
= back();
422 // access to protected class members for XMLPos and XMLReader
423 friend struct XMLPos
;
424 friend struct const_XMLPos
;
425 friend struct XMLReaderBase
;
427 XMLNode(const XS_String
& name
)
432 XMLNode(const XS_String
& name
, const std::string
& leading
)
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
)
445 for(Children::const_iterator it
=other
._children
.begin(); it
!=other
._children
.end(); ++it
)
446 _children
.push_back(new XMLNode(**it
));
451 while(!_children
.empty()) {
452 delete _children
.back();
453 _children
.pop_back();
461 _end_leading
.erase();
470 XMLNode
& operator=(const XMLNode
& other
)
472 _children
.assign(other
._children
);
474 _attributes
= other
._attributes
;
476 _leading
= other
._leading
;
477 _content
= other
._content
;
478 _end_leading
= other
._end_leading
;
479 _trailing
= other
._trailing
;
484 /// add a new child node
485 void add_child(XMLNode
* child
)
487 _children
.push_back(child
);
490 /// write access to an attribute
491 void put(const XS_String
& attr_name
, const XS_String
& value
)
493 _attributes
[attr_name
] = value
;
496 /// C++ write access to an attribute
497 XS_String
& operator[](const XS_String
& attr_name
)
499 return _attributes
[attr_name
];
502 /// read only access to an attribute
503 template<typename T
> XS_String
get(const T
& attr_name
) const
505 AttributeMap::const_iterator found
= _attributes
.find(attr_name
);
507 if (found
!= _attributes
.end())
508 return found
->second
;
513 /// convenient value access in children node
514 XS_String
subvalue(const XS_String
& name
, const XS_String
& attr_name
, int n
=0) const
516 const XMLNode
* node
= find(name
, n
);
519 return node
->get(attr_name
);
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)
527 XMLNode
* node
= find(name
, n
);
530 node
= new XMLNode(name
);
534 return (*node
)[attr_name
];
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
541 const XMLNode
* node
= find(name
, n
);
544 return node
->get(attr_name
);
549 /// convenient storage of distinct values in children node
550 XS_String
& subvalue(const char* name
, const XS_String
& attr_name
, int n
=0)
552 XMLNode
* node
= find(name
, n
);
555 node
= new XMLNode(name
);
559 return (*node
)[attr_name
];
563 const Children
& get_children() const
568 Children
& get_children()
573 XS_String
get_content() const
575 #ifdef XS_STRING_UTF8
576 const XS_String
& ret
= _content
;
579 assign_utf8(ret
, _content
.c_str());
582 return DecodeXMLString(ret
.c_str());
585 void set_content(const XS_String
& s
)
587 _content
.assign(EncodeXMLString(s
.c_str()));
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
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
601 pretty_write_worker(out
, indent
);
604 case FORMAT_ORIGINAL
:
605 write_worker(out
, indent
);
608 default: // FORMAT_SMART
609 smart_write_worker(out
, indent
);
617 AttributeMap _attributes
;
619 std::string _leading
;
620 std::string _content
;
621 std::string _end_leading
;
622 std::string _trailing
;
624 XMLNode
* get_first_child() const
626 if (!_children
.empty())
627 return _children
.front();
632 XMLNode
* find(const XS_String
& name
, int n
=0) const
634 for(Children::const_iterator it
=_children
.begin(); it
!=_children
.end(); ++it
)
642 XMLNode
* find(const XS_String
& name
, const XS_String
& attr_name
, const XS_String
& attr_value
, int n
=0) const
644 for(Children::const_iterator it
=_children
.begin(); it
!=_children
.end(); ++it
) {
645 const XMLNode
& node
= **it
;
647 if (node
==name
&& node
.get(attr_name
)==attr_value
)
655 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
656 XMLNode
* find(const char* name
, int n
=0) const
658 for(Children::const_iterator it
=_children
.begin(); it
!=_children
.end(); ++it
)
666 template<typename T
, typename U
>
667 XMLNode
* find(const char* name
, const T
& attr_name
, const U
& attr_value
, int n
=0) const
669 for(Children::const_iterator it
=_children
.begin(); it
!=_children
.end(); ++it
) {
670 const XMLNode
& node
= **it
;
672 if (node
==name
&& node
.get(attr_name
)==attr_value
)
681 /// XPath find functions
682 const XMLNode
* find_relative(const char* path
) const;
684 XMLNode
* find_relative(const char* path
)
685 {return const_cast<XMLNode
*>(const_cast<const XMLNode
*>(this)->find_relative(path
));}
687 /// relative XPath create function
688 XMLNode
* create_relative(const char* path
);
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;
696 /// iterator access to children nodes with name filtering
697 struct XMLChildrenFilter
699 XMLChildrenFilter(XMLNode::Children
& children
, const XS_String
& name
)
700 : _begin(children
.begin(), children
.end(), name
),
701 _end(children
.end(), children
.end(), name
)
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
)
713 typedef XMLNode::Children::iterator BaseIterator
;
715 iterator(BaseIterator begin
, BaseIterator end
, const XS_String
& filter_name
)
718 _filter_name(filter_name
)
723 operator BaseIterator()
728 const XMLNode
* operator*() const
738 iterator
& operator++()
746 iterator
operator++(int)
748 iterator ret
= *this;
756 bool operator==(const BaseIterator
& other
) const
758 return _cur
== other
;
761 bool operator!=(const BaseIterator
& other
) const
763 return _cur
!= other
;
769 XS_String _filter_name
;
773 while(_cur
!=_end
&& **_cur
!=_filter_name
)
794 /// read only iterator access to children nodes with name filtering
795 struct const_XMLChildrenFilter
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
)
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
)
809 struct const_iterator
811 typedef XMLNode::Children::const_iterator BaseIterator
;
813 const_iterator(BaseIterator begin
, BaseIterator end
, const XS_String
& filter_name
)
816 _filter_name(filter_name
)
821 operator BaseIterator()
826 const XMLNode
* operator*() const
831 const_iterator
& operator++()
839 const_iterator
operator++(int)
841 const_iterator ret
= *this;
849 bool operator==(const BaseIterator
& other
) const
851 return _cur
== other
;
854 bool operator!=(const BaseIterator
& other
) const
856 return _cur
!= other
;
862 XS_String _filter_name
;
866 while(_cur
!=_end
&& **_cur
!=_filter_name
)
871 const_iterator
begin()
882 const_iterator _begin
;
887 /// iterator for XML trees
890 XMLPos(XMLNode
* root
)
896 XMLPos(const XMLPos
& other
)
897 : _root(other
._root
),
899 { // don't copy _stack
902 XMLPos(XMLNode
* node
, const XS_String
& name
)
909 XMLPos(XMLNode
* node
, const XS_String
& name
, const XS_String
& attr_name
, const XS_String
& attr_value
)
913 smart_create(name
, attr_name
, attr_value
);
916 XMLPos(const XMLPos
& other
, const XS_String
& name
)
917 : _root(other
._root
),
923 XMLPos(const XMLPos
& other
, const XS_String
& name
, const XS_String
& attr_name
, const XS_String
& attr_value
)
924 : _root(other
._root
),
927 smart_create(name
, attr_name
, attr_value
);
930 /// access to current node
936 const XMLNode
& cur() const
941 /// C++ access to current node
942 operator const XMLNode
*() const {return _cur
;}
943 operator XMLNode
*() {return _cur
;}
945 const XMLNode
* operator->() const {return _cur
;}
946 XMLNode
* operator->() {return _cur
;}
948 const XMLNode
& operator*() const {return *_cur
;}
949 XMLNode
& operator*() {return *_cur
;}
952 XS_String
get(const XS_String
& attr_name
) const
954 return _cur
->get(attr_name
);
957 void put(const XS_String
& attr_name
, const XS_String
& value
)
959 _cur
->put(attr_name
, value
);
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
];}
966 /// insert children when building tree
967 void add_down(XMLNode
* child
)
969 _cur
->add_child(child
);
973 /// go back to previous position
976 if (!_stack
.empty()) {
984 /// go down to first child
987 XMLNode
* node
= _cur
->get_first_child();
996 /// search for child and go down
997 bool go_down(const XS_String
& name
, int n
=0)
999 XMLNode
* node
= _cur
->find(name
, n
);
1008 /// move XPath like to position in XML tree
1009 bool go(const char* path
);
1011 /// create child nodes using XPath notation and move to the deepest child
1012 bool create_relative(const char* path
)
1014 XMLNode
* node
= _cur
->create_relative(path
);
1016 return false; // invalid path specified
1022 /// create node and move to it
1023 void create(const XS_String
& name
)
1025 add_down(new XMLNode(name
));
1028 /// create node if not already existing and move to it
1029 void smart_create(const XS_String
& name
)
1031 XMLNode
* node
= _cur
->find(name
);
1036 add_down(new XMLNode(name
));
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
)
1042 XMLNode
* node
= _cur
->find(name
, attr_name
, attr_value
);
1047 node
= new XMLNode(name
);
1049 (*node
)[attr_name
] = attr_value
;
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)
1057 XMLNode
* node
= _cur
->find(name
, n
);
1066 /// create node and move to it
1067 void create(const char* name
)
1069 add_down(new XMLNode(name
));
1072 /// create node if not already existing and move to it
1073 void smart_create(const char* name
)
1075 XMLNode
* node
= _cur
->find(name
);
1080 add_down(new XMLNode(name
));
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
)
1087 XMLNode
* node
= _cur
->find(name
, attr_name
, attr_value
);
1092 XMLNode
* node
= new XMLNode(name
);
1094 (*node
)[attr_name
] = attr_value
;
1099 XS_String
& str() {return *_cur
;}
1100 const XS_String
& str() const {return *_cur
;}
1105 std::stack
<XMLNode
*> _stack
;
1107 /// go to specified node
1108 void go_to(XMLNode
* child
)
1116 /// iterator for XML trees
1119 const_XMLPos(const XMLNode
* root
)
1125 const_XMLPos(const const_XMLPos
& other
)
1126 : _root(other
._root
),
1128 { // don't copy _stack
1131 /// access to current node
1132 const XMLNode
& cur() const
1137 /// C++ access to current node
1138 operator const XMLNode
*() const {return _cur
;}
1140 const XMLNode
* operator->() const {return _cur
;}
1142 const XMLNode
& operator*() const {return *_cur
;}
1144 /// attribute access
1145 XS_String
get(const XS_String
& attr_name
) const
1147 return _cur
->get(attr_name
);
1150 /// C++ attribute access
1151 template<typename T
> XS_String
get(const T
& attr_name
) const {return _cur
->get(attr_name
);}
1153 /// go back to previous position
1156 if (!_stack
.empty()) {
1157 _cur
= _stack
.top();
1164 /// go down to first child
1167 const XMLNode
* node
= _cur
->get_first_child();
1176 /// search for child and go down
1177 bool go_down(const XS_String
& name
, int n
=0)
1179 XMLNode
* node
= _cur
->find(name
, n
);
1188 /// move XPath like to position in XML tree
1189 bool go(const char* path
);
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)
1195 XMLNode
* node
= _cur
->find(name
, n
);
1205 const XS_String
& str() const {return *_cur
;}
1208 const XMLNode
* _root
;
1209 const XMLNode
* _cur
;
1210 std::stack
<const XMLNode
*> _stack
;
1212 /// go to specified node
1213 void go_to(const XMLNode
* child
)
1221 // work around GCC's wide string constant bug
1223 extern const LPCXSSTR XS_TRUE
;
1224 extern const LPCXSSTR XS_FALSE
;
1225 extern const LPCXSSTR XS_NUMBERFMT
;
1227 #define XS_TRUE XS_TEXT("true")
1228 #define XS_FALSE XS_TEXT("false")
1229 #define XS_NUMBERFMT XS_TEXT("%d")
1235 XMLBool(bool value
=false)
1240 XMLBool(LPCXSSTR value
, bool def
=false)
1242 if (value
&& *value
)
1243 _value
= !XS_icmp(value
, XS_TRUE
);
1248 XMLBool(const XMLNode
* node
, const XS_String
& attr_name
, bool def
=false)
1250 const XS_String
& value
= node
->get(attr_name
);
1253 _value
= !XS_icmp(value
.c_str(), XS_TRUE
);
1258 operator bool() const
1263 bool operator!() const
1268 operator LPCXSSTR() const
1270 return _value
? XS_TRUE
: XS_FALSE
;
1277 void operator=(const XMLBool
&); // disallow assignment operations
1282 XMLBoolRef(XMLNode
* node
, const XS_String
& attr_name
, bool def
=false)
1283 : _ref((*node
)[attr_name
])
1289 operator bool() const
1291 return !XS_icmp(_ref
.c_str(), XS_TRUE
);
1294 bool operator!() const
1296 return XS_icmp(_ref
.c_str(), XS_TRUE
)? true: false;
1299 XMLBoolRef
& operator=(bool value
)
1306 void assign(bool value
)
1308 _ref
.assign(value
? XS_TRUE
: XS_FALSE
);
1313 assign(!operator bool());
1328 XMLInt(LPCXSSTR value
, int def
=0)
1330 if (value
&& *value
)
1331 _value
= XS_toi(value
);
1336 XMLInt(const XMLNode
* node
, const XS_String
& attr_name
, int def
=0)
1338 const XS_String
& value
= node
->get(attr_name
);
1341 _value
= XS_toi(value
.c_str());
1346 operator int() const
1351 operator XS_String() const
1354 XS_sprintf(buffer
, XS_NUMBERFMT
, _value
);
1362 void operator=(const XMLInt
&); // disallow assignment operations
1367 XMLIntRef(XMLNode
* node
, const XS_String
& attr_name
, int def
=0)
1368 : _ref((*node
)[attr_name
])
1374 XMLIntRef
& operator=(int value
)
1381 operator int() const
1383 return XS_toi(_ref
.c_str());
1386 void assign(int value
)
1389 XS_sprintf(buffer
, XS_NUMBERFMT
, value
);
1390 _ref
.assign(buffer
);
1400 XMLString(const XS_String
& value
)
1405 XMLString(LPCXSSTR value
, LPCXSSTR def
=XS_TEXT(""))
1407 if (value
&& *value
)
1413 XMLString(const XMLNode
* node
, const XS_String
& attr_name
, LPCXSSTR def
=XS_TEXT(""))
1415 const XS_String
& value
= node
->get(attr_name
);
1423 operator const XS_String
&() const
1428 const XS_String
& c_str() const
1437 void operator=(const XMLString
&); // disallow assignment operations
1442 XMStringRef(XMLNode
* node
, const XS_String
& attr_name
, LPCXSSTR def
=XS_TEXT(""))
1443 : _ref((*node
)[attr_name
])
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
))
1456 XMStringRef
& operator=(const XS_String
& value
)
1463 operator const XS_String
&() const
1468 void assign(const XS_String
& value
)
1478 template<typename T
>
1479 inline void read_option(T
& var
, const_XMLPos
& cfg
, LPCXSSTR key
)
1481 const XS_String
& val
= cfg
.get(key
);
1488 inline void read_option(int& var
, const_XMLPos
& cfg
, LPCXSSTR key
)
1490 const XS_String
& val
= cfg
.get(key
);
1493 var
= XS_toi(val
.c_str());
1498 #pragma warning(disable: 4355)
1501 /// XML reader base class
1502 struct XMLReaderBase
1504 XMLReaderBase(XMLNode
* node
)
1506 _parser(XML_ParserCreate(NULL
))
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
);
1513 _last_tag
= TAG_NONE
;
1516 virtual ~XMLReaderBase()
1518 XML_ParserFree(_parser
);
1523 virtual int read_buffer(char* buffer
, int len
) = 0;
1525 std::string
get_position() const
1527 int line
= XML_GetCurrentLineNumber(_parser
);
1528 int column
= XML_GetCurrentColumnNumber(_parser
);
1530 std::ostringstream out
;
1531 out
<< "(" << line
<< ") : [column " << column
<< "]";
1536 std::string
get_instructions() const {return _instructions
;}
1538 XML_Error
get_error_code() {return XML_GetErrorCode(_parser
);}
1539 std::string
get_error_string() const;
1544 std::string _xml_version
;
1545 std::string _encoding
;
1546 std::string _instructions
;
1548 std::string _content
;
1549 enum {TAG_NONE
, TAG_START
, TAG_END
} _last_tag
;
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
);
1559 struct XMLReader
: public XMLReaderBase
1561 XMLReader(XMLNode
* node
, std::istream
& in
)
1562 : XMLReaderBase(node
),
1567 /// read XML stream into XML tree below _pos
1568 int read_buffer(char* buffer
, int len
)
1573 _in
.read(buffer
, len
);
1575 return _in
.gcount();
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
),
1592 void print(std::ostream
& out
) const
1594 out
<< "<?xml version=\"" << _version
<< "\" encoding=\"" << _encoding
<< "\"?>\n";
1596 if (!_doctype
.empty())
1597 out
<< _doctype
<< '\n';
1598 if (!_additional
.empty())
1599 out
<< _additional
<< '\n';
1602 std::string _version
;
1603 std::string _encoding
;
1604 std::string _doctype
;
1605 std::string _additional
;
1609 struct XMLDoc
: public XMLNode
1613 _last_error(XML_ERROR_NONE
)
1617 XMLDoc(LPCTSTR path
)
1619 _last_error(XML_ERROR_NONE
)
1624 std::istream
& read(std::istream
& in
)
1626 XMLReader
reader(this, in
);
1633 bool read(LPCTSTR path
)
1636 XMLReader
reader(this, in
);
1638 //#if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8)
1639 // return read(reader, std::string(ANS(path)));
1641 return read(reader
, XS_String(path
));
1645 bool read(XMLReaderBase
& reader
)
1647 XML_Status status
= reader
.read();
1649 _header
._additional
= reader
.get_instructions();
1651 if (status
== XML_STATUS_ERROR
) {
1652 std::ostringstream out
;
1654 out
<< "input stream" << reader
.get_position() << " " << reader
.get_error_string();
1656 _last_error
= reader
.get_error_code();
1657 _last_error_msg
= out
.str();
1660 return status
!= XML_STATUS_ERROR
;
1663 bool read(XMLReaderBase
& reader
, const std::string
& display_path
)
1665 XML_Status status
= reader
.read();
1667 _header
._additional
= reader
.get_instructions();
1669 if (status
== XML_STATUS_ERROR
) {
1670 std::ostringstream out
;
1672 out
<< display_path
<< reader
.get_position() << " " << reader
.get_error_string();
1674 _last_error
= reader
.get_error_code();
1675 _last_error_msg
= out
.str();
1678 return status
!= XML_STATUS_ERROR
;
1681 /// write XML stream preserving previous white space and comments
1682 std::ostream
& write(std::ostream
& out
, WRITE_MODE mode
=FORMAT_SMART
) const
1686 if (!_children
.empty())
1687 _children
.front()->write(out
);
1692 /// write XML stream with formating
1693 std::ostream
& write_formating(std::ostream
& out
) const
1695 return write(out
, FORMAT_PRETTY
);
1698 void write(LPCTSTR path
, WRITE_MODE mode
=FORMAT_SMART
) const
1700 tofstream
out(path
);
1705 void write_formating(LPCTSTR path
) const
1707 tofstream
out(path
);
1709 write_formating(out
);
1713 XML_Error _last_error
;
1714 std::string _last_error_msg
;
1718 struct XMLMessage
: public XMLDoc
1720 XMLMessage(const char* name
)
1730 } // namespace XMLStorage
1732 #define _XMLSTORAGE_H
1733 #endif // _XMLSTORAGE_H