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 
XS_StringXS_String300 	XS_String() {}
301 
XS_StringXS_String302 	XS_String(LPCXSSTR s) {if (s) super::assign(s);}
XS_StringXS_String303 	XS_String(LPCXSSTR s, size_t l) : super(s, l) {}
304 
XS_StringXS_String305 	XS_String(const super& other) : super(other) {}
XS_StringXS_String306 	XS_String(const XS_String& other) : super(other) {}
307 
308 #ifdef _WIN32
309 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
XS_StringXS_String310 	XS_String(LPCSTR s) {assign(s);}
XS_StringXS_String311 	XS_String(LPCSTR s, size_t l) {assign(s, l);}
XS_StringXS_String312 	XS_String(const std::string& s) {assign(s.c_str());}
313 	XS_String& operator=(LPCSTR s) {assign(s); return *this;}
assignXS_String314 	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();}
assignXS_String315 	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
XS_StringXS_String317 	XS_String(LPCWSTR s) {assign(s);}
XS_StringXS_String318 	XS_String(LPCWSTR s, size_t l) {assign(s, l);}
XS_StringXS_String319 	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
assignXS_String322 	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();}
assignXS_String323 	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
assignXS_String325 	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();}
assignXS_String326 	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
assignXS_String338 	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;}
assignXS_String343 	void assign(LPCXSSTR s) {super::assign(s);}
assignXS_String344 	void assign(LPCXSSTR s, size_t l) {super::assign(s, l);}
345 
LPCXSSTRXS_String346 	operator LPCXSSTR() const {return c_str();}
347 
348 #ifdef _WIN32
349 #ifdef XS_STRING_UTF8
wstringXS_String350 	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)
stringXS_String352 	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
wstringXS_String354 	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 
printfXS_String358 	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 
vprintfXS_String370 	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 
appendfXS_String379 	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 
vappendfXS_String391 	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
assign_utf8(XS_String & s,const char * str,size_t lutf8)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
assign_utf8(XS_String & s,const char * str)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
get_utf8(LPCTSTR s,size_t l)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
get_utf8(const char * s,size_t l)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
get_utf8(const XS_String & s)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 protected:
FileHolderFileHolder520 	FileHolder()
521 	{
522 	}
523 
~FileHolderFileHolder524 	~FileHolder()
525 	{
526 		if (_pfile)
527 			fclose(_pfile);
528 		delete _buf;
529 	}
530 
init_bufFileHolder531 	FILE_FILEBUF* init_buf(LPCTSTR path, std::ios_base::openmode mode)
532 	{
533 		PCTSTR modestr = mode == std::ios::in ? TEXT("rb") : TEXT("wb");
534 //@@ _MS_VER: temporarily needed for the ReactOS build environment
535 #if defined(__STDC_WANT_SECURE_LIB__) && defined(_MS_VER)	// secure CRT functions using VS 2005
536 		if (_tfopen_s(&_pfile, path, modestr) != 0)
537 			_pfile = NULL;
538 #else
539 		_pfile = _tfopen(path, modestr);
540 #endif
541 
542 #ifdef __GNUC__
543 		_buf = new FILE_FILEBUF(_pfile, mode);
544 #else
545 		_buf = new FILE_FILEBUF;
546 		if (_pfile)
547 			_buf->open(_pfile, mode);
548 #endif
549 		return _buf;
550 	}
551 
552 	FILE*			_pfile;
553 	FILE_FILEBUF*	_buf;
554 };
555 
556  /// input file stream with ANSI/UNICODE file names
557 struct tifstream : public std::istream, FileHolder
558 {
559 	typedef std::istream super;
560 
tifstreamtifstream561 	tifstream(LPCTSTR path)
562 	 :	super(init_buf(path, std::ios::in))
563 	{
564 		if (!_pfile)
565 			setstate(badbit);
566 	}
567 };
568 
569  /// output file stream with ANSI/UNICODE file names
570 struct tofstream : public std::ostream, FileHolder
571 {
572 	typedef std::ostream super;
573 
tofstreamtofstream574 	tofstream(LPCTSTR path)
575 	 :	super(init_buf(path, std::ios::out))
576 	{
577 		if (!_pfile)
578 			setstate(badbit);
579 	}
580 
~tofstreamtofstream581 	~tofstream()
582 	{
583 		flush();
584 	}
585 };
586 
587 #else // FILE_FILEBUF
588 
589 #ifdef UNICODE
590 #error UNICODE not supported for this platform
591 #endif
592 
593 struct tifstream : public std::ifstream
594 {
595 	typedef std::ifstream super;
596 
tifstreamtifstream597 	tifstream(const char* path)
598 	 : super(path, std::ios::in|std::ios::binary)
599 	{
600 	}
601 };
602 
603 struct tofstream : public std::ofstream
604 {
605 	typedef std::ofstream super;
606 
tofstreamtofstream607 	tofstream(const char* path)
608 	 : super(path, std::ios::out|std::ios::binary)
609 	{
610 	}
611 };
612 
613 #endif
614 
615 
616  // write XML files with 2 spaces indenting
617 #define XML_INDENT_SPACE "  "
618 
619 
620 #if defined(XS_USE_XERCES) || defined(XS_USE_EXPAT)
621 
622 #if defined(XML_UNICODE)/*Expat*/ || defined(XS_USE_XERCES)/*Xerces*/	// Are Expat/Xerces XML strings UTF-16 encoded?
623 typedef XS_String String_from_XML_Char;
624 
625 #elif defined(XS_STRING_UTF8)
626 typedef XS_String String_from_XML_Char;
627 
628 #else
629 
630  /// converter from Expat/Xerces strings to XMLStorage internal strings
631 struct String_from_XML_Char : public XS_String
632 {
String_from_XML_CharString_from_XML_Char633 	String_from_XML_Char(const XML_Char* str)
634 	{
635 		assign_utf8(*this, str);
636 	}
637 };
638 
639 #endif
640 
641 #endif // defined(XS_USE_XERCES) || defined(XS_USE_EXPAT)
642 
643 
644 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
645 
646  // optimization for faster UNICODE/ASCII string comparison without temporary A/U conversion
647 inline bool operator==(const XS_String& s1, const char* s2)
648 {
649 	LPCWSTR p = s1;
650 	const unsigned char* q = (const unsigned char*)s2;
651 
652 	while(*p && *q)
653 		if (*p++ != *q++)
654 			return false;
655 
656 	return *p == *q;
657 };
658 
659 #endif
660 
661 
662  /// XML Error with message and location
663 struct XMLError
664 {
XMLErrorXMLError665 	XMLError()
666 	 :	_line(0),
667 		_column(0),
668 		_error_code(0)
669 	{
670 	}
671 
672 	std::string str() const;
673 	friend std::ostream& operator<<(std::ostream&, const XMLError& err);
674 
675 	XS_String _message;
676 	XS_String _systemId;
677 	int _line;
678 	int _column;
679 	int _error_code;
680 };
681 
682  /// list of XMLError entries
683 struct XMLErrorList : public std::list<XMLError>
684 {
685 	XS_String str() const;
686 };
687 
688 
689 #ifdef XMLNODE_LOCATION
690  /// location of XML Node including XML file name
691 struct XMLLocation
692 {
XMLLocationXMLLocation693 	XMLLocation()
694 	 :	_pdisplay_path(NULL),
695 		_line(0),
696 		_column(0)
697 	{
698 	}
699 
XMLLocationXMLLocation700 	XMLLocation(const char* display_path, int line, int column)
701 	 :	_pdisplay_path(display_path),
702 		_line(line),
703 		_column(column)
704 	{
705 	}
706 
707 	std::string str() const;
708 
709 protected:
710 	const char*	_pdisplay_path;	// character pointer for fast reference
711 	int	_line;
712 	int	_column;
713 };
714 #endif
715 
716 
717 enum PRETTY_FLAGS {
718 	PRETTY_PLAIN	= 0,
719 	PRETTY_LINEFEED	= 1,
720 	PRETTY_INDENT	= 2
721 };
722 
723 
724  /// XML Stylesheet entry
725 struct StyleSheet
726 {
727 	std::string	_href;		// CDATA #REQUIRED
728 	std::string	_type;		// CDATA #REQUIRED
729 	std::string	_title;		// CDATA #IMPLIED
730 	std::string	_media;		// CDATA #IMPLIED
731 	std::string	_charset;	// CDATA #IMPLIED
732 	bool		_alternate;	// (yes|no) "no"
733 
StyleSheetStyleSheet734 	StyleSheet() : _alternate(false) {}
735 
736 	StyleSheet(const std::string& href, const std::string& type="text/xsl", bool alternate=false)
_hrefStyleSheet737 	 :	_href(href),
738 		_type(type),
739 		_alternate(alternate)
740 	{
741 	}
742 
emptyStyleSheet743 	bool empty() const {return _href.empty();}
744 	void print(std::ostream& out) const;
745 };
746 
747  /// list of StyleSheet entries
748 struct StyleSheetList : public std::list<StyleSheet>
749 {
setStyleSheetList750 	void set(const StyleSheet& stylesheet)
751 	{
752 		clear();
753 		push_back(stylesheet);
754 	}
755 };
756 
757 
758  /// XML document type description
759 struct DocType
760 {
761 	std::string	_name;
762 
763 	 // External Document Types are noted, but not parsed.
764 	std::string	_public;
765 	std::string	_system;
766 
767 	 // Internal DTDs are not supported.
768 
769 	void parse(const char* str);
emptyDocType770 	bool empty() const {return _name.empty();}
771 };
772 
773  /// Management of XML file headers and formating
774 struct XMLFormat
775 {
776 	XMLFormat(PRETTY_FLAGS pretty=PRETTY_INDENT, const std::string& xml_version="1.0", const std::string& encoding="utf-8", const DocType& doctype=DocType())
_prettyXMLFormat777 	 :	_pretty(pretty),
778 		_endl("\n"),
779 		_version(xml_version),
780 		_encoding(encoding),
781 		_doctype(doctype),
782 		_standalone(-1)
783 	{
784 	}
785 
786 	void print_header(std::ostream& out, bool lf=true) const;
787 
788 	PRETTY_FLAGS _pretty;
789 	const char*	_endl;		// line ending string: "\n" or "\r\n"
790 
791 	std::string _version;
792 	std::string _encoding;
793 
794 	DocType		_doctype;
795 
796 	StyleSheetList _stylesheets;
797 
798 //	std::string _additional;
799 
800 	int		_standalone;
801 };
802 
803 
804 enum WRITE_MODE {
805 	FORMAT_PLAIN,		/// write XML without any white space
806 	FORMAT_SMART,		/// preserve original white space and comments if present; pretty print otherwise
807 	FORMAT_ORIGINAL,	/// write XML stream preserving original white space and comments
808 	FORMAT_PRETTY 		/// pretty print node to stream without preserving original white space
809 };
810 
811 
812 struct XMLNode;
813 
814 struct XPathElement
815 {
XPathElementXPathElement816 	XPathElement() : _child_idx(-1) {}
817 
818 	XPathElement(const XS_String& child_name, int child_idx=-1)
_child_nameXPathElement819 	 :	_child_name(child_name), _child_idx(child_idx) {}
820 
XPathElementXPathElement821 	XPathElement(const XS_String& child_name, int child_idx, const XS_String& attr_name, const XS_String& attr_value)
822 	 :	_child_name(child_name), _child_idx(child_idx),
823 		_attr_name(attr_name), _attr_value(attr_value)
824 	{
825 	}
826 
827 	XS_String	_child_name;
828 	int			_child_idx;
829 
830 	XS_String	_attr_name;
831 	XS_String	_attr_value;
832 
833 	const char* parse(const char* path);
834 
835 	XMLNode* find(XMLNode* node) const;
836 	const XMLNode* const_find(const XMLNode* node) const;
837 
838 	bool	matches(const XMLNode& node, int& n) const;
839 };
840 
841 struct XPath : std::list<XPathElement>
842 {
XPathXPath843 	XPath() : _absolute(false) {}
XPathXPath844 	XPath(const char* path) {init(path);}
XPathXPath845 	XPath(const std::string path) {init(path.c_str());}
846 
847 	void	init(const char* path);
848 
849 	bool	_absolute;
850 };
851 
852 
853  /// in memory representation of an XML node
854 struct XMLNode : public XS_String
855 {
856 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
857 	 /// map of XML node attributes
858 	 // optimized read access without temporary A/U conversion when using ASCII attribute names
859 	struct AttributeMap : public std::map<XS_String, XS_String>
860 	{
861 		typedef std::map<XS_String, XS_String> super;
862 
findXMLNode::AttributeMap863 		const_iterator find(const char* x) const
864 		{
865 			for(const_iterator it=begin(); it!=end(); ++it)
866 				if (it->first == x)
867 					return it;
868 
869 			return end();
870 		}
871 
findXMLNode::AttributeMap872 		const_iterator find(const key_type& x) const
873 		{
874 			return super::find(x);
875 		}
876 
findXMLNode::AttributeMap877 		iterator find(const key_type& x)
878 		{
879 			return super::find(x);
880 		}
881 
882 		XS_String get(const char* x, LPCXSSTR def=XS_EMPTY_STR) const
883 		{
884 			const_iterator found = find(x);
885 
886 			if (found != end())
887 				return found->second;
888 			else
889 				return def;
890 		}
891 	};
892 #else
893 	 /// map of XML node attributes
894 	struct AttributeMap : public std::map<XS_String, XS_String>
895 	{
896 		XS_String get(const char* x, LPCXSSTR def=XS_EMPTY_STR) const
897 		{
898 			const_iterator found = find(x);
899 
900 			if (found != end())
901 				return found->second;
902 			else
903 				return def;
904 		}
905 	};
906 #endif
907 
908 	 /// internal children node list
909 	struct Children : public std::list<XMLNode*>
910 	{
911 		typedef std::list<XMLNode*> super;
912 
ChildrenXMLNode::Children913 		Children()
914 		{
915 		}
916 
ChildrenXMLNode::Children917 		Children(Children& other)
918 		{
919 			for(Children::const_iterator it=other.begin(); it!=other.end(); ++it)
920 				push_back(*it);
921 		}
922 
assignXMLNode::Children923 		void assign(Children& other)
924 		{
925 			clear();
926 			move(other);
927 		}
928 
moveXMLNode::Children929 		void move(Children& other)
930 		{
931 			for(Children::const_iterator it=other.begin(); it!=other.end(); ++it)
932 				push_back(*it);
933 
934 			other.reset();
935 		}
936 
937 		Children& operator=(Children& other)
938 		{
939 			assign(other);
940 			return *this;
941 		}
942 
copyXMLNode::Children943 		void copy(const Children& other)
944 		{
945 			for(Children::const_iterator it=other.begin(); it!=other.end(); ++it)
946 				push_back(new XMLNode(**it));
947 		}
948 
clearXMLNode::Children949 		void clear()
950 		{
951 			while(!empty()) {
952 				XMLNode* node = back();
953 				pop_back();
954 
955 				node->clear();
956 				delete node;
957 			}
958 		}
959 
removeXMLNode::Children960 		bool remove(XMLNode* node)
961 		{
962 			for(iterator it=begin(); it!=end(); ++it)
963 				if (*it == node) {
964 					erase(it);
965 					return true;
966 				}
967 
968 			return false;
969 		}
970 
971 	private:
resetXMLNode::Children972 		void reset()
973 		{
974 			super::clear();
975 		}
976 	};
977 
978 	 // access to protected class members for XMLPos and XMLReader
979 	friend struct XMLPos;
980 	friend struct const_XMLPos;
981 	friend struct XMLReaderBase;
982 	friend struct XPathElement;
983 
XMLNodeXMLNode984 	XMLNode(const XS_String& name)
985 	 :	XS_String(name),
986 		_cdata_content(false)
987 	{
988 	}
989 
XMLNodeXMLNode990 	XMLNode(const XS_String& name, const std::string& leading)
991 	 :	XS_String(name),
992 		_leading(leading),
993 		_cdata_content(false)
994 	{
995 	}
996 
XMLNodeXMLNode997 	XMLNode(const XMLNode& other)
998 	 :	XS_String(other),
999 		_attributes(other._attributes),
1000 		_leading(other._leading),
1001 		_content(other._content),
1002 		_end_leading(other._end_leading),
1003 		_trailing(other._trailing),
1004 #ifdef XMLNODE_LOCATION
1005 		_location(other._location),
1006 #endif
1007 		_cdata_content(false)
1008 	{
1009 		for(Children::const_iterator it=other._children.begin(); it!=other._children.end(); ++it)
1010 			_children.push_back(new XMLNode(**it));
1011 	}
1012 
1013 	enum COPY_FLAGS {COPY_NOCHILDREN};
1014 
XMLNodeXMLNode1015 	XMLNode(const XMLNode& other, COPY_FLAGS copy_no_children)
1016 	 :	XS_String(other),
1017 		_attributes(other._attributes),
1018 		_leading(other._leading),
1019 		_content(other._content),
1020 		_end_leading(other._end_leading),
1021 		_trailing(other._trailing),
1022 #ifdef XMLNODE_LOCATION
1023 		_location(other._location),
1024 #endif
1025 		_cdata_content(false)
1026 	{
1027 //		assert(copy_no_children==COPY_NOCHILDREN);
1028 	}
1029 
~XMLNodeXMLNode1030 	virtual ~XMLNode()
1031 	{
1032 		while(!_children.empty()) {
1033 			delete _children.back();
1034 			_children.pop_back();
1035 		}
1036 	}
1037 
clearXMLNode1038 	void clear()
1039 	{
1040 		_leading.erase();
1041 		_content.erase();
1042 		_end_leading.erase();
1043 		_trailing.erase();
1044 
1045 		_attributes.clear();
1046 		_children.clear();
1047 
1048 		XS_String::erase();
1049 	}
1050 
1051 	XMLNode& operator=(const XMLNode& other)
1052 	{
1053 		_children.clear();
1054 		_children.copy(other._children);
1055 
1056 		_attributes = other._attributes;
1057 
1058 		_leading = other._leading;
1059 		_content = other._content;
1060 		_end_leading = other._end_leading;
1061 		_trailing = other._trailing;
1062 
1063 		return *this;
1064 	}
1065 
1066 	 /// add a new child node
add_childXMLNode1067 	void add_child(XMLNode* child)
1068 	{
1069 		_children.push_back(child);
1070 	}
1071 
1072 	 /// remove all children named 'name'
remove_childrenXMLNode1073 	void remove_children(const XS_String& name)
1074 	{
1075 		Children::iterator it, next=_children.begin();
1076 
1077 		while((it=next++) != _children.end())
1078 			if (**it == name)
1079 				_children.erase(it);
1080 	}
1081 
1082 	 /// write access to an attribute
putXMLNode1083 	void put(const XS_String& attr_name, const XS_String& value)
1084 	{
1085 		_attributes[attr_name] = value;
1086 	}
1087 
1088 	 /// index operator write access to an attribute
1089 	XS_String& operator[](const XS_String& attr_name)
1090 	{
1091 		return _attributes[attr_name];
1092 	}
1093 
1094 	 /// read only access to an attribute
1095 	template<typename T> XS_String get(const T& attr_name, LPCXSSTR def=XS_EMPTY_STR) const
1096 	{
1097 		AttributeMap::const_iterator found = _attributes.find(attr_name);
1098 
1099 		if (found != _attributes.end())
1100 			return found->second;
1101 		else
1102 			return def;
1103 	}
1104 
1105 	 /// remove the attribute 'attr_name'
eraseXMLNode1106 	void erase(const XS_String& attr_name)
1107 	{
1108 		_attributes.erase(attr_name);
1109 	}
1110 
1111 	 /// convenient value access in children node
1112 	XS_String subvalue(const XS_String& child_name, const XS_String& attr_name, int n=0) const
1113 	{
1114 		const XMLNode* node = XPathElement(child_name, n).const_find(this);
1115 
1116 		if (node)
1117 			return node->get(attr_name);
1118 		else
1119 			return XS_String();
1120 	}
1121 
1122 	 /// convenient storage of distinct values in children node
1123 	XS_String& subvalue(const XS_String& child_name, const XS_String& attr_name, int n=0)
1124 	{
1125 		XMLNode* node = XPathElement(child_name, n).find(this);
1126 
1127 		if (!node) {
1128 			node = new XMLNode(child_name);
1129 			add_child(node);
1130 		}
1131 
1132 		return (*node)[attr_name];
1133 	}
1134 
1135 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
1136 	 /// convenient value access in children node
1137 	XS_String subvalue(const char* child_name, const char* attr_name, int n=0) const
1138 	{
1139 		const XMLNode* node = XPathElement(child_name, n).const_find(this);
1140 
1141 		if (node)
1142 			return node->get(attr_name);
1143 		else
1144 			return XS_String();
1145 	}
1146 
1147 	 /// convenient storage of distinct values in children node
1148 	XS_String& subvalue(const char* child_name, const XS_String& attr_name, int n=0)
1149 	{
1150 		XMLNode* node = XPathElement(child_name, n).find(this);
1151 
1152 		if (!node) {
1153 			node = new XMLNode(child_name);
1154 			add_child(node);
1155 		}
1156 
1157 		return (*node)[attr_name];
1158 	}
1159 #endif
1160 
get_childrenXMLNode1161 	const Children& get_children() const
1162 	{
1163 		return _children;
1164 	}
1165 
get_childrenXMLNode1166 	Children& get_children()
1167 	{
1168 		return _children;
1169 	}
1170 
get_attributesXMLNode1171 	const AttributeMap& get_attributes() const
1172 	{
1173 		return _attributes;
1174 	}
1175 
get_attributesXMLNode1176 	AttributeMap& get_attributes()
1177 	{
1178 		return _attributes;
1179 	}
1180 
1181 	 /// read element node content
get_contentXMLNode1182 	XS_String get_content() const
1183 	{
1184 		return DecodeXMLString(_content);
1185 	}
1186 
1187 	 /// read content of a subnode specified by an XPath expression
get_sub_contentXMLNode1188 	XS_String get_sub_content(const XPath& xpath) const
1189 	{
1190 		const XMLNode* node = find_relative(xpath);
1191 
1192 		if (node)
1193 			return node->get_content();
1194 		else
1195 			return XS_EMPTY_STR;
1196 	}
1197 
1198 	 /// set element node content
1199 	void set_content(const XS_String& s, bool cdata=false)
1200 	{
1201 		_content.assign(EncodeXMLString(s.c_str(), cdata));
1202 	}
1203 
1204 	 /// set content of a subnode specified by an XPath expression
1205 	bool set_sub_content(const XPath& xpath, const XS_String& s, bool cdata=false)
1206 	{
1207 		XMLNode* node = create_relative(xpath);
1208 
1209 		if (node) {
1210 			node->set_content(s, cdata);
1211 			return true;
1212 		} else
1213 			return false;
1214 	}
1215 
1216 #ifdef XMLNODE_LOCATION
get_locationXMLNode1217 	const XMLLocation& get_location() const {return _location;}
1218 #endif
1219 
1220 	 /// write node with children tree to output stream
1221 	bool write(std::ostream& out, const XMLFormat& format, WRITE_MODE mode=FORMAT_SMART, int indent=0) const
1222 	{
1223 		switch(mode) {
1224 		  case FORMAT_PLAIN:
1225 			plain_write_worker(out);
1226 			break;
1227 
1228 		  case FORMAT_PRETTY:
1229 			pretty_write_worker(out, format, indent);
1230 			break;
1231 
1232 		  case FORMAT_ORIGINAL:
1233 			original_write_worker(out);
1234 			break;
1235 
1236 		  default:	// FORMAT_SMART
1237 			smart_write_worker(out, format, indent);
1238 		}
1239 
1240 		return out.good();
1241 	}
1242 
1243 	 /// count the nodes matching the given relative XPath expression
countXMLNode1244 	int count(const XPath& xpath) const
1245 	{
1246 		return count(xpath.begin(), xpath.end());
1247 	}
1248 
1249 	 /// count the nodes matching the given relative XPath expression
1250 	int count(XPath::const_iterator from, const XPath::const_iterator& to) const;
1251 
1252 	 /// copy matching tree nodes using the given XPath filter expression
1253 	bool filter(const XPath& xpath, XMLNode& target) const;
1254 
1255 	 /// XPath find function (const)
1256 	const XMLNode* find_relative(const XPath& xpath) const;
1257 
1258 	 /// XPath find function
1259 	XMLNode* find_relative(const XPath& xpath);
1260 
get_first_childXMLNode1261 	XMLNode* get_first_child() const
1262 	{
1263 		if (!_children.empty())
1264 			return _children.front();
1265 		else
1266 			return NULL;
1267 	}
1268 
1269 protected:
1270 	Children _children;
1271 	AttributeMap _attributes;
1272 
1273 	std::string _leading;		// UTF-8 encoded
1274 	std::string _content;		// UTF-8 and entity encoded, may contain CDATA sections; decode with DecodeXMLString()
1275 	std::string _end_leading;	// UTF-8 encoded
1276 	std::string _trailing;		// UTF-8 encoded
1277 
1278 #ifdef XMLNODE_LOCATION
1279 	XMLLocation	_location;
1280 #endif
1281 
1282 	bool	_cdata_content;
1283 
1284 	 /// relative XPath create function
1285 	XMLNode* create_relative(const XPath& xpath);
1286 
1287 	 /// create a new node tree using the given XPath filter expression
1288 	XMLNode* filter(XPath::const_iterator from, const XPath::const_iterator& to) const;
1289 
1290 	void	original_write_worker(std::ostream& out) const;
1291 	void	plain_write_worker(std::ostream& out) const;
1292 	void	pretty_write_worker(std::ostream& out, const XMLFormat& format, int indent) const;
1293 	void	smart_write_worker(std::ostream& out, const XMLFormat& format, int indent) const;
1294 };
1295 
1296 
1297  /// iterator access to children nodes with name filtering
1298 struct XMLChildrenFilter
1299 {
XMLChildrenFilterXMLChildrenFilter1300 	XMLChildrenFilter(XMLNode::Children& children, const XS_String& name)
1301 	 :	_begin(children.begin(), children.end(), name),
1302 		_end(children.end(), children.end(), name)
1303 	{
1304 	}
1305 
XMLChildrenFilterXMLChildrenFilter1306 	XMLChildrenFilter(XMLNode* node, const XS_String& name)
1307 	 :	_begin(node->get_children().begin(), node->get_children().end(), name),
1308 		_end(node->get_children().end(), node->get_children().end(), name)
1309 	{
1310 	}
1311 
1312 	 /// internal iterator class
1313 	struct iterator
1314 	{
1315 		typedef XMLNode::Children::iterator BaseIterator;
1316 		typedef iterator myType;
1317 
iteratorXMLChildrenFilter::iterator1318 		iterator(BaseIterator begin, BaseIterator end, const XS_String& filter_name)
1319 		 :	_cur(begin),
1320 			_end(end),
1321 			_filter_name(filter_name)
1322 		{
1323 			search_next();
1324 		}
1325 
BaseIteratorXMLChildrenFilter::iterator1326 		operator BaseIterator()
1327 		{
1328 			return _cur;
1329 		}
1330 
1331 		const XMLNode* operator*() const
1332 		{
1333 			return *_cur;
1334 		}
1335 
1336 		XMLNode* operator*()
1337 		{
1338 			return *_cur;
1339 		}
1340 
1341 		myType& operator++()
1342 		{
1343 			++_cur;
1344 			search_next();
1345 
1346 			return *this;
1347 		}
1348 
1349 		myType operator++(int)
1350 		{
1351 			myType ret = *this;
1352 
1353 			++_cur;
1354 			search_next();
1355 
1356 			return ret;
1357 		}
1358 
1359 		bool operator==(const myType& other) const
1360 		{
1361 			return _cur == other._cur;
1362 		}
1363 
1364 		bool operator!=(const myType& other) const
1365 		{
1366 			return _cur != other._cur;
1367 		}
1368 
1369 	protected:
1370 		BaseIterator	_cur;
1371 		BaseIterator	_end;
1372 		XS_String	_filter_name;
1373 
search_nextXMLChildrenFilter::iterator1374 		void search_next()
1375 		{
1376 			while(_cur!=_end && **_cur!=_filter_name)
1377 				++_cur;
1378 		}
1379 	};
1380 
beginXMLChildrenFilter1381 	iterator begin()
1382 	{
1383 		return _begin;
1384 	}
1385 
endXMLChildrenFilter1386 	iterator end()
1387 	{
1388 		return _end;
1389 	}
1390 
1391 protected:
1392 	iterator	_begin;
1393 	iterator	_end;
1394 };
1395 
1396 
1397  /// read only iterator access to children nodes with name filtering
1398 struct const_XMLChildrenFilter
1399 {
const_XMLChildrenFilterconst_XMLChildrenFilter1400 	const_XMLChildrenFilter(const XMLNode::Children& children, const XS_String& name)
1401 	 :	_begin(children.begin(), children.end(), name),
1402 		_end(children.end(), children.end(), name)
1403 	{
1404 	}
1405 
const_XMLChildrenFilterconst_XMLChildrenFilter1406 	const_XMLChildrenFilter(const XMLNode* node, const XS_String& name)
1407 	 :	_begin(node->get_children().begin(), node->get_children().end(), name),
1408 		_end(node->get_children().end(), node->get_children().end(), name)
1409 	{
1410 	}
1411 
1412 	 /// internal iterator class
1413 	struct const_iterator
1414 	{
1415 		typedef XMLNode::Children::const_iterator BaseIterator;
1416 		typedef const_iterator myType;
1417 
const_iteratorconst_XMLChildrenFilter::const_iterator1418 		const_iterator(BaseIterator begin, BaseIterator end, const XS_String& filter_name)
1419 		 :	_cur(begin),
1420 			_end(end),
1421 			_filter_name(filter_name)
1422 		{
1423 			search_next();
1424 		}
1425 
BaseIteratorconst_XMLChildrenFilter::const_iterator1426 		operator BaseIterator()
1427 		{
1428 			return _cur;
1429 		}
1430 
1431 		const XMLNode* operator*() const
1432 		{
1433 			return *_cur;
1434 		}
1435 
1436 		myType& operator++()
1437 		{
1438 			++_cur;
1439 			search_next();
1440 
1441 			return *this;
1442 		}
1443 
1444 		myType operator++(int)
1445 		{
1446 			myType ret = *this;
1447 
1448 			++_cur;
1449 			search_next();
1450 
1451 			return ret;
1452 		}
1453 
1454 		bool operator==(const myType& other) const
1455 		{
1456 			return _cur == other._cur;
1457 		}
1458 
1459 		bool operator!=(const myType& other) const
1460 		{
1461 			return _cur != other._cur;
1462 		}
1463 
1464 	protected:
1465 		BaseIterator	_cur;
1466 		BaseIterator	_end;
1467 		XS_String	_filter_name;
1468 
search_nextconst_XMLChildrenFilter::const_iterator1469 		void search_next()
1470 		{
1471 			while(_cur!=_end && **_cur!=_filter_name)
1472 				++_cur;
1473 		}
1474 	};
1475 
beginconst_XMLChildrenFilter1476 	const_iterator begin()
1477 	{
1478 		return _begin;
1479 	}
1480 
endconst_XMLChildrenFilter1481 	const_iterator end()
1482 	{
1483 		return _end;
1484 	}
1485 
1486 protected:
1487 	const_iterator	_begin;
1488 	const_iterator	_end;
1489 };
1490 
1491 
1492  /// iterator for XML trees
1493 struct XMLPos
1494 {
XMLPosXMLPos1495 	XMLPos(XMLNode* root)
1496 	 :	_root(root),
1497 		_cur(root)
1498 	{
1499 	}
1500 
XMLPosXMLPos1501 	XMLPos(const XMLPos& other)
1502 	 :	_root(other._root),
1503 		_cur(other._cur)
1504 	{	// don't copy _stack
1505 	}
1506 
XMLPosXMLPos1507 	XMLPos(XMLNode* node, const XS_String& name)
1508 	 :	_root(node),
1509 		_cur(node)
1510 	{
1511 		smart_create(name);
1512 	}
1513 
XMLPosXMLPos1514 	XMLPos(XMLNode* node, const XS_String& name, const XS_String& attr_name, const XS_String& attr_value)
1515 	 :	_root(node),
1516 		_cur(node)
1517 	{
1518 		smart_create(name, attr_name, attr_value);
1519 	}
1520 
XMLPosXMLPos1521 	XMLPos(const XMLPos& other, const XS_String& name)
1522 	 :	_root(other._root),
1523 		_cur(other._cur)
1524 	{
1525 		smart_create(name);
1526 	}
1527 
XMLPosXMLPos1528 	XMLPos(const XMLPos& other, const XS_String& name, const XS_String& attr_name, const XS_String& attr_value)
1529 	 :	_root(other._root),
1530 		_cur(other._cur)
1531 	{
1532 		smart_create(name, attr_name, attr_value);
1533 	}
1534 
1535 	 /// access to current node
curXMLPos1536 	XMLNode& cur()
1537 	{
1538 		return *_cur;
1539 	}
1540 
curXMLPos1541 	const XMLNode& cur() const
1542 	{
1543 		return *_cur;
1544 	}
1545 
1546 	 /// automatic access to current node
1547 	operator const XMLNode*() const {return _cur;}
1548 	operator XMLNode*() {return _cur;}
1549 
1550 	const XMLNode* operator->() const {return _cur;}
1551 	XMLNode* operator->() {return _cur;}
1552 
1553 	const XMLNode& operator*() const {return *_cur;}
1554 	XMLNode& operator*() {return *_cur;}
1555 
1556 	 /// attribute access
1557 	XS_String get(const XS_String& attr_name, LPCXSSTR def=XS_EMPTY_STR) const
1558 	{
1559 		return _cur->get(attr_name, def);
1560 	}
1561 
1562 	 /// attribute setting
putXMLPos1563 	void put(const XS_String& attr_name, const XS_String& value)
1564 	{
1565 		_cur->put(attr_name, value);
1566 	}
1567 
1568 	 /// index operator attribute access
getXMLPos1569 	template<typename T> XS_String get(const T& attr_name) const {return (*_cur)[attr_name];}
1570 	XS_String& operator[](const XS_String& attr_name) {return (*_cur)[attr_name];}
1571 	const XS_String& operator[](const XS_String& attr_name) const {return (*_cur)[attr_name];}
1572 
1573 	 /// insert children when building tree
add_downXMLPos1574 	void add_down(XMLNode* child)
1575 	{
1576 		_cur->add_child(child);
1577 		go_to(child);
1578 	}
1579 
1580 	 /// go back to previous position
backXMLPos1581 	bool back()
1582 	{
1583 		if (!_stack.empty()) {
1584 			_cur = _stack.top();
1585 			_stack.pop();
1586 			return true;
1587 		} else
1588 			return false;
1589 	}
1590 
1591 	 /// go down to first child
go_downXMLPos1592 	bool go_down()
1593 	{
1594 		XMLNode* node = _cur->get_first_child();
1595 
1596 		if (node) {
1597 			go_to(node);
1598 			return true;
1599 		} else
1600 			return false;
1601 	}
1602 
1603 	 /// search for child and go down
1604 	bool go_down(const XS_String& child_name, int n=0)
1605 	{
1606 		XMLNode* node = XPathElement(child_name, n).find(_cur);
1607 
1608 		if (node) {
1609 			go_to(node);
1610 			return true;
1611 		} else
1612 			return false;
1613 	}
1614 
1615 	 /// iterate to the next matching child
iterateXMLPos1616 	bool iterate(const XS_String& child_name, size_t& cnt)
1617 	{
1618 		XMLNode* node = XPathElement(child_name, cnt).find(_cur);
1619 
1620 		if (node) {
1621 			go_to(node);
1622 			++cnt;
1623 			return true;
1624 		} else
1625 			return false;
1626 	}
1627 
1628 	 /// move to the position defined by xpath in XML tree
1629 	bool go(const XPath& xpath);
1630 
1631 	 /// create child nodes using XPath notation and move to the deepest child
create_relativeXMLPos1632 	bool create_relative(const XPath& xpath)
1633 	{
1634 		XMLNode* node = _cur->create_relative(xpath);
1635 		if (!node)
1636 			return false;	// invalid path specified
1637 
1638 		go_to(node);
1639 		return true;
1640 	}
1641 
1642 	 /// create node and move to it
createXMLPos1643 	void create(const XS_String& name)
1644 	{
1645 		add_down(new XMLNode(name));
1646 	}
1647 
1648 	 /// create node with string content
create_node_contentXMLPos1649 	void create_node_content(const XS_String& node_name, const XS_String& content)
1650 	{
1651 		XMLNode* pNode = new XMLNode(node_name);
1652 			pNode->set_content(content);
1653 		_cur->add_child(pNode);
1654 	}
1655 
1656 	 /// create node if not already existing and move to it
smart_createXMLPos1657 	void smart_create(const XS_String& child_name)
1658 	{
1659 		XMLNode* node = XPathElement(child_name).find(_cur);
1660 
1661 		if (node)
1662 			go_to(node);
1663 		else
1664 			add_down(new XMLNode(child_name));
1665 	}
1666 
1667 	 /// search matching child node identified by key name and an attribute value
smart_createXMLPos1668 	void smart_create(const XS_String& child_name, const XS_String& attr_name, const XS_String& attr_value)
1669 	{
1670 		XMLNode* node = XPathElement(child_name, 0, attr_name, attr_value).find(_cur);
1671 
1672 		if (node)
1673 			go_to(node);
1674 		else {
1675 			node = new XMLNode(child_name);
1676 			add_down(node);
1677 			(*node)[attr_name] = attr_value;
1678 		}
1679 	}
1680 
1681 	 /// count the nodes matching the given relative XPath expression
countXMLPos1682 	int count(const XPath& xpath) const
1683 	{
1684 		return _cur->count(xpath);
1685 	}
1686 
1687 	 /// create a new node tree using the given XPath filter expression
filterXMLPos1688 	int filter(const XPath& xpath, XMLNode& target) const
1689 	{
1690 		return _cur->filter(xpath, target);
1691 	}
1692 
1693 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
1694 	 /// search for child and go down
1695 	bool go_down(const char* child_name, int n=0)
1696 	{
1697 		XMLNode* node = XPathElement(child_name, n).find(_cur);
1698 
1699 		if (node) {
1700 			go_to(node);
1701 			return true;
1702 		} else
1703 			return false;
1704 	}
1705 
1706 	 /// create node and move to it
createXMLPos1707 	void create(const char* child_name)
1708 	{
1709 		add_down(new XMLNode(child_name));
1710 	}
1711 
1712 	 /// create node if not already existing and move to it
smart_createXMLPos1713 	void smart_create(const char* child_name)
1714 	{
1715 		XMLNode* node = XPathElement(child_name).find(_cur);
1716 
1717 		if (node)
1718 			go_to(node);
1719 		else
1720 			add_down(new XMLNode(child_name));
1721 	}
1722 
1723 	 /// search matching child node identified by key name and an attribute value
1724 	template<typename T, typename U>
smart_createXMLPos1725 	void smart_create(const char* child_name, const T& attr_name, const U& attr_value)
1726 	{
1727 		XMLNode* node = XPathElement(child_name, 0, attr_name, attr_value).find(_cur);
1728 
1729 		if (node)
1730 			go_to(node);
1731 		else {
1732 			node = new XMLNode(child_name);
1733 			add_down(node);
1734 			(*node)[attr_name] = attr_value;
1735 		}
1736 	}
1737 #endif
1738 
1739 	 /// delete current node and go back to previous position
delete_thisXMLPos1740 	bool delete_this()
1741 	{
1742 		if (!_stack.empty()) {
1743 			XMLNode* pLast = _stack.top();
1744 
1745 			if (pLast->_children.remove(_cur)) {
1746 				_cur = _stack.top();
1747 				return true;
1748 			}
1749 		}
1750 
1751 		return false;
1752 	}
1753 
1754 	 /// remove all children named 'name'
remove_childrenXMLPos1755 	void remove_children(const XS_String& name)
1756 	{
1757 		_cur->remove_children(name);
1758 	}
1759 
1760 	 /// remove the attribute 'attr_name' from the current node
eraseXMLPos1761 	void erase(const XS_String& attr_name)
1762 	{
1763 		_cur->erase(attr_name);
1764 	}
1765 
strXMLPos1766 	XS_String& str() {return *_cur;}
strXMLPos1767 	const XS_String& str() const {return *_cur;}
1768 
1769 	 // property (key/value pair) setter functions
1770 	void set_property(const XS_String& key, int value, const XS_String& name=XS_PROPERTY);
1771 	void set_property(const XS_String& key, double value, const XS_String& name=XS_PROPERTY);
1772 	void set_property(const XS_String& key, const XS_String& value, const XS_String& name=XS_PROPERTY);
1773 	void set_property(const XS_String& key, const struct XMLBool& value, const XS_String& name=XS_PROPERTY);
1774 
1775 	void set_property(const XS_String& key, const char* value, const XS_String& name=XS_PROPERTY)
1776 		{set_property(key, XS_String(value), name);}
1777 
1778 protected:
1779 	friend struct const_XMLPos;	// access to _root
1780 
1781 	XMLNode* _root;
1782 	XMLNode* _cur;
1783 	std::stack<XMLNode*> _stack;
1784 
1785 	 /// go to specified node
go_toXMLPos1786 	void go_to(XMLNode* child)
1787 	{
1788 		_stack.push(_cur);
1789 		_cur = child;
1790 	}
1791 };
1792 
1793 
1794  /// iterator for XML trees
1795 struct const_XMLPos
1796 {
const_XMLPosconst_XMLPos1797 	const_XMLPos(const XMLNode* root)
1798 	 :	_root(root),
1799 		_cur(root)
1800 	{
1801 	}
1802 
const_XMLPosconst_XMLPos1803 	const_XMLPos(const const_XMLPos& other)
1804 	 :	_root(other._root),
1805 		_cur(other._cur)
1806 	{	// don't copy _stack
1807 	}
1808 
const_XMLPosconst_XMLPos1809 	const_XMLPos(const XMLPos& other)
1810 	 :	_root(other._root),
1811 		_cur(other._cur)
1812 	{	// don't copy _stack
1813 	}
1814 
1815 	 /// access to current node
curconst_XMLPos1816 	const XMLNode& cur() const
1817 	{
1818 		return *_cur;
1819 	}
1820 
1821 	 /// automatic access to current node
1822 	operator const XMLNode*() const {return _cur;}
1823 
1824 	const XMLNode* operator->() const {return _cur;}
1825 
1826 	const XMLNode& operator*() const {return *_cur;}
1827 
1828 	 /// attribute access
getconst_XMLPos1829 	XS_String get(const XS_String& attr_name) const
1830 	{
1831 		return _cur->get(attr_name);
1832 	}
1833 
1834 	 /// index operator attribute access
getconst_XMLPos1835 	template<typename T> XS_String get(const T& attr_name) const {return _cur->get(attr_name);}
1836 	XS_String operator[](const XS_String& attr_name) const {return _cur->get(attr_name);}
1837 
1838 	 /// go back to previous position
backconst_XMLPos1839 	bool back()
1840 	{
1841 		if (!_stack.empty()) {
1842 			_cur = _stack.top();
1843 			_stack.pop();
1844 			return true;
1845 		} else
1846 			return false;
1847 	}
1848 
1849 	 /// go down to first child
go_downconst_XMLPos1850 	bool go_down()
1851 	{
1852 		const XMLNode* node = _cur->get_first_child();
1853 
1854 		if (node) {
1855 			go_to(node);
1856 			return true;
1857 		} else
1858 			return false;
1859 	}
1860 
1861 	 /// search for child and go down
1862 	bool go_down(const XS_String& child_name, int n=0)
1863 	{
1864 		const XMLNode* node = XPathElement(child_name, n).const_find(_cur);
1865 
1866 		if (node) {
1867 			go_to(node);
1868 			return true;
1869 		} else
1870 			return false;
1871 	}
1872 
1873 	 /// iterate to the next matching child
iterateconst_XMLPos1874 	bool iterate(const XS_String& child_name, size_t& cnt)
1875 	{
1876 		const XMLNode* node = XPathElement(child_name, cnt).const_find(_cur);
1877 
1878 		if (node) {
1879 			go_to(node);
1880 			++cnt;
1881 			return true;
1882 		} else
1883 			return false;
1884 	}
1885 
1886 	 /// move to the position defined by xpath in XML tree
1887 	bool go(const XPath& xpath);
1888 
1889 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
1890 	 /// search for child and go down
1891 	bool go_down(const char* child_name, int n=0)
1892 	{
1893 		const XMLNode* node = XPathElement(child_name, n).const_find(_cur);
1894 
1895 		if (node) {
1896 			go_to(node);
1897 			return true;
1898 		} else
1899 			return false;
1900 	}
1901 #endif
1902 
strconst_XMLPos1903 	const XS_String& str() const {return *_cur;}
1904 
1905 protected:
1906 	const XMLNode* _root;
1907 	const XMLNode* _cur;
1908 	std::stack<const XMLNode*> _stack;
1909 
1910 	 /// go to specified node
go_toconst_XMLPos1911 	void go_to(const XMLNode* child)
1912 	{
1913 		_stack.push(_cur);
1914 		_cur = child;
1915 	}
1916 };
1917 
1918 
1919  /// type converter for boolean data
1920 struct XMLBool
1921 {
1922 	XMLBool(bool value=false)
_valueXMLBool1923 	 :	_value(value)
1924 	{
1925 	}
1926 
1927 	XMLBool(LPCXSSTR value, bool def=false)
1928 	{
1929 		if (value && *value)//@@ also handle white space and return def instead of false
1930 			_value = !XS_icmp(value, XS_TRUE);
1931 		else
1932 			_value = def;
1933 	}
1934 
1935 	XMLBool(const XMLNode* node, const XS_String& attr_name, bool def=false)
1936 	{
1937 		const XS_String& value = node->get(attr_name);
1938 
1939 		if (!value.empty())
1940 			_value = !XS_icmp(value.c_str(), XS_TRUE);
1941 		else
1942 			_value = def;
1943 	}
1944 
1945 	operator bool() const
1946 	{
1947 		return _value;
1948 	}
1949 
1950 	bool operator!() const
1951 	{
1952 		return !_value;
1953 	}
1954 
LPCXSSTRXMLBool1955 	operator LPCXSSTR() const
1956 	{
1957 		return _value? XS_TRUE: XS_FALSE;
1958 	}
1959 
1960 protected:
1961 	bool	_value;
1962 
1963 private:
1964 	void operator=(const XMLBool&); // disallow assignment operations
1965 };
1966 
1967  /// type converter for boolean data with write access
1968 struct XMLBoolRef
1969 {
1970 	XMLBoolRef(XMLNode* node, const XS_String& attr_name, bool def=false)
1971 	 :	_ref((*node)[attr_name])
1972 	{
1973 		if (_ref.empty())
1974 			assign(def);
1975 	}
1976 
1977 	operator bool() const
1978 	{
1979 		return !XS_icmp(_ref.c_str(), XS_TRUE);
1980 	}
1981 
1982 	bool operator!() const
1983 	{
1984 		return XS_icmp(_ref.c_str(), XS_TRUE)? true: false;
1985 	}
1986 
1987 	XMLBoolRef& operator=(bool value)
1988 	{
1989 		assign(value);
1990 
1991 		return *this;
1992 	}
1993 
assignXMLBoolRef1994 	void assign(bool value)
1995 	{
1996 		_ref.assign(value? XS_TRUE: XS_FALSE);
1997 	}
1998 
toggleXMLBoolRef1999 	void toggle()
2000 	{
2001 		assign(!operator bool());
2002 	}
2003 
2004 protected:
2005 	XS_String& _ref;
2006 };
2007 
2008 
2009  /// type converter for integer data
2010 struct XMLInt
2011 {
XMLIntXMLInt2012 	XMLInt(int value)
2013 	 :	_value(value)
2014 	{
2015 	}
2016 
2017 	XMLInt(LPCXSSTR value, int def=0)
2018 	{
2019 		if (value && *value)//@@ also handle white space and return def instead of 0
2020 			_value = XS_toi(value);
2021 		else
2022 			_value = def;
2023 	}
2024 
2025 	XMLInt(const XMLNode* node, const XS_String& attr_name, int def=0)
2026 	{
2027 		const XS_String& value = node->get(attr_name);
2028 
2029 		if (!value.empty())
2030 			_value = XS_toi(value.c_str());
2031 		else
2032 			_value = def;
2033 	}
2034 
2035 	operator int() const
2036 	{
2037 		return _value;
2038 	}
2039 
XS_StringXMLInt2040 	operator XS_String() const
2041 	{
2042 		XS_CHAR buffer[32];
2043 		XS_snprintf(buffer, COUNTOF(buffer), XS_INTFMT, _value);
2044 		return XS_String(buffer);
2045 	}
2046 
2047 protected:
2048 	int _value;
2049 
2050 private:
2051 	void operator=(const XMLInt&); // disallow assignment operations
2052 };
2053 
2054  /// type converter for integer data with write access
2055 struct XMLIntRef
2056 {
2057 	XMLIntRef(XMLNode* node, const XS_String& attr_name, int def=0)
2058 	 :	_ref((*node)[attr_name])
2059 	{
2060 		if (_ref.empty())
2061 			assign(def);
2062 	}
2063 
2064 	XMLIntRef& operator=(int value)
2065 	{
2066 		assign(value);
2067 
2068 		return *this;
2069 	}
2070 
2071 	operator int() const
2072 	{
2073 		return XS_toi(_ref.c_str());
2074 	}
2075 
assignXMLIntRef2076 	void assign(int value)
2077 	{
2078 		XS_CHAR buffer[32];
2079 		XS_snprintf(buffer, COUNTOF(buffer), XS_INTFMT, value);
2080 		_ref.assign(buffer);
2081 	}
2082 
2083 protected:
2084 	XS_String& _ref;
2085 };
2086 
2087 
2088  /// type converter for numeric data
2089 struct XMLDouble
2090 {
XMLDoubleXMLDouble2091 	XMLDouble(double value)
2092 	 :	_value(value)
2093 	{
2094 	}
2095 
2096 	XMLDouble(LPCXSSTR value, double def=0.)
2097 	{
2098 		LPTSTR end;
2099 
2100 		if (value && *value)//@@ also handle white space and return def instead of 0
2101 			_value = XS_tod(value, &end);
2102 		else
2103 			_value = def;
2104 	}
2105 
2106 	XMLDouble(const XMLNode* node, const XS_String& attr_name, double def=0.)
2107 	{
2108 		LPTSTR end;
2109 		const XS_String& value = node->get(attr_name);
2110 
2111 		if (!value.empty())
2112 			_value = XS_tod(value.c_str(), &end);
2113 		else
2114 			_value = def;
2115 	}
2116 
2117 	operator double() const
2118 	{
2119 		return _value;
2120 	}
2121 
XS_StringXMLDouble2122 	operator XS_String() const
2123 	{
2124 		XS_CHAR buffer[32];
2125 		XS_snprintf(buffer, COUNTOF(buffer), XS_FLOATFMT, _value);
2126 		return XS_String(buffer);
2127 	}
2128 
2129 protected:
2130 	double _value;
2131 
2132 private:
2133 	void operator=(const XMLDouble&); // disallow assignment operations
2134 };
2135 
2136  /// type converter for numeric data with write access
2137 struct XMLDoubleRef
2138 {
2139 	XMLDoubleRef(XMLNode* node, const XS_String& attr_name, double def=0.)
2140 	 :	_ref((*node)[attr_name])
2141 	{
2142 		if (_ref.empty())
2143 			assign(def);
2144 	}
2145 
2146 	XMLDoubleRef& operator=(double value)
2147 	{
2148 		assign(value);
2149 
2150 		return *this;
2151 	}
2152 
2153 	operator double() const
2154 	{
2155 		LPTSTR end;
2156 		return XS_tod(_ref.c_str(), &end);
2157 	}
2158 
assignXMLDoubleRef2159 	void assign(double value)
2160 	{
2161 		XS_CHAR buffer[32];
2162 		XS_snprintf(buffer, COUNTOF(buffer), XS_FLOATFMT, value);
2163 		_ref.assign(buffer);
2164 	}
2165 
2166 protected:
2167 	XS_String& _ref;
2168 };
2169 
2170 
2171  /// type converter for string data
2172 struct XMLString
2173 {
XMLStringXMLString2174 	XMLString(const XS_String& value)
2175 	 :	_value(value)
2176 	{
2177 	}
2178 
2179 	XMLString(LPCXSSTR value, LPCXSSTR def=XS_EMPTY)
2180 	{
2181 		if (value && *value)
2182 			_value = value;
2183 		else
2184 			_value = def;
2185 	}
2186 
2187 	XMLString(const XMLNode* node, const XS_String& attr_name, LPCXSSTR def=XS_EMPTY)
2188 	{
2189 		const XS_String& value = node->get(attr_name);
2190 
2191 		if (!value.empty())
2192 			_value = value;
2193 		else
2194 			_value = def;
2195 	}
2196 
2197 	operator const XS_String&() const
2198 	{
2199 		return _value;
2200 	}
2201 
c_strXMLString2202 	const XS_String& c_str() const
2203 	{
2204 		return _value;
2205 	}
2206 
2207 protected:
2208 	XS_String	_value;
2209 
2210 private:
2211 	void operator=(const XMLString&); // disallow assignment operations
2212 };
2213 
2214  /// type converter for string data with write access
2215 struct XMLStringRef
2216 {
2217 	XMLStringRef(XMLNode* node, const XS_String& attr_name, LPCXSSTR def=XS_EMPTY)
2218 	 :	_ref((*node)[attr_name])
2219 	{
2220 		if (_ref.empty())
2221 			assign(def);
2222 	}
2223 
2224 	XMLStringRef(const XS_String& node_name, XMLNode* node, const XS_String& attr_name, LPCXSSTR def=XS_EMPTY)
2225 	 :	_ref(node->subvalue(node_name, attr_name))
2226 	{
2227 		if (_ref.empty())
2228 			assign(def);
2229 	}
2230 
2231 	XMLStringRef& operator=(const XS_String& value)
2232 	{
2233 		assign(value);
2234 
2235 		return *this;
2236 	}
2237 
2238 	operator const XS_String&() const
2239 	{
2240 		return _ref;
2241 	}
2242 
assignXMLStringRef2243 	void assign(const XS_String& value)
2244 	{
2245 		_ref.assign(value);
2246 	}
2247 
2248 protected:
2249 	XS_String& _ref;
2250 };
2251 
2252 
2253  // read option (for example configuration) values from XML node attributes
2254 template<typename T>
read_option(T & var,const_XMLPos & cfg,LPCXSSTR key)2255 	inline void read_option(T& var, const_XMLPos& cfg, LPCXSSTR key)
2256 	{
2257 		const XS_String& val = cfg.get(key);
2258 
2259 		if (!val.empty())
2260 			var = val;
2261 	}
2262 
2263  // read integer option values from XML node attributes
2264 template<>
read_option(int & var,const_XMLPos & cfg,LPCXSSTR key)2265 	inline void read_option(int& var, const_XMLPos& cfg, LPCXSSTR key)
2266 	{
2267 		const XS_String& val = cfg.get(key);
2268 
2269 		if (!val.empty())
2270 			var = XS_toi(val.c_str());
2271 	}
2272 
2273 
set_property(const XS_String & key,int value,const XS_String & name)2274 inline void XMLPos::set_property(const XS_String& key, int value, const XS_String& name)
2275 {
2276 	smart_create(name, XS_KEY, key);
2277 		XMLIntRef(_cur, XS_VALUE) = value;
2278 	back();
2279 }
2280 
set_property(const XS_String & key,double value,const XS_String & name)2281 inline void XMLPos::set_property(const XS_String& key, double value, const XS_String& name)
2282 {
2283 	smart_create(name, XS_KEY, key);
2284 		XMLDoubleRef(_cur, XS_VALUE) = value;
2285 	back();
2286 }
2287 
set_property(const XS_String & key,const XS_String & value,const XS_String & name)2288 inline void XMLPos::set_property(const XS_String& key, const XS_String& value, const XS_String& name)
2289 {
2290 	smart_create(name, XS_KEY, key);
2291 		put(XS_VALUE, value);
2292 	back();
2293 }
2294 
set_property(const XS_String & key,const XMLBool & value,const XS_String & name)2295 inline void XMLPos::set_property(const XS_String& key, const XMLBool& value, const XS_String& name)
2296 {
2297 	smart_create(name, XS_KEY, key);
2298 		XMLBoolRef(_cur, XS_VALUE) = value;
2299 	back();
2300 }
2301 
2302 
2303  /// a key/value pair for property data access
2304 struct XMLProperty {
XMLPropertyXMLProperty2305 	XMLProperty(const XMLNode* node)
2306 	 :	_key(node->get(XS_KEY)),
2307 		_value(node->get(XS_VALUE))
2308 	{
2309 	}
2310 
2311 	XS_String	_key;
2312 	XS_String	_value;
2313 };
2314 
2315 
2316  /// utility class to read property settings from a XML tree
2317 struct XMLPropertyReader
2318 {
XMLPropertyReaderXMLPropertyReader2319 	XMLPropertyReader(const XMLNode::Children& children)
2320 	 :	_filter(children, XS_PROPERTY),
2321 		_begin(_filter.begin(), _filter.end()),
2322 		_end(_filter.end(), _filter.end())
2323 	{
2324 	}
2325 
XMLPropertyReaderXMLPropertyReader2326 	XMLPropertyReader(const XMLNode* node)
2327 	 :	_filter(node, XS_PROPERTY),
2328 		_begin(_filter.begin(), _filter.end()),
2329 		_end(_filter.end(), _filter.end())
2330 	{
2331 	}
2332 
2333 	 /// internal iterator class
2334 	struct const_iterator
2335 	{
2336 		typedef const_XMLChildrenFilter::const_iterator BaseIterator;
2337 		typedef const_iterator myType;
2338 
const_iteratorXMLPropertyReader::const_iterator2339 		const_iterator(BaseIterator begin, BaseIterator end)
2340 		 :	_cur(begin),
2341 			_end(end)
2342 		{
2343 		}
2344 
BaseIteratorXMLPropertyReader::const_iterator2345 		operator BaseIterator()
2346 		{
2347 			return _cur;
2348 		}
2349 
2350 		XMLProperty operator*() const
2351 		{
2352 			return XMLProperty(*_cur);
2353 		}
2354 
get_nodeXMLPropertyReader::const_iterator2355 		const XMLNode* get_node() const
2356 		{
2357 			return *_cur;
2358 		}
2359 
2360 		myType& operator++()
2361 		{
2362 			++_cur;
2363 
2364 			return *this;
2365 		}
2366 
2367 		myType operator++(int)
2368 		{
2369 			myType ret = *this;
2370 
2371 			++_cur;
2372 
2373 			return ret;
2374 		}
2375 
2376 		bool operator==(const myType& other) const
2377 		{
2378 			return _cur == other._cur;
2379 		}
2380 
2381 		bool operator!=(const myType& other) const
2382 		{
2383 			return _cur != other._cur;
2384 		}
2385 
2386 	protected:
2387 		BaseIterator	_cur;
2388 		BaseIterator	_end;
2389 	};
2390 
beginXMLPropertyReader2391 	const_iterator begin()
2392 	{
2393 		return _begin;
2394 	}
2395 
endXMLPropertyReader2396 	const_iterator end()
2397 	{
2398 		return _end;
2399 	}
2400 
2401 protected:
2402 	const_XMLChildrenFilter	_filter;
2403 
2404 	const_iterator	_begin;
2405 	const_iterator	_end;
2406 };
2407 
2408 
2409 #ifdef _MSC_VER
2410 #pragma warning(disable: 4355)
2411 #endif
2412 
2413  /// XML reader base class
2414 struct XMLReaderBase
2415 #ifdef XS_USE_XERCES
2416  : public HandlerBase
2417 #endif
2418 {
2419 #ifdef XS_USE_XERCES
2420 
2421 	XMLReaderBase(XMLNode* node, InputSource* source, bool adoptSource=false);
2422 	virtual ~XMLReaderBase();
2423 
2424 	void read();
2425 
2426 protected:
2427 	SAXParser*	_parser;
2428 	InputSource* _source;
2429 	bool		_deleteSource;
2430 
2431 	virtual void XMLDecl(const XMLCh* const versionStr, const XMLCh* const encodingStr,
2432 						 const XMLCh* const standaloneStr, const XMLCh* const actualEncodingStr);
2433 
2434      // Handlers for the SAX DocumentHandler interface
2435 	virtual void setDocumentLocator(const Locator* const locator);
2436 	virtual void startElement(const XMLCh* const name, AttributeList& attributes);
2437     virtual void endElement(const XMLCh* const name);
2438     virtual void characters(const XMLCh* const chars, const unsigned int length);
2439     virtual void ignorableWhitespace(const XMLCh* const chars, const unsigned int length);
2440 
2441      // Handlers for the SAX ErrorHandler interface
2442     virtual void error(const SAXParseException& e);
2443     virtual void fatalError(const SAXParseException& e);
2444 	virtual void warning(const SAXParseException& e);
2445     virtual void resetErrors();
2446 
2447 #elif defined(XS_USE_EXPAT) // !XS_USE_XERCES
2448 
2449 	XMLReaderBase(XMLNode* node);
2450 	virtual ~XMLReaderBase();
2451 
2452 protected:
2453 	XML_Parser	_parser;
2454 
2455 	static void XMLCALL XML_XmlDeclHandler(void* userData, const XML_Char* version, const XML_Char* encoding, int standalone=-1);
2456 	static void XMLCALL XML_StartElementHandler(void* userData, const XML_Char* name, const XML_Char** atts);
2457 	static void XMLCALL XML_EndElementHandler(void* userData, const XML_Char* name);
2458 	static void XMLCALL XML_DefaultHandler(void* userData, const XML_Char* s, int len);
2459 
2460 	static std::string get_expat_error_string(XML_Error error_code);
2461 
2462 #else // XS_USE_EXPAT
2463 
2464 	XMLReaderBase(XMLNode* node)
2465 	 :	_pos(node),
2466 		_endl_defined(false),
2467 		_utf8(false)
2468 	{
2469 		_last_tag = TAG_NONE;
2470 	}
2471 
2472 	virtual ~XMLReaderBase();
2473 
2474 	bool	parse();
2475 
2476 #endif
2477 
2478 public:
2479 #ifndef XS_USE_XERCES
2480 	void read();
2481 
2482 	std::string	get_position() const;
2483 #endif
get_formatXMLReaderBase2484 	const XMLFormat& get_format() const {return _format;}
get_endlXMLReaderBase2485 	const char* get_endl() const {return _endl_defined? _format._endl: "\n";}
2486 
get_errorsXMLReaderBase2487 	const XMLErrorList& get_errors() const {return _errors;}
get_warningsXMLReaderBase2488 	const XMLErrorList& get_warnings() const {return _warnings;}
2489 
clear_errorsXMLReaderBase2490 	void clear_errors() {_errors.clear(); _warnings.clear();}
2491 
2492 #ifdef XMLNODE_LOCATION
2493 	const char* _display_path;	// character pointer for fast reference in XMLLocation
2494 
2495 #ifdef XS_USE_XERCES
2496 	const Locator* _locator;
2497 #endif
2498 
2499 	XMLLocation get_location() const;
2500 #endif
2501 
2502 protected:
2503 	XMLPos		_pos;
2504 
2505 	std::string _content;		// UTF-8 encoded
2506 	enum {TAG_NONE, TAG_START, TAG_END} _last_tag;
2507 
2508 	XMLErrorList _errors;
2509 	XMLErrorList _warnings;
2510 
2511 	XMLFormat	_format;
2512 	bool	_endl_defined;
2513 
2514 #ifdef XS_USE_XERCES
2515 	//@@
2516 #elif defined(XS_USE_EXPAT)
2517 	virtual int read_buffer(char* buffer, int len) = 0;
2518 #else
2519 	virtual int get() = 0;
2520 	int		eat_endl();
2521 
2522 	bool	_utf8;
2523 #endif
2524 
2525 	void	finish_read();
2526 
2527 	virtual void XmlDeclHandler(const char* version, const char* encoding, int standalone);
2528 	virtual void StartElementHandler(const XS_String& name, const XMLNode::AttributeMap& attributes);
2529 	virtual void EndElementHandler();
2530 #if defined(XS_USE_XERCES) || defined(XS_USE_EXPAT)
2531 	virtual void DefaultHandler(const XML_Char* s, int len);
2532 #else
2533 	virtual void DefaultHandler(const std::string& s);
2534 #endif
2535 };
2536 
2537 
2538  /// XML file reader
2539 
2540 #ifdef XS_USE_XERCES
2541 
2542 struct XercesXMLReader : public XMLReaderBase
2543 {
2544 	XercesXMLReader(XMLNode* node, InputSource* source, bool adoptSource=false)
XMLReaderBaseXercesXMLReader2545 	 :	XMLReaderBase(node, source, adoptSource)
2546 	{
2547 	}
2548 
2549 	XercesXMLReader(XMLNode* node, LPCTSTR path);
2550 	XercesXMLReader(XMLNode* node, const XMLByte* buffer, size_t bytes, const std::string& system_id=std::string());
2551 };
2552 
2553 #define XMLReader XercesXMLReader
2554 
2555 #elif defined(XS_USE_EXPAT)
2556 
2557 struct ExpatXMLReader : public XMLReaderBase
2558 {
ExpatXMLReaderExpatXMLReader2559 	ExpatXMLReader(XMLNode* node, std::istream& in)
2560 	 :	XMLReaderBase(node),
2561 		_in(in)
2562 	{
2563 	}
2564 
2565 	 /// read XML stream into XML tree below _pos
read_bufferExpatXMLReader2566 	int read_buffer(char* buffer, int len)
2567 	{
2568 		if (!_in.good())
2569 			return -1;
2570 
2571 		_in.read(buffer, len);
2572 
2573 		return _in.gcount();
2574 	}
2575 
2576 protected:
2577 	std::istream&	_in;
2578 };
2579 
2580 #define XMLReader ExpatXMLReader
2581 
2582 #else // XS_USE_XERCES, XS_USE_EXPAT
2583 
2584 struct XMLReader : public XMLReaderBase
2585 {
XMLReaderXMLReader2586 	XMLReader(XMLNode* node, std::istream& in)
2587 	 :	XMLReaderBase(node),
2588 		_in(in)
2589 	{
2590 	}
2591 
2592 	 /// read one character from XML stream
getXMLReader2593 	int get()
2594 	{
2595 		return _in.get();
2596 	}
2597 
2598 protected:
2599 	std::istream&	_in;
2600 };
2601 
2602 #endif // XS_USE_XERCES
2603 
2604 
2605 #if defined(_MSC_VER) && _MSC_VER<1400
2606 
2607 struct fast_ostringbuffer : public std::streambuf
2608 {
2609 	typedef char _E;
2610 	typedef std::char_traits<_E> _Tr;
2611 
fast_ostringbufferfast_ostringbuffer2612 	explicit fast_ostringbuffer()
2613 		{_Init(0, 0, std::_Noread);}	// optimized for ios::out mode
2614 
~fast_ostringbufferfast_ostringbuffer2615 	virtual ~fast_ostringbuffer()
2616 		{_Tidy();}
2617 
strfast_ostringbuffer2618 	std::string str() const
2619 		{if (pptr() != 0)
2620 			{std::string _Str(pbase(),
2621 				(_Seekhigh<pptr()? pptr(): _Seekhigh) - pbase());
2622 			return _Str;}
2623 		else
2624 			return std::string();}
2625 
2626 protected:
2627 	virtual int_type overflow(int_type _C = _Tr::eof())
2628 		{if (_Tr::eq_int_type(_Tr::eof(), _C))
2629 			return _Tr::not_eof(_C);
2630 		else if (pptr() != 0 && pptr() < epptr())
2631 			{*_Pninc() = _Tr::to_char_type(_C);
2632 			return _C;}
2633 		else
2634 			{size_t _Os = gptr() == 0 ? 0 : epptr() - eback();
2635 			size_t _Ns = _Os + _Alsize;
2636 			_E *_P = _Al.allocate(_Ns, (void *)0);
2637 			if (0 < _Os)
2638 				_Tr::copy(_P, eback(), _Os);
2639 			else if (_ALSIZE < _Alsize)
2640 				_Alsize = _ALSIZE;
2641 
2642 			if (_Strmode & std::_Allocated)
2643 				_Al.deallocate(eback(), _Os);
2644 
2645 			_Strmode |= std::_Allocated;
2646 
2647 			if (_Os == 0)
2648 				{_Seekhigh = _P;
2649 				setp(_P, _P + _Ns);
2650 				setg(_P, _P, _P); }
2651 			else
2652 				{_Seekhigh = _Seekhigh - eback() + _P;
2653 				setp(pbase() - eback() + _P, pptr() - eback() + _P, _P + _Ns);
2654 				setg(_P, _P, _P);}
2655 			*_Pninc() = _Tr::to_char_type(_C);
2656 
2657 			return _C;}}
2658 
_Initfast_ostringbuffer2659 	void _Init(const _E *_S, size_t _N, std::_Strstate _M)
2660 		{_Pendsave = 0, _Seekhigh = 0;
2661 		_Alsize = _MINSIZE, _Strmode = _M;
2662 		setg(0, 0, 0);
2663 		setp(0, 0);}
2664 
_Tidyfast_ostringbuffer2665 	void _Tidy()
2666 		{if (_Strmode & std::_Allocated)
2667 			_Al.deallocate(eback(), (pptr() != 0 ? epptr() : egptr()) - eback());
2668 		_Seekhigh = 0;
2669 		_Strmode &= ~std::_Allocated;}
2670 
2671 private:
2672 	enum {_ALSIZE = 65536/*512*/, _MINSIZE = 32768/*32*/};	// bigger buffer sizes
2673 
2674 	_E *_Pendsave, *_Seekhigh;
2675 	int _Alsize;
2676 	std::_Strstate _Strmode;
2677 	std::allocator<_E> _Al;
2678 };
2679 
2680 struct fast_ostringstream : public std::iostream
2681 {
2682 	typedef std::iostream super;
2683 
fast_ostringstreamfast_ostringstream2684 	explicit fast_ostringstream()
2685 		: super(&_Sb) {}
2686 
strfast_ostringstream2687 	std::string str() const
2688 		{return _Sb.str();}
2689 
2690 private:
2691 	fast_ostringbuffer _Sb;
2692 };
2693 
2694 #else
2695 
2696 typedef std::ostringstream fast_ostringstream;
2697 
2698 #endif
2699 
2700 
2701  /// XML document holder
2702 struct XMLDoc : public XMLNode
2703 {
XMLDocXMLDoc2704 	XMLDoc()
2705 	 :	XMLNode("")
2706 	{
2707 	}
2708 
XMLDocXMLDoc2709 	XMLDoc(LPCTSTR path)
2710 	 :	XMLNode("")
2711 	{
2712 		read_file(path);
2713 	}
2714 
2715 #ifdef XS_USE_XERCES
read_fileXMLDoc2716 	bool read_file(LPCTSTR path)
2717 	{
2718 		XMLReader reader(this, path);
2719 
2720 #if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8)
2721 		return read(reader, std::string(ANS(path)));
2722 #else
2723 		return read(reader, XS_String(path));
2724 #endif
2725 	}
2726 
2727 	bool read_buffer(const char* buffer, size_t len, const std::string& system_id=std::string())
2728 	{
2729 		XMLReader reader(this, (const XMLByte*)buffer, len, system_id);
2730 
2731 		return read(reader, system_id);
2732 	}
2733 
2734 	bool read_buffer(const std::string& in, const std::string& system_id=std::string())
2735 	{
2736 		return read_buffer(in.c_str(), in.length(), system_id);
2737 	}
2738 
2739 #else // XS_USE_XERCES
2740 
read_fileXMLDoc2741 	bool read_file(LPCTSTR path)
2742 	{
2743 		tifstream in(path);
2744 		if (!in.good())
2745 			return false;
2746 
2747 		XMLReader reader(this, in);
2748 
2749 #if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8)
2750 		return read(reader, std::string(ANS(path)));
2751 #else
2752 		return read(reader, XS_String(path));
2753 #endif
2754 	}
2755 
2756 	bool read_buffer(const char* buffer, size_t len, const std::string& system_id=std::string())
2757 	{
2758 		return read_buffer(std::string(buffer, len), system_id);
2759 	}
2760 
2761 	bool read_buffer(const std::string& buffer, const std::string& system_id=std::string())
2762 	{
2763 		std::istringstream istr(buffer);
2764 
2765 		return read_stream(istr, system_id);
2766 	}
2767 
2768 	bool read_stream(std::istream& in, const std::string& system_id=std::string())
2769 	{
2770 		XMLReader reader(this, in);
2771 
2772 		return read(reader, system_id);
2773 	}
2774 #endif // XS_USE_XERCES
2775 
readXMLDoc2776 	bool read(XMLReaderBase& reader, const std::string& display_path)
2777 	{
2778 #ifdef XMLNODE_LOCATION
2779 		 // make a string copy to handle temporary string objects
2780 		_display_path = display_path;
2781 		reader._display_path = _display_path.c_str();
2782 #endif
2783 
2784 		reader.clear_errors();
2785 		reader.read();
2786 
2787 		_format = reader.get_format();
2788 		_format._endl = reader.get_endl();
2789 
2790 		if (!reader.get_errors().empty()) {
2791 			_errors = reader.get_errors();
2792 			return false;
2793 		}
2794 
2795 		return true;
2796 	}
2797 
2798 	 /// write XML stream
2799 	 // FORMAT_SMART: preserving previous white space and comments
2800 	bool write(std::ostream& out, WRITE_MODE mode=FORMAT_SMART) const
2801 	{
2802 		_format.print_header(out, mode!=FORMAT_PLAIN);
2803 
2804 		if (_children.size() == 1)
2805 			_children.front()->write(out, _format, mode);
2806 		else if (!_children.empty()) {
2807 			//throw Exception("more than one XML root!");
2808 			return false;
2809 		}
2810 
2811 		return out.good();
2812 	}
2813 
2814 	 /// write XML stream with formating
write_formatingXMLDoc2815 	bool write_formating(std::ostream& out) const
2816 	{
2817 		return write(out, FORMAT_PRETTY);
2818 	}
2819 
2820 	bool write_file(LPCTSTR path, WRITE_MODE mode=FORMAT_SMART) const
2821 	{
2822 		tofstream out(path);
2823 
2824 		return write(out, mode);
2825 	}
2826 
write_formatingXMLDoc2827 	bool write_formating(LPCTSTR path) const
2828 	{
2829 		tofstream out(path);
2830 
2831 		return write_formating(out);
2832 	}
2833 
2834 	XMLFormat		_format;
2835 	XMLErrorList	_errors;
2836 
2837 #ifdef XMLNODE_LOCATION
2838 	std::string		_display_path;
2839 #endif
2840 };
2841 
2842 
2843  /// XML message wrapper
2844 struct XMLMessage : public XMLDoc
2845 {
XMLMessageXMLMessage2846 	XMLMessage(const char* name)
2847 	 :	_pos(this)
2848 	{
2849 		_pos.create(name);
2850 	}
2851 
toStringXMLMessage2852 	std::string toString() const
2853 	{
2854 		std::ostringstream out;
2855 
2856 		write(out);
2857 
2858 		return out.str();
2859 	}
2860 
2861 	XMLPos	_pos;
2862 
2863 protected:
XMLMessageXMLMessage2864 	XMLMessage()
2865 	 :	_pos(this)
2866 	{
2867 	}
2868 };
2869 
2870 
2871  /// helper structure to read XML messages from strings
2872 struct XMLMessageFromString : public XMLMessage
2873 {
2874 	XMLMessageFromString(const std::string& xml_str, const std::string& system_id=std::string())
2875 	{
2876 		read_buffer(xml_str.c_str(), xml_str.length(), system_id);
2877 	}
2878 };
2879 
2880 
2881  /// Reader for XML Messages
2882 struct XMLMessageReader : public XMLPos
2883 {
2884 	XMLMessageReader(const std::string& xml_str, const std::string& system_id=std::string())
2885 	 :	XMLPos(&_msg)
2886 	{
2887 		_msg.read_buffer(xml_str.c_str(), xml_str.length(), system_id);
2888 	}
2889 
get_documentXMLMessageReader2890 	const XMLDoc& get_document()
2891 	{
2892 		return _msg;
2893 	}
2894 
2895 protected:
2896 	XMLDoc	_msg;
2897 };
2898 
2899 
2900  /// on the fly XML writer
2901 struct XMLWriter
2902 {
2903 	XMLWriter(std::ostream& out, const XMLFormat& format=XMLFormat())
_pofstreamXMLWriter2904 	 :	_pofstream(NULL),
2905 		_out(out),
2906 		_format(format)
2907 	{
2908 		format.print_header(_out, false);	// _format._endl is printed in write_pre()
2909 	}
2910 
2911 	XMLWriter(LPCTSTR path, const XMLFormat& format=XMLFormat())
_pofstreamXMLWriter2912 	 :	_pofstream(new tofstream(path)),
2913 		_out(*_pofstream),
2914 		_format(format)
2915 	{
2916 		format.print_header(_out, false);	// _format._endl is printed in write_pre()
2917 	}
2918 
~XMLWriterXMLWriter2919 	~XMLWriter()
2920 	{
2921 		_out << _format._endl;
2922 		delete _pofstream;
2923 	}
2924 
2925 	 /// create node and move to it
2926 	void create(const XS_String& name);
2927 
2928 	 /// go back to previous position
2929 	bool back();
2930 
2931 	 /// attribute setting
putXMLWriter2932 	void put(const XS_String& attr_name, const XS_String& value)
2933 	{
2934 		if (!_stack.empty())
2935 			_stack.top()._attributes[attr_name] = value;
2936 	}
2937 
2938 	 /// index operator write access to an attribute
2939 	XS_String& operator[](const XS_String& attr_name)
2940 	{
2941 		if (_stack.empty())
2942 			return s_empty_attr;
2943 
2944 		return _stack.top()._attributes[attr_name];
2945 	}
2946 
2947 	void set_content(const XS_String& s, bool cdata=false)
2948 	{
2949 		if (!_stack.empty())
2950 			_stack.top()._content = EncodeXMLString(s.c_str(), cdata);
2951 	}
2952 
2953 	 /// create node with string content
create_node_contentXMLWriter2954 	void create_node_content(const XS_String& node_name, const XS_String& content)
2955 	{
2956 		create(node_name);
2957 			set_content(content);
2958 		back();
2959 	}
2960 
2961 	 // public for access in StackEntry
2962 	enum WRITESTATE {
2963 		NOTHING, /*PRE,*/ ATTRIBUTES, PRE_CLOSED, /*CONTENT,*/ POST
2964 	};
2965 
2966 protected:
2967 	tofstream*		_pofstream;
2968 	std::ostream&	_out;
2969 	XMLFormat		_format;
2970 
2971 	typedef XMLNode::AttributeMap AttrMap;
2972 
2973 	 /// container for XMLWriter state information
2974 	struct StackEntry {
2975 		XS_String	_node_name;
2976 		AttrMap		_attributes;
2977 		std::string	_content;
2978 		WRITESTATE	_state;
2979 		bool		_children;
2980 
StackEntryXMLWriter::StackEntry2981 		StackEntry() : _state(NOTHING), _children(false) {}
2982 	};
2983 
2984 	std::stack<StackEntry> _stack;
2985 
2986 	static XS_String s_empty_attr;
2987 
2988 	void close_pre(StackEntry& entry);
2989 	void write_pre(StackEntry& entry);
2990 	void write_attributes(StackEntry& entry);
2991 	void write_post(StackEntry& entry);
2992 };
2993 
2994 
2995 }	// namespace XMLStorage
2996 
2997 #define _XMLSTORAGE_H
2998 #endif // _XMLSTORAGE_H
2999