• Main Page
  • Namespaces
  • Classes
  • Files
  • Directories
  • File List
  • File Members

xmlstorage.h

Go to the documentation of this file.
00001 
00002  //
00003  // XML storage C++ classes version 1.6
00004  //
00005  // Copyright (c) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2014 Martin Fuchs <martin-fuchs@gmx.net>
00006  //
00007 
00008  /// \file xmlstorage.h
00009  /// XMLStorage header file
00010 
00011 
00012 /*
00013 
00014   All rights reserved.
00015 
00016   Redistribution and use in source and binary forms, with or without
00017   modification, are permitted provided that the following conditions are met:
00018 
00019   * Redistributions of source code must retain the above copyright
00020     notice, this list of conditions and the following disclaimer.
00021   * Redistributions in binary form must reproduce the above copyright
00022     notice, this list of conditions and the following disclaimer in
00023     the documentation and/or other materials provided with the
00024     distribution.
00025 
00026   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00027   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00028   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00029   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00030   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00031   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00032   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00033   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00034   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00035   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00036   POSSIBILITY OF SUCH DAMAGE.
00037 
00038 */
00039 
00040 #ifndef _XMLSTORAGE_H
00041 
00042 #ifndef XS_STRICT_XML_1_0
00043 //#define XS_STRICT_XML_1_0 // suppress characters invalid for the XML 1.0 specification
00044 #endif
00045 
00046 
00047 #ifdef UNICODE
00048 #ifndef _UNICODE
00049 #define _UNICODE
00050 #endif
00051 #else
00052 #ifdef _UNICODE
00053 #define UNICODE
00054 #endif
00055 #endif
00056 
00057 #ifndef _WIN32
00058 #ifdef UNICODE
00059 #error no UNICODE build in Unix version available
00060 #endif
00061 #ifndef XS_STRING_UTF8
00062 #define XS_STRING_UTF8
00063 #endif
00064 #endif
00065 
00066 
00067 #if _MSC_VER>=1400 // VS2005 or higher
00068 #ifndef _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
00069 #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES         1
00070 #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT   1
00071 #define _CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES           1
00072 #endif
00073 #endif
00074 
00075 
00076 #ifdef XS_USE_XERCES
00077 
00078 #ifndef UNICODE
00079 #ifndef XS_STRING_UTF8
00080 #define XS_STRING_UTF8
00081 #endif
00082 #endif
00083 
00084 #include <xercesc/parsers/SAXParser.hpp>
00085 #include <xercesc/sax/HandlerBase.hpp>
00086 
00087 using XERCES_CPP_NAMESPACE_QUALIFIER Locator;
00088 using XERCES_CPP_NAMESPACE_QUALIFIER SAXParser;
00089 using XERCES_CPP_NAMESPACE_QUALIFIER HandlerBase;
00090 using XERCES_CPP_NAMESPACE_QUALIFIER InputSource;
00091 using XERCES_CPP_NAMESPACE_QUALIFIER AttributeList;
00092 using XERCES_CPP_NAMESPACE_QUALIFIER SAXParseException;
00093 
00094 typedef XMLCh XML_Char;
00095 
00096 #elif defined(XS_USE_EXPAT)
00097 
00098 #include <expat/expat.h>
00099 
00100 #else
00101 #define XS_NATIVE
00102 #endif
00103 
00104 
00105 #ifdef _MSC_VER
00106 #pragma warning(disable: 4786)  // identifier was truncated to 'number' characters in the debug information
00107 
00108 #pragma warning(push)
00109 #pragma warning(disable: 4512) // assignment operator could not be generated
00110 
00111 #ifndef XS_NO_COMMENT
00112 
00113 #ifdef XS_USE_XERCES
00114 #ifdef _DEBUG
00115 #pragma comment(lib, "xerces-c_2D")
00116 #else
00117 #pragma comment(lib, "xerces-c_2")
00118 #endif
00119 #elif defined(XS_USE_EXPAT)
00120 #ifdef XML_STATIC
00121 #ifndef _DEBUG
00122 #pragma comment(lib, "libexpatMT")
00123 #endif
00124 #else
00125 #pragma comment(lib, "libexpat")
00126 #endif
00127 #endif
00128 
00129 #ifndef _STRING_DEFINED // _STRING_DEFINED only allowed if using xmlstorage.cpp embedded in the project
00130 #if defined(_DEBUG) && defined(_DLL)    // DEBUG version only supported with MSVCRTD
00131 #if _MSC_VER==1600 // VS2010
00132 #pragma comment(lib, "xmlstorage-vc10d")
00133 #elif _MSC_VER==1500 // VS2008
00134 #pragma comment(lib, "xmlstorage-vc9d")
00135 #elif _MSC_VER==1400 // VS2005
00136 #pragma comment(lib, "xmlstorage-vc8d")
00137 #else
00138 #pragma comment(lib, "xmlstorage-vc6d")
00139 #endif
00140 #else
00141 #ifdef _DLL
00142 #if _MSC_VER==1600 // VS2010
00143 #pragma comment(lib, "xmlstorage-vc10")
00144 #elif _MSC_VER==1500 // VS2008
00145 #pragma comment(lib, "xmlstorage-vc9")
00146 #elif _MSC_VER==1400 // VS2005
00147 #pragma comment(lib, "xmlstorage-vc8")
00148 #else
00149 #pragma comment(lib, "xmlstorage-vc6")
00150 #endif
00151 #elif defined(_MT)
00152 #if _MSC_VER==1600 // VS2010
00153 #pragma comment(lib, "xmlstorage-vc10t")
00154 #elif _MSC_VER==1500 // VS2008
00155 #pragma comment(lib, "xmlstorage-vc9t")
00156 #elif _MSC_VER==1400 // VS2005
00157 #pragma comment(lib, "xmlstorage-vc8t")
00158 #else
00159 #pragma comment(lib, "xmlstorage-vc6t")
00160 #endif
00161 #else
00162  // -ML is no more supported since VS2005.
00163 #pragma comment(lib, "xmlstorage-vc6l")
00164 #endif
00165 #endif
00166 #endif // _STRING_DEFINED
00167 
00168 #endif // XS_NO_COMMENT
00169 
00170 #endif // _MSC_VER
00171 
00172 
00173 #ifdef _WIN32
00174 
00175 #include <windows.h>    // for LPCTSTR
00176 #include <tchar.h>
00177 #include <malloc.h>
00178 
00179 #ifndef _MSC_VER
00180 #include <stdio.h>  // vsnprintf(), snprintf()
00181 #endif
00182 
00183 #else // _WIN32
00184 
00185 #include <wchar.h>
00186 #include <stdlib.h>
00187 #include <string.h> // strcasecmp()
00188 #include <stdarg.h>
00189 #include <alloca.h> // alloca()
00190 
00191 typedef char CHAR;
00192 #ifdef _WCHAR_T_DEFINED
00193 #define __wchar_t wchar_t
00194 #endif
00195 
00196 typedef __wchar_t WCHAR;
00197 typedef unsigned char UCHAR;
00198 typedef char* LPSTR;
00199 typedef const char* LPCSTR;
00200 typedef WCHAR* LPWSTR;
00201 typedef const WCHAR* LPCWSTR;
00202 
00203 #ifndef UNICODE
00204 #define TEXT(x) x
00205 typedef char TCHAR;
00206 typedef unsigned char _TUCHAR;
00207 typedef CHAR* PTSTR;
00208 typedef CHAR* LPTSTR;
00209 typedef const CHAR* LPCTSTR;
00210 
00211 #define _ttoi atoi
00212 #define _tfopen fopen
00213 #define _tcstod strtod
00214 #define _tcslen strlen
00215 #define _tcschr strchr
00216 #define _tcsstr strstr
00217 #define _snprintf snprintf
00218 #define _sntprintf snprintf
00219 #define _vsnprintf vsnprintf
00220 #define _vsntprintf vsnprintf
00221 #define _stricmp strcasecmp
00222 #define _tcsicmp strcasecmp
00223 #define strnicmp strncasecmp
00224 #define _tcsnicmp strncasecmp
00225 #endif // UNICODE
00226 
00227 #endif // _WIN32
00228 
00229 #include <assert.h>
00230 
00231 #ifdef __BORLANDC__
00232 #define _stricmp stricmp
00233 #endif
00234 
00235 
00236 #include <fstream>
00237 #include <sstream>
00238 #include <string>
00239 #include <stack>
00240 #include <list>
00241 #include <map>
00242 
00243 
00244 #ifndef BUFFER_LEN
00245 #define BUFFER_LEN 2048
00246 #endif
00247 
00248 #define BUFFER_HUGE 0x7F80
00249 
00250 #ifndef ALLOCA_MAX
00251 #define ALLOCA_MAX 0x10000
00252 #endif
00253 
00254 
00255 namespace XMLStorage {
00256 
00257 
00258 #ifndef XS_String
00259 
00260 #ifdef XS_STRING_UTF8
00261 #define XS_CHAR char
00262 #define XS_TEXT(x) x
00263 #define LPXSSTR LPSTR
00264 #define LPCXSSTR LPCSTR
00265 #define XS_cmp strcmp
00266 #define XS_icmp _stricmp
00267 #define XS_ncmp strncmp
00268 #define XS_nicmp strnicmp
00269 #define XS_toi atoi
00270 #define XS_toi64 _atoi64
00271 #define XS_tod strtod
00272 #define XS_len strlen
00273 #define XS_snprintf _snprintf
00274 #define XS_vsnprintf _vsnprintf
00275 #define XS_vsnprintf_s _vsnprintf_s
00276 #define XS_strstr strstr
00277 #else
00278 #define XS_CHAR TCHAR
00279 #define XS_TEXT(x) TEXT(x)
00280 #define LPXSSTR LPTSTR
00281 #define LPCXSSTR LPCTSTR
00282 #define XS_cmp _tcscmp
00283 #define XS_icmp _tcsicmp
00284 #define XS_ncmp _tcsncmp
00285 #define XS_nicmp _tcsnicmp
00286 #define XS_toi _ttoi
00287 #define XS_toi64 _ttoi64
00288 #define XS_tod _tcstod
00289 #define XS_len _tcslen
00290 #define XS_snprintf _sntprintf
00291 #define XS_vsnprintf _vsntprintf
00292 #define XS_vsnprintf_s _vsntprintf_s
00293 #define XS_strstr _tcsstr
00294 #endif
00295 
00296 #ifndef COUNTOF
00297 #if _MSC_VER>=1400 // VS2005 or higher
00298 #define COUNTOF _countof
00299 #else
00300 #define COUNTOF(b) (sizeof(b)/sizeof(b[0]))
00301 #endif
00302 #endif
00303 
00304 #ifndef _MSC_VER
00305 typedef long long INT64;
00306 typedef unsigned long long UINT64;
00307 #define _atoi64 atoll
00308 #endif
00309 
00310 
00311  // manage a locally allocated heap pointer
00312 struct TmpHeap
00313 {
00314     TmpHeap()
00315     {
00316         _pHeap = NULL;
00317     }
00318 
00319     ~TmpHeap()
00320     {
00321         if (_pHeap)
00322             free(_pHeap);
00323     }
00324 
00325     void operator=(void* p)
00326     {
00327         _pHeap = p;
00328     }
00329 
00330 private:
00331     void*   _pHeap;
00332 };
00333 
00334  // temporary memory allocation using alloca() or malloc() for bigger buffer sizes
00335 #define TMP_ALLOC(T, b, h, l) \
00336 TmpHeap h; T* b; \
00337 if (l <= ALLOCA_MAX) b = (T*)alloca(sizeof(T)*l); \
00338 else h = b = (T*)malloc(sizeof(T)*l)
00339 
00340 
00341 extern const char* get_xmlsym_end_utf8(const char* p);
00342 
00343 
00344 #if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8)
00345 
00346 #define XS_String String
00347 
00348 #else // _STRING_DEFINED, !XS_STRING_UTF8
00349 
00350  /// string class for TCHAR strings
00351 
00352 struct XS_String
00353 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
00354  : public std::wstring
00355 #else
00356  : public std::string
00357 #endif
00358 {
00359 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
00360     typedef std::wstring super;
00361 #else
00362     typedef std::string super;
00363 #endif
00364 
00365     XS_String() {}
00366 
00367     XS_String(LPCXSSTR s) {if (s) super::assign(s);}
00368     XS_String(LPCXSSTR s, size_t l) : super(s, l) {}
00369 
00370     XS_String(const super& other) : super(other) {}
00371     XS_String(const XS_String& other) : super(other) {}
00372 
00373 #ifdef _WIN32
00374 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
00375     XS_String(LPCSTR s) {assign(s);}
00376     XS_String(LPCSTR s, size_t l) {assign(s, l);}
00377     XS_String(const std::string& s) {assign(s.c_str());}
00378     XS_String& operator=(LPCSTR s) {assign(s); return *this;}
00379     void assign(LPCSTR s) {if (s) {size_t bl=strlen(s); TMP_ALLOC(WCHAR, b, h, bl); if (b) super::assign(b, MultiByteToWideChar(CP_ACP, 0, s, (int)bl, b, (int)bl));} else erase();}
00380     void assign(LPCSTR s, size_t l) {if (s) {size_t bl=l; TMP_ALLOC(WCHAR, b, h, bl); if (b) super::assign(b, MultiByteToWideChar(CP_ACP, 0, s, (int)l, b, (int)bl));} else erase();}
00381 #else
00382     XS_String(LPCWSTR s) {assign(s);}
00383     XS_String(LPCWSTR s, size_t l) {assign(s, l);}
00384     XS_String(const std::wstring& ws) {assign(ws.c_str());}
00385     XS_String& operator=(LPCWSTR s) {assign(s); return *this;}
00386 #ifdef XS_STRING_UTF8
00387     void assign(LPCWSTR s) {if (s) {size_t bl=4*wcslen(s); TMP_ALLOC(char, b, h, bl); if (b) super::assign(b, WideCharToMultiByte(CP_UTF8, 0, s, (int)bl, b, (int)bl, 0, 0));} else erase();}
00388     void assign(LPCWSTR s, size_t l) {if (s) {size_t bl=4*l; TMP_ALLOC(char, b, h, bl); if (b) super::assign(b, WideCharToMultiByte(CP_UTF8, 0, s, (int)l, b, (int)bl, 0, 0));} else erase();}
00389 #else // if !UNICODE && !XS_STRING_UTF8
00390     void assign(LPCWSTR s) {if (s) {size_t bl=wcslen(s); TMP_ALLOC(char, b, h, bl); if (b) super::assign(b, WideCharToMultiByte(CP_ACP, 0, s, (int)bl, b, (int)bl, 0, 0));} else erase();}
00391     void assign(LPCWSTR s, size_t l) {if (s) {size_t bl=l; TMP_ALLOC(char, b, h, bl); if (b) super::assign(b, WideCharToMultiByte(CP_ACP, 0, s, (int)l, b, (int)bl, 0, 0));} else erase();}
00392 #endif
00393 #endif
00394 #endif // _WIN32
00395 
00396 #ifdef __ISSD_H
00397 //  XS_String(const _ISSD RString& s) {assign(s.c_str());}
00398 //  void assign(const _ISSD RString& s) {assign(s.c_str());}
00399     XS_String& operator=(const _ISSD RString& s) {assign(s); return *this;}
00400 #endif
00401 
00402 #ifdef XS_STRING_UTF8
00403     void assign(const XS_String& s) {assign(s.c_str());}
00404 #endif
00405 
00406     XS_String& operator=(LPCXSSTR s) {if (s) super::assign(s); else erase(); return *this;}
00407     XS_String& operator=(const super& s) {super::assign(s); return *this;}
00408     void assign(LPCXSSTR s) {super::assign(s);}
00409     void assign(LPCXSSTR s, size_t l) {super::assign(s, l);}
00410 
00411     operator LPCXSSTR() const {return c_str();}
00412 
00413 #ifdef _WIN32
00414 #ifdef XS_STRING_UTF8
00415     operator std::wstring() const {size_t bl=length(); TMP_ALLOC(WCHAR, b, h, bl); return b? std::wstring(b, MultiByteToWideChar(CP_UTF8, 0, c_str(), bl, b, bl)): std::wstring();}
00416 #elif defined(UNICODE)
00417     operator std::string() const {size_t bl=length(); TMP_ALLOC(char, b, h, bl); return b? std::string(b, WideCharToMultiByte(CP_ACP, 0, c_str(), (int)bl, b, (int)bl, 0, 0)): std::string();}
00418 #else
00419     operator std::wstring() const {size_t bl=length(); TMP_ALLOC(WCHAR, b, h, bl); return b? std::wstring(b, MultiByteToWideChar(CP_ACP, 0, c_str(), (int)bl, b, (int)bl)): std::wstring();}
00420 #endif
00421 #endif
00422 
00423     XS_String& printf(LPCXSSTR fmt, ...)
00424     {
00425         va_list vl;
00426 
00427         va_start(vl, fmt);
00428         vprintf(fmt, vl);
00429         va_end(vl);
00430 
00431         return *this;
00432     }
00433 
00434     XS_String& vprintf(LPCXSSTR fmt, va_list vl)
00435     {
00436         XS_CHAR b[BUFFER_LEN];
00437 
00438         int l = XS_vsnprintf(b, COUNTOF(b), fmt, vl);
00439 
00440         if (l >= 0)
00441             super::assign(b, l);
00442         else {
00443             LPTSTR p = (LPTSTR)malloc(sizeof(TCHAR)*BUFFER_HUGE);
00444 
00445             if (p) {
00446 #ifdef __STDC_WANT_SECURE_LIB__
00447                 l = XS_vsnprintf_s(p, BUFFER_HUGE, _TRUNCATE, fmt, vl);
00448 #else
00449                 l = XS_vsnprintf(p, BUFFER_HUGE, fmt, vl);
00450 #endif
00451                 if (l >= 0)
00452                     super::assign(p, l);
00453                 else
00454                     super::assign(fmt); // snprintf() failed
00455 
00456                 free(p);
00457             } else
00458                 super::assign(fmt); // malloc() failed
00459         }
00460 
00461         return *this;
00462     }
00463 
00464     XS_String& appendf(LPCXSSTR fmt, ...)
00465     {
00466         va_list vl;
00467 
00468         va_start(vl, fmt);
00469         vappendf(fmt, vl);
00470         va_end(vl);
00471 
00472         return *this;
00473     }
00474 
00475     XS_String& vappendf(LPCXSSTR fmt, va_list vl)
00476     {
00477         XS_CHAR b[BUFFER_LEN];
00478 
00479         int l = XS_vsnprintf(b, COUNTOF(b), fmt, vl);
00480 
00481         if (l >= 0)
00482             super::append(b, l);
00483         else {
00484             LPTSTR p = (LPTSTR)malloc(sizeof(TCHAR)*BUFFER_HUGE);
00485 
00486             if (p) {
00487 #ifdef __STDC_WANT_SECURE_LIB__
00488                 l = XS_vsnprintf_s(p, BUFFER_HUGE, _TRUNCATE, fmt, vl);
00489 #else
00490                 l = XS_vsnprintf(p, BUFFER_HUGE, fmt, vl);
00491 #endif
00492                 if (l >= 0)
00493                     super::append(p, l);
00494                 else
00495                     super::append(fmt); // snprintf() failed
00496 
00497                 free(p);
00498             } else
00499                 super::append(fmt); // malloc() failed
00500         }
00501 
00502         return *this;
00503     }
00504 };
00505 
00506 #endif // _STRING_DEFINED, !XS_STRING_UTF8
00507 
00508 #endif // XS_String
00509 
00510 
00511 #define XS_EMPTY_STR XS_TEXT("")
00512 #define XS_TRUE_STR XS_TEXT("true")
00513 #define XS_FALSE_STR XS_TEXT("false")
00514 #define XS_INTFMT_STR XS_TEXT("%d")
00515 #define XS_INT64FMT_STR XS_TEXT("%I64d")
00516 #define XS_FLOATFMT_STR XS_TEXT("%f")
00517 
00518 #define XS_KEY_STR XS_TEXT("key")
00519 #define XS_VALUE_STR XS_TEXT("value")
00520 #define XS_PROPERTY_STR XS_TEXT("property")
00521 
00522  // work around GCC's wide string constant bug
00523 #ifdef __GNUC__
00524 extern const LPCXSSTR XS_EMPTY;
00525 extern const LPCXSSTR XS_TRUE;
00526 extern const LPCXSSTR XS_FALSE;
00527 extern const LPCXSSTR XS_INTFMT;
00528 extern const LPCXSSTR XS_INT64FMT;
00529 extern const LPCXSSTR XS_FLOATFMT;
00530 #else
00531 #define XS_EMPTY XS_EMPTY_STR
00532 #define XS_TRUE XS_TRUE_STR
00533 #define XS_FALSE XS_FALSE_STR
00534 #define XS_INTFMT XS_INTFMT_STR
00535 #define XS_INT64FMT XS_INT64FMT_STR
00536 #define XS_FLOATFMT XS_FLOATFMT_STR
00537 #endif
00538 
00539 extern const XS_String XS_KEY;
00540 extern const XS_String XS_VALUE;
00541 extern const XS_String XS_PROPERTY;
00542 
00543 #define CDATA_START "<![CDATA["
00544 #define CDATA_END "]]>"
00545 
00546 
00547 #ifndef _MSC_VER
00548 inline int _istspace(TCHAR c)
00549 {
00550 #ifdef UNICODE
00551     return u_isspace(c);
00552 #else
00553     return isspace(c);
00554 #endif
00555 }
00556 #endif
00557 
00558 inline LPCXSSTR safe_skip_space(LPCXSSTR s)
00559 {
00560     if (s) {
00561          // strip leading white space
00562         while(_istspace(*s))
00563             ++s;
00564 
00565         return s;
00566     } else
00567         return XS_EMPTY_STR;
00568 }
00569 
00570 
00571 #ifdef XS_STRING_UTF8
00572 
00573 template<typename T> inline XS_String from_utf8(const T& s)
00574 {
00575     return s;
00576 }
00577 
00578 inline XS_String from_utf8(const char* s, size_t l)
00579 {
00580     return XS_String(s, l);
00581 }
00582 
00583 #else
00584 
00585  // from UTF-8 to XS internal string encoding
00586 inline void assign_utf8(XS_String& s, const char* str, size_t lutf8)
00587 {
00588     int l;
00589 
00590     // Benutzung von malloc() für Strings größer als BUFFER_LEN
00591 #ifdef UNICODE
00592     TMP_ALLOC(TCHAR, buffer, h, lutf8);
00593     l = buffer? MultiByteToWideChar(CP_UTF8, 0, str, (int)lutf8, buffer, (int)lutf8): 0;
00594 #else
00595     TMP_ALLOC(WCHAR, wbuffer, hw, lutf8);
00596     l = wbuffer? MultiByteToWideChar(CP_UTF8, 0, str, (int)lutf8, wbuffer, (int)lutf8): 0;
00597 
00598     int bl = 2*l;
00599     TMP_ALLOC(char, buffer, h, bl);
00600     l = wbuffer && buffer? WideCharToMultiByte(CP_ACP, 0, wbuffer, l, buffer, bl, 0, 0): 0;
00601 #endif
00602 
00603     if (buffer)
00604         s.assign(buffer, l);
00605 }
00606 
00607  // from UTF-8 to XS internal string encoding
00608 inline void assign_utf8(XS_String& s, const char* str)
00609 {
00610     assign_utf8(s, str, strlen(str));
00611 }
00612 
00613  // from XS internal string encoding to UTF-8
00614 inline std::string get_utf8(LPCTSTR s, size_t l)
00615 {
00616 #ifdef UNICODE
00617     size_t bl = 4*l;
00618     TMP_ALLOC(char, buffer, h, bl);
00619     l = buffer? WideCharToMultiByte(CP_UTF8, 0, s, (int)l, buffer, (int)bl, 0, 0): 0;
00620 #else
00621     TMP_ALLOC(WCHAR, wbuffer, hw, l);
00622     l = wbuffer? MultiByteToWideChar(CP_ACP, 0, s, (int)l, wbuffer, (int)l): 0;
00623 
00624     size_t bl = 4*l;
00625     TMP_ALLOC(char, buffer, h, bl);
00626     l = wbuffer && buffer? WideCharToMultiByte(CP_UTF8, 0, wbuffer, (int)l, buffer, (int)bl, 0, 0): 0;
00627 #endif
00628 
00629     return buffer? std::string(buffer, l): std::string();
00630 }
00631 
00632 #ifdef UNICODE
00633  // from XS internal string encoding to UTF-8
00634 inline std::string get_utf8(const char* s, size_t l)
00635 {
00636     TMP_ALLOC(WCHAR, wbuffer, wh, l);
00637     l = wbuffer? MultiByteToWideChar(CP_ACP, 0, s, (int)l, wbuffer, (int)l): 0;
00638 
00639     size_t bl = 4*l;
00640     TMP_ALLOC(char, buffer, h, bl);
00641     l = buffer? WideCharToMultiByte(CP_UTF8, 0, wbuffer, (int)l, buffer, (int)bl, 0, 0): 0;
00642 
00643     return wbuffer && buffer? std::string(buffer, l): std::string();
00644 }
00645 #endif
00646 
00647  // from XS internal string encoding to UTF-8
00648 inline std::string get_utf8(const XS_String& s)
00649 {
00650     return get_utf8(s.c_str(), s.length());
00651 }
00652 
00653 inline XS_String from_utf8(const char* s)
00654 {
00655     XS_String ret;
00656     assign_utf8(ret, s, strlen(s));
00657     return ret;
00658 }
00659 
00660 inline XS_String from_utf8(const std::string& s)
00661 {
00662     XS_String ret;
00663     assign_utf8(ret, s.c_str(), s.length());
00664     return ret;
00665 }
00666 
00667 inline XS_String from_utf8(const char* s, size_t l)
00668 {
00669     XS_String ret;
00670     assign_utf8(ret, s, l);
00671     return ret;
00672 }
00673 
00674 #endif // XS_STRING_UTF8
00675 
00676 extern std::string EncodeXMLString(const XS_String& str, bool cdata=false);
00677 extern XS_String DecodeXMLString(const std::string& str_utf8);
00678 
00679 
00680 #ifdef __GNUC__
00681 #include <ext/stdio_filebuf.h>
00682 #define FILE_FILEBUF __gnu_cxx::stdio_filebuf<char>
00683 #elif defined(_MSC_VER)
00684 #define FILE_FILEBUF std::filebuf
00685 #endif
00686 
00687 #ifdef FILE_FILEBUF
00688 
00689  /// base class for XMLStorage::tifstream and XMLStorage::tofstream
00690 struct FileHolder
00691 {
00692     FileHolder(LPCTSTR path, LPCTSTR mode)
00693      :  _own_file(true)
00694     {
00695 #ifdef __STDC_WANT_SECURE_LIB__ // secure CRT functions using VS 2005
00696         if (_tfopen_s(&_pfile, path, mode) != 0)
00697             _pfile = NULL;
00698 #else
00699         _pfile = _tfopen(path, mode);
00700 #endif
00701     }
00702 
00703     FileHolder(FILE* pfile)
00704      :  _pfile(pfile),
00705         _own_file(false)
00706     {
00707     }
00708 
00709     ~FileHolder()
00710     {
00711         if (_own_file && _pfile)
00712             fclose(_pfile);
00713     }
00714 
00715     operator FILE*() {return _pfile;}
00716 
00717 protected:
00718     FILE*   _pfile;
00719     bool    _own_file;
00720 };
00721 
00722  /// input file stream with ANSI/UNICODE file names
00723 struct tifstream : public std::istream, FileHolder
00724 {
00725     typedef std::istream super;
00726 
00727     tifstream(LPCTSTR path)
00728      :  super(&_buf),
00729         FileHolder(path, TEXT("rb")),   // binary mode is important for XMLReader::read_buffer() with MinGW libraries
00730 #ifdef __GNUC__
00731         _buf(_pfile, std::ios::in)
00732 #else
00733         _buf(_pfile)
00734 #endif
00735     {
00736         if (!_pfile)
00737             setstate(badbit);
00738     }
00739 
00740 protected:
00741     FILE_FILEBUF _buf;
00742 };
00743 
00744  /// output file stream with ANSI/UNICODE file names
00745 struct tofstream : public std::ostream, FileHolder
00746 {
00747     typedef std::ostream super;
00748 
00749     tofstream(LPCTSTR path, LPCTSTR mode=TEXT("wb"))
00750      :  super(&_buf),
00751         FileHolder(path, mode),
00752 #ifdef __GNUC__
00753         _buf(_pfile, std::ios::out)
00754 #else
00755         _buf(_pfile)
00756 #endif
00757     {
00758         if (!_pfile)
00759             setstate(badbit);
00760     }
00761 
00762     tofstream(FILE* pFile)
00763      :  super(&_buf),
00764         FileHolder(pFile),
00765 #ifdef __GNUC__
00766         _buf(_pfile, std::ios::out)
00767 #else
00768         _buf(_pfile)
00769 #endif
00770     {
00771         if (!_pfile)
00772             setstate(badbit);
00773     }
00774 
00775     ~tofstream()
00776     {
00777         flush();
00778     }
00779 
00780 protected:
00781     FILE_FILEBUF _buf;
00782 };
00783 
00784 #else // FILE_FILEBUF
00785 
00786 #ifdef UNICODE
00787 #error UNICODE not supported for this platform
00788 #endif
00789 
00790 struct tifstream : public std::ifstream
00791 {
00792     typedef std::ifstream super;
00793 
00794     tifstream(const char* path)
00795      : super(path, std::ios::in|std::ios::binary)
00796     {
00797     }
00798 };
00799 
00800 struct tofstream : public std::ofstream
00801 {
00802     typedef std::ofstream super;
00803 
00804     tofstream(const char* path)
00805      : super(path, std::ios::out|std::ios::binary)
00806     {
00807     }
00808 };
00809 
00810 #endif
00811 
00812 
00813  // write XML files with 2 spaces indenting
00814 #define XML_INDENT_SPACE "  "
00815 
00816 
00817 #if defined(XS_USE_XERCES) || defined(XS_USE_EXPAT)
00818 
00819 #if defined(XML_UNICODE)/*Expat*/ || defined(XS_USE_XERCES)/*Xerces*/   // Are Expat/Xerces XML strings UTF-16 encoded?
00820 typedef XS_String String_from_XML_Char;
00821 
00822 #elif defined(XS_STRING_UTF8)
00823 typedef XS_String String_from_XML_Char;
00824 
00825 #else
00826 
00827  /// converter from Expat/Xerces strings to XMLStorage internal strings
00828 struct String_from_XML_Char : public XS_String
00829 {
00830     String_from_XML_Char(const XML_Char* str)
00831     {
00832         assign_utf8(*this, str);
00833     }
00834 };
00835 
00836 #endif
00837 
00838 #endif // defined(XS_USE_XERCES) || defined(XS_USE_EXPAT)
00839 
00840 
00841 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
00842 
00843  // optimization for faster UNICODE/ASCII string comparison without temporary A/U conversion
00844 inline bool operator==(const XS_String& s1, const char* s2)
00845 {
00846     LPCWSTR p = s1;
00847     const unsigned char* q = (const unsigned char*)s2;
00848 
00849     while(*p && *q)
00850         if (*p++ != *q++)
00851             return false;
00852 
00853     return *p == *q;
00854 };
00855 
00856 #endif
00857 
00858 
00859 #if defined(XS_NATIVE) || defined(XMLNODE_LOCATION)
00860  /// location of XML Node including XML file name
00861 struct XMLLocation
00862 {
00863     XMLLocation()
00864      :  _pdisplay_path(NULL),
00865         _line(0),
00866         _column(0)
00867     {
00868     }
00869 
00870     XMLLocation(const char* display_path, int line, int column)
00871      :  _pdisplay_path(display_path),
00872         _line(line),
00873         _column(column)
00874     {
00875     }
00876 
00877     std::string str() const;
00878 
00879     const char* get_path() const {return _pdisplay_path? _pdisplay_path: "";}
00880     int get_line() const {return _line;}
00881     int get_column() const {return _column;}
00882 
00883     void set_path(const char* path)
00884     {
00885         _pdisplay_path = path;
00886         _line = 1;
00887         _column = 1;
00888     }
00889 
00890 protected:
00891     const char* _pdisplay_path; // character pointer for fast reference
00892     int _line;
00893     int _column;
00894 
00895     friend struct XMLReader;
00896 };
00897 #endif
00898 
00899 
00900  /// XML Error with message and location
00901 struct XMLError
00902 {
00903     XMLError()
00904      :  _line(0),
00905         _column(0),
00906         _error_code(0)
00907     {
00908     }
00909 
00910     XMLError(const char* msg)
00911      :  _line(0),
00912         _column(0),
00913         _error_code(0),
00914         _message(msg)
00915     {
00916     }
00917 
00918     XMLError(const XMLLocation& location, const char* msg)
00919      :  _systemId(location.get_path()),
00920         _line(location.get_line()),
00921         _column(location.get_column()),
00922         _error_code(0),
00923         _message(msg)
00924     {
00925     }
00926 
00927     std::string str() const;
00928 
00929     friend std::ostream& operator<<(std::ostream&, const XMLError& err);
00930 
00931     std::string _message;
00932     std::string _systemId;
00933     int _line;
00934     int _column;
00935     int _error_code;
00936 };
00937 
00938  /// list of XMLError entries
00939 struct XMLErrorList : public std::list<XMLError>
00940 {
00941     XS_String str(const char* del="\n") const;
00942 };
00943 
00944 
00945 enum PRETTY_FLAGS {
00946     PRETTY_PLAIN    = 0,
00947     PRETTY_LINEFEED = 1,
00948     PRETTY_INDENT   = 2
00949 };
00950 
00951 
00952  /// XML Stylesheet entry
00953 struct StyleSheet
00954 {
00955     std::string _href;      // CDATA #REQUIRED
00956     std::string _type;      // CDATA #REQUIRED
00957     std::string _title;     // CDATA #IMPLIED
00958     std::string _media;     // CDATA #IMPLIED
00959     std::string _charset;   // CDATA #IMPLIED
00960     bool        _alternate; // (yes|no) "no"
00961 
00962     StyleSheet() : _alternate(false) {}
00963 
00964     StyleSheet(const std::string& href, const std::string& type="text/xsl", bool alternate=false)
00965      :  _href(href),
00966         _type(type),
00967         _alternate(alternate)
00968     {
00969     }
00970 
00971     bool empty() const {return _href.empty();}
00972     void print(std::ostream& out) const;
00973 };
00974 
00975  /// list of StyleSheet entries
00976 struct StyleSheetList : public std::list<StyleSheet>
00977 {
00978     void set(const StyleSheet& stylesheet)
00979     {
00980         clear();
00981         push_back(stylesheet);
00982     }
00983 };
00984 
00985 
00986  /// XML document type description
00987 struct DocType
00988 {
00989     std::string _name;
00990 
00991      // External Document Types are noted, but not parsed.
00992     std::string _public;
00993     std::string _system;
00994 
00995      // Internal DTDs are not supported.
00996 
00997     void parse(const char* str);
00998     bool empty() const {return _name.empty();}
00999 };
01000 
01001  /// Management of XML file headers and formating
01002 struct XMLFormat
01003 {
01004     XMLFormat(PRETTY_FLAGS pretty=PRETTY_INDENT, const std::string& encoding="utf-8", const DocType& doctype=DocType()
01005 #ifndef XS_STRICT_XML_1_0
01006             , const std::string& xml_version="1.0"
01007 #endif
01008     )
01009      :  _pretty(pretty),
01010         _endl("\n"),
01011 #ifdef XS_STRICT_XML_1_0
01012         _version("1.0"),
01013 #else
01014         _version(xml_version),
01015 #endif
01016         _encoding(encoding),
01017         _utf8_bom(false),
01018         _inhibit_header(false),
01019         _doctype(doctype),
01020         _standalone(-1)
01021     {
01022     }
01023 
01024     XMLFormat(PRETTY_FLAGS pretty, bool utf8_bom, const DocType& doctype=DocType())
01025      :  _pretty(pretty),
01026         _endl("\n"),
01027         _version("1.0"),
01028         _encoding("utf-8"),
01029         _utf8_bom(utf8_bom),
01030         _inhibit_header(false),
01031         _doctype(doctype),
01032         _standalone(-1)
01033     {
01034     }
01035 
01036     void print_header(std::ostream& out, bool lf=true) const;
01037 
01038     PRETTY_FLAGS _pretty;
01039     const char* _endl;      // line ending string: "\n" or "\r\n"
01040 
01041     std::string _version;
01042     std::string _encoding;
01043     bool        _utf8_bom;
01044     bool        _inhibit_header;
01045 
01046     DocType     _doctype;
01047 
01048     StyleSheetList _stylesheets;
01049 
01050 //  std::string _additional;
01051 
01052     int     _standalone;
01053 };
01054 
01055 struct HeaderlessXMLFormat : public XMLFormat
01056 {
01057     HeaderlessXMLFormat(PRETTY_FLAGS pretty=PRETTY_INDENT)
01058      :  XMLFormat(pretty)
01059     {
01060         _inhibit_header = true;
01061     }
01062 };
01063 
01064 
01065 enum WRITE_MODE {
01066     FORMAT_PLAIN,       /// write XML without any white space
01067     FORMAT_SMART,       /// preserve original white space and comments if present; pretty print otherwise
01068     FORMAT_ORIGINAL,    /// write XML stream preserving original white space and comments
01069     FORMAT_PRETTY       /// pretty print node to stream without preserving original white space
01070 };
01071 
01072 
01073 #if 1
01074 
01075  // XS_StringMap node
01076 struct XS_SMNode
01077 {
01078     XS_SMNode(const XS_String& key)
01079      :  first(key),
01080         _pNext(NULL)
01081     {
01082     }
01083 
01084      // copy a chain of XS_SMNode objects
01085     XS_SMNode(const XS_SMNode& other)
01086      :  first(other.first),
01087         second(other.second)
01088     {
01089         if (other._pNext)
01090             _pNext = new XS_SMNode(*other._pNext);
01091         else
01092             _pNext = NULL;
01093     }
01094 
01095     ~XS_SMNode()
01096     {
01097         delete _pNext;
01098     }
01099 
01100     XS_String   first;
01101     XS_String   second;
01102 
01103     XS_SMNode*  _pNext;
01104 
01105 private:
01106     XS_SMNode& operator=(const XS_SMNode&); // disallow assignment operations
01107 };
01108 
01109  // optimized string map for small numbers of values implemented as sorted linked list
01110 struct XS_StringMap
01111 {
01112     typedef XS_String key_type;
01113     typedef XS_String value_type;
01114 
01115     struct iterator
01116     {
01117         iterator(XS_SMNode* ptr)
01118          :  _ptr(ptr)
01119         {
01120         }
01121 
01122         operator bool() const
01123         {
01124             return _ptr != NULL;
01125         }
01126 
01127         XS_SMNode* operator->()
01128         {
01129             return _ptr;
01130         }
01131 
01132         const XS_SMNode* operator->() const
01133         {
01134             return _ptr;
01135         }
01136 
01137         void operator++()
01138         {
01139             _ptr = _ptr->_pNext;
01140         }
01141 
01142         XS_SMNode* ptr()
01143         {
01144             return _ptr;
01145         }
01146 
01147         const XS_SMNode* ptr() const
01148         {
01149             return _ptr;
01150         }
01151 
01152         XS_SMNode& operator*()
01153         {
01154             return *_ptr;
01155         }
01156 
01157         const XS_SMNode& operator*() const
01158         {
01159             return *_ptr;
01160         }
01161 
01162     private:
01163         XS_SMNode*  _ptr;
01164     };
01165 
01166     struct const_iterator
01167     {
01168         const_iterator(const XS_SMNode* ptr)
01169          :  _ptr(ptr)
01170         {
01171         }
01172 
01173         const_iterator(const iterator& it)
01174          :  _ptr(it.ptr())
01175         {
01176         }
01177 
01178         operator bool() const
01179         {
01180             return _ptr != NULL;
01181         }
01182 
01183         const XS_SMNode* operator->() const
01184         {
01185             return _ptr;
01186         }
01187 
01188         void operator++()
01189         {
01190             _ptr = _ptr->_pNext;
01191         }
01192 
01193         const XS_SMNode* ptr() const
01194         {
01195             return _ptr;
01196         }
01197 
01198         const XS_SMNode& operator*() const
01199         {
01200             return *_ptr;
01201         }
01202 
01203     private:
01204         const XS_SMNode* _ptr;
01205     };
01206 
01207     XS_StringMap()
01208      :  _firstNode(NULL)
01209     {
01210     }
01211 
01212     XS_StringMap(const XS_StringMap& other)
01213      :  _firstNode(NULL)
01214     {
01215         assign(other);
01216     }
01217 
01218     XS_StringMap& operator=(const XS_StringMap& other)
01219     {
01220         clear();
01221         assign(other);
01222         return *this;
01223     }
01224 
01225     ~XS_StringMap()
01226     {
01227         clear();
01228     }
01229 
01230     void clear()
01231     {
01232         XS_SMNode* node = _firstNode;
01233         _firstNode = NULL;
01234 
01235         while(node) {
01236             XS_SMNode* pNext = node->_pNext;
01237             node->_pNext = NULL;
01238 
01239             delete node;
01240 
01241             node = pNext;
01242         }
01243     }
01244 
01245     iterator begin()
01246     {
01247         return _firstNode;
01248     }
01249 
01250     const_iterator begin() const
01251     {
01252         return _firstNode;
01253     }
01254 
01255     iterator end()
01256     {
01257         return NULL;
01258     }
01259 
01260     const_iterator end() const
01261     {
01262         return NULL;
01263     }
01264 
01265     iterator find(const key_type& key)
01266     {
01267         for(iterator node=_firstNode; node; node=node->_pNext) {
01268             int c = node->first.compare(key);
01269 
01270             if (c == 0)
01271                 return node;
01272             else if (c > 0)
01273                 break;
01274         }
01275 
01276         return NULL;
01277     }
01278 
01279     const_iterator find(const key_type& key) const
01280     {
01281         for(const_iterator node=_firstNode; node; node=node->_pNext) {
01282             int c = node->first.compare(key);
01283 
01284             if (c == 0)
01285                 return node;
01286             else if (c > 0)
01287                 break;
01288         }
01289 
01290         return NULL;
01291     }
01292 
01293     value_type& operator[](const key_type& key)
01294     {
01295         iterator last = NULL;
01296         iterator node = _firstNode;
01297 
01298         for(; node; node=(last=node)->_pNext) {
01299             int c = node->first.compare(key);
01300 
01301             if (c == 0)
01302                 break; // key matched
01303             else if (c > 0) {
01304                 node = NULL;
01305                 break;
01306             }
01307         }
01308 
01309         if (!node) {
01310              // insert a new node into the linked list
01311             node = new XS_SMNode(key);
01312 
01313             if (last) {
01314                 node->_pNext = last->_pNext;
01315                 last->_pNext = node.ptr();
01316             } else {
01317                 node->_pNext = _firstNode;
01318                 _firstNode = node.ptr();
01319             }
01320         }
01321 
01322         return node->second;
01323     }
01324 
01325     bool empty() const
01326     {
01327         return _firstNode == NULL;
01328     }
01329 
01330     size_t size() const
01331     {
01332         size_t count = 0;
01333 
01334         for(iterator node=_firstNode; node; node=node->_pNext)
01335             ++count;
01336 
01337         return count;
01338     }
01339 
01340     bool erase(const key_type& key)
01341     {
01342         iterator last = NULL;
01343         iterator node = _firstNode;
01344 
01345         for(; node; node=(last=node)->_pNext) {
01346             int c = node->first.compare(key);
01347 
01348             if (c == 0) {
01349                  // remove the node from linked list
01350                 if (last)
01351                     last->_pNext = node->_pNext;
01352                 else
01353                     _firstNode = node->_pNext;
01354 
01355                 node->_pNext = NULL;
01356 
01357                 delete node.ptr();
01358 
01359                 return true;
01360             } else if (c > 0)
01361                 break;
01362         }
01363 
01364         return false;   // key not found
01365     }
01366 
01367     bool operator==(const XS_StringMap& other) const
01368     {
01369         const_iterator it1 = _firstNode;
01370         const_iterator it2 = other._firstNode;
01371 
01372         while(it1 || it2) {
01373             if (!it1 || !it2)
01374                 return false;
01375 
01376             if (it1->first != it2->first)
01377                 return false;
01378 
01379             if (it1->second != it2->second)
01380                 return false;
01381 
01382             it1 = it1->_pNext;
01383             it2 = it2->_pNext;
01384         }
01385 
01386         return !it1 && !it2;
01387     }
01388 
01389     bool operator!=(const XS_StringMap& other) const
01390     {
01391         return !operator==(other);
01392     }
01393 
01394 private:
01395     XS_SMNode*  _firstNode;
01396 
01397     void assign(const XS_StringMap& other)
01398     {
01399         if (other._firstNode)
01400             _firstNode = new XS_SMNode(*other._firstNode);
01401     }
01402 };
01403 
01404 #else
01405 
01406 typedef std::map<XS_String, XS_String> XS_StringMap;
01407 
01408 #endif
01409 
01410 
01411 struct XMLNode;
01412 
01413 struct XPathElement
01414 {
01415     XPathElement() : _child_idx(-1) {}
01416 
01417     XPathElement(const XS_String& child_name, int child_idx=-1)
01418      :  _child_name(child_name), _child_idx(child_idx)
01419     {
01420     }
01421 
01422     XPathElement(const XS_String& child_name, int child_idx, const XS_String& attr_name, const XS_String& attr_value)
01423      :  _child_name(child_name), _child_idx(child_idx)
01424     {
01425         _mAttrAndAttr[attr_name] = attr_value;
01426     }
01427 
01428     XS_String   _child_name;
01429     int         _child_idx;
01430 
01431     typedef XS_StringMap MAPATTR; // maps attribute names to its value
01432     MAPATTR     _mAttrAndAttr;  // map to handle AND conditions
01433 
01434     LPCXSSTR parse(LPCXSSTR path);
01435 
01436     XMLNode* find(XMLNode* node) const;
01437     const XMLNode* const_find(const XMLNode* node) const;
01438 
01439     bool    matches(const XMLNode& node, int& n) const;
01440 };
01441 
01442 struct XPath : std::list<XPathElement>
01443 {
01444     XPath() : _absolute(false) {}
01445     XPath(LPCXSSTR path) {init(path);}
01446     XPath(const XS_String& path) {init(path.c_str());}
01447 
01448     void    init(LPCXSSTR path);
01449 
01450     bool    _absolute;
01451 };
01452 
01453 
01454  /// in memory representation of an XML node
01455 struct XMLNode : public XS_String
01456 {
01457 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
01458      /// map of XML node attributes
01459      // optimized read access without temporary A/U conversion when using ASCII attribute names
01460     struct AttributeMap : public XS_StringMap
01461     {
01462         typedef XS_StringMap super;
01463 
01464         const_iterator find(const char* x) const
01465         {
01466             for(const_iterator it=begin(); it!=end(); ++it)
01467                 if (it->first == x)
01468                     return it;
01469 
01470             return end();
01471         }
01472 
01473         const_iterator find(const key_type& x) const
01474         {
01475             return super::find(x);
01476         }
01477 
01478         iterator find(const key_type& x)
01479         {
01480             return super::find(x);
01481         }
01482 
01483         XS_String get(const char* x, LPCXSSTR def=XS_EMPTY_STR) const
01484         {
01485             const_iterator found = find(x);
01486 
01487             if (found != end())
01488                 return found->second;
01489             else
01490                 return def;
01491         }
01492     };
01493 #else
01494      /// map of XML node attributes
01495     struct AttributeMap : public XS_StringMap
01496     {
01497         XS_String get(const char* x, LPCXSSTR def=XS_EMPTY_STR) const
01498         {
01499             const_iterator found = find(x);
01500 
01501             if (found != end())
01502                 return found->second;
01503             else
01504                 return def;
01505         }
01506     };
01507 #endif
01508 
01509      /// internal children node list
01510     struct Children : public std::list<XMLNode*>
01511     {
01512         typedef std::list<XMLNode*> super;
01513 
01514         Children()
01515         {
01516         }
01517 
01518         Children(Children& other)
01519         {
01520             for(Children::const_iterator it=other.begin(); it!=other.end(); ++it)
01521                 push_back(*it);
01522         }
01523 
01524         void assign(Children& other)
01525         {
01526             clear();
01527             move(other);
01528         }
01529 
01530         void move(Children& other)
01531         {
01532             for(Children::const_iterator it=other.begin(); it!=other.end(); ++it)
01533                 push_back(*it);
01534 
01535             other.reset();
01536         }
01537 
01538         Children& operator=(Children& other)
01539         {
01540             assign(other);
01541             return *this;
01542         }
01543 
01544         void copy(const Children& other)
01545         {
01546             for(Children::const_iterator it=other.begin(); it!=other.end(); ++it)
01547                 push_back(new XMLNode(**it));
01548         }
01549 
01550         void clear()
01551         {
01552             while(!empty()) {
01553                 XMLNode* node = back();
01554                 pop_back();
01555 
01556                 node->clear();
01557                 delete node;
01558             }
01559         }
01560 
01561         bool remove(XMLNode* node)
01562         {
01563             for(iterator it=begin(); it!=end(); ++it)
01564                 if (*it == node) {
01565                     erase(it);
01566                     return true;
01567                 }
01568 
01569             return false;
01570         }
01571 
01572     private:
01573         void reset()
01574         {
01575             super::clear();
01576         }
01577     };
01578 
01579      // access to protected class members for XMLPos and XMLReader
01580     friend struct XMLPos;
01581     friend struct const_XMLPos;
01582     friend struct XMLReaderBase;
01583     friend struct XPathElement;
01584 
01585     XMLNode(const XS_String& name)
01586      :  XS_String(name),
01587         _cdata_content(false)
01588     {
01589     }
01590 
01591     XMLNode(const XS_String& name, const std::string& leading)
01592      :  XS_String(name),
01593         _leading(leading),
01594         _cdata_content(false)
01595     {
01596     }
01597 
01598     XMLNode(const XMLNode& other)
01599      :  XS_String(other),
01600         _attributes(other._attributes),
01601         _leading(other._leading),
01602         _content(other._content),
01603         _end_leading(other._end_leading),
01604         _trailing(other._trailing),
01605 #ifdef XMLNODE_LOCATION
01606         _location(other._location),
01607 #endif
01608         _cdata_content(false)
01609     {
01610         for(Children::const_iterator it=other._children.begin(); it!=other._children.end(); ++it)
01611             _children.push_back(new XMLNode(**it));
01612     }
01613 
01614     enum COPY_FLAGS {COPY_NOCHILDREN};
01615 
01616 #ifdef _MSC_VER
01617 #pragma warning(disable: 4100)  // unreferenced formal parameter
01618 #endif
01619     XMLNode(const XMLNode& other, COPY_FLAGS copy_no_children)
01620      :  XS_String(other),
01621         _attributes(other._attributes),
01622         _leading(other._leading),
01623         _content(other._content),
01624         _end_leading(other._end_leading),
01625         _trailing(other._trailing),
01626 #ifdef XMLNODE_LOCATION
01627         _location(other._location),
01628 #endif
01629         _cdata_content(false)
01630     {
01631         assert(copy_no_children==COPY_NOCHILDREN);
01632     }
01633 
01634     virtual ~XMLNode()
01635     {
01636         while(!_children.empty()) {
01637             delete _children.back();
01638             _children.pop_back();
01639         }
01640     }
01641 
01642     void clear()
01643     {
01644         _leading.erase();
01645         _content.erase();
01646         _end_leading.erase();
01647         _trailing.erase();
01648 
01649         _attributes.clear();
01650         _children.clear();
01651 
01652         XS_String::erase();
01653     }
01654 
01655     XMLNode& operator=(const XMLNode& other)
01656     {
01657         _children.clear();
01658         _children.copy(other._children);
01659 
01660         _attributes = other._attributes;
01661 
01662         _leading = other._leading;
01663         _content = other._content;
01664         _end_leading = other._end_leading;
01665         _trailing = other._trailing;
01666         _cdata_content = other._cdata_content;
01667 
01668         return *this;
01669     }
01670 
01671      /// add a new child node
01672     void add_child(XMLNode* child)
01673     {
01674         _children.push_back(child);
01675     }
01676 
01677      /// remove all children named 'name'
01678     void remove_children(const XS_String& name)
01679     {
01680         Children::iterator it, next=_children.begin();
01681 
01682         while((it=next) != _children.end()) {
01683             ++next;
01684 
01685             if (**it == name)
01686                 _children.erase(it);
01687         }
01688     }
01689 
01690      /// write access to an attribute
01691     void put(const XS_String& attr_name, const XS_String& value)
01692     {
01693         _attributes[attr_name] = value;
01694     }
01695 
01696      /// index operator write access to an attribute
01697     XS_String& operator[](const XS_String& attr_name)
01698     {
01699         return _attributes[attr_name];
01700     }
01701 
01702      /// index operator read access to an attribute
01703     XS_String operator[](const XS_String& attr_name) const
01704     {
01705 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
01706         return _attributes.get(((std::string)attr_name).c_str());
01707 #else
01708         return _attributes.get(attr_name.c_str());
01709 #endif
01710     }
01711 
01712      /// read only access to an attribute
01713     template<typename T> XS_String get(const T& attr_name, LPCXSSTR def=XS_EMPTY_STR) const
01714     {
01715         AttributeMap::const_iterator found = _attributes.find(attr_name);
01716 
01717         if (found != _attributes.end())
01718             return found->second;
01719         else
01720             return def;
01721     }
01722 
01723      /// remove the attribute 'attr_name'
01724     void erase(const XS_String& attr_name)
01725     {
01726         _attributes.erase(attr_name);
01727     }
01728 
01729      /// convenient value access in children node
01730     XS_String subvalue(const XS_String& child_name, const XS_String& attr_name, int n=0) const
01731     {
01732         const XMLNode* node = XPathElement(child_name, n).const_find(this);
01733 
01734         if (node)
01735             return node->get(attr_name);
01736         else
01737             return XS_String();
01738     }
01739 
01740      /// convenient storage of distinct values in children node
01741     XS_String& subvalue(const XS_String& child_name, const XS_String& attr_name, int n=0)
01742     {
01743         XMLNode* node = XPathElement(child_name, n).find(this);
01744 
01745         if (!node) {
01746             node = new XMLNode(child_name);
01747             add_child(node);
01748         }
01749 
01750         return (*node)[attr_name];
01751     }
01752 
01753 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
01754      /// convenient value access in children node
01755     XS_String subvalue(const char* child_name, const char* attr_name, int n=0) const
01756     {
01757         const XMLNode* node = XPathElement(child_name, n).const_find(this);
01758 
01759         if (node)
01760             return node->get(attr_name);
01761         else
01762             return XS_String();
01763     }
01764 
01765      /// convenient storage of distinct values in children node
01766     XS_String& subvalue(const char* child_name, const XS_String& attr_name, int n=0)
01767     {
01768         XMLNode* node = XPathElement(child_name, n).find(this);
01769 
01770         if (!node) {
01771             node = new XMLNode(child_name);
01772             add_child(node);
01773         }
01774 
01775         return (*node)[attr_name];
01776     }
01777 #endif
01778 
01779     const Children& get_children() const
01780     {
01781         return _children;
01782     }
01783 
01784     Children& get_children()
01785     {
01786         return _children;
01787     }
01788 
01789     const AttributeMap& get_attributes() const
01790     {
01791         return _attributes;
01792     }
01793 
01794     AttributeMap& get_attributes()
01795     {
01796         return _attributes;
01797     }
01798 
01799      /// read element node content
01800     XS_String get_content() const
01801     {
01802         return DecodeXMLString(_content);
01803     }
01804 
01805      /// read element node content as encoded string
01806     std::string get_encoded_content() const
01807     {
01808         return _content;
01809     }
01810 
01811      /// read content of a subnode specified by an XPath expression
01812     XS_String get_sub_content(const XPath& xpath) const
01813     {
01814         const XMLNode* node = find_relative(xpath);
01815 
01816         if (node)
01817             return node->get_content();
01818         else
01819             return XS_EMPTY_STR;
01820     }
01821 
01822      /// set element node content
01823     void set_content(const XS_String& s, bool cdata=false)
01824     {
01825         _content.assign(EncodeXMLString(s.c_str(), cdata));
01826     }
01827 
01828      /// set element node content from encoded string
01829     void set_encoded_content(const std::string& s)
01830     {
01831         _content.assign(s);
01832     }
01833 
01834      /// set content of a subnode specified by an XPath expression
01835     bool set_sub_content(const XPath& xpath, const XS_String& s, bool cdata=false)
01836     {
01837         XMLNode* node = create_relative(xpath);
01838 
01839         if (node) {
01840             node->set_content(s, cdata);
01841             return true;
01842         } else
01843             return false;
01844     }
01845 
01846     XS_String get_trailing() const
01847     {
01848         return DecodeXMLString(_trailing);
01849     }
01850 
01851 #ifdef XMLNODE_LOCATION
01852     const XMLLocation& get_location() const {return _location;}
01853 #endif
01854 
01855      /// write node with children tree to output stream
01856     bool write(std::ostream& out, const XMLFormat& format, WRITE_MODE mode=FORMAT_SMART, int indent=0) const
01857     {
01858         switch(mode) {
01859           case FORMAT_PLAIN:
01860             plain_write_worker(out);
01861             break;
01862 
01863           case FORMAT_PRETTY:
01864             pretty_write_worker(out, format, indent);
01865             break;
01866 
01867           case FORMAT_ORIGINAL:
01868             original_write_worker(out);
01869             break;
01870 
01871           default:  // FORMAT_SMART
01872             smart_write_worker(out, format, indent);
01873         }
01874 
01875         return out.good();
01876     }
01877 
01878      /// count the nodes matching the given relative XPath expression
01879     int count(const XPath& xpath) const
01880     {
01881         return count(xpath.begin(), xpath.end());
01882     }
01883 
01884      /// count the nodes matching the given relative XPath expression
01885     int count(XPath::const_iterator from, const XPath::const_iterator& to) const;
01886 
01887      /// copy matching tree nodes using the given XPath filter expression
01888     bool filter(const XPath& xpath, XMLNode& target) const;
01889 
01890      /// XPath find function (const)
01891     const XMLNode* find_relative(const XPath& xpath) const;
01892 
01893      /// XPath find function
01894     XMLNode* find_relative(const XPath& xpath);
01895 
01896     XMLNode* get_first_child() const
01897     {
01898         if (!_children.empty())
01899             return _children.front();
01900         else
01901             return NULL;
01902     }
01903 
01904 protected:
01905     Children _children;
01906     AttributeMap _attributes;
01907 
01908     std::string _leading;       // UTF-8 encoded
01909     std::string _content;       // UTF-8 and entity encoded, may contain CDATA sections; decode with DecodeXMLString()
01910     std::string _end_leading;   // UTF-8 encoded
01911     std::string _trailing;      // UTF-8 encoded
01912 
01913 #ifdef XMLNODE_LOCATION
01914     XMLLocation _location;
01915 #endif
01916 
01917     bool    _cdata_content;
01918 
01919      /// relative XPath create function
01920     XMLNode* create_relative(const XPath& xpath);
01921 
01922      /// create a new node tree using the given XPath filter expression
01923     XMLNode* filter(XPath::const_iterator from, const XPath::const_iterator& to) const;
01924 
01925     void    original_write_worker(std::ostream& out) const;
01926     void    plain_write_worker(std::ostream& out) const;
01927     void    pretty_write_worker(std::ostream& out, const XMLFormat& format, int indent) const;
01928     void    smart_write_worker(std::ostream& out, const XMLFormat& format, int indent) const;
01929 };
01930 
01931 
01932  /// iterator access to children nodes with name filtering
01933 struct XMLChildrenFilter
01934 {
01935     XMLChildrenFilter(XMLNode::Children& children, const XS_String& name)
01936      :  _begin(children.begin(), children.end(), name),
01937         _end(children.end(), children.end(), name)
01938     {
01939     }
01940 
01941     XMLChildrenFilter(XMLNode* node, const XS_String& name)
01942      :  _begin(node->get_children().begin(), node->get_children().end(), name),
01943         _end(node->get_children().end(), node->get_children().end(), name)
01944     {
01945     }
01946 
01947      /// internal iterator class
01948     struct iterator
01949     {
01950         typedef XMLNode::Children::iterator BaseIterator;
01951         typedef iterator myType;
01952 
01953         iterator(BaseIterator begin, BaseIterator end, const XS_String& filter_name)
01954          :  _cur(begin),
01955             _end(end),
01956             _filter_name(filter_name)
01957         {
01958             search_next();
01959         }
01960 
01961         operator BaseIterator()
01962         {
01963             return _cur;
01964         }
01965 
01966         const XMLNode* operator*() const
01967         {
01968             return *_cur;
01969         }
01970 
01971         XMLNode* operator*()
01972         {
01973             return *_cur;
01974         }
01975 
01976         myType& operator++()
01977         {
01978             ++_cur;
01979             search_next();
01980 
01981             return *this;
01982         }
01983 
01984         myType operator++(int)
01985         {
01986             myType ret = *this;
01987 
01988             ++_cur;
01989             search_next();
01990 
01991             return ret;
01992         }
01993 
01994         bool operator==(const myType& other) const
01995         {
01996             return _cur == other._cur;
01997         }
01998 
01999         bool operator!=(const myType& other) const
02000         {
02001             return _cur != other._cur;
02002         }
02003 
02004     protected:
02005         BaseIterator    _cur;
02006         BaseIterator    _end;
02007         XS_String   _filter_name;
02008 
02009         void search_next()
02010         {
02011             while(_cur!=_end && **_cur!=_filter_name)
02012                 ++_cur;
02013         }
02014     };
02015 
02016     iterator begin()
02017     {
02018         return _begin;
02019     }
02020 
02021     iterator end()
02022     {
02023         return _end;
02024     }
02025 
02026 protected:
02027     iterator    _begin;
02028     iterator    _end;
02029 };
02030 
02031 
02032  /// read only iterator access to children nodes with name filtering
02033 struct const_XMLChildrenFilter
02034 {
02035     const_XMLChildrenFilter(const XMLNode::Children& children, const XS_String& name)
02036      :  _begin(children.begin(), children.end(), name),
02037         _end(children.end(), children.end(), name)
02038     {
02039     }
02040 
02041     const_XMLChildrenFilter(const XMLNode* node, const XS_String& name)
02042      :  _begin(node->get_children().begin(), node->get_children().end(), name),
02043         _end(node->get_children().end(), node->get_children().end(), name)
02044     {
02045     }
02046 
02047      /// internal iterator class
02048     struct const_iterator
02049     {
02050         typedef XMLNode::Children::const_iterator BaseIterator;
02051         typedef const_iterator myType;
02052 
02053         const_iterator(BaseIterator begin, BaseIterator end, const XS_String& filter_name)
02054          :  _cur(begin),
02055             _end(end),
02056             _filter_name(filter_name)
02057         {
02058             search_next();
02059         }
02060 
02061         operator BaseIterator()
02062         {
02063             return _cur;
02064         }
02065 
02066         const XMLNode* operator*() const
02067         {
02068             return *_cur;
02069         }
02070 
02071         const XMLNode* operator->() const
02072         {
02073             return *_cur;
02074         }
02075 
02076         myType& operator++()
02077         {
02078             ++_cur;
02079             search_next();
02080 
02081             return *this;
02082         }
02083 
02084         myType operator++(int)
02085         {
02086             myType ret = *this;
02087 
02088             ++_cur;
02089             search_next();
02090 
02091             return ret;
02092         }
02093 
02094         bool operator==(const myType& other) const
02095         {
02096             return _cur == other._cur;
02097         }
02098 
02099         bool operator!=(const myType& other) const
02100         {
02101             return _cur != other._cur;
02102         }
02103 
02104     protected:
02105         BaseIterator    _cur;
02106         BaseIterator    _end;
02107         XS_String   _filter_name;
02108 
02109         void search_next()
02110         {
02111             while(_cur!=_end && **_cur!=_filter_name)
02112                 ++_cur;
02113         }
02114     };
02115 
02116     const_iterator begin()
02117     {
02118         return _begin;
02119     }
02120 
02121     const_iterator end()
02122     {
02123         return _end;
02124     }
02125 
02126     bool empty() const
02127     {
02128         return _end == _begin;
02129     }
02130 
02131 protected:
02132     const_iterator  _begin;
02133     const_iterator  _end;
02134 };
02135 
02136 
02137  /// iterator for XML trees
02138 struct XMLPos
02139 {
02140     XMLPos(XMLNode* root)
02141      :  _root(root),
02142         _cur(root)
02143     {
02144     }
02145 
02146     XMLPos(const XMLPos& other)
02147      :  _root(other._root),
02148         _cur(other._cur)
02149     {   // don't copy _stack
02150     }
02151 
02152     XMLPos(XMLNode* node, const XS_String& name)
02153      :  _root(node),
02154         _cur(node)
02155     {
02156         smart_create(name);
02157     }
02158 
02159     XMLPos(XMLNode* node, const XS_String& name, const XS_String& attr_name, const XS_String& attr_value)
02160      :  _root(node),
02161         _cur(node)
02162     {
02163         smart_create(name, attr_name, attr_value);
02164     }
02165 
02166     XMLPos(const XMLPos& other, const XS_String& name)
02167      :  _root(other._root),
02168         _cur(other._cur)
02169     {
02170         smart_create(name);
02171     }
02172 
02173     XMLPos(const XMLPos& other, const XS_String& name, const XS_String& attr_name, const XS_String& attr_value)
02174      :  _root(other._root),
02175         _cur(other._cur)
02176     {
02177         smart_create(name, attr_name, attr_value);
02178     }
02179 
02180      /// access to current node
02181     XMLNode& cur()
02182     {
02183         return *_cur;
02184     }
02185 
02186     const XMLNode& cur() const
02187     {
02188         return *_cur;
02189     }
02190 
02191      /// automatic access to current node
02192     operator const XMLNode*() const {return _cur;}
02193     operator XMLNode*() {return _cur;}
02194 
02195     const XMLNode* operator->() const {return _cur;}
02196     XMLNode* operator->() {return _cur;}
02197 
02198     const XMLNode& operator*() const {return *_cur;}
02199     XMLNode& operator*() {return *_cur;}
02200 
02201      /// attribute access
02202     XS_String get(const XS_String& attr_name, LPCXSSTR def=XS_EMPTY_STR) const
02203     {
02204         return _cur->get(attr_name, def);
02205     }
02206 
02207      /// attribute setting
02208     void put(const XS_String& attr_name, const XS_String& value)
02209     {
02210         _cur->put(attr_name, value);
02211     }
02212 
02213      /// index operator attribute access
02214     template<typename T> XS_String get(const T& attr_name) const {return (*_cur)[attr_name];}
02215     XS_String& operator[](const XS_String& attr_name) {return (*_cur)[attr_name];}
02216     const XS_String& operator[](const XS_String& attr_name) const {return (*_cur)[attr_name];}
02217 
02218      /// insert children when building tree
02219     void add_down(XMLNode* child)
02220     {
02221         _cur->add_child(child);
02222         go_to(child);
02223     }
02224 
02225      /// go back to previous position
02226     bool back()
02227     {
02228         if (!_stack.empty()) {
02229             _cur = _stack.top();
02230             _stack.pop();
02231             return true;
02232         } else {
02233             assert(!_stack.empty());
02234             return false;
02235         }
02236     }
02237 
02238      /// go down to first child
02239     bool go_down()
02240     {
02241         XMLNode* node = _cur->get_first_child();
02242 
02243         if (node) {
02244             go_to(node);
02245             return true;
02246         } else
02247             return false;
02248     }
02249 
02250      /// search for child and go down
02251     bool go_down(const XS_String& child_name, int n=0)
02252     {
02253         XMLNode* node = XPathElement(child_name, n).find(_cur);
02254 
02255         if (node) {
02256             go_to(node);
02257             return true;
02258         } else
02259             return false;
02260     }
02261 
02262      /// iterate to the next matching child
02263     bool iterate(const XS_String& child_name, int& cnt)
02264     {
02265         XMLNode* node = XPathElement(child_name, cnt).find(_cur);
02266 
02267         if (node) {
02268             go_to(node);
02269             ++cnt;
02270             return true;
02271         } else
02272             return false;
02273     }
02274 
02275      /// move to the position defined by xpath in XML tree
02276     bool go(const XPath& xpath);
02277 
02278      /// create child nodes using XPath notation and move to the deepest child
02279     bool create_relative(const XPath& xpath)
02280     {
02281         XMLNode* node = _cur->create_relative(xpath);
02282         if (!node)
02283             return false;   // invalid path specified
02284 
02285         go_to(node);
02286         return true;
02287     }
02288 
02289      /// create node and move to it
02290     void create(const XS_String& name)
02291     {
02292         add_down(new XMLNode(name));
02293     }
02294 
02295      /// create node with string content
02296     void create_node_content(const XS_String& node_name, const XS_String& content)
02297     {
02298         XMLNode* pNode = new XMLNode(node_name);
02299             pNode->set_content(content);
02300         _cur->add_child(pNode);
02301     }
02302 
02303      /// create node if not already existing and move to it
02304     void smart_create(const XS_String& child_name)
02305     {
02306         XMLNode* node = XPathElement(child_name).find(_cur);
02307 
02308         if (node)
02309             go_to(node);
02310         else
02311             add_down(new XMLNode(child_name));
02312     }
02313 
02314      /// search matching child node identified by key name and an attribute value
02315     void smart_create(const XS_String& child_name, const XS_String& attr_name, const XS_String& attr_value)
02316     {
02317         XMLNode* node = XPathElement(child_name, 0, attr_name, attr_value).find(_cur);
02318 
02319         if (node)
02320             go_to(node);
02321         else {
02322             node = new XMLNode(child_name);
02323             add_down(node);
02324             (*node)[attr_name] = attr_value;
02325         }
02326     }
02327 
02328      /// count the nodes matching the given relative XPath expression
02329     int count(const XPath& xpath) const
02330     {
02331         return _cur->count(xpath);
02332     }
02333 
02334      /// create a new node tree using the given XPath filter expression
02335     int filter(const XPath& xpath, XMLNode& target) const
02336     {
02337         return _cur->filter(xpath, target);
02338     }
02339 
02340 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
02341      /// search for child and go down
02342     bool go_down(const char* child_name, int n=0)
02343     {
02344         XMLNode* node = XPathElement(child_name, n).find(_cur);
02345 
02346         if (node) {
02347             go_to(node);
02348             return true;
02349         } else
02350             return false;
02351     }
02352 
02353      /// create node and move to it
02354     void create(const char* child_name)
02355     {
02356         add_down(new XMLNode(child_name));
02357     }
02358 
02359      /// create node if not already existing and move to it
02360     void smart_create(const char* child_name)
02361     {
02362         XMLNode* node = XPathElement(child_name).find(_cur);
02363 
02364         if (node)
02365             go_to(node);
02366         else
02367             add_down(new XMLNode(child_name));
02368     }
02369 
02370      /// search matching child node identified by key name and an attribute value
02371     template<typename T, typename U>
02372     void smart_create(const char* child_name, const T& attr_name, const U& attr_value)
02373     {
02374         XMLNode* node = XPathElement(child_name, 0, attr_name, attr_value).find(_cur);
02375 
02376         if (node)
02377             go_to(node);
02378         else {
02379             node = new XMLNode(child_name);
02380             add_down(node);
02381             (*node)[attr_name] = attr_value;
02382         }
02383     }
02384 #endif
02385 
02386      /// delete current node and go back to previous position
02387     bool delete_this()
02388     {
02389         if (!_stack.empty()) {
02390             XMLNode* pLast = _stack.top();
02391 
02392             if (pLast->_children.remove(_cur)) {
02393                 _cur = _stack.top();
02394                 return true;
02395             }
02396         }
02397 
02398         return false;
02399     }
02400 
02401      /// remove all children named 'name'
02402     void remove_children(const XS_String& name)
02403     {
02404         _cur->remove_children(name);
02405     }
02406 
02407      /// remove the attribute 'attr_name' from the current node
02408     void erase(const XS_String& attr_name)
02409     {
02410         _cur->erase(attr_name);
02411     }
02412 
02413     XS_String& str() {return *_cur;}
02414     const XS_String& str() const {return *_cur;}
02415 
02416      // property (key/value pair) setter functions
02417     void set_property(const XS_String& key, int value, const XS_String& name=XS_PROPERTY);
02418     void set_property(const XS_String& key, double value, const XS_String& name=XS_PROPERTY);
02419     void set_property(const XS_String& key, const XS_String& value, const XS_String& name=XS_PROPERTY);
02420     void set_property(const XS_String& key, const struct XMLBool& value, const XS_String& name=XS_PROPERTY);
02421 
02422     void set_property(const XS_String& key, const char* value, const XS_String& name=XS_PROPERTY)
02423         {set_property(key, XS_String(value), name);}
02424 
02425 protected:
02426     friend struct const_XMLPos; // access to _root
02427 
02428     XMLNode* _root;
02429     XMLNode* _cur;
02430     std::stack<XMLNode*> _stack;
02431 
02432      /// go to specified node
02433     void go_to(XMLNode* child)
02434     {
02435         _stack.push(_cur);
02436         _cur = child;
02437     }
02438 };
02439 
02440 
02441  /// iterator for XML trees
02442 struct const_XMLPos
02443 {
02444     const_XMLPos(const XMLNode* root)
02445      :  _root(root),
02446         _cur(root)
02447     {
02448     }
02449 
02450     const_XMLPos(const const_XMLPos& other)
02451      :  _root(other._root),
02452         _cur(other._cur)
02453     {   // don't copy _stack
02454     }
02455 
02456     const_XMLPos(const XMLPos& other)
02457      :  _root(other._root),
02458         _cur(other._cur)
02459     {   // don't copy _stack
02460     }
02461 
02462      /// access to current node
02463     const XMLNode& cur() const
02464     {
02465         return *_cur;
02466     }
02467 
02468      /// automatic access to current node
02469     operator const XMLNode*() const {return _cur;}
02470 
02471     const XMLNode* operator->() const {return _cur;}
02472 
02473     const XMLNode& operator*() const {return *_cur;}
02474 
02475      /// attribute access
02476     XS_String get(const XS_String& attr_name) const
02477     {
02478         return _cur->get(attr_name);
02479     }
02480 
02481      /// index operator attribute access
02482     template<typename T> XS_String get(const T& attr_name) const {return _cur->get(attr_name);}
02483     XS_String operator[](const XS_String& attr_name) const {return _cur->get(attr_name);}
02484 
02485      /// go back to previous position
02486     bool back()
02487     {
02488         if (!_stack.empty()) {
02489             _cur = _stack.top();
02490             _stack.pop();
02491             return true;
02492         } else {
02493             assert(!_stack.empty());
02494             return false;
02495         }
02496     }
02497 
02498      /// go down to first child
02499     bool go_down()
02500     {
02501         const XMLNode* node = _cur->get_first_child();
02502 
02503         if (node) {
02504             go_to(node);
02505             return true;
02506         } else
02507             return false;
02508     }
02509 
02510      /// search for child and go down
02511     bool go_down(const XS_String& child_name, int n=0)
02512     {
02513         const XMLNode* node = XPathElement(child_name, n).const_find(_cur);
02514 
02515         if (node) {
02516             go_to(node);
02517             return true;
02518         } else
02519             return false;
02520     }
02521 
02522      /// iterate to the next matching child
02523     bool iterate(const XS_String& child_name, int& cnt)
02524     {
02525         const XMLNode* node = XPathElement(child_name, cnt).const_find(_cur);
02526 
02527         if (node) {
02528             go_to(node);
02529             ++cnt;
02530             return true;
02531         } else
02532             return false;
02533     }
02534 
02535      /// move to the position defined by xpath in XML tree
02536     bool go(const XPath& xpath);
02537 
02538 #if defined(UNICODE) && !defined(XS_STRING_UTF8)
02539      /// search for child and go down
02540     bool go_down(const char* child_name, int n=0)
02541     {
02542         const XMLNode* node = XPathElement(child_name, n).const_find(_cur);
02543 
02544         if (node) {
02545             go_to(node);
02546             return true;
02547         } else
02548             return false;
02549     }
02550 #endif
02551 
02552     const XS_String& str() const {return *_cur;}
02553 
02554 protected:
02555     const XMLNode* _root;
02556     const XMLNode* _cur;
02557     std::stack<const XMLNode*> _stack;
02558 
02559      /// go to specified node
02560     void go_to(const XMLNode* child)
02561     {
02562         _stack.push(_cur);
02563         _cur = child;
02564     }
02565 };
02566 
02567 
02568 #ifdef _MSC_VER
02569 #pragma warning(disable: 4355)  // 'this' : used in base member initializer list 
02570 #endif
02571 
02572  /// XML reader base class
02573 struct XMLReaderBase
02574 #ifdef XS_USE_XERCES
02575  : public HandlerBase
02576 #endif
02577 {
02578 #ifdef XS_USE_XERCES
02579 
02580     XMLReaderBase(XMLNode* node, InputSource* source, bool adoptSource=false);
02581     virtual ~XMLReaderBase();
02582 
02583     void read(bool force_utf8=false);
02584 
02585 protected:
02586     SAXParser*  _parser;
02587     InputSource* _source;
02588     bool        _deleteSource;
02589 
02590     virtual void XMLDecl(const XMLCh* const versionStr, const XMLCh* const encodingStr,
02591                          const XMLCh* const standaloneStr, const XMLCh* const actualEncodingStr);
02592 
02593      // Handlers for the SAX DocumentHandler interface
02594     virtual void setDocumentLocator(const Locator* const locator);
02595     virtual void startElement(const XMLCh* const name, AttributeList& attributes);
02596     virtual void endElement(const XMLCh* const name);
02597     virtual void characters(const XMLCh* const chars, const unsigned int length);
02598     virtual void ignorableWhitespace(const XMLCh* const chars, const unsigned int length);
02599 
02600      // Handlers for the SAX ErrorHandler interface
02601     virtual void error(const SAXParseException& e);
02602     virtual void fatalError(const SAXParseException& e);
02603     virtual void warning(const SAXParseException& e);
02604     virtual void resetErrors();
02605 
02606 #elif defined(XS_USE_EXPAT) // !XS_USE_XERCES
02607 
02608     XMLReaderBase(XMLNode* node);
02609     virtual ~XMLReaderBase();
02610 
02611 protected:
02612     XML_Parser  _parser;
02613 
02614     static void XMLCALL XML_XmlDeclHandler(void* userData, const XML_Char* version, const XML_Char* encoding, int standalone=-1);
02615     static void XMLCALL XML_StartElementHandler(void* userData, const XML_Char* name, const XML_Char** atts);
02616     static void XMLCALL XML_EndElementHandler(void* userData, const XML_Char* name);
02617     static void XMLCALL XML_DefaultHandler(void* userData, const XML_Char* s, int len);
02618 
02619     static std::string get_expat_error_string(XML_Error error_code);
02620 
02621 #else // XS_USE_EXPAT
02622 
02623     XMLReaderBase(XMLNode* node)
02624      :  _pos(node),
02625         _endl_defined(false)
02626     {
02627         _last_tag = TAG_NONE;
02628     }
02629 
02630     virtual ~XMLReaderBase();
02631 
02632     bool    parse(bool force_utf8=false);
02633 
02634 #endif
02635 
02636 public:
02637 #ifndef XS_USE_XERCES
02638     void read(bool force_utf8=false);
02639 
02640     std::string get_position() const {return _location.str();}
02641 #endif
02642     const XMLFormat& get_format() const {return _format;}
02643     const char* get_endl() const {return _endl_defined? _format._endl: "\n";}
02644 
02645     const XMLErrorList& get_errors() const {return _errors;}
02646     const XMLErrorList& get_warnings() const {return _warnings;}
02647 
02648     void clear_errors() {_errors.clear(); _warnings.clear();}
02649 
02650 #ifdef XS_NATIVE
02651     XMLLocation get_location() const {return _location;}
02652     void setSystemId(const char* systemId) {_location.set_path(systemId);}
02653 #elif defined(XMLNODE_LOCATION)
02654     const char* _display_path;  // character pointer for fast reference in XMLLocation
02655 
02656 #ifdef XS_USE_XERCES
02657     const Locator* _locator;
02658 #endif
02659 
02660     XMLLocation get_location() const;
02661     void setSystemId(const char* systemId) {_display_path = systemId;}
02662 #endif
02663 
02664     std::string get_encoded_content() const {return _content;}
02665 
02666 protected:
02667     XMLPos      _pos;
02668 
02669     std::string _content;       // UTF-8 encoded
02670     enum {TAG_NONE, TAG_START, TAG_END} _last_tag;
02671 
02672     XMLErrorList _errors;
02673     XMLErrorList _warnings;
02674 
02675     XMLFormat   _format;
02676     bool    _endl_defined;
02677 
02678 #ifdef XS_NATIVE
02679     XMLLocation _location;
02680 
02681     virtual int get() = 0;
02682     int     eat_endl();
02683 #elif defined(XS_USE_XERCES)
02684     //TODO
02685 #elif defined(XS_USE_EXPAT)
02686     virtual int read_buffer(char* buffer, int len) = 0;
02687 #endif
02688 
02689     void    finish_read();
02690 
02691     virtual void XmlDeclHandler(const char* version, const char* encoding, int standalone);
02692     virtual void StartElementHandler(const XS_String& name, const XMLNode::AttributeMap& attributes);
02693     virtual void EndElementHandler();
02694 #if defined(XS_USE_XERCES) || defined(XS_USE_EXPAT)
02695     virtual void DefaultHandler(const XML_Char* s, int len);
02696 #else
02697     virtual void DefaultHandler(const std::string& s);
02698 #endif
02699 
02700 #if !defined(XS_USE_XERCES) && !defined(XS_USE_EXPAT)
02701     friend struct ParseContext;
02702 #endif
02703 };
02704 
02705 
02706  /// XML file reader
02707 
02708 #ifdef XS_USE_XERCES
02709 
02710 struct XercesXMLReader : public XMLReaderBase
02711 {
02712     XercesXMLReader(XMLNode* node, InputSource* source, bool adoptSource=false)
02713      :  XMLReaderBase(node, source, adoptSource)
02714     {
02715     }
02716 
02717     XercesXMLReader(XMLNode* node, LPCTSTR path);
02718     XercesXMLReader(XMLNode* node, const XMLByte* buffer, size_t bytes, const std::string& system_id=std::string());
02719 };
02720 
02721 #define XMLReader XercesXMLReader
02722 
02723 #elif defined(XS_USE_EXPAT)
02724 
02725 struct ExpatXMLReader : public XMLReaderBase
02726 {
02727     ExpatXMLReader(XMLNode* node, std::istream& in)
02728      :  XMLReaderBase(node),
02729         _in(in)
02730     {
02731     }
02732 
02733      /// read XML stream into XML tree below _pos
02734     int read_buffer(char* buffer, int len)
02735     {
02736         if (!_in.good())
02737             return -1;
02738 
02739         _in.read(buffer, len);
02740 
02741         return _in.gcount();
02742     }
02743 
02744 protected:
02745     std::istream&   _in;
02746 };
02747 
02748 #define XMLReader ExpatXMLReader
02749 
02750 #else // XS_USE_XERCES, XS_USE_EXPAT
02751 
02752 struct XMLReader : public XMLReaderBase
02753 {
02754     XMLReader(XMLNode* node, std::istream& in)
02755      :  XMLReaderBase(node),
02756         _in(in),
02757         _last_crlf(0)
02758     {
02759     }
02760 
02761      /// read one character from XML stream
02762     int get()
02763     {
02764         int c = _in.get();
02765 
02766 //       // increment line counter on LF
02767 //      if (c == '\n') {
02768 //          _location._column = 1;
02769 //          ++_location._line;
02770          // increment line counter on LF, CR, CR/LF or LF/CR line endings
02771         if (c=='\n' || c=='\r') {
02772             if (!_last_crlf || c==_last_crlf) {
02773                 _location._column = 1;
02774                 ++_location._line;
02775                 _last_crlf = c;
02776             } else
02777                 _last_crlf = 0;
02778         } else {
02779             ++_location._column;
02780             _last_crlf = 0;
02781         }
02782 
02783         return c;
02784     }
02785 
02786 protected:
02787     std::istream&   _in;
02788     int _last_crlf;
02789 };
02790 
02791 struct ReadBuffer
02792 {
02793     ReadBuffer(XMLErrorList& errors, XMLLocation& location);
02794     ~ReadBuffer();
02795 
02796     void    reset();
02797     bool    empty() const {return _wptr==_buffer;}
02798     bool    append(int c);
02799     const std::string& str(bool utf8);
02800     size_t  len() const;
02801     bool    has_CDEnd() const;
02802     XS_String get_tag() const;
02803     void    get_attributes(XMLNode::AttributeMap& attributes) const;
02804     XMLLocation& get_location() const {return _location;}
02805 
02806 protected:
02807     XMLErrorList& _errors;
02808     XMLLocation& _location;
02809     char*   _buffer;
02810     char*   _wptr;
02811     size_t  _len;
02812     std::string _buffer_str;    // UTF-8 encoded
02813 
02814 private:
02815     ReadBuffer(const ReadBuffer&); // disallow object copy
02816 };
02817 
02818 struct ParseContext
02819 {
02820     ParseContext(XMLReaderBase& reader, bool force_utf8=false);
02821 
02822     void    read_bom();
02823     bool    proceed();
02824     int     process_next(int c);
02825 
02826     XMLReaderBase& _reader;
02827     ReadBuffer  _buffer;
02828     int         _next;
02829     bool        _in_comment;
02830     bool        _utf8;
02831 };
02832 
02833 #endif // XS_USE_XERCES
02834 
02835 
02836 #if defined(_MSC_VER) && _MSC_VER<1400
02837 
02838 struct fast_ostringbuffer : public std::streambuf
02839 {
02840     typedef char _E;
02841     typedef std::char_traits<_E> _Tr;
02842 
02843     explicit fast_ostringbuffer()
02844         {_Init(0, 0, std::_Noread);}    // optimized for ios::out mode
02845 
02846     virtual ~fast_ostringbuffer()
02847         {_Tidy();}
02848 
02849     std::string str() const
02850         {if (pptr() != 0)
02851             {std::string _Str(pbase(),
02852                 (_Seekhigh<pptr()? pptr(): _Seekhigh) - pbase());
02853             return _Str;}
02854         else
02855             return std::string();}
02856 
02857 protected:
02858     virtual int_type overflow(int_type _C = _Tr::eof())
02859         {if (_Tr::eq_int_type(_Tr::eof(), _C))
02860             return _Tr::not_eof(_C);
02861         else if (pptr() != 0 && pptr() < epptr())
02862             {*_Pninc() = _Tr::to_char_type(_C);
02863             return _C;}
02864         else
02865             {size_t _Os = gptr() == 0 ? 0 : epptr() - eback();
02866             size_t _Ns = _Os + _Alsize;
02867             _E *_P = _Al.allocate(_Ns, (void *)0);
02868             if (0 < _Os)
02869                 _Tr::copy(_P, eback(), _Os);
02870             else if (_ALSIZE < _Alsize)
02871                 _Alsize = _ALSIZE;
02872 
02873             if (_Strmode & std::_Allocated)
02874                 _Al.deallocate(eback(), _Os);
02875 
02876             _Strmode |= std::_Allocated;
02877 
02878             if (_Os == 0)
02879                 {_Seekhigh = _P;
02880                 setp(_P, _P + _Ns);
02881                 setg(_P, _P, _P); }
02882             else
02883                 {_Seekhigh = _Seekhigh - eback() + _P;
02884                 setp(pbase() - eback() + _P, pptr() - eback() + _P, _P + _Ns);
02885                 setg(_P, _P, _P);}
02886             *_Pninc() = _Tr::to_char_type(_C);
02887 
02888             return _C;}}
02889 
02890     void _Init(const _E *_S, size_t _N, std::_Strstate _M)
02891         {_Pendsave = 0, _Seekhigh = 0;
02892         _Alsize = _MINSIZE, _Strmode = _M;
02893         setg(0, 0, 0);
02894         setp(0, 0);}
02895 
02896     void _Tidy()
02897         {if (_Strmode & std::_Allocated)
02898             _Al.deallocate(eback(), (pptr() != 0 ? epptr() : egptr()) - eback());
02899         _Seekhigh = 0;
02900         _Strmode &= ~std::_Allocated;}
02901 
02902 private:
02903     enum {_ALSIZE = 65536/*512*/, _MINSIZE = 32768/*32*/};  // bigger buffer sizes
02904 
02905     _E *_Pendsave, *_Seekhigh;
02906     int _Alsize;
02907     std::_Strstate _Strmode;
02908     std::allocator<_E> _Al;
02909 };
02910 
02911 struct fast_ostringstream : public std::iostream
02912 {
02913     typedef std::iostream super;
02914 
02915     explicit fast_ostringstream()
02916         : super(&_Sb) {}
02917 
02918     std::string str() const
02919         {return _Sb.str();}
02920 
02921 private:
02922     fast_ostringbuffer _Sb;
02923 };
02924 
02925 #else
02926 
02927 typedef std::ostringstream fast_ostringstream;
02928 
02929 #endif
02930 
02931 
02932  /// XML document holder
02933 struct XMLDoc : public XMLNode
02934 {
02935     XMLDoc()
02936      :  XMLNode("")
02937     {
02938     }
02939 
02940     XMLDoc(LPCTSTR path, bool force_utf8=false)
02941      :  XMLNode("")
02942     {
02943         read_file(path, force_utf8);
02944     }
02945 
02946 #ifdef XS_USE_XERCES
02947     bool read_file(LPCTSTR path, bool force_utf8=false)
02948     {
02949         XMLReader reader(this, path);
02950 
02951 #if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8)
02952         return read(reader, std::string(ANS(path)), force_utf8);
02953 #else
02954         return read(reader, XS_String(path), force_utf8);
02955 #endif
02956     }
02957 
02958     bool read_buffer(const char* buffer, size_t len, const std::string& system_id=std::string(), bool force_utf8=false)
02959     {
02960         XMLReader reader(this, (const XMLByte*)buffer, len, system_id);
02961 
02962         return read(reader, system_id, force_utf8);
02963     }
02964 
02965     bool read_buffer(const std::string& in, const std::string& system_id=std::string(), bool force_utf8=false)
02966     {
02967         return read_buffer(in.c_str(), in.length(), system_id, force_utf8);
02968     }
02969 
02970 #else // XS_USE_XERCES
02971 
02972     bool read_file(LPCTSTR path, bool force_utf8=false)
02973     {
02974         tifstream in(path);
02975         if (!in.good())
02976             return false;
02977 
02978         XMLReader reader(this, in);
02979 
02980 #if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8)
02981         return read(reader, std::string(ANS(path)), force_utf8);
02982 #else
02983         return read(reader, XS_String(path), force_utf8);
02984 #endif
02985     }
02986 
02987     bool read_buffer(const char* buffer, size_t len, const std::string& system_id=std::string(), bool force_utf8=false)
02988     {
02989         return read_buffer(std::string(buffer, len), system_id, force_utf8);
02990     }
02991 
02992     bool read_buffer(const std::string& buffer, const std::string& system_id=std::string(), bool force_utf8=false)
02993     {
02994         std::istringstream istr(buffer);
02995 
02996         return read_stream(istr, system_id, force_utf8);
02997     }
02998 
02999     bool read_stream(std::istream& in, const std::string& system_id=std::string(), bool force_utf8=false)
03000     {
03001         XMLReader reader(this, in);
03002 
03003         return read(reader, system_id, force_utf8);
03004     }
03005 #endif // XS_USE_XERCES
03006 
03007     bool read(XMLReaderBase& reader, const std::string& display_path, bool force_utf8=false)
03008     {
03009 #ifdef XS_NATIVE
03010         reader.setSystemId(display_path.c_str());
03011 #elif defiend(XMLNODE_LOCATION)
03012          // make a string copy to handle temporary string objects
03013         _display_path = display_path;
03014         reader._display_path = _display_path.c_str();
03015 #endif
03016 
03017         reader.clear_errors();
03018         reader.read(force_utf8);
03019 
03020         _format = reader.get_format();
03021         _format._endl = reader.get_endl();
03022 
03023         if (!reader.get_errors().empty()) {
03024             _errors = reader.get_errors();
03025             return false;
03026         }
03027 
03028         return true;
03029     }
03030 
03031      /// write XML stream
03032      // FORMAT_SMART: preserving previous white space and comments
03033     bool write(std::ostream& out, WRITE_MODE mode=FORMAT_SMART) const
03034     {
03035         _format.print_header(out, mode!=FORMAT_PLAIN);
03036 
03037         if (_children.size() == 1)
03038             _children.front()->write(out, _format, mode);
03039         else if (!_children.empty()) {
03040             //throw Exception("more than one XML root!");
03041             return false;
03042         }
03043 
03044         return out.good();
03045     }
03046 
03047      /// write XML stream with formating
03048     bool write_formating(std::ostream& out) const
03049     {
03050         return write(out, FORMAT_PRETTY);
03051     }
03052 
03053     bool write_file(LPCTSTR path, WRITE_MODE mode=FORMAT_SMART) const
03054     {
03055         tofstream out(path);
03056 
03057         return write(out, mode);
03058     }
03059 
03060     bool write_formating(LPCTSTR path) const
03061     {
03062         tofstream out(path);
03063 
03064         return write_formating(out);
03065     }
03066 
03067     XMLFormat       _format;
03068     XMLErrorList    _errors;
03069 
03070 #ifdef XMLNODE_LOCATION
03071     std::string     _display_path;
03072 #endif
03073 };
03074 
03075 
03076 struct XMLStateReader : public XMLReader
03077 {
03078     enum XML_STATE {
03079         XSS_NONE,
03080         XSS_START_ELEMENT,
03081         XSS_END_ELEMENT,
03082         XSS_ELEMENT,
03083         XSS_CHARACTERS,
03084     //  XSS_COMMENT,
03085     //  XSS_SPACE,
03086     //  XSS_CDATA,
03087     //  XSS_PROCESSING_INSTRUCTION
03088     };
03089 
03090     XMLStateReader(XMLNode* node, std::istream& in)
03091      :  XMLReader(node, in),
03092         _parse_ctx(*this),
03093         _state(XSS_NONE)
03094     {
03095     }
03096 
03097     bool    has_next();
03098     void    next();
03099 
03100 //  virtual void XmlDeclHandler(const char* version, const char* encoding, int standalone);
03101     virtual void StartElementHandler(const XS_String& name, const XMLNode::AttributeMap& attr);
03102     virtual void EndElementHandler();
03103     virtual void DefaultHandler(const std::string& s);
03104 
03105     ParseContext    _parse_ctx;
03106 
03107     enum XML_STATE  _state;
03108     XS_String       _node_name;
03109     XMLNode::AttributeMap _attrs;
03110 };
03111 
03112 
03113 struct XMLStreamReader
03114 {
03115     typedef XMLReader super;
03116 
03117     XMLStreamReader(std::istream& in)
03118      :  _pInFile(NULL),
03119         _state_rdr(NULL, in),
03120         _level(0),
03121         _node(XS_EMPTY_STR)
03122     {
03123     }
03124 
03125     XMLStreamReader(LPCTSTR path)
03126      :  _pInFile(new tifstream(path)),
03127         _state_rdr(NULL, *_pInFile),
03128         _level(0),
03129         _node(XS_EMPTY_STR)
03130     {
03131 #ifdef UNICODE
03132         _state_rdr._parse_ctx._reader.setSystemId(std::string(XS_String(path)).c_str());
03133 #else
03134         _state_rdr._parse_ctx._reader.setSystemId(path);
03135 #endif
03136     }
03137 
03138     ~XMLStreamReader()
03139     {
03140         delete _pInFile;
03141     }
03142 
03143 /*TODO
03144     XS_String getInstructions() const
03145     {
03146         return _instructions;
03147     }
03148 */
03149     const XMLNode* operator->() const
03150     {
03151         return &_node;
03152     }
03153 
03154     operator const XMLNode*() const
03155     {
03156         return &_node;
03157     }
03158 
03159     XS_String str() const
03160     {
03161         return _node;
03162     }
03163 
03164     /**
03165      * Return the value of an attribute in the current node.
03166      * @param attr_name
03167      * @return
03168      */
03169     XS_String operator[](const XS_String& attr_name) const
03170     {
03171         return _node[attr_name];
03172     }
03173 
03174     /**
03175      * Go down to first child.
03176      * @return true if successfull
03177      */
03178     bool go_down()
03179     {
03180         return first_child();
03181     }
03182 
03183     /**
03184      * Search for child and go down.
03185      * @param child_name
03186      * @return
03187      */
03188     bool go_down(LPCXSSTR child_name)
03189     {
03190         return first_child(child_name);
03191     }
03192 
03193     /**
03194      * Move back to the next higher nesting level.
03195      * Remark: This implementation does _not_ jump more than one level up like XMLPos.node()
03196      * when using go() to move down more than one level at a time.
03197      * @return true if successfull
03198      */
03199     bool back()
03200     {
03201         if (find_node(NULL, -1, _level+1, false))
03202 //      if (find_node(NULL, _level-1, _level-1, false))
03203             return true;
03204         else {
03205             assert(_level>=0); // tried to move out of the tree hierarchy
03206             return false;
03207         }
03208     }
03209 
03210     /**
03211      * Move to the first child node with the specified name.
03212      * @return true on success
03213      */
03214     bool first_child(LPCXSSTR node_name=NULL)
03215     {
03216         return find_node(node_name, _level+1, _level, false);
03217     }
03218 
03219     /**
03220      * Move to the next sibling node independent from its name.
03221      * @return true on success
03222      */
03223     bool next()
03224     {
03225         return find_node(NULL, _level, _level-1, false);
03226     }
03227 
03228     /**
03229      * Move to the next sibling node with the specified name.
03230      * @return true on success
03231      */
03232     bool next_skip_others(const XS_String& node_name)
03233     {
03234         return find_node(node_name, _level, _level-1, false);
03235     }
03236 
03237     /**
03238      * Move to the next sibling node with the specified name
03239      * but stop on other tags.
03240      * @return true on success
03241      */
03242     bool next_stop_on_others(LPCXSSTR node_name=NULL)
03243     {
03244         return find_node(node_name, _level, _level-1, true);
03245     }
03246 
03247      // Search matching child node identified by key name and an attribute value.
03248     bool find(const XPathElement& xelem)
03249     {
03250         // cppcheck-suppress variableScope
03251         int n = 0;
03252 
03253         if (first_child(xelem._child_name)) {
03254             if (xelem.matches(_node, n))
03255                 return true;
03256 
03257             while(next_skip_others(xelem._child_name))
03258                 if (xelem.matches(_node, n))
03259                     return true;
03260         }
03261 
03262         return false;
03263     }
03264 
03265     bool    find_relative(const XPath& xpath);
03266 
03267     const XMLErrorList& get_errors() const {return _state_rdr.get_errors();}
03268 
03269     int     _level;
03270 
03271 private:
03272     tifstream*  _pInFile;
03273     XMLStateReader _state_rdr;
03274     std::string _content;
03275 
03276     XMLStreamReader(const XMLStreamReader&); // disallow object copy
03277 
03278 protected:
03279     bool    find_node(LPCXSSTR target_tag, int target_level, int min_level, bool stop_on_others);
03280 
03281     XMLNode _node;
03282 
03283 //protected:    XS_String   _instructions;
03284 
03285     virtual void StartElementHandler(const XS_String& name, const XMLNode::AttributeMap& attr);
03286     virtual void EndElementHandler();
03287     virtual void DefaultHandler(const std::string& s);
03288 };
03289 
03290 
03291  /// read only iterator access to XMLStreamReader nodes
03292 struct XMLStreamChildrenIterator
03293 {
03294     XMLStreamChildrenIterator(XMLStreamReader& reader)
03295      :  _begin(reader, false),
03296         _end(reader, true)
03297     {
03298     }
03299 
03300      /// internal iterator class
03301     struct const_iterator
03302     {
03303         typedef const_iterator myType;
03304 
03305         const_iterator(XMLStreamReader& reader, bool is_end)
03306          :  _reader(reader),
03307             _start_level(reader._level),
03308             _is_end(is_end)
03309         {
03310             search_next();
03311         }
03312 
03313         const XMLStreamReader& operator->() const
03314         {
03315             return _reader;
03316         }
03317 
03318         XS_String operator*() const
03319         {
03320             return _reader.str();
03321         }
03322 
03323         myType& operator++()
03324         {
03325             if (!_at_end)
03326                 search_next();
03327 
03328             return *this;
03329         }
03330 
03331         myType operator++(int)
03332         {
03333             myType ret = *this;
03334 
03335             if (!_at_end)
03336                 search_next();
03337 
03338             return ret;
03339         }
03340 
03341         bool operator==(const myType& other) const
03342         {
03343             if (other._is_end)
03344                 return _at_end;
03345             else if (_is_end)
03346                 return other._at_end;
03347             else
03348                 return _reader.str() == other._reader.str();
03349         }
03350 
03351         bool operator!=(const myType& other) const
03352         {
03353             if (other._is_end)
03354                 return !_at_end;
03355             else if (_is_end)
03356                 return !other._at_end;
03357             else
03358                 return _reader.str() != other._reader.str();
03359         }
03360 
03361     protected:
03362         XMLStreamReader& _reader;
03363         int         _start_level;
03364         bool        _is_end;
03365         bool        _at_end;
03366 
03367         void search_next()
03368         {
03369             while(!_at_end) {
03370                 _reader.next();
03371 
03372                 if (_reader._level == _start_level)
03373                     _at_end = true;
03374             }
03375         }
03376     };
03377 
03378     const_iterator begin()
03379     {
03380         return _begin;
03381     }
03382 
03383     const_iterator end()
03384     {
03385         return _end;
03386     }
03387 
03388     bool empty() const
03389     {
03390         return _end == _begin;
03391     }
03392 
03393 protected:
03394     const_iterator  _begin;
03395     const_iterator  _end;
03396 };
03397 
03398 
03399  /// read only iterator access to children nodes to XMLStreamReader nodes with name filtering
03400 struct XMLStreamChildrenFilter
03401 {
03402     XMLStreamChildrenFilter(XMLStreamReader& reader, const XS_String& name)
03403      :  _begin(reader, name, false),
03404         _end(reader, name, true)
03405     {
03406     }
03407 
03408      /// internal iterator class
03409     struct const_iterator
03410     {
03411         typedef const_iterator myType;
03412 
03413         const_iterator(XMLStreamReader& reader, const XS_String& filter_name, bool is_end)
03414          :  _reader(reader),
03415             _filter_name(filter_name),
03416             _start_level(reader._level),
03417             _is_end(is_end)
03418         {
03419             search_next();
03420         }
03421 
03422         const XMLStreamReader& operator->() const
03423         {
03424             return _reader;
03425         }
03426 
03427         XS_String operator*() const
03428         {
03429             return _reader.str();
03430         }
03431 
03432         myType& operator++()
03433         {
03434             if (!_at_end)
03435                 search_next();
03436 
03437             return *this;
03438         }
03439 
03440         myType operator++(int)
03441         {
03442             myType ret = *this;
03443 
03444             if (!_at_end)
03445                 search_next();
03446 
03447             return ret;
03448         }
03449 
03450         bool operator==(const myType& other) const
03451         {
03452             if (other._is_end)
03453                 return _at_end;
03454             else if (_is_end)
03455                 return other._at_end;
03456             else
03457                 return _reader.str() == other._reader.str();
03458         }
03459 
03460         bool operator!=(const myType& other) const
03461         {
03462             if (other._is_end)
03463                 return !_at_end;
03464             else if (_is_end)
03465                 return !other._at_end;
03466             else
03467                 return _reader.str() != other._reader.str();
03468         }
03469 
03470     protected:
03471         XMLStreamReader& _reader;
03472         XS_String   _filter_name;
03473         int         _start_level;
03474         bool        _is_end;
03475         bool        _at_end;
03476 
03477         void search_next()
03478         {
03479             while(!_at_end) {
03480                 _reader.next_skip_others(_filter_name);
03481 
03482                 if (_reader._level == _start_level)
03483                     _at_end = true;
03484             }
03485         }
03486     };
03487 
03488     const_iterator begin()
03489     {
03490         return _begin;
03491     }
03492 
03493     const_iterator end()
03494     {
03495         return _end;
03496     }
03497 
03498     bool empty() const
03499     {
03500         return _end == _begin;
03501     }
03502 
03503 protected:
03504     const_iterator  _begin;
03505     const_iterator  _end;
03506 };
03507 
03508 
03509  /// type converter for boolean data
03510 struct XMLBool
03511 {
03512     XMLBool(bool value=false)
03513      :  _value(value)
03514     {
03515     }
03516 
03517     XMLBool(LPCXSSTR value, bool def=false)
03518     {
03519         LPCXSSTR p = safe_skip_space(value);
03520 
03521         if (*p)
03522             _value = !XS_nicmp(p, XS_TRUE, 4); //_tcslen(XS_TRUE_STR)=4
03523         else
03524             _value = def;
03525     }
03526 
03527     XMLBool(const XMLNode* node, const XS_String& attr_name, bool def=false)
03528     {
03529         const XS_String& value = node->get(attr_name);
03530 
03531         if (!value.empty())
03532             _value = !XS_icmp(value.c_str(), XS_TRUE);
03533         else
03534             _value = def;
03535     }
03536 
03537     operator bool() const
03538     {
03539         return _value;
03540     }
03541 
03542     bool operator!() const
03543     {
03544         return !_value;
03545     }
03546 
03547     operator LPCXSSTR() const
03548     {
03549         return _value? XS_TRUE: XS_FALSE;
03550     }
03551 
03552 protected:
03553     bool    _value;
03554 
03555 private:
03556     XMLBool& operator=(const XMLBool&); // disallow assignment operations
03557 };
03558 
03559  /// type converter for boolean data with write access
03560 struct XMLBoolRef
03561 {
03562     XMLBoolRef(XMLNode* node, const XS_String& attr_name, bool def=false)
03563      :  _ref((*node)[attr_name])
03564     {
03565         if (_ref.empty())
03566             assign(def);
03567     }
03568 
03569     operator bool() const
03570     {
03571         return !XS_icmp(_ref.c_str(), XS_TRUE);
03572     }
03573 
03574     bool operator!() const
03575     {
03576         return XS_icmp(_ref.c_str(), XS_TRUE)? true: false;
03577     }
03578 
03579     XMLBoolRef& operator=(bool value)
03580     {
03581         assign(value);
03582 
03583         return *this;
03584     }
03585 
03586     void assign(bool value)
03587     {
03588         _ref.assign(value? XS_TRUE: XS_FALSE);
03589     }
03590 
03591     void toggle()
03592     {
03593         assign(!operator bool());
03594     }
03595 
03596 protected:
03597     XS_String& _ref;
03598 };
03599 
03600 
03601  /// type converter for integer data
03602 struct XMLInt
03603 {
03604     XMLInt(int value)
03605      :  _value(value)
03606     {
03607     }
03608 
03609     XMLInt(size_t value)
03610      :  _value((int)value)
03611     {
03612     }
03613 
03614     XMLInt(LPCXSSTR value, int def=0)
03615     {
03616         LPCXSSTR p = safe_skip_space(value);
03617 
03618         if (*p)
03619             _value = XS_toi(p);
03620         else
03621             _value = def;
03622     }
03623 
03624     XMLInt(const XMLNode* node, const XS_String& attr_name, int def=0)
03625     {
03626         const XS_String& value = node->get(attr_name);
03627 
03628         if (!value.empty())
03629             _value = XS_toi(value.c_str());
03630         else
03631             _value = def;
03632     }
03633 
03634     operator int() const
03635     {
03636         return _value;
03637     }
03638 
03639     operator XS_String() const
03640     {
03641         XS_CHAR buffer[32];
03642         XS_snprintf(buffer, COUNTOF(buffer), XS_INTFMT, _value);
03643         return XS_String(buffer);
03644     }
03645 
03646 protected:
03647     int _value;
03648 
03649 private:
03650     XMLInt& operator=(const XMLInt&); // disallow assignment operations
03651 };
03652 
03653  /// type converter for integer data with write access
03654 struct XMLIntRef
03655 {
03656     XMLIntRef(XMLNode* node, const XS_String& attr_name, int def=0)
03657      :  _ref((*node)[attr_name])
03658     {
03659         if (_ref.empty())
03660             assign(def);
03661     }
03662 
03663     XMLIntRef& operator=(int value)
03664     {
03665         assign(value);
03666 
03667         return *this;
03668     }
03669 
03670     operator int() const
03671     {
03672         return XS_toi(_ref.c_str());
03673     }
03674 
03675     void assign(int value)
03676     {
03677         XS_CHAR buffer[32];
03678         XS_snprintf(buffer, COUNTOF(buffer), XS_INTFMT, value);
03679         _ref.assign(buffer);
03680     }
03681 
03682 protected:
03683     XS_String& _ref;
03684 };
03685 
03686 
03687  /// type converter for integer data
03688 struct XMLInt64
03689 {
03690     XMLInt64(INT64 value)
03691      :  _value(value)
03692     {
03693     }
03694 
03695     XMLInt64(UINT64 value)
03696      :  _value((INT64)value)
03697     {
03698     }
03699 
03700     XMLInt64(LPCXSSTR value, INT64 def=0)
03701     {
03702         LPCXSSTR p = safe_skip_space(value);
03703 
03704         if (*p)
03705             _value = XS_toi64(p);
03706         else
03707             _value = def;
03708     }
03709 
03710     XMLInt64(const XMLNode* node, const XS_String& attr_name, INT64 def=0)
03711     {
03712         const XS_String& value = node->get(attr_name);
03713 
03714         if (!value.empty())
03715             _value = XS_toi64(value.c_str());
03716         else
03717             _value = def;
03718     }
03719 
03720     operator INT64() const
03721     {
03722         return _value;
03723     }
03724 
03725     operator XS_String() const
03726     {
03727         XS_CHAR buffer[64];
03728         XS_snprintf(buffer, COUNTOF(buffer), XS_INT64FMT, _value);
03729         return XS_String(buffer);
03730     }
03731 
03732 protected:
03733     INT64 _value;
03734 
03735 private:
03736     XMLInt64& operator=(const XMLInt64&); // disallow assignment operations
03737 };
03738 
03739  /// type converter for integer data with write access
03740 struct XMLInt64Ref
03741 {
03742     XMLInt64Ref(XMLNode* node, const XS_String& attr_name, INT64 def=0)
03743      :  _ref((*node)[attr_name])
03744     {
03745         if (_ref.empty())
03746             assign(def);
03747     }
03748 
03749     XMLInt64Ref& operator=(INT64 value)
03750     {
03751         assign(value);
03752 
03753         return *this;
03754     }
03755 
03756     operator INT64() const
03757     {
03758         return XS_toi64(_ref.c_str());
03759     }
03760 
03761     void assign(INT64 value)
03762     {
03763         XS_CHAR buffer[64];
03764         XS_snprintf(buffer, COUNTOF(buffer), XS_INT64FMT, value);
03765         _ref.assign(buffer);
03766     }
03767 
03768 protected:
03769     XS_String& _ref;
03770 };
03771 
03772 
03773  /// type converter for numeric data
03774 struct XMLDouble
03775 {
03776     XMLDouble(double value)
03777      :  _value(value)
03778     {
03779     }
03780 
03781     XMLDouble(LPCXSSTR value, double def=0.)
03782     {
03783         LPCXSSTR p = safe_skip_space(value);
03784         LPTSTR end;
03785 
03786         if (*p)
03787             _value = XS_tod(p, &end);
03788         else
03789             _value = def;
03790     }
03791 
03792     XMLDouble(const XMLNode* node, const XS_String& attr_name, double def=0.)
03793     {
03794         LPTSTR end;
03795         const XS_String& value = node->get(attr_name);
03796 
03797         if (!value.empty())
03798             _value = XS_tod(value.c_str(), &end);
03799         else
03800             _value = def;
03801     }
03802 
03803     operator double() const
03804     {
03805         return _value;
03806     }
03807 
03808     operator XS_String() const
03809     {
03810         XS_CHAR buffer[32];
03811         XS_snprintf(buffer, COUNTOF(buffer), XS_FLOATFMT, _value);
03812         return XS_String(buffer);
03813     }
03814 
03815 protected:
03816     double _value;
03817 
03818 private:
03819     XMLDouble& operator=(const XMLDouble&); // disallow assignment operations
03820 };
03821 
03822  /// type converter for numeric data with write access
03823 struct XMLDoubleRef
03824 {
03825     XMLDoubleRef(XMLNode* node, const XS_String& attr_name, double def=0.)
03826      :  _ref((*node)[attr_name])
03827     {
03828         if (_ref.empty())
03829             assign(def);
03830     }
03831 
03832     XMLDoubleRef& operator=(double value)
03833     {
03834         assign(value);
03835 
03836         return *this;
03837     }
03838 
03839     operator double() const
03840     {
03841         LPTSTR end;
03842         return XS_tod(_ref.c_str(), &end);
03843     }
03844 
03845     void assign(double value)
03846     {
03847         XS_CHAR buffer[32];
03848         XS_snprintf(buffer, COUNTOF(buffer), XS_FLOATFMT, value);
03849         _ref.assign(buffer);
03850     }
03851 
03852 protected:
03853     XS_String& _ref;
03854 };
03855 
03856 
03857  /// type converter for string data
03858 struct XMLString
03859 {
03860     XMLString(const XS_String& value)
03861      :  _value(value)
03862     {
03863     }
03864 
03865     XMLString(LPCXSSTR value, LPCXSSTR def=XS_EMPTY)
03866     {
03867         if (value && *value)
03868             _value = value;
03869         else
03870             _value = def;
03871     }
03872 
03873     XMLString(const XMLNode* node, const XS_String& attr_name, LPCXSSTR def=XS_EMPTY)
03874     {
03875         const XS_String& value = node->get(attr_name);
03876 
03877         if (!value.empty())
03878             _value = value;
03879         else
03880             _value = def;
03881     }
03882 
03883     operator const XS_String&() const
03884     {
03885         return _value;
03886     }
03887 
03888     const XS_String& c_str() const
03889     {
03890         return _value;
03891     }
03892 
03893 protected:
03894     XS_String   _value;
03895 
03896 private:
03897     XMLString& operator=(const XMLString&); // disallow assignment operations
03898 };
03899 
03900  /// type converter for string data with write access
03901 struct XMLStringRef
03902 {
03903     XMLStringRef(XMLNode* node, const XS_String& attr_name, LPCXSSTR def=XS_EMPTY)
03904      :  _ref((*node)[attr_name])
03905     {
03906         if (_ref.empty())
03907             assign(def);
03908     }
03909 
03910     XMLStringRef(const XS_String& node_name, XMLNode* node, const XS_String& attr_name, LPCXSSTR def=XS_EMPTY)
03911      :  _ref(node->subvalue(node_name, attr_name))
03912     {
03913         if (_ref.empty())
03914             assign(def);
03915     }
03916 
03917     XMLStringRef& operator=(const XS_String& value)
03918     {
03919         assign(value);
03920 
03921         return *this;
03922     }
03923 
03924     operator const XS_String&() const
03925     {
03926         return _ref;
03927     }
03928 
03929     void assign(const XS_String& value)
03930     {
03931         _ref.assign(value);
03932     }
03933 
03934 protected:
03935     XS_String& _ref;
03936 };
03937 
03938 
03939  // read option (for example configuration) values from XML node attributes
03940 template<typename T>
03941     inline void read_option(T& var, const_XMLPos& cfg, LPCXSSTR key)
03942     {
03943         const XS_String& val = cfg.get(key);
03944 
03945         if (!val.empty())
03946             var = val;
03947     }
03948 
03949  // read integer option values from XML node attributes
03950 template<>
03951     inline void read_option(int& var, const_XMLPos& cfg, LPCXSSTR key)
03952     {
03953         const XS_String& val = cfg.get(key);
03954 
03955         if (!val.empty())
03956             var = XS_toi(val.c_str());
03957     }
03958 
03959 
03960 inline void XMLPos::set_property(const XS_String& key, int value, const XS_String& name)
03961 {
03962     smart_create(name, XS_KEY, key);
03963         XMLIntRef(_cur, XS_VALUE) = value;
03964     back();
03965 }
03966 
03967 inline void XMLPos::set_property(const XS_String& key, double value, const XS_String& name)
03968 {
03969     smart_create(name, XS_KEY, key);
03970         XMLDoubleRef(_cur, XS_VALUE) = value;
03971     back();
03972 }
03973 
03974 inline void XMLPos::set_property(const XS_String& key, const XS_String& value, const XS_String& name)
03975 {
03976     smart_create(name, XS_KEY, key);
03977         put(XS_VALUE, value);
03978     back();
03979 }
03980 
03981 inline void XMLPos::set_property(const XS_String& key, const XMLBool& value, const XS_String& name)
03982 {
03983     smart_create(name, XS_KEY, key);
03984         XMLBoolRef(_cur, XS_VALUE) = value;
03985     back();
03986 }
03987 
03988 
03989  /// a key/value pair for property data access
03990 struct XMLProperty {
03991     XMLProperty(const XMLNode* node)
03992      :  _key(node->get(XS_KEY)),
03993         _value(node->get(XS_VALUE))
03994     {
03995     }
03996 
03997     XS_String   _key;
03998     XS_String   _value;
03999 };
04000 
04001 
04002  /// utility class to read property settings from a XML tree
04003 struct XMLPropertyReader
04004 {
04005     XMLPropertyReader(const XMLNode::Children& children)
04006      :  _filter(children, XS_PROPERTY),
04007         _begin(_filter.begin(), _filter.end()),
04008         _end(_filter.end(), _filter.end())
04009     {
04010     }
04011 
04012     XMLPropertyReader(const XMLNode* node)
04013      :  _filter(node, XS_PROPERTY),
04014         _begin(_filter.begin(), _filter.end()),
04015         _end(_filter.end(), _filter.end())
04016     {
04017     }
04018 
04019      /// internal iterator class
04020     struct const_iterator
04021     {
04022         typedef const_XMLChildrenFilter::const_iterator BaseIterator;
04023         typedef const_iterator myType;
04024 
04025         const_iterator(BaseIterator begin, BaseIterator end)
04026          :  _cur(begin),
04027             _end(end)
04028         {
04029         }
04030 
04031         operator BaseIterator()
04032         {
04033             return _cur;
04034         }
04035 
04036         XMLProperty operator*() const
04037         {
04038             return XMLProperty(*_cur);
04039         }
04040 
04041         const XMLNode* get_node() const
04042         {
04043             return *_cur;
04044         }
04045 
04046         myType& operator++()
04047         {
04048             ++_cur;
04049 
04050             return *this;
04051         }
04052 
04053         myType operator++(int)
04054         {
04055             myType ret = *this;
04056 
04057             ++_cur;
04058 
04059             return ret;
04060         }
04061 
04062         bool operator==(const myType& other) const
04063         {
04064             return _cur == other._cur;
04065         }
04066 
04067         bool operator!=(const myType& other) const
04068         {
04069             return _cur != other._cur;
04070         }
04071 
04072     protected:
04073         BaseIterator    _cur;
04074         BaseIterator    _end;
04075     };
04076 
04077     const_iterator begin()
04078     {
04079         return _begin;
04080     }
04081 
04082     const_iterator end()
04083     {
04084         return _end;
04085     }
04086 
04087     bool empty() const
04088     {
04089         return _end == _begin;
04090     }
04091 
04092 protected:
04093     const_XMLChildrenFilter _filter;
04094 
04095     const_iterator  _begin;
04096     const_iterator  _end;
04097 };
04098 
04099 
04100  /// XML message wrapper
04101 struct XMLMessage : public XMLDoc
04102 {
04103     XMLMessage(const char* name)
04104      :  _pos(this)
04105     {
04106         _pos.create(name);
04107     }
04108 
04109     std::string toString() const
04110     {
04111         std::ostringstream out;
04112 
04113         write(out);
04114 
04115         return out.str();
04116     }
04117 
04118     XMLPos  _pos;
04119 
04120 protected:
04121     XMLMessage()
04122      :  _pos(this)
04123     {
04124     }
04125 };
04126 
04127 
04128  /// helper structure to read XML messages from strings
04129 struct XMLMessageFromString : public XMLMessage
04130 {
04131     XMLMessageFromString(const std::string& xml_str, const std::string& system_id=std::string())
04132     {
04133         read_buffer(xml_str.c_str(), xml_str.length(), system_id);
04134     }
04135 };
04136 
04137 
04138  /// Reader for XML Messages
04139 struct XMLMessageReader : public XMLPos
04140 {
04141     XMLMessageReader(const std::string& xml_str, const std::string& system_id=std::string())
04142      :  XMLPos(&_msg)
04143     {
04144         _msg.read_buffer(xml_str.c_str(), xml_str.length(), system_id);
04145     }
04146 
04147     const XMLDoc& get_document()
04148     {
04149         return _msg;
04150     }
04151 
04152 protected:
04153     XMLDoc  _msg;
04154 };
04155 
04156 
04157  /// on the fly XML writer
04158 struct XMLWriter
04159 {
04160     XMLWriter(std::ostream& out, const XMLFormat& format=XMLFormat())
04161      :  _pofstream(NULL),
04162         _out(out),
04163         _format(format)
04164     {
04165         format.print_header(_out, false);   // _format._endl is printed in write_pre()
04166     }
04167 
04168     XMLWriter(FILE* pFile, const XMLFormat& format=XMLFormat())
04169      :  _pofstream(new tofstream(pFile)),
04170         _out(*_pofstream),
04171         _format(format)
04172     {
04173         format.print_header(_out, false);   // _format._endl is printed in write_pre()
04174     }
04175 
04176     XMLWriter(LPCTSTR path, const XMLFormat& format=XMLFormat())
04177      :  _pofstream(new tofstream(path)),
04178         _out(*_pofstream),
04179         _format(format)
04180     {
04181         format.print_header(_out, false);   // _format._endl is printed in write_pre()
04182     }
04183 
04184     ~XMLWriter()
04185     {
04186         _out << _format._endl;
04187         _out.flush();
04188         delete _pofstream;
04189     }
04190 
04191     bool good() const
04192     {
04193         return _out.good();
04194     }
04195 
04196      /// create node and move to it
04197     void create(const XS_String& name);
04198 
04199      /// go back to previous position
04200     bool back();
04201 
04202      /// attribute setting
04203     void put(const XS_String& attr_name, const XS_String& value)
04204     {
04205         if (!_stack.empty())
04206             _stack.top()._attributes[attr_name] = value;
04207     }
04208 
04209      /// index operator write access to an attribute
04210     XS_String& operator[](const XS_String& attr_name)
04211     {
04212         if (_stack.empty())
04213             return s_empty_attr;
04214 
04215         return _stack.top()._attributes[attr_name];
04216     }
04217 
04218     void set_attributes(const XMLNode::AttributeMap& attrs)
04219     {
04220         if (!_stack.empty())
04221             _stack.top()._attributes = attrs;
04222     }
04223 
04224      /// set element node content
04225     void set_content(const XS_String& s, bool cdata=false)
04226     {
04227         if (!_stack.empty())
04228             _stack.top()._content = EncodeXMLString(s.c_str(), cdata);
04229     }
04230 
04231      /// set element node content from encoded string
04232     void set_encoded_content(const std::string& s)
04233     {
04234         if (!_stack.empty())
04235             _stack.top()._content = s;
04236     }
04237 
04238      /// create node with string content
04239     void create_node_content(const XS_String& node_name, const XS_String& content)
04240     {
04241         create(node_name);
04242             set_content(content);
04243         back();
04244     }
04245 
04246      /// direct string output
04247     void write(const std::string& s);
04248 
04249      // public for access in StackEntry
04250     enum WRITESTATE {
04251         NOTHING, /*PRE,*/ ATTRIBUTES, PRE_CLOSED, /*CONTENT,*/ POST
04252     };
04253 
04254 protected:
04255     tofstream*      _pofstream;
04256     std::ostream&   _out;
04257     XMLFormat       _format;
04258 
04259     typedef XMLNode::AttributeMap AttrMap;
04260 
04261      /// container for XMLWriter state information
04262     struct StackEntry {
04263         XS_String   _node_name;
04264         AttrMap     _attributes;
04265         std::string _content;
04266         WRITESTATE  _state;
04267         bool        _children;
04268 
04269         StackEntry() : _state(NOTHING), _children(false) {}
04270     };
04271 
04272     std::stack<StackEntry> _stack;
04273 
04274     static XS_String s_empty_attr;
04275 
04276     void close_pre(StackEntry& entry);
04277     void write_pre(StackEntry& entry);
04278     void write_attributes(StackEntry& entry);
04279     void write_post(StackEntry& entry);
04280 
04281 private:
04282     XMLWriter(const XMLWriter&); // disallow object copy
04283 };
04284 
04285 
04286 }   // namespace XMLStorage
04287 
04288 #ifdef _MSC_VER
04289 #pragma warning(pop) // C4512: assignment operator could not be generated
04290 #endif
04291 
04292 #define _XMLSTORAGE_H
04293 #endif // _XMLSTORAGE_H

Generated on Fri Nov 14 2014 00:05:04 for XMLStorage/C++ by  doxygen 1.7.2