xmlstorage.h

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

ROS Explorer Source Code Documentation
generated on 02.01.2013 by doxygen

ROS Explorer Homepage