- Merge from trunk up to r45543
[reactos.git] / base / shell / explorer / utility / xmlstorage.h
1
2 //
3 // XML storage C++ classes version 1.3
4 //
5 // Copyright (c) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Martin Fuchs <martin-fuchs@gmx.net>
6 //
7
8 /// \file xmlstorage.h
9 /// XMLStorage header file
10
11
12 /*
13
14 All rights reserved.
15
16 Redistribution and use in source and binary forms, with or without
17 modification, are permitted provided that the following conditions are met:
18
19 * Redistributions of source code must retain the above copyright
20 notice, this list of conditions and the following disclaimer.
21 * Redistributions in binary form must reproduce the above copyright
22 notice, this list of conditions and the following disclaimer in
23 the documentation and/or other materials provided with the
24 distribution.
25
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 POSSIBILITY OF SUCH DAMAGE.
37
38 */
39
40 #ifndef _XMLSTORAGE_H
41
42
43 #ifdef UNICODE
44 #ifndef _UNICODE
45 #define _UNICODE
46 #endif
47 #else
48 #ifdef _UNICODE
49 #define UNICODE
50 #endif
51 #endif
52
53 #ifndef _WIN32
54 #ifdef UNICODE
55 #error no UNICODE build in Unix version available
56 #endif
57 #ifndef XS_STRING_UTF8
58 #define XS_STRING_UTF8
59 #endif
60 #endif
61
62
63 #if _MSC_VER>=1400 // VS2005 or higher
64 #ifndef _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
65 #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
66 #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 1
67 #define _CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES 1
68 #endif
69 #endif
70
71
72 #ifdef XS_USE_XERCES
73
74 #ifndef UNICODE
75 #ifndef XS_STRING_UTF8
76 #define XS_STRING_UTF8
77 #endif
78 #endif
79
80 #include <xercesc/parsers/SAXParser.hpp>
81 #include <xercesc/sax/HandlerBase.hpp>
82
83 using XERCES_CPP_NAMESPACE_QUALIFIER Locator;
84 using XERCES_CPP_NAMESPACE_QUALIFIER SAXParser;
85 using XERCES_CPP_NAMESPACE_QUALIFIER HandlerBase;
86 using XERCES_CPP_NAMESPACE_QUALIFIER InputSource;
87 using XERCES_CPP_NAMESPACE_QUALIFIER AttributeList;
88 using XERCES_CPP_NAMESPACE_QUALIFIER SAXParseException;
89
90 typedef XMLCh XML_Char;
91
92 #elif defined(XS_USE_EXPAT)
93
94 #include <expat/expat.h>
95
96 #endif
97
98
99 #ifdef _MSC_VER
100 #pragma warning(disable: 4786)
101
102 #ifndef XS_NO_COMMENT
103
104 #ifdef XS_USE_XERCES
105 #ifdef _DEBUG
106 #pragma comment(lib, "xerces-c_2D")
107 #else
108 #pragma comment(lib, "xerces-c_2")
109 #endif
110 #elif defined(XS_USE_EXPAT)
111 #ifdef XML_STATIC
112 #ifndef _DEBUG
113 #pragma comment(lib, "libexpatMT")
114 #endif
115 #else
116 #pragma comment(lib, "libexpat")
117 #endif
118 #endif
119
120 #ifndef _STRING_DEFINED // _STRING_DEFINED only allowed if using xmlstorage.cpp embedded in the project
121 #if defined(_DEBUG) && defined(_DLL) // DEBUG version only supported with MSVCRTD
122 #if _MSC_VER==1500
123 #pragma comment(lib, "xmlstorage-vc9d")
124 #elif _MSC_VER==1400
125 #pragma comment(lib, "xmlstorage-vc8d")
126 #else
127 #pragma comment(lib, "xmlstorage-vc6d")
128 #endif
129 #else
130 #ifdef _DLL
131 #if _MSC_VER==1500
132 #pragma comment(lib, "xmlstorage-vc9")
133 #elif _MSC_VER==1400
134 #pragma comment(lib, "xmlstorage-vc8")
135 #else
136 #pragma comment(lib, "xmlstorage-vc6")
137 #endif
138 #elif defined(_MT)
139 #if _MSC_VER==1500
140 #pragma comment(lib, "xmlstorage-vc9t")
141 #elif _MSC_VER==1400
142 #pragma comment(lib, "xmlstorage-vc8t")
143 #else
144 #pragma comment(lib, "xmlstorage-vc6t")
145 #endif
146 #else
147 // -ML is no more supported since VS2005.
148 #pragma comment(lib, "xmlstorage-vc6l")
149 #endif
150 #endif
151 #endif // _STRING_DEFINED
152
153 #endif // XS_NO_COMMENT
154
155 #endif // _MSC_VER
156
157
158 #ifdef _WIN32
159
160 #include <windows.h> // for LPCTSTR
161 #include <tchar.h>
162 #include <malloc.h>
163
164 #ifndef _MSC_VER
165 #include <stdio.h> // vsnprintf(), snprintf()
166 #endif
167
168 #else // _WIN32
169
170 #include <wchar.h>
171 #include <stdlib.h>
172 #include <string.h> // strcasecmp()
173 #include <stdarg.h>
174
175 typedef char CHAR;
176 #ifdef _WCHAR_T_DEFINED
177 #define __wchar_t wchar_t
178 #endif
179
180 typedef __wchar_t WCHAR;
181 typedef unsigned char UCHAR;
182 typedef char* LPSTR;
183 typedef const char* LPCSTR;
184 typedef WCHAR* LPWSTR;
185 typedef const WCHAR* LPCWSTR;
186
187 #ifndef UNICODE
188 #define TEXT(x) x
189 typedef char TCHAR;
190 typedef unsigned char _TUCHAR;
191 typedef CHAR* PTSTR;
192 typedef CHAR* LPTSTR;
193 typedef const CHAR* LPCTSTR;
194
195 #define _ttoi atoi
196 #define _tfopen fopen
197 #define _tcstod strtod
198 #define _tcslen strlen
199 #define _tcsstr strstr
200 #define _snprintf snprintf
201 #define _sntprintf snprintf
202 #define _vsnprintf vsnprintf
203 #define _vsntprintf vsnprintf
204 #define _stricmp strcasecmp
205 #define _tcsicmp strcasecmp
206 #define strnicmp strncasecmp
207 #define _tcsnicmp strncasecmp
208 #endif // UNICODE
209
210 #endif // _WIN32
211
212 #ifdef __BORLANDC__
213 #define _stricmp stricmp
214 #endif
215
216
217 #include <fstream>
218 #include <sstream>
219 #include <string>
220 #include <stack>
221 #include <list>
222 #include <map>
223
224
225 #ifndef BUFFER_LEN
226 #define BUFFER_LEN 2048
227 #endif
228
229
230 namespace XMLStorage {
231
232
233 #ifndef XS_String
234
235 #ifdef XS_STRING_UTF8
236 #define XS_CHAR char
237 #define XS_TEXT(x) x
238 #define LPXSSTR LPSTR
239 #define LPCXSSTR LPCSTR
240 #define XS_cmp strcmp
241 #define XS_icmp _stricmp
242 #define XS_ncmp strncmp
243 #define XS_nicmp strnicmp
244 #define XS_toi atoi
245 #define XS_tod strtod
246 #define XS_len strlen
247 #define XS_snprintf _snprintf
248 #define XS_vsnprintf _vsnprintf
249 #define XS_strstr strstr
250 #else
251 #define XS_CHAR TCHAR
252 #define XS_TEXT(x) TEXT(x)
253 #define LPXSSTR LPTSTR
254 #define LPCXSSTR LPCTSTR
255 #define XS_cmp _tcscmp
256 #define XS_icmp _tcsicmp
257 #define XS_ncmp _tcsncmp
258 #define XS_nicmp _tcsnicmp
259 #define XS_toi _ttoi
260 #define XS_tod _tcstod
261 #define XS_len _tcslen
262 #define XS_snprintf _sntprintf
263 #define XS_vsnprintf _vsntprintf
264 #define XS_strstr _tcsstr
265 #endif
266
267 #ifndef COUNTOF
268 #if _MSC_VER>=1400
269 #define COUNTOF _countof
270 #else
271 #define COUNTOF(b) (sizeof(b)/sizeof(b[0]))
272 #endif
273 #endif
274
275
276 extern const char* get_xmlsym_end_utf8(const char* p);
277
278
279 #if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8)
280
281 #define XS_String String
282
283 #else // _STRING_DEFINED, !XS_STRING_UTF8
284
285 /// string class for TCHAR strings
286
287 struct XS_String
288 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
289 : public std::wstring
290 #else
291 : public std::string
292 #endif
293 {
294 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
295 typedef std::wstring super;
296 #else
297 typedef std::string super;
298 #endif
299
300 XS_String() {}
301
302 XS_String(LPCXSSTR s) {if (s) super::assign(s);}
303 XS_String(LPCXSSTR s, size_t l) : super(s, l) {}
304
305 XS_String(const super& other) : super(other) {}
306 XS_String(const XS_String& other) : super(other) {}
307
308 #ifdef _WIN32
309 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
310 XS_String(LPCSTR s) {assign(s);}
311 XS_String(LPCSTR s, size_t l) {assign(s, l);}
312 XS_String(const std::string& s) {assign(s.c_str());}
313 XS_String& operator=(LPCSTR s) {assign(s); return *this;}
314 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();}
315 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();}
316 #else
317 XS_String(LPCWSTR s) {assign(s);}
318 XS_String(LPCWSTR s, size_t l) {assign(s, l);}
319 XS_String(const std::wstring& ws) {assign(ws.c_str());}
320 XS_String& operator=(LPCWSTR s) {assign(s); return *this;}
321 #ifdef XS_STRING_UTF8
322 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();}
323 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();}
324 #else // if !UNICODE && !XS_STRING_UTF8
325 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();}
326 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();}
327 #endif
328 #endif
329 #endif // _WIN32
330
331 #ifdef __ISSD_H
332 // XS_String(const _ISSD RString& s) {assign(s.c_str());}
333 // void assign(const _ISSD RString& s) {assign(s.c_str());}
334 XS_String& operator=(const _ISSD RString& s) {assign(s); return *this;}
335 #endif
336
337 #ifdef XS_STRING_UTF8
338 void assign(const XS_String& s) {assign(s.c_str());}
339 #endif
340
341 XS_String& operator=(LPCXSSTR s) {if (s) super::assign(s); else erase(); return *this;}
342 XS_String& operator=(const super& s) {super::assign(s); return *this;}
343 void assign(LPCXSSTR s) {super::assign(s);}
344 void assign(LPCXSSTR s, size_t l) {super::assign(s, l);}
345
346 operator LPCXSSTR() const {return c_str();}
347
348 #ifdef _WIN32
349 #ifdef XS_STRING_UTF8
350 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));}
351 #elif defined(UNICODE)
352 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));}
353 #else
354 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));}
355 #endif
356 #endif
357
358 XS_String& printf(LPCXSSTR fmt, ...)
359 {
360 va_list l;
361 XS_CHAR b[BUFFER_LEN];
362
363 va_start(l, fmt);
364 super::assign(b, XS_vsnprintf(b, COUNTOF(b), fmt, l));
365 va_end(l);
366
367 return *this;
368 }
369
370 XS_String& vprintf(LPCXSSTR fmt, va_list l)
371 {
372 XS_CHAR b[BUFFER_LEN];
373
374 super::assign(b, XS_vsnprintf(b, COUNTOF(b), fmt, l));
375
376 return *this;
377 }
378
379 XS_String& appendf(LPCXSSTR fmt, ...)
380 {
381 va_list l;
382 XS_CHAR b[BUFFER_LEN];
383
384 va_start(l, fmt);
385 super::append(b, XS_vsnprintf(b, COUNTOF(b), fmt, l));
386 va_end(l);
387
388 return *this;
389 }
390
391 XS_String& vappendf(LPCXSSTR fmt, va_list l)
392 {
393 XS_CHAR b[BUFFER_LEN];
394
395 super::append(b, XS_vsnprintf(b, COUNTOF(b), fmt, l));
396
397 return *this;
398 }
399 };
400
401 #endif // _STRING_DEFINED, !XS_STRING_UTF8
402
403 #endif // XS_String
404
405
406 #define XS_EMPTY_STR XS_TEXT("")
407 #define XS_TRUE_STR XS_TEXT("true")
408 #define XS_FALSE_STR XS_TEXT("false")
409 #define XS_INTFMT_STR XS_TEXT("%d")
410 #define XS_FLOATFMT_STR XS_TEXT("%f")
411
412 #define XS_KEY_STR XS_TEXT("key")
413 #define XS_VALUE_STR XS_TEXT("value")
414 #define XS_PROPERTY_STR XS_TEXT("property")
415
416 // work around GCC's wide string constant bug
417 #ifdef __GNUC__
418 extern const LPCXSSTR XS_EMPTY;
419 extern const LPCXSSTR XS_TRUE;
420 extern const LPCXSSTR XS_FALSE;
421 extern const LPCXSSTR XS_INTFMT;
422 extern const LPCXSSTR XS_FLOATFMT;
423 #else
424 #define XS_EMPTY XS_EMPTY_STR
425 #define XS_TRUE XS_TRUE_STR
426 #define XS_FALSE XS_FALSE_STR
427 #define XS_INTFMT XS_INTFMT_STR
428 #define XS_FLOATFMT XS_FLOATFMT_STR
429 #endif
430
431 extern const XS_String XS_KEY;
432 extern const XS_String XS_VALUE;
433 extern const XS_String XS_PROPERTY;
434
435 #define CDATA_START "<![CDATA["
436 #define CDATA_END "]]>"
437
438
439 #ifndef XS_STRING_UTF8
440
441 // from UTF-8 to XS internal string encoding
442 inline void assign_utf8(XS_String& s, const char* str, size_t lutf8)
443 {
444 #ifdef UNICODE
445 LPTSTR buffer = (LPTSTR)alloca(sizeof(TCHAR)*lutf8);
446 int l = MultiByteToWideChar(CP_UTF8, 0, str, (int)lutf8, buffer, (int)lutf8);
447 #else
448 LPWSTR wbuffer = (LPWSTR)alloca(sizeof(WCHAR)*lutf8);
449 int l = MultiByteToWideChar(CP_UTF8, 0, str, (int)lutf8, wbuffer, (int)lutf8);
450
451 int bl=2*l; LPSTR buffer = (LPSTR)alloca(bl);
452 l = WideCharToMultiByte(CP_ACP, 0, wbuffer, l, buffer, bl, 0, 0);
453 #endif
454
455 s.assign(buffer, l);
456 }
457
458 // from UTF-8 to XS internal string encoding
459 inline void assign_utf8(XS_String& s, const char* str)
460 {
461 assign_utf8(s, str, strlen(str));
462 }
463
464 // from XS internal string encoding to UTF-8
465 inline std::string get_utf8(LPCTSTR s, size_t l)
466 {
467 #ifdef UNICODE
468 size_t bl=2*l; LPSTR buffer = (LPSTR)alloca(bl);
469 l = WideCharToMultiByte(CP_UTF8, 0, s, (int)l, buffer, (int)bl, 0, 0);
470 #else
471 LPWSTR wbuffer = (LPWSTR)alloca(sizeof(WCHAR)*l);
472 l = MultiByteToWideChar(CP_ACP, 0, s, (int)l, wbuffer, (int)l);
473
474 size_t bl=2*l; LPSTR buffer = (LPSTR)alloca(bl);
475 l = WideCharToMultiByte(CP_UTF8, 0, wbuffer, (int)l, buffer, (int)bl, 0, 0);
476 #endif
477
478 return std::string(buffer, l);
479 }
480
481 #ifdef UNICODE
482 // from XS internal string encoding to UTF-8
483 inline std::string get_utf8(const char* s, size_t l)
484 {
485 LPWSTR wbuffer = (LPWSTR)alloca(sizeof(WCHAR)*l);
486 l = MultiByteToWideChar(CP_ACP, 0, s, (int)l, wbuffer, (int)l);
487
488 size_t bl=2*l; LPSTR buffer = (LPSTR)alloca(bl);
489 l = WideCharToMultiByte(CP_UTF8, 0, wbuffer, (int)l, buffer, (int)bl, 0, 0);
490
491 return std::string(buffer, l);
492 }
493 #endif
494
495 // from XS internal string encoding to UTF-8
496 inline std::string get_utf8(const XS_String& s)
497 {
498 return get_utf8(s.c_str(), s.length());
499 }
500
501 #endif // XS_STRING_UTF8
502
503 extern std::string EncodeXMLString(const XS_String& str, bool cdata=false);
504 extern XS_String DecodeXMLString(const std::string& str);
505
506
507 #ifdef __GNUC__
508 #include <ext/stdio_filebuf.h>
509 #define FILE_FILEBUF __gnu_cxx::stdio_filebuf<char>
510 #elif defined(_MSC_VER)
511 #define FILE_FILEBUF std::filebuf
512 #endif
513
514 #ifdef FILE_FILEBUF
515
516 /// base class for XMLStorage::tifstream and XMLStorage::tofstream
517 struct FileHolder
518 {
519 FileHolder(LPCTSTR path, LPCTSTR mode)
520 {
521 //@@ _MS_VER: temporarily needed for the ReactOS build environment
522 #if defined(__STDC_WANT_SECURE_LIB__) && defined(_MS_VER) // secure CRT functions using VS 2005
523 if (_tfopen_s(&_pfile, path, mode) != 0)
524 _pfile = NULL;
525 #else
526 _pfile = _tfopen(path, mode);
527 #endif
528 }
529
530 ~FileHolder()
531 {
532 if (_pfile)
533 fclose(_pfile);
534 }
535
536 protected:
537 FILE* _pfile;
538 };
539
540 /// input file stream with ANSI/UNICODE file names
541 struct tifstream : public std::istream, FileHolder
542 {
543 typedef std::istream super;
544
545 tifstream(LPCTSTR path)
546 : super(&_buf),
547 FileHolder(path, TEXT("rb")), // binary mode is important for XMLReader::read_buffer() with MinGW libraries
548 #ifdef __GNUC__
549 _buf(_pfile, std::ios::in)
550 #else
551 _buf(_pfile)
552 #endif
553 {
554 if (!_pfile)
555 setstate(badbit);
556 }
557
558 protected:
559 FILE_FILEBUF _buf;
560 };
561
562 /// output file stream with ANSI/UNICODE file names
563 struct tofstream : public std::ostream, FileHolder
564 {
565 typedef std::ostream super;
566
567 tofstream(LPCTSTR path)
568 : super(&_buf),
569 FileHolder(path, TEXT("wb")),
570 #ifdef __GNUC__
571 _buf(_pfile, std::ios::out)
572 #else
573 _buf(_pfile)
574 #endif
575 {
576 if (!_pfile)
577 setstate(badbit);
578 }
579
580 ~tofstream()
581 {
582 flush();
583 }
584
585 protected:
586 FILE_FILEBUF _buf;
587 };
588
589 #else // FILE_FILEBUF
590
591 #ifdef UNICODE
592 #error UNICODE not supported for this platform
593 #endif
594
595 struct tifstream : public std::ifstream
596 {
597 typedef std::ifstream super;
598
599 tifstream(const char* path)
600 : super(path, std::ios::in|std::ios::binary)
601 {
602 }
603 };
604
605 struct tofstream : public std::ofstream
606 {
607 typedef std::ofstream super;
608
609 tofstream(const char* path)
610 : super(path, std::ios::out|std::ios::binary)
611 {
612 }
613 };
614
615 #endif
616
617
618 // write XML files with 2 spaces indenting
619 #define XML_INDENT_SPACE " "
620
621
622 #if defined(XS_USE_XERCES) || defined(XS_USE_EXPAT)
623
624 #if defined(XML_UNICODE)/*Expat*/ || defined(XS_USE_XERCES)/*Xerces*/ // Are Expat/Xerces XML strings UTF-16 encoded?
625 typedef XS_String String_from_XML_Char;
626
627 #elif defined(XS_STRING_UTF8)
628 typedef XS_String String_from_XML_Char;
629
630 #else
631
632 /// converter from Expat/Xerces strings to XMLStorage internal strings
633 struct String_from_XML_Char : public XS_String
634 {
635 String_from_XML_Char(const XML_Char* str)
636 {
637 assign_utf8(*this, str);
638 }
639 };
640
641 #endif
642
643 #endif // defined(XS_USE_XERCES) || defined(XS_USE_EXPAT)
644
645
646 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
647
648 // optimization for faster UNICODE/ASCII string comparison without temporary A/U conversion
649 inline bool operator==(const XS_String& s1, const char* s2)
650 {
651 LPCWSTR p = s1;
652 const unsigned char* q = (const unsigned char*)s2;
653
654 while(*p && *q)
655 if (*p++ != *q++)
656 return false;
657
658 return *p == *q;
659 };
660
661 #endif
662
663
664 /// XML Error with message and location
665 struct XMLError
666 {
667 XMLError()
668 : _line(0),
669 _column(0),
670 _error_code(0)
671 {
672 }
673
674 std::string str() const;
675 friend std::ostream& operator<<(std::ostream&, const XMLError& err);
676
677 XS_String _message;
678 XS_String _systemId;
679 int _line;
680 int _column;
681 int _error_code;
682 };
683
684 /// list of XMLError entries
685 struct XMLErrorList : public std::list<XMLError>
686 {
687 XS_String str() const;
688 };
689
690
691 #ifdef XMLNODE_LOCATION
692 /// location of XML Node including XML file name
693 struct XMLLocation
694 {
695 XMLLocation()
696 : _pdisplay_path(NULL),
697 _line(0),
698 _column(0)
699 {
700 }
701
702 XMLLocation(const char* display_path, int line, int column)
703 : _pdisplay_path(display_path),
704 _line(line),
705 _column(column)
706 {
707 }
708
709 std::string str() const;
710
711 protected:
712 const char* _pdisplay_path; // character pointer for fast reference
713 int _line;
714 int _column;
715 };
716 #endif
717
718
719 enum PRETTY_FLAGS {
720 PRETTY_PLAIN = 0,
721 PRETTY_LINEFEED = 1,
722 PRETTY_INDENT = 2
723 };
724
725
726 /// XML Stylesheet entry
727 struct StyleSheet
728 {
729 std::string _href; // CDATA #REQUIRED
730 std::string _type; // CDATA #REQUIRED
731 std::string _title; // CDATA #IMPLIED
732 std::string _media; // CDATA #IMPLIED
733 std::string _charset; // CDATA #IMPLIED
734 bool _alternate; // (yes|no) "no"
735
736 StyleSheet() : _alternate(false) {}
737
738 StyleSheet(const std::string& href, const std::string& type="text/xsl", bool alternate=false)
739 : _href(href),
740 _type(type),
741 _alternate(alternate)
742 {
743 }
744
745 bool empty() const {return _href.empty();}
746 void print(std::ostream& out) const;
747 };
748
749 /// list of StyleSheet entries
750 struct StyleSheetList : public std::list<StyleSheet>
751 {
752 void set(const StyleSheet& stylesheet)
753 {
754 clear();
755 push_back(stylesheet);
756 }
757 };
758
759
760 /// XML document type description
761 struct DocType
762 {
763 std::string _name;
764
765 // External Document Types are noted, but not parsed.
766 std::string _public;
767 std::string _system;
768
769 // Internal DTDs are not supported.
770
771 void parse(const char* str);
772 bool empty() const {return _name.empty();}
773 };
774
775 /// Management of XML file headers and formating
776 struct XMLFormat
777 {
778 XMLFormat(PRETTY_FLAGS pretty=PRETTY_INDENT, const std::string& xml_version="1.0", const std::string& encoding="utf-8", const DocType& doctype=DocType())
779 : _pretty(pretty),
780 _endl("\n"),
781 _version(xml_version),
782 _encoding(encoding),
783 _doctype(doctype),
784 _standalone(-1)
785 {
786 }
787
788 void print_header(std::ostream& out, bool lf=true) const;
789
790 PRETTY_FLAGS _pretty;
791 const char* _endl; // line ending string: "\n" or "\r\n"
792
793 std::string _version;
794 std::string _encoding;
795
796 DocType _doctype;
797
798 StyleSheetList _stylesheets;
799
800 // std::string _additional;
801
802 int _standalone;
803 };
804
805
806 enum WRITE_MODE {
807 FORMAT_PLAIN, /// write XML without any white space
808 FORMAT_SMART, /// preserve original white space and comments if present; pretty print otherwise
809 FORMAT_ORIGINAL, /// write XML stream preserving original white space and comments
810 FORMAT_PRETTY /// pretty print node to stream without preserving original white space
811 };
812
813
814 struct XMLNode;
815
816 struct XPathElement
817 {
818 XPathElement() : _child_idx(-1) {}
819
820 XPathElement(const XS_String& child_name, int child_idx=-1)
821 : _child_name(child_name), _child_idx(child_idx) {}
822
823 XPathElement(const XS_String& child_name, int child_idx, const XS_String& attr_name, const XS_String& attr_value)
824 : _child_name(child_name), _child_idx(child_idx),
825 _attr_name(attr_name), _attr_value(attr_value)
826 {
827 }
828
829 XS_String _child_name;
830 int _child_idx;
831
832 XS_String _attr_name;
833 XS_String _attr_value;
834
835 const char* parse(const char* path);
836
837 XMLNode* find(XMLNode* node) const;
838 const XMLNode* const_find(const XMLNode* node) const;
839
840 bool matches(const XMLNode& node, int& n) const;
841 };
842
843 struct XPath : std::list<XPathElement>
844 {
845 XPath() : _absolute(false) {}
846 XPath(const char* path) {init(path);}
847 XPath(const std::string path) {init(path.c_str());}
848
849 void init(const char* path);
850
851 bool _absolute;
852 };
853
854
855 /// in memory representation of an XML node
856 struct XMLNode : public XS_String
857 {
858 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
859 /// map of XML node attributes
860 // optimized read access without temporary A/U conversion when using ASCII attribute names
861 struct AttributeMap : public std::map<XS_String, XS_String>
862 {
863 typedef std::map<XS_String, XS_String> super;
864
865 const_iterator find(const char* x) const
866 {
867 for(const_iterator it=begin(); it!=end(); ++it)
868 if (it->first == x)
869 return it;
870
871 return end();
872 }
873
874 const_iterator find(const key_type& x) const
875 {
876 return super::find(x);
877 }
878
879 iterator find(const key_type& x)
880 {
881 return super::find(x);
882 }
883
884 XS_String get(const char* x, LPCXSSTR def=XS_EMPTY_STR) const
885 {
886 const_iterator found = find(x);
887
888 if (found != end())
889 return found->second;
890 else
891 return def;
892 }
893 };
894 #else
895 /// map of XML node attributes
896 struct AttributeMap : public std::map<XS_String, XS_String>
897 {
898 XS_String get(const char* x, LPCXSSTR def=XS_EMPTY_STR) const
899 {
900 const_iterator found = find(x);
901
902 if (found != end())
903 return found->second;
904 else
905 return def;
906 }
907 };
908 #endif
909
910 /// internal children node list
911 struct Children : public std::list<XMLNode*>
912 {
913 typedef std::list<XMLNode*> super;
914
915 Children()
916 {
917 }
918
919 Children(Children& other)
920 {
921 for(Children::const_iterator it=other.begin(); it!=other.end(); ++it)
922 push_back(*it);
923 }
924
925 void assign(Children& other)
926 {
927 clear();
928 move(other);
929 }
930
931 void move(Children& other)
932 {
933 for(Children::const_iterator it=other.begin(); it!=other.end(); ++it)
934 push_back(*it);
935
936 other.reset();
937 }
938
939 Children& operator=(Children& other)
940 {
941 assign(other);
942 return *this;
943 }
944
945 void copy(const Children& other)
946 {
947 for(Children::const_iterator it=other.begin(); it!=other.end(); ++it)
948 push_back(new XMLNode(**it));
949 }
950
951 void clear()
952 {
953 while(!empty()) {
954 XMLNode* node = back();
955 pop_back();
956
957 node->clear();
958 delete node;
959 }
960 }
961
962 bool remove(XMLNode* node)
963 {
964 for(iterator it=begin(); it!=end(); ++it)
965 if (*it == node) {
966 erase(it);
967 return true;
968 }
969
970 return false;
971 }
972
973 private:
974 void reset()
975 {
976 super::clear();
977 }
978 };
979
980 // access to protected class members for XMLPos and XMLReader
981 friend struct XMLPos;
982 friend struct const_XMLPos;
983 friend struct XMLReaderBase;
984 friend struct XPathElement;
985
986 XMLNode(const XS_String& name)
987 : XS_String(name),
988 _cdata_content(false)
989 {
990 }
991
992 XMLNode(const XS_String& name, const std::string& leading)
993 : XS_String(name),
994 _leading(leading),
995 _cdata_content(false)
996 {
997 }
998
999 XMLNode(const XMLNode& other)
1000 : XS_String(other),
1001 _attributes(other._attributes),
1002 _leading(other._leading),
1003 _content(other._content),
1004 _end_leading(other._end_leading),
1005 _trailing(other._trailing),
1006 #ifdef XMLNODE_LOCATION
1007 _location(other._location),
1008 #endif
1009 _cdata_content(false)
1010 {
1011 for(Children::const_iterator it=other._children.begin(); it!=other._children.end(); ++it)
1012 _children.push_back(new XMLNode(**it));
1013 }
1014
1015 enum COPY_FLAGS {COPY_NOCHILDREN};
1016
1017 XMLNode(const XMLNode& other, COPY_FLAGS copy_no_children)
1018 : XS_String(other),
1019 _attributes(other._attributes),
1020 _leading(other._leading),
1021 _content(other._content),
1022 _end_leading(other._end_leading),
1023 _trailing(other._trailing),
1024 #ifdef XMLNODE_LOCATION
1025 _location(other._location),
1026 #endif
1027 _cdata_content(false)
1028 {
1029 // assert(copy_no_children==COPY_NOCHILDREN);
1030 }
1031
1032 virtual ~XMLNode()
1033 {
1034 while(!_children.empty()) {
1035 delete _children.back();
1036 _children.pop_back();
1037 }
1038 }
1039
1040 void clear()
1041 {
1042 _leading.erase();
1043 _content.erase();
1044 _end_leading.erase();
1045 _trailing.erase();
1046
1047 _attributes.clear();
1048 _children.clear();
1049
1050 XS_String::erase();
1051 }
1052
1053 XMLNode& operator=(const XMLNode& other)
1054 {
1055 _children.clear();
1056 _children.copy(other._children);
1057
1058 _attributes = other._attributes;
1059
1060 _leading = other._leading;
1061 _content = other._content;
1062 _end_leading = other._end_leading;
1063 _trailing = other._trailing;
1064
1065 return *this;
1066 }
1067
1068 /// add a new child node
1069 void add_child(XMLNode* child)
1070 {
1071 _children.push_back(child);
1072 }
1073
1074 /// remove all children named 'name'
1075 void remove_children(const XS_String& name)
1076 {
1077 Children::iterator it, next=_children.begin();
1078
1079 while((it=next++) != _children.end())
1080 if (**it == name)
1081 _children.erase(it);
1082 }
1083
1084 /// write access to an attribute
1085 void put(const XS_String& attr_name, const XS_String& value)
1086 {
1087 _attributes[attr_name] = value;
1088 }
1089
1090 /// index operator write access to an attribute
1091 XS_String& operator[](const XS_String& attr_name)
1092 {
1093 return _attributes[attr_name];
1094 }
1095
1096 /// read only access to an attribute
1097 template<typename T> XS_String get(const T& attr_name, LPCXSSTR def=XS_EMPTY_STR) const
1098 {
1099 AttributeMap::const_iterator found = _attributes.find(attr_name);
1100
1101 if (found != _attributes.end())
1102 return found->second;
1103 else
1104 return def;
1105 }
1106
1107 /// remove the attribute 'attr_name'
1108 void erase(const XS_String& attr_name)
1109 {
1110 _attributes.erase(attr_name);
1111 }
1112
1113 /// convenient value access in children node
1114 XS_String subvalue(const XS_String& child_name, const XS_String& attr_name, int n=0) const
1115 {
1116 const XMLNode* node = XPathElement(child_name, n).const_find(this);
1117
1118 if (node)
1119 return node->get(attr_name);
1120 else
1121 return XS_String();
1122 }
1123
1124 /// convenient storage of distinct values in children node
1125 XS_String& subvalue(const XS_String& child_name, const XS_String& attr_name, int n=0)
1126 {
1127 XMLNode* node = XPathElement(child_name, n).find(this);
1128
1129 if (!node) {
1130 node = new XMLNode(child_name);
1131 add_child(node);
1132 }
1133
1134 return (*node)[attr_name];
1135 }
1136
1137 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
1138 /// convenient value access in children node
1139 XS_String subvalue(const char* child_name, const char* attr_name, int n=0) const
1140 {
1141 const XMLNode* node = XPathElement(child_name, n).const_find(this);
1142
1143 if (node)
1144 return node->get(attr_name);
1145 else
1146 return XS_String();
1147 }
1148
1149 /// convenient storage of distinct values in children node
1150 XS_String& subvalue(const char* child_name, const XS_String& attr_name, int n=0)
1151 {
1152 XMLNode* node = XPathElement(child_name, n).find(this);
1153
1154 if (!node) {
1155 node = new XMLNode(child_name);
1156 add_child(node);
1157 }
1158
1159 return (*node)[attr_name];
1160 }
1161 #endif
1162
1163 const Children& get_children() const
1164 {
1165 return _children;
1166 }
1167
1168 Children& get_children()
1169 {
1170 return _children;
1171 }
1172
1173 const AttributeMap& get_attributes() const
1174 {
1175 return _attributes;
1176 }
1177
1178 AttributeMap& get_attributes()
1179 {
1180 return _attributes;
1181 }
1182
1183 /// read element node content
1184 XS_String get_content() const
1185 {
1186 return DecodeXMLString(_content);
1187 }
1188
1189 /// read content of a subnode specified by an XPath expression
1190 XS_String get_sub_content(const XPath& xpath) const
1191 {
1192 const XMLNode* node = find_relative(xpath);
1193
1194 if (node)
1195 return node->get_content();
1196 else
1197 return XS_EMPTY_STR;
1198 }
1199
1200 /// set element node content
1201 void set_content(const XS_String& s, bool cdata=false)
1202 {
1203 _content.assign(EncodeXMLString(s.c_str(), cdata));
1204 }
1205
1206 /// set content of a subnode specified by an XPath expression
1207 bool set_sub_content(const XPath& xpath, const XS_String& s, bool cdata=false)
1208 {
1209 XMLNode* node = create_relative(xpath);
1210
1211 if (node) {
1212 node->set_content(s, cdata);
1213 return true;
1214 } else
1215 return false;
1216 }
1217
1218 #ifdef XMLNODE_LOCATION
1219 const XMLLocation& get_location() const {return _location;}
1220 #endif
1221
1222 /// write node with children tree to output stream
1223 bool write(std::ostream& out, const XMLFormat& format, WRITE_MODE mode=FORMAT_SMART, int indent=0) const
1224 {
1225 switch(mode) {
1226 case FORMAT_PLAIN:
1227 plain_write_worker(out);
1228 break;
1229
1230 case FORMAT_PRETTY:
1231 pretty_write_worker(out, format, indent);
1232 break;
1233
1234 case FORMAT_ORIGINAL:
1235 original_write_worker(out);
1236 break;
1237
1238 default: // FORMAT_SMART
1239 smart_write_worker(out, format, indent);
1240 }
1241
1242 return out.good();
1243 }
1244
1245 /// count the nodes matching the given relative XPath expression
1246 int count(const XPath& xpath) const
1247 {
1248 return count(xpath.begin(), xpath.end());
1249 }
1250
1251 /// count the nodes matching the given relative XPath expression
1252 int count(XPath::const_iterator from, const XPath::const_iterator& to) const;
1253
1254 /// copy matching tree nodes using the given XPath filter expression
1255 bool filter(const XPath& xpath, XMLNode& target) const;
1256
1257 /// XPath find function (const)
1258 const XMLNode* find_relative(const XPath& xpath) const;
1259
1260 /// XPath find function
1261 XMLNode* find_relative(const XPath& xpath);
1262
1263 XMLNode* get_first_child() const
1264 {
1265 if (!_children.empty())
1266 return _children.front();
1267 else
1268 return NULL;
1269 }
1270
1271 protected:
1272 Children _children;
1273 AttributeMap _attributes;
1274
1275 std::string _leading; // UTF-8 encoded
1276 std::string _content; // UTF-8 and entity encoded, may contain CDATA sections; decode with DecodeXMLString()
1277 std::string _end_leading; // UTF-8 encoded
1278 std::string _trailing; // UTF-8 encoded
1279
1280 #ifdef XMLNODE_LOCATION
1281 XMLLocation _location;
1282 #endif
1283
1284 bool _cdata_content;
1285
1286 /// relative XPath create function
1287 XMLNode* create_relative(const XPath& xpath);
1288
1289 /// create a new node tree using the given XPath filter expression
1290 XMLNode* filter(XPath::const_iterator from, const XPath::const_iterator& to) const;
1291
1292 void original_write_worker(std::ostream& out) const;
1293 void plain_write_worker(std::ostream& out) const;
1294 void pretty_write_worker(std::ostream& out, const XMLFormat& format, int indent) const;
1295 void smart_write_worker(std::ostream& out, const XMLFormat& format, int indent) const;
1296 };
1297
1298
1299 /// iterator access to children nodes with name filtering
1300 struct XMLChildrenFilter
1301 {
1302 XMLChildrenFilter(XMLNode::Children& children, const XS_String& name)
1303 : _begin(children.begin(), children.end(), name),
1304 _end(children.end(), children.end(), name)
1305 {
1306 }
1307
1308 XMLChildrenFilter(XMLNode* node, const XS_String& name)
1309 : _begin(node->get_children().begin(), node->get_children().end(), name),
1310 _end(node->get_children().end(), node->get_children().end(), name)
1311 {
1312 }
1313
1314 /// internal iterator class
1315 struct iterator
1316 {
1317 typedef XMLNode::Children::iterator BaseIterator;
1318 typedef iterator myType;
1319
1320 iterator(BaseIterator begin, BaseIterator end, const XS_String& filter_name)
1321 : _cur(begin),
1322 _end(end),
1323 _filter_name(filter_name)
1324 {
1325 search_next();
1326 }
1327
1328 operator BaseIterator()
1329 {
1330 return _cur;
1331 }
1332
1333 const XMLNode* operator*() const
1334 {
1335 return *_cur;
1336 }
1337
1338 XMLNode* operator*()
1339 {
1340 return *_cur;
1341 }
1342
1343 myType& operator++()
1344 {
1345 ++_cur;
1346 search_next();
1347
1348 return *this;
1349 }
1350
1351 myType operator++(int)
1352 {
1353 myType ret = *this;
1354
1355 ++_cur;
1356 search_next();
1357
1358 return ret;
1359 }
1360
1361 bool operator==(const myType& other) const
1362 {
1363 return _cur == other._cur;
1364 }
1365
1366 bool operator!=(const myType& other) const
1367 {
1368 return _cur != other._cur;
1369 }
1370
1371 protected:
1372 BaseIterator _cur;
1373 BaseIterator _end;
1374 XS_String _filter_name;
1375
1376 void search_next()
1377 {
1378 while(_cur!=_end && **_cur!=_filter_name)
1379 ++_cur;
1380 }
1381 };
1382
1383 iterator begin()
1384 {
1385 return _begin;
1386 }
1387
1388 iterator end()
1389 {
1390 return _end;
1391 }
1392
1393 protected:
1394 iterator _begin;
1395 iterator _end;
1396 };
1397
1398
1399 /// read only iterator access to children nodes with name filtering
1400 struct const_XMLChildrenFilter
1401 {
1402 const_XMLChildrenFilter(const XMLNode::Children& children, const XS_String& name)
1403 : _begin(children.begin(), children.end(), name),
1404 _end(children.end(), children.end(), name)
1405 {
1406 }
1407
1408 const_XMLChildrenFilter(const XMLNode* node, const XS_String& name)
1409 : _begin(node->get_children().begin(), node->get_children().end(), name),
1410 _end(node->get_children().end(), node->get_children().end(), name)
1411 {
1412 }
1413
1414 /// internal iterator class
1415 struct const_iterator
1416 {
1417 typedef XMLNode::Children::const_iterator BaseIterator;
1418 typedef const_iterator myType;
1419
1420 const_iterator(BaseIterator begin, BaseIterator end, const XS_String& filter_name)
1421 : _cur(begin),
1422 _end(end),
1423 _filter_name(filter_name)
1424 {
1425 search_next();
1426 }
1427
1428 operator BaseIterator()
1429 {
1430 return _cur;
1431 }
1432
1433 const XMLNode* operator*() const
1434 {
1435 return *_cur;
1436 }
1437
1438 myType& operator++()
1439 {
1440 ++_cur;
1441 search_next();
1442
1443 return *this;
1444 }
1445
1446 myType operator++(int)
1447 {
1448 myType ret = *this;
1449
1450 ++_cur;
1451 search_next();
1452
1453 return ret;
1454 }
1455
1456 bool operator==(const myType& other) const
1457 {
1458 return _cur == other._cur;
1459 }
1460
1461 bool operator!=(const myType& other) const
1462 {
1463 return _cur != other._cur;
1464 }
1465
1466 protected:
1467 BaseIterator _cur;
1468 BaseIterator _end;
1469 XS_String _filter_name;
1470
1471 void search_next()
1472 {
1473 while(_cur!=_end && **_cur!=_filter_name)
1474 ++_cur;
1475 }
1476 };
1477
1478 const_iterator begin()
1479 {
1480 return _begin;
1481 }
1482
1483 const_iterator end()
1484 {
1485 return _end;
1486 }
1487
1488 protected:
1489 const_iterator _begin;
1490 const_iterator _end;
1491 };
1492
1493
1494 /// iterator for XML trees
1495 struct XMLPos
1496 {
1497 XMLPos(XMLNode* root)
1498 : _root(root),
1499 _cur(root)
1500 {
1501 }
1502
1503 XMLPos(const XMLPos& other)
1504 : _root(other._root),
1505 _cur(other._cur)
1506 { // don't copy _stack
1507 }
1508
1509 XMLPos(XMLNode* node, const XS_String& name)
1510 : _root(node),
1511 _cur(node)
1512 {
1513 smart_create(name);
1514 }
1515
1516 XMLPos(XMLNode* node, const XS_String& name, const XS_String& attr_name, const XS_String& attr_value)
1517 : _root(node),
1518 _cur(node)
1519 {
1520 smart_create(name, attr_name, attr_value);
1521 }
1522
1523 XMLPos(const XMLPos& other, const XS_String& name)
1524 : _root(other._root),
1525 _cur(other._cur)
1526 {
1527 smart_create(name);
1528 }
1529
1530 XMLPos(const XMLPos& other, const XS_String& name, const XS_String& attr_name, const XS_String& attr_value)
1531 : _root(other._root),
1532 _cur(other._cur)
1533 {
1534 smart_create(name, attr_name, attr_value);
1535 }
1536
1537 /// access to current node
1538 XMLNode& cur()
1539 {
1540 return *_cur;
1541 }
1542
1543 const XMLNode& cur() const
1544 {
1545 return *_cur;
1546 }
1547
1548 /// automatic access to current node
1549 operator const XMLNode*() const {return _cur;}
1550 operator XMLNode*() {return _cur;}
1551
1552 const XMLNode* operator->() const {return _cur;}
1553 XMLNode* operator->() {return _cur;}
1554
1555 const XMLNode& operator*() const {return *_cur;}
1556 XMLNode& operator*() {return *_cur;}
1557
1558 /// attribute access
1559 XS_String get(const XS_String& attr_name, LPCXSSTR def=XS_EMPTY_STR) const
1560 {
1561 return _cur->get(attr_name, def);
1562 }
1563
1564 /// attribute setting
1565 void put(const XS_String& attr_name, const XS_String& value)
1566 {
1567 _cur->put(attr_name, value);
1568 }
1569
1570 /// index operator attribute access
1571 template<typename T> XS_String get(const T& attr_name) const {return (*_cur)[attr_name];}
1572 XS_String& operator[](const XS_String& attr_name) {return (*_cur)[attr_name];}
1573 const XS_String& operator[](const XS_String& attr_name) const {return (*_cur)[attr_name];}
1574
1575 /// insert children when building tree
1576 void add_down(XMLNode* child)
1577 {
1578 _cur->add_child(child);
1579 go_to(child);
1580 }
1581
1582 /// go back to previous position
1583 bool back()
1584 {
1585 if (!_stack.empty()) {
1586 _cur = _stack.top();
1587 _stack.pop();
1588 return true;
1589 } else
1590 return false;
1591 }
1592
1593 /// go down to first child
1594 bool go_down()
1595 {
1596 XMLNode* node = _cur->get_first_child();
1597
1598 if (node) {
1599 go_to(node);
1600 return true;
1601 } else
1602 return false;
1603 }
1604
1605 /// search for child and go down
1606 bool go_down(const XS_String& child_name, int n=0)
1607 {
1608 XMLNode* node = XPathElement(child_name, n).find(_cur);
1609
1610 if (node) {
1611 go_to(node);
1612 return true;
1613 } else
1614 return false;
1615 }
1616
1617 /// iterate to the next matching child
1618 bool iterate(const XS_String& child_name, size_t& cnt)
1619 {
1620 XMLNode* node = XPathElement(child_name, cnt).find(_cur);
1621
1622 if (node) {
1623 go_to(node);
1624 ++cnt;
1625 return true;
1626 } else
1627 return false;
1628 }
1629
1630 /// move to the position defined by xpath in XML tree
1631 bool go(const XPath& xpath);
1632
1633 /// create child nodes using XPath notation and move to the deepest child
1634 bool create_relative(const XPath& xpath)
1635 {
1636 XMLNode* node = _cur->create_relative(xpath);
1637 if (!node)
1638 return false; // invalid path specified
1639
1640 go_to(node);
1641 return true;
1642 }
1643
1644 /// create node and move to it
1645 void create(const XS_String& name)
1646 {
1647 add_down(new XMLNode(name));
1648 }
1649
1650 /// create node with string content
1651 void create_node_content(const XS_String& node_name, const XS_String& content)
1652 {
1653 XMLNode* pNode = new XMLNode(node_name);
1654 pNode->set_content(content);
1655 _cur->add_child(pNode);
1656 }
1657
1658 /// create node if not already existing and move to it
1659 void smart_create(const XS_String& child_name)
1660 {
1661 XMLNode* node = XPathElement(child_name).find(_cur);
1662
1663 if (node)
1664 go_to(node);
1665 else
1666 add_down(new XMLNode(child_name));
1667 }
1668
1669 /// search matching child node identified by key name and an attribute value
1670 void smart_create(const XS_String& child_name, const XS_String& attr_name, const XS_String& attr_value)
1671 {
1672 XMLNode* node = XPathElement(child_name, 0, attr_name, attr_value).find(_cur);
1673
1674 if (node)
1675 go_to(node);
1676 else {
1677 node = new XMLNode(child_name);
1678 add_down(node);
1679 (*node)[attr_name] = attr_value;
1680 }
1681 }
1682
1683 /// count the nodes matching the given relative XPath expression
1684 int count(const XPath& xpath) const
1685 {
1686 return _cur->count(xpath);
1687 }
1688
1689 /// create a new node tree using the given XPath filter expression
1690 int filter(const XPath& xpath, XMLNode& target) const
1691 {
1692 return _cur->filter(xpath, target);
1693 }
1694
1695 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
1696 /// search for child and go down
1697 bool go_down(const char* child_name, int n=0)
1698 {
1699 XMLNode* node = XPathElement(child_name, n).find(_cur);
1700
1701 if (node) {
1702 go_to(node);
1703 return true;
1704 } else
1705 return false;
1706 }
1707
1708 /// create node and move to it
1709 void create(const char* child_name)
1710 {
1711 add_down(new XMLNode(child_name));
1712 }
1713
1714 /// create node if not already existing and move to it
1715 void smart_create(const char* child_name)
1716 {
1717 XMLNode* node = XPathElement(child_name).find(_cur);
1718
1719 if (node)
1720 go_to(node);
1721 else
1722 add_down(new XMLNode(child_name));
1723 }
1724
1725 /// search matching child node identified by key name and an attribute value
1726 template<typename T, typename U>
1727 void smart_create(const char* child_name, const T& attr_name, const U& attr_value)
1728 {
1729 XMLNode* node = XPathElement(child_name, 0, attr_name, attr_value).find(_cur);
1730
1731 if (node)
1732 go_to(node);
1733 else {
1734 node = new XMLNode(child_name);
1735 add_down(node);
1736 (*node)[attr_name] = attr_value;
1737 }
1738 }
1739 #endif
1740
1741 /// delete current node and go back to previous position
1742 bool delete_this()
1743 {
1744 if (!_stack.empty()) {
1745 XMLNode* pLast = _stack.top();
1746
1747 if (pLast->_children.remove(_cur)) {
1748 _cur = _stack.top();
1749 return true;
1750 }
1751 }
1752
1753 return false;
1754 }
1755
1756 /// remove all children named 'name'
1757 void remove_children(const XS_String& name)
1758 {
1759 _cur->remove_children(name);
1760 }
1761
1762 /// remove the attribute 'attr_name' from the current node
1763 void erase(const XS_String& attr_name)
1764 {
1765 _cur->erase(attr_name);
1766 }
1767
1768 XS_String& str() {return *_cur;}
1769 const XS_String& str() const {return *_cur;}
1770
1771 // property (key/value pair) setter functions
1772 void set_property(const XS_String& key, int value, const XS_String& name=XS_PROPERTY);
1773 void set_property(const XS_String& key, double value, const XS_String& name=XS_PROPERTY);
1774 void set_property(const XS_String& key, const XS_String& value, const XS_String& name=XS_PROPERTY);
1775 void set_property(const XS_String& key, const struct XMLBool& value, const XS_String& name=XS_PROPERTY);
1776
1777 void set_property(const XS_String& key, const char* value, const XS_String& name=XS_PROPERTY)
1778 {set_property(key, XS_String(value), name);}
1779
1780 protected:
1781 friend struct const_XMLPos; // access to _root
1782
1783 XMLNode* _root;
1784 XMLNode* _cur;
1785 std::stack<XMLNode*> _stack;
1786
1787 /// go to specified node
1788 void go_to(XMLNode* child)
1789 {
1790 _stack.push(_cur);
1791 _cur = child;
1792 }
1793 };
1794
1795
1796 /// iterator for XML trees
1797 struct const_XMLPos
1798 {
1799 const_XMLPos(const XMLNode* root)
1800 : _root(root),
1801 _cur(root)
1802 {
1803 }
1804
1805 const_XMLPos(const const_XMLPos& other)
1806 : _root(other._root),
1807 _cur(other._cur)
1808 { // don't copy _stack
1809 }
1810
1811 const_XMLPos(const XMLPos& other)
1812 : _root(other._root),
1813 _cur(other._cur)
1814 { // don't copy _stack
1815 }
1816
1817 /// access to current node
1818 const XMLNode& cur() const
1819 {
1820 return *_cur;
1821 }
1822
1823 /// automatic access to current node
1824 operator const XMLNode*() const {return _cur;}
1825
1826 const XMLNode* operator->() const {return _cur;}
1827
1828 const XMLNode& operator*() const {return *_cur;}
1829
1830 /// attribute access
1831 XS_String get(const XS_String& attr_name) const
1832 {
1833 return _cur->get(attr_name);
1834 }
1835
1836 /// index operator attribute access
1837 template<typename T> XS_String get(const T& attr_name) const {return _cur->get(attr_name);}
1838 XS_String operator[](const XS_String& attr_name) const {return _cur->get(attr_name);}
1839
1840 /// go back to previous position
1841 bool back()
1842 {
1843 if (!_stack.empty()) {
1844 _cur = _stack.top();
1845 _stack.pop();
1846 return true;
1847 } else
1848 return false;
1849 }
1850
1851 /// go down to first child
1852 bool go_down()
1853 {
1854 const XMLNode* node = _cur->get_first_child();
1855
1856 if (node) {
1857 go_to(node);
1858 return true;
1859 } else
1860 return false;
1861 }
1862
1863 /// search for child and go down
1864 bool go_down(const XS_String& child_name, int n=0)
1865 {
1866 const XMLNode* node = XPathElement(child_name, n).const_find(_cur);
1867
1868 if (node) {
1869 go_to(node);
1870 return true;
1871 } else
1872 return false;
1873 }
1874
1875 /// iterate to the next matching child
1876 bool iterate(const XS_String& child_name, size_t& cnt)
1877 {
1878 const XMLNode* node = XPathElement(child_name, cnt).const_find(_cur);
1879
1880 if (node) {
1881 go_to(node);
1882 ++cnt;
1883 return true;
1884 } else
1885 return false;
1886 }
1887
1888 /// move to the position defined by xpath in XML tree
1889 bool go(const XPath& xpath);
1890
1891 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
1892 /// search for child and go down
1893 bool go_down(const char* child_name, int n=0)
1894 {
1895 const XMLNode* node = XPathElement(child_name, n).const_find(_cur);
1896
1897 if (node) {
1898 go_to(node);
1899 return true;
1900 } else
1901 return false;
1902 }
1903 #endif
1904
1905 const XS_String& str() const {return *_cur;}
1906
1907 protected:
1908 const XMLNode* _root;
1909 const XMLNode* _cur;
1910 std::stack<const XMLNode*> _stack;
1911
1912 /// go to specified node
1913 void go_to(const XMLNode* child)
1914 {
1915 _stack.push(_cur);
1916 _cur = child;
1917 }
1918 };
1919
1920
1921 /// type converter for boolean data
1922 struct XMLBool
1923 {
1924 XMLBool(bool value=false)
1925 : _value(value)
1926 {
1927 }
1928
1929 XMLBool(LPCXSSTR value, bool def=false)
1930 {
1931 if (value && *value)//@@ also handle white space and return def instead of false
1932 _value = !XS_icmp(value, XS_TRUE);
1933 else
1934 _value = def;
1935 }
1936
1937 XMLBool(const XMLNode* node, const XS_String& attr_name, bool def=false)
1938 {
1939 const XS_String& value = node->get(attr_name);
1940
1941 if (!value.empty())
1942 _value = !XS_icmp(value.c_str(), XS_TRUE);
1943 else
1944 _value = def;
1945 }
1946
1947 operator bool() const
1948 {
1949 return _value;
1950 }
1951
1952 bool operator!() const
1953 {
1954 return !_value;
1955 }
1956
1957 operator LPCXSSTR() const
1958 {
1959 return _value? XS_TRUE: XS_FALSE;
1960 }
1961
1962 protected:
1963 bool _value;
1964
1965 private:
1966 void operator=(const XMLBool&); // disallow assignment operations
1967 };
1968
1969 /// type converter for boolean data with write access
1970 struct XMLBoolRef
1971 {
1972 XMLBoolRef(XMLNode* node, const XS_String& attr_name, bool def=false)
1973 : _ref((*node)[attr_name])
1974 {
1975 if (_ref.empty())
1976 assign(def);
1977 }
1978
1979 operator bool() const
1980 {
1981 return !XS_icmp(_ref.c_str(), XS_TRUE);
1982 }
1983
1984 bool operator!() const
1985 {
1986 return XS_icmp(_ref.c_str(), XS_TRUE)? true: false;
1987 }
1988
1989 XMLBoolRef& operator=(bool value)
1990 {
1991 assign(value);
1992
1993 return *this;
1994 }
1995
1996 void assign(bool value)
1997 {
1998 _ref.assign(value? XS_TRUE: XS_FALSE);
1999 }
2000
2001 void toggle()
2002 {
2003 assign(!operator bool());
2004 }
2005
2006 protected:
2007 XS_String& _ref;
2008 };
2009
2010
2011 /// type converter for integer data
2012 struct XMLInt
2013 {
2014 XMLInt(int value)
2015 : _value(value)
2016 {
2017 }
2018
2019 XMLInt(LPCXSSTR value, int def=0)
2020 {
2021 if (value && *value)//@@ also handle white space and return def instead of 0
2022 _value = XS_toi(value);
2023 else
2024 _value = def;
2025 }
2026
2027 XMLInt(const XMLNode* node, const XS_String& attr_name, int def=0)
2028 {
2029 const XS_String& value = node->get(attr_name);
2030
2031 if (!value.empty())
2032 _value = XS_toi(value.c_str());
2033 else
2034 _value = def;
2035 }
2036
2037 operator int() const
2038 {
2039 return _value;
2040 }
2041
2042 operator XS_String() const
2043 {
2044 XS_CHAR buffer[32];
2045 XS_snprintf(buffer, COUNTOF(buffer), XS_INTFMT, _value);
2046 return XS_String(buffer);
2047 }
2048
2049 protected:
2050 int _value;
2051
2052 private:
2053 void operator=(const XMLInt&); // disallow assignment operations
2054 };
2055
2056 /// type converter for integer data with write access
2057 struct XMLIntRef
2058 {
2059 XMLIntRef(XMLNode* node, const XS_String& attr_name, int def=0)
2060 : _ref((*node)[attr_name])
2061 {
2062 if (_ref.empty())
2063 assign(def);
2064 }
2065
2066 XMLIntRef& operator=(int value)
2067 {
2068 assign(value);
2069
2070 return *this;
2071 }
2072
2073 operator int() const
2074 {
2075 return XS_toi(_ref.c_str());
2076 }
2077
2078 void assign(int value)
2079 {
2080 XS_CHAR buffer[32];
2081 XS_snprintf(buffer, COUNTOF(buffer), XS_INTFMT, value);
2082 _ref.assign(buffer);
2083 }
2084
2085 protected:
2086 XS_String& _ref;
2087 };
2088
2089
2090 /// type converter for numeric data
2091 struct XMLDouble
2092 {
2093 XMLDouble(double value)
2094 : _value(value)
2095 {
2096 }
2097
2098 XMLDouble(LPCXSSTR value, double def=0.)
2099 {
2100 LPTSTR end;
2101
2102 if (value && *value)//@@ also handle white space and return def instead of 0
2103 _value = XS_tod(value, &end);
2104 else
2105 _value = def;
2106 }
2107
2108 XMLDouble(const XMLNode* node, const XS_String& attr_name, double def=0.)
2109 {
2110 LPTSTR end;
2111 const XS_String& value = node->get(attr_name);
2112
2113 if (!value.empty())
2114 _value = XS_tod(value.c_str(), &end);
2115 else
2116 _value = def;
2117 }
2118
2119 operator double() const
2120 {
2121 return _value;
2122 }
2123
2124 operator XS_String() const
2125 {
2126 XS_CHAR buffer[32];
2127 XS_snprintf(buffer, COUNTOF(buffer), XS_FLOATFMT, _value);
2128 return XS_String(buffer);
2129 }
2130
2131 protected:
2132 double _value;
2133
2134 private:
2135 void operator=(const XMLDouble&); // disallow assignment operations
2136 };
2137
2138 /// type converter for numeric data with write access
2139 struct XMLDoubleRef
2140 {
2141 XMLDoubleRef(XMLNode* node, const XS_String& attr_name, double def=0.)
2142 : _ref((*node)[attr_name])
2143 {
2144 if (_ref.empty())
2145 assign(def);
2146 }
2147
2148 XMLDoubleRef& operator=(double value)
2149 {
2150 assign(value);
2151
2152 return *this;
2153 }
2154
2155 operator double() const
2156 {
2157 LPTSTR end;
2158 return XS_tod(_ref.c_str(), &end);
2159 }
2160
2161 void assign(double value)
2162 {
2163 XS_CHAR buffer[32];
2164 XS_snprintf(buffer, COUNTOF(buffer), XS_FLOATFMT, value);
2165 _ref.assign(buffer);
2166 }
2167
2168 protected:
2169 XS_String& _ref;
2170 };
2171
2172
2173 /// type converter for string data
2174 struct XMLString
2175 {
2176 XMLString(const XS_String& value)
2177 : _value(value)
2178 {
2179 }
2180
2181 XMLString(LPCXSSTR value, LPCXSSTR def=XS_EMPTY)
2182 {
2183 if (value && *value)
2184 _value = value;
2185 else
2186 _value = def;
2187 }
2188
2189 XMLString(const XMLNode* node, const XS_String& attr_name, LPCXSSTR def=XS_EMPTY)
2190 {
2191 const XS_String& value = node->get(attr_name);
2192
2193 if (!value.empty())
2194 _value = value;
2195 else
2196 _value = def;
2197 }
2198
2199 operator const XS_String&() const
2200 {
2201 return _value;
2202 }
2203
2204 const XS_String& c_str() const
2205 {
2206 return _value;
2207 }
2208
2209 protected:
2210 XS_String _value;
2211
2212 private:
2213 void operator=(const XMLString&); // disallow assignment operations
2214 };
2215
2216 /// type converter for string data with write access
2217 struct XMLStringRef
2218 {
2219 XMLStringRef(XMLNode* node, const XS_String& attr_name, LPCXSSTR def=XS_EMPTY)
2220 : _ref((*node)[attr_name])
2221 {
2222 if (_ref.empty())
2223 assign(def);
2224 }
2225
2226 XMLStringRef(const XS_String& node_name, XMLNode* node, const XS_String& attr_name, LPCXSSTR def=XS_EMPTY)
2227 : _ref(node->subvalue(node_name, attr_name))
2228 {
2229 if (_ref.empty())
2230 assign(def);
2231 }
2232
2233 XMLStringRef& operator=(const XS_String& value)
2234 {
2235 assign(value);
2236
2237 return *this;
2238 }
2239
2240 operator const XS_String&() const
2241 {
2242 return _ref;
2243 }
2244
2245 void assign(const XS_String& value)
2246 {
2247 _ref.assign(value);
2248 }
2249
2250 protected:
2251 XS_String& _ref;
2252 };
2253
2254
2255 // read option (for example configuration) values from XML node attributes
2256 template<typename T>
2257 inline void read_option(T& var, const_XMLPos& cfg, LPCXSSTR key)
2258 {
2259 const XS_String& val = cfg.get(key);
2260
2261 if (!val.empty())
2262 var = val;
2263 }
2264
2265 // read integer option values from XML node attributes
2266 template<>
2267 inline void read_option(int& var, const_XMLPos& cfg, LPCXSSTR key)
2268 {
2269 const XS_String& val = cfg.get(key);
2270
2271 if (!val.empty())
2272 var = XS_toi(val.c_str());
2273 }
2274
2275
2276 inline void XMLPos::set_property(const XS_String& key, int value, const XS_String& name)
2277 {
2278 smart_create(name, XS_KEY, key);
2279 XMLIntRef(_cur, XS_VALUE) = value;
2280 back();
2281 }
2282
2283 inline void XMLPos::set_property(const XS_String& key, double value, const XS_String& name)
2284 {
2285 smart_create(name, XS_KEY, key);
2286 XMLDoubleRef(_cur, XS_VALUE) = value;
2287 back();
2288 }
2289
2290 inline void XMLPos::set_property(const XS_String& key, const XS_String& value, const XS_String& name)
2291 {
2292 smart_create(name, XS_KEY, key);
2293 put(XS_VALUE, value);
2294 back();
2295 }
2296
2297 inline void XMLPos::set_property(const XS_String& key, const XMLBool& value, const XS_String& name)
2298 {
2299 smart_create(name, XS_KEY, key);
2300 XMLBoolRef(_cur, XS_VALUE) = value;
2301 back();
2302 }
2303
2304
2305 /// a key/value pair for property data access
2306 struct XMLProperty {
2307 XMLProperty(const XMLNode* node)
2308 : _key(node->get(XS_KEY)),
2309 _value(node->get(XS_VALUE))
2310 {
2311 }
2312
2313 XS_String _key;
2314 XS_String _value;
2315 };
2316
2317
2318 /// utility class to read property settings from a XML tree
2319 struct XMLPropertyReader
2320 {
2321 XMLPropertyReader(const XMLNode::Children& children)
2322 : _filter(children, XS_PROPERTY),
2323 _begin(_filter.begin(), _filter.end()),
2324 _end(_filter.end(), _filter.end())
2325 {
2326 }
2327
2328 XMLPropertyReader(const XMLNode* node)
2329 : _filter(node, XS_PROPERTY),
2330 _begin(_filter.begin(), _filter.end()),
2331 _end(_filter.end(), _filter.end())
2332 {
2333 }
2334
2335 /// internal iterator class
2336 struct const_iterator
2337 {
2338 typedef const_XMLChildrenFilter::const_iterator BaseIterator;
2339 typedef const_iterator myType;
2340
2341 const_iterator(BaseIterator begin, BaseIterator end)
2342 : _cur(begin),
2343 _end(end)
2344 {
2345 }
2346
2347 operator BaseIterator()
2348 {
2349 return _cur;
2350 }
2351
2352 XMLProperty operator*() const
2353 {
2354 return XMLProperty(*_cur);
2355 }
2356
2357 const XMLNode* get_node() const
2358 {
2359 return *_cur;
2360 }
2361
2362 myType& operator++()
2363 {
2364 ++_cur;
2365
2366 return *this;
2367 }
2368
2369 myType operator++(int)
2370 {
2371 myType ret = *this;
2372
2373 ++_cur;
2374
2375 return ret;
2376 }
2377
2378 bool operator==(const myType& other) const
2379 {
2380 return _cur == other._cur;
2381 }
2382
2383 bool operator!=(const myType& other) const
2384 {
2385 return _cur != other._cur;
2386 }
2387
2388 protected:
2389 BaseIterator _cur;
2390 BaseIterator _end;
2391 };
2392
2393 const_iterator begin()
2394 {
2395 return _begin;
2396 }
2397
2398 const_iterator end()
2399 {
2400 return _end;
2401 }
2402
2403 protected:
2404 const_XMLChildrenFilter _filter;
2405
2406 const_iterator _begin;
2407 const_iterator _end;
2408 };
2409
2410
2411 #ifdef _MSC_VER
2412 #pragma warning(disable: 4355)
2413 #endif
2414
2415 /// XML reader base class
2416 struct XMLReaderBase
2417 #ifdef XS_USE_XERCES
2418 : public HandlerBase
2419 #endif
2420 {
2421 #ifdef XS_USE_XERCES
2422
2423 XMLReaderBase(XMLNode* node, InputSource* source, bool adoptSource=false);
2424 virtual ~XMLReaderBase();
2425
2426 void read();
2427
2428 protected:
2429 SAXParser* _parser;
2430 InputSource* _source;
2431 bool _deleteSource;
2432
2433 virtual void XMLDecl(const XMLCh* const versionStr, const XMLCh* const encodingStr,
2434 const XMLCh* const standaloneStr, const XMLCh* const actualEncodingStr);
2435
2436 // Handlers for the SAX DocumentHandler interface
2437 virtual void setDocumentLocator(const Locator* const locator);
2438 virtual void startElement(const XMLCh* const name, AttributeList& attributes);
2439 virtual void endElement(const XMLCh* const name);
2440 virtual void characters(const XMLCh* const chars, const unsigned int length);
2441 virtual void ignorableWhitespace(const XMLCh* const chars, const unsigned int length);
2442
2443 // Handlers for the SAX ErrorHandler interface
2444 virtual void error(const SAXParseException& e);
2445 virtual void fatalError(const SAXParseException& e);
2446 virtual void warning(const SAXParseException& e);
2447 virtual void resetErrors();
2448
2449 #elif defined(XS_USE_EXPAT) // !XS_USE_XERCES
2450
2451 XMLReaderBase(XMLNode* node);
2452 virtual ~XMLReaderBase();
2453
2454 protected:
2455 XML_Parser _parser;
2456
2457 static void XMLCALL XML_XmlDeclHandler(void* userData, const XML_Char* version, const XML_Char* encoding, int standalone=-1);
2458 static void XMLCALL XML_StartElementHandler(void* userData, const XML_Char* name, const XML_Char** atts);
2459 static void XMLCALL XML_EndElementHandler(void* userData, const XML_Char* name);
2460 static void XMLCALL XML_DefaultHandler(void* userData, const XML_Char* s, int len);
2461
2462 static std::string get_expat_error_string(XML_Error error_code);
2463
2464 #else // XS_USE_EXPAT
2465
2466 XMLReaderBase(XMLNode* node)
2467 : _pos(node),
2468 _endl_defined(false),
2469 _utf8(false)
2470 {
2471 _last_tag = TAG_NONE;
2472 }
2473
2474 virtual ~XMLReaderBase();
2475
2476 bool parse();
2477
2478 #endif
2479
2480 public:
2481 #ifndef XS_USE_XERCES
2482 void read();
2483
2484 std::string get_position() const;
2485 #endif
2486 const XMLFormat& get_format() const {return _format;}
2487 const char* get_endl() const {return _endl_defined? _format._endl: "\n";}
2488
2489 const XMLErrorList& get_errors() const {return _errors;}
2490 const XMLErrorList& get_warnings() const {return _warnings;}
2491
2492 void clear_errors() {_errors.clear(); _warnings.clear();}
2493
2494 #ifdef XMLNODE_LOCATION
2495 const char* _display_path; // character pointer for fast reference in XMLLocation
2496
2497 #ifdef XS_USE_XERCES
2498 const Locator* _locator;
2499 #endif
2500
2501 XMLLocation get_location() const;
2502 #endif
2503
2504 protected:
2505 XMLPos _pos;
2506
2507 std::string _content; // UTF-8 encoded
2508 enum {TAG_NONE, TAG_START, TAG_END} _last_tag;
2509
2510 XMLErrorList _errors;
2511 XMLErrorList _warnings;
2512
2513 XMLFormat _format;
2514 bool _endl_defined;
2515
2516 #ifdef XS_USE_XERCES
2517 //@@
2518 #elif defined(XS_USE_EXPAT)
2519 virtual int read_buffer(char* buffer, int len) = 0;
2520 #else
2521 virtual int get() = 0;
2522 int eat_endl();
2523
2524 bool _utf8;
2525 #endif
2526
2527 void finish_read();
2528
2529 virtual void XmlDeclHandler(const char* version, const char* encoding, int standalone);
2530 virtual void StartElementHandler(const XS_String& name, const XMLNode::AttributeMap& attributes);
2531 virtual void EndElementHandler();
2532 #if defined(XS_USE_XERCES) || defined(XS_USE_EXPAT)
2533 virtual void DefaultHandler(const XML_Char* s, int len);
2534 #else
2535 virtual void DefaultHandler(const std::string& s);
2536 #endif
2537 };
2538
2539
2540 /// XML file reader
2541
2542 #ifdef XS_USE_XERCES
2543
2544 struct XercesXMLReader : public XMLReaderBase
2545 {
2546 XercesXMLReader(XMLNode* node, InputSource* source, bool adoptSource=false)
2547 : XMLReaderBase(node, source, adoptSource)
2548 {
2549 }
2550
2551 XercesXMLReader(XMLNode* node, LPCTSTR path);
2552 XercesXMLReader(XMLNode* node, const XMLByte* buffer, size_t bytes, const std::string& system_id=std::string());
2553 };
2554
2555 #define XMLReader XercesXMLReader
2556
2557 #elif defined(XS_USE_EXPAT)
2558
2559 struct ExpatXMLReader : public XMLReaderBase
2560 {
2561 ExpatXMLReader(XMLNode* node, std::istream& in)
2562 : XMLReaderBase(node),
2563 _in(in)
2564 {
2565 }
2566
2567 /// read XML stream into XML tree below _pos
2568 int read_buffer(char* buffer, int len)
2569 {
2570 if (!_in.good())
2571 return -1;
2572
2573 _in.read(buffer, len);
2574
2575 return _in.gcount();
2576 }
2577
2578 protected:
2579 std::istream& _in;
2580 };
2581
2582 #define XMLReader ExpatXMLReader
2583
2584 #else // XS_USE_XERCES, XS_USE_EXPAT
2585
2586 struct XMLReader : public XMLReaderBase
2587 {
2588 XMLReader(XMLNode* node, std::istream& in)
2589 : XMLReaderBase(node),
2590 _in(in)
2591 {
2592 }
2593
2594 /// read one character from XML stream
2595 int get()
2596 {
2597 return _in.get();
2598 }
2599
2600 protected:
2601 std::istream& _in;
2602 };
2603
2604 #endif // XS_USE_XERCES
2605
2606
2607 #if defined(_MSC_VER) && _MSC_VER<1400
2608
2609 struct fast_ostringbuffer : public std::streambuf
2610 {
2611 typedef char _E;
2612 typedef std::char_traits<_E> _Tr;
2613
2614 explicit fast_ostringbuffer()
2615 {_Init(0, 0, std::_Noread);} // optimized for ios::out mode
2616
2617 virtual ~fast_ostringbuffer()
2618 {_Tidy();}
2619
2620 std::string str() const
2621 {if (pptr() != 0)
2622 {std::string _Str(pbase(),
2623 (_Seekhigh<pptr()? pptr(): _Seekhigh) - pbase());
2624 return _Str;}
2625 else
2626 return std::string();}
2627
2628 protected:
2629 virtual int_type overflow(int_type _C = _Tr::eof())
2630 {if (_Tr::eq_int_type(_Tr::eof(), _C))
2631 return _Tr::not_eof(_C);
2632 else if (pptr() != 0 && pptr() < epptr())
2633 {*_Pninc() = _Tr::to_char_type(_C);
2634 return _C;}
2635 else
2636 {size_t _Os = gptr() == 0 ? 0 : epptr() - eback();
2637 size_t _Ns = _Os + _Alsize;
2638 _E *_P = _Al.allocate(_Ns, (void *)0);
2639 if (0 < _Os)
2640 _Tr::copy(_P, eback(), _Os);
2641 else if (_ALSIZE < _Alsize)
2642 _Alsize = _ALSIZE;
2643
2644 if (_Strmode & std::_Allocated)
2645 _Al.deallocate(eback(), _Os);
2646
2647 _Strmode |= std::_Allocated;
2648
2649 if (_Os == 0)
2650 {_Seekhigh = _P;
2651 setp(_P, _P + _Ns);
2652 setg(_P, _P, _P); }
2653 else
2654 {_Seekhigh = _Seekhigh - eback() + _P;
2655 setp(pbase() - eback() + _P, pptr() - eback() + _P, _P + _Ns);
2656 setg(_P, _P, _P);}
2657 *_Pninc() = _Tr::to_char_type(_C);
2658
2659 return _C;}}
2660
2661 void _Init(const _E *_S, size_t _N, std::_Strstate _M)
2662 {_Pendsave = 0, _Seekhigh = 0;
2663 _Alsize = _MINSIZE, _Strmode = _M;
2664 setg(0, 0, 0);
2665 setp(0, 0);}
2666
2667 void _Tidy()
2668 {if (_Strmode & std::_Allocated)
2669 _Al.deallocate(eback(), (pptr() != 0 ? epptr() : egptr()) - eback());
2670 _Seekhigh = 0;
2671 _Strmode &= ~std::_Allocated;}
2672
2673 private:
2674 enum {_ALSIZE = 65536/*512*/, _MINSIZE = 32768/*32*/}; // bigger buffer sizes
2675
2676 _E *_Pendsave, *_Seekhigh;
2677 int _Alsize;
2678 std::_Strstate _Strmode;
2679 std::allocator<_E> _Al;
2680 };
2681
2682 struct fast_ostringstream : public std::iostream
2683 {
2684 typedef std::iostream super;
2685
2686 explicit fast_ostringstream()
2687 : super(&_Sb) {}
2688
2689 std::string str() const
2690 {return _Sb.str();}
2691
2692 private:
2693 fast_ostringbuffer _Sb;
2694 };
2695
2696 #else
2697
2698 typedef std::ostringstream fast_ostringstream;
2699
2700 #endif
2701
2702
2703 /// XML document holder
2704 struct XMLDoc : public XMLNode
2705 {
2706 XMLDoc()
2707 : XMLNode("")
2708 {
2709 }
2710
2711 XMLDoc(LPCTSTR path)
2712 : XMLNode("")
2713 {
2714 read_file(path);
2715 }
2716
2717 #ifdef XS_USE_XERCES
2718 bool read_file(LPCTSTR path)
2719 {
2720 XMLReader reader(this, path);
2721
2722 #if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8)
2723 return read(reader, std::string(ANS(path)));
2724 #else
2725 return read(reader, XS_String(path));
2726 #endif
2727 }
2728
2729 bool read_buffer(const char* buffer, size_t len, const std::string& system_id=std::string())
2730 {
2731 XMLReader reader(this, (const XMLByte*)buffer, len, system_id);
2732
2733 return read(reader, system_id);
2734 }
2735
2736 bool read_buffer(const std::string& in, const std::string& system_id=std::string())
2737 {
2738 return read_buffer(in.c_str(), in.length(), system_id);
2739 }
2740
2741 #else // XS_USE_XERCES
2742
2743 bool read_file(LPCTSTR path)
2744 {
2745 tifstream in(path);
2746 if (!in.good())
2747 return false;
2748
2749 XMLReader reader(this, in);
2750
2751 #if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8)
2752 return read(reader, std::string(ANS(path)));
2753 #else
2754 return read(reader, XS_String(path));
2755 #endif
2756 }
2757
2758 bool read_buffer(const char* buffer, size_t len, const std::string& system_id=std::string())
2759 {
2760 return read_buffer(std::string(buffer, len), system_id);
2761 }
2762
2763 bool read_buffer(const std::string& buffer, const std::string& system_id=std::string())
2764 {
2765 std::istringstream istr(buffer);
2766
2767 return read_stream(istr, system_id);
2768 }
2769
2770 bool read_stream(std::istream& in, const std::string& system_id=std::string())
2771 {
2772 XMLReader reader(this, in);
2773
2774 return read(reader, system_id);
2775 }
2776 #endif // XS_USE_XERCES
2777
2778 bool read(XMLReaderBase& reader, const std::string& display_path)
2779 {
2780 #ifdef XMLNODE_LOCATION
2781 // make a string copy to handle temporary string objects
2782 _display_path = display_path;
2783 reader._display_path = _display_path.c_str();
2784 #endif
2785
2786 reader.clear_errors();
2787 reader.read();
2788
2789 _format = reader.get_format();
2790 _format._endl = reader.get_endl();
2791
2792 if (!reader.get_errors().empty()) {
2793 _errors = reader.get_errors();
2794 return false;
2795 }
2796
2797 return true;
2798 }
2799
2800 /// write XML stream
2801 // FORMAT_SMART: preserving previous white space and comments
2802 bool write(std::ostream& out, WRITE_MODE mode=FORMAT_SMART) const
2803 {
2804 _format.print_header(out, mode!=FORMAT_PLAIN);
2805
2806 if (_children.size() == 1)
2807 _children.front()->write(out, _format, mode);
2808 else if (!_children.empty()) {
2809 //throw Exception("more than one XML root!");
2810 return false;
2811 }
2812
2813 return out.good();
2814 }
2815
2816 /// write XML stream with formating
2817 bool write_formating(std::ostream& out) const
2818 {
2819 return write(out, FORMAT_PRETTY);
2820 }
2821
2822 bool write_file(LPCTSTR path, WRITE_MODE mode=FORMAT_SMART) const
2823 {
2824 tofstream out(path);
2825
2826 return write(out, mode);
2827 }
2828
2829 bool write_formating(LPCTSTR path) const
2830 {
2831 tofstream out(path);
2832
2833 return write_formating(out);
2834 }
2835
2836 XMLFormat _format;
2837 XMLErrorList _errors;
2838
2839 #ifdef XMLNODE_LOCATION
2840 std::string _display_path;
2841 #endif
2842 };
2843
2844
2845 /// XML message wrapper
2846 struct XMLMessage : public XMLDoc
2847 {
2848 XMLMessage(const char* name)
2849 : _pos(this)
2850 {
2851 _pos.create(name);
2852 }
2853
2854 std::string toString() const
2855 {
2856 std::ostringstream out;
2857
2858 write(out);
2859
2860 return out.str();
2861 }
2862
2863 XMLPos _pos;
2864
2865 protected:
2866 XMLMessage()
2867 : _pos(this)
2868 {
2869 }
2870 };
2871
2872
2873 /// helper structure to read XML messages from strings
2874 struct XMLMessageFromString : public XMLMessage
2875 {
2876 XMLMessageFromString(const std::string& xml_str, const std::string& system_id=std::string())
2877 {
2878 read_buffer(xml_str.c_str(), xml_str.length(), system_id);
2879 }
2880 };
2881
2882
2883 /// Reader for XML Messages
2884 struct XMLMessageReader : public XMLPos
2885 {
2886 XMLMessageReader(const std::string& xml_str, const std::string& system_id=std::string())
2887 : XMLPos(&_msg)
2888 {
2889 _msg.read_buffer(xml_str.c_str(), xml_str.length(), system_id);
2890 }
2891
2892 const XMLDoc& get_document()
2893 {
2894 return _msg;
2895 }
2896
2897 protected:
2898 XMLDoc _msg;
2899 };
2900
2901
2902 /// on the fly XML writer
2903 struct XMLWriter
2904 {
2905 XMLWriter(std::ostream& out, const XMLFormat& format=XMLFormat())
2906 : _pofstream(NULL),
2907 _out(out),
2908 _format(format)
2909 {
2910 format.print_header(_out, false); // _format._endl is printed in write_pre()
2911 }
2912
2913 XMLWriter(LPCTSTR path, const XMLFormat& format=XMLFormat())
2914 : _pofstream(new tofstream(path)),
2915 _out(*_pofstream),
2916 _format(format)
2917 {
2918 format.print_header(_out, false); // _format._endl is printed in write_pre()
2919 }
2920
2921 ~XMLWriter()
2922 {
2923 _out << _format._endl;
2924 delete _pofstream;
2925 }
2926
2927 /// create node and move to it
2928 void create(const XS_String& name);
2929
2930 /// go back to previous position
2931 bool back();
2932
2933 /// attribute setting
2934 void put(const XS_String& attr_name, const XS_String& value)
2935 {
2936 if (!_stack.empty())
2937 _stack.top()._attributes[attr_name] = value;
2938 }
2939
2940 /// index operator write access to an attribute
2941 XS_String& operator[](const XS_String& attr_name)
2942 {
2943 if (_stack.empty())
2944 return s_empty_attr;
2945
2946 return _stack.top()._attributes[attr_name];
2947 }
2948
2949 void set_content(const XS_String& s, bool cdata=false)
2950 {
2951 if (!_stack.empty())
2952 _stack.top()._content = EncodeXMLString(s.c_str(), cdata);
2953 }
2954
2955 /// create node with string content
2956 void create_node_content(const XS_String& node_name, const XS_String& content)
2957 {
2958 create(node_name);
2959 set_content(content);
2960 back();
2961 }
2962
2963 // public for access in StackEntry
2964 enum WRITESTATE {
2965 NOTHING, /*PRE,*/ ATTRIBUTES, PRE_CLOSED, /*CONTENT,*/ POST
2966 };
2967
2968 protected:
2969 tofstream* _pofstream;
2970 std::ostream& _out;
2971 XMLFormat _format;
2972
2973 typedef XMLNode::AttributeMap AttrMap;
2974
2975 /// container for XMLWriter state information
2976 struct StackEntry {
2977 XS_String _node_name;
2978 AttrMap _attributes;
2979 std::string _content;
2980 WRITESTATE _state;
2981 bool _children;
2982
2983 StackEntry() : _state(NOTHING), _children(false) {}
2984 };
2985
2986 std::stack<StackEntry> _stack;
2987
2988 static XS_String s_empty_attr;
2989
2990 void close_pre(StackEntry& entry);
2991 void write_pre(StackEntry& entry);
2992 void write_attributes(StackEntry& entry);
2993 void write_post(StackEntry& entry);
2994 };
2995
2996
2997 } // namespace XMLStorage
2998
2999 #define _XMLSTORAGE_H
3000 #endif // _XMLSTORAGE_H