00001 00002 // 00003 // XML storage classes 00004 // 00005 // xmlstorage.h 00006 // 00007 // Copyright (c) 2004, 2005, 2006 Martin Fuchs <martin-fuchs@gmx.net> 00008 // 00009 00010 00011 /* 00012 00013 All rights reserved. 00014 00015 Redistribution and use in source and binary forms, with or without 00016 modification, are permitted provided that the following conditions are met: 00017 00018 * Redistributions of source code must retain the above copyright 00019 notice, this list of conditions and the following disclaimer. 00020 * Redistributions in binary form must reproduce the above copyright 00021 notice, this list of conditions and the following disclaimer in 00022 the documentation and/or other materials provided with the 00023 distribution. 00024 00025 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00026 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00027 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00028 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00029 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00030 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00031 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00032 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00033 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00034 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00035 POSSIBILITY OF SUCH DAMAGE. 00036 00037 */ 00038 00039 #ifndef _XMLSTORAGE_H 00040 00041 00042 #if _MSC_VER>=1400 00043 #ifndef _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 00044 #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 00045 #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 1 00046 #define _CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES 1 00047 #endif 00048 #endif 00049 00050 00051 #ifdef XS_USE_XERCES 00052 00053 #ifndef UNICODE 00054 #ifndef XS_STRING_UTF8 00055 #define XS_STRING_UTF8 00056 #endif 00057 #endif 00058 00059 #include <xercesc/parsers/SAXParser.hpp> 00060 #include <xercesc/sax/HandlerBase.hpp> 00061 00062 using XERCES_CPP_NAMESPACE_QUALIFIER Locator; 00063 using XERCES_CPP_NAMESPACE_QUALIFIER SAXParser; 00064 using XERCES_CPP_NAMESPACE_QUALIFIER HandlerBase; 00065 using XERCES_CPP_NAMESPACE_QUALIFIER InputSource; 00066 using XERCES_CPP_NAMESPACE_QUALIFIER AttributeList; 00067 using XERCES_CPP_NAMESPACE_QUALIFIER SAXParseException; 00068 00069 typedef XMLCh XML_Char; 00070 00071 #elif defined(XS_USE_EXPAT) 00072 00073 #include <expat/expat.h> 00074 00075 #endif 00076 00077 00078 #ifdef _MSC_VER 00079 #pragma warning(disable: 4786) 00080 00081 #ifndef XS_NO_COMMENT 00082 00083 #ifdef XS_USE_XERCES 00084 #ifdef _DEBUG 00085 #pragma comment(lib, "xerces-c_2D") 00086 #else 00087 #pragma comment(lib, "xerces-c_2") 00088 #endif 00089 #elif defined(XS_USE_EXPAT) 00090 #ifdef XML_STATIC 00091 #ifndef _DEBUG 00092 #pragma comment(lib, "libexpatMT") 00093 #endif 00094 #else 00095 #pragma comment(lib, "libexpat") 00096 #endif 00097 #endif 00098 00099 #ifndef _STRING_DEFINED // _STRING_DEFINED only allowed if using xmlstorage.cpp embedded in the project 00100 #if defined(_DEBUG) && defined(_DLL) // DEBUG version only supported with MSVCRTD 00101 #if _MSC_VER==1400 00102 #pragma comment(lib, "xmlstorage-vc8d") 00103 #else 00104 #pragma comment(lib, "xmlstorage-vc6d") 00105 #endif 00106 #else 00107 #ifdef _DLL 00108 #if _MSC_VER==1400 00109 #pragma comment(lib, "xmlstorage-vc8") 00110 #else 00111 #pragma comment(lib, "xmlstorage-vc6") 00112 #endif 00113 #elif defined(_MT) 00114 #if _MSC_VER==1400 00115 #pragma comment(lib, "xmlstorage-vc8t") 00116 #else 00117 #pragma comment(lib, "xmlstorage-vc6t") 00118 #endif 00119 #else 00120 // -ML is no more supported by VS2005. 00121 #pragma comment(lib, "xmlstorage-vc6l") 00122 #endif 00123 #endif 00124 #endif // _STRING_DEFINED 00125 00126 #endif // XS_NO_COMMENT 00127 00128 #endif // _MSC_VER 00129 00130 00131 #ifdef UNICODE 00132 #ifndef _UNICODE 00133 #define _UNICODE 00134 #endif 00135 #else 00136 #ifdef _UNICODE 00137 #define UNICODE 00138 #endif 00139 #endif 00140 00141 #include <windows.h> // for LPCTSTR 00142 00143 #include <tchar.h> 00144 #include <malloc.h> 00145 00146 #include <fstream> 00147 #include <sstream> 00148 #include <string> 00149 #include <stack> 00150 #include <list> 00151 #include <map> 00152 00153 00154 #ifndef BUFFER_LEN 00155 #define BUFFER_LEN 2048 00156 #endif 00157 00158 00159 namespace XMLStorage { 00160 00161 00162 #ifndef XS_String 00163 00164 #ifdef XS_STRING_UTF8 00165 #define XS_CHAR char 00166 #define XS_TEXT(x) x 00167 #define LPXSSTR LPSTR 00168 #define LPCXSSTR LPCSTR 00169 #define XS_cmp strcmp 00170 #define XS_icmp stricmp 00171 #define XS_ncmp strncmp 00172 #define XS_nicmp strnicmp 00173 #define XS_toi atoi 00174 #define XS_tod strtod 00175 #define XS_len strlen 00176 #define XS_snprintf _snprintf 00177 #define XS_vsnprintf _vsnprintf 00178 #define XS_strstr strstr 00179 #else 00180 #define XS_CHAR TCHAR 00181 #define XS_TEXT(x) TEXT(x) 00182 #define LPXSSTR LPTSTR 00183 #define LPCXSSTR LPCTSTR 00184 #define XS_cmp _tcscmp 00185 #define XS_icmp _tcsicmp 00186 #define XS_ncmp _tcsncmp 00187 #define XS_nicmp _tcsnicmp 00188 #define XS_toi _ttoi 00189 #define XS_tod _tcstod 00190 #define XS_len _tcslen 00191 #define XS_snprintf _sntprintf 00192 #define XS_vsnprintf _vsntprintf 00193 #define XS_strstr _tcsstr 00194 #endif 00195 00196 #ifndef COUNTOF 00197 #if _MSC_VER>=1400 00198 #define COUNTOF _countof 00199 #else 00200 #define COUNTOF(b) (sizeof(b)/sizeof(b[0])) 00201 #endif 00202 #endif 00203 00204 00205 int inline isxmlsym(unsigned char c) 00206 { 00207 return isalnum(c) || c=='_' || c=='-'; 00208 } 00209 00210 00211 #if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8) 00212 00213 #define XS_String String 00214 00215 #else // _STRING_DEFINED, !XS_STRING_UTF8 00216 00217 /// string class for TCHAR strings 00218 00219 struct XS_String 00220 #if defined(UNICODE) && !defined(XS_STRING_UTF8) 00221 : public std::wstring 00222 #else 00223 : public std::string 00224 #endif 00225 { 00226 #if defined(UNICODE) && !defined(XS_STRING_UTF8) 00227 typedef std::wstring super; 00228 #else 00229 typedef std::string super; 00230 #endif 00231 00232 XS_String() {} 00233 00234 XS_String(LPCXSSTR s) {if (s) super::assign(s);} 00235 XS_String(LPCXSSTR s, size_t l) : super(s, l) {} 00236 00237 XS_String(const super& other) : super(other) {} 00238 XS_String(const XS_String& other) : super(other) {} 00239 00240 #if defined(UNICODE) && !defined(XS_STRING_UTF8) 00241 XS_String(LPCSTR s) {assign(s);} 00242 XS_String(LPCSTR s, size_t l) {assign(s, l);} 00243 XS_String(const std::string& other) {assign(other.c_str());} 00244 XS_String& operator=(LPCSTR s) {assign(s); return *this;} 00245 void assign(LPCSTR s) {if (s) {size_t bl=strlen(s); LPWSTR b=(LPWSTR)alloca(sizeof(WCHAR)*bl); super::assign(b, MultiByteToWideChar(CP_ACP, 0, s, bl, b, bl));} else erase();} 00246 void assign(LPCSTR s, size_t l) {if (s) {size_t bl=l; LPWSTR b=(LPWSTR)alloca(sizeof(WCHAR)*bl); super::assign(b, MultiByteToWideChar(CP_ACP, 0, s, l, b, bl));} else erase();} 00247 #else 00248 XS_String(LPCWSTR s) {assign(s);} 00249 XS_String(LPCWSTR s, size_t l) {assign(s, l);} 00250 XS_String(const std::wstring& other) {assign(other.c_str());} 00251 XS_String& operator=(LPCWSTR s) {assign(s); return *this;} 00252 #ifdef XS_STRING_UTF8 00253 void assign(const XS_String& s) {assign(s.c_str());} 00254 void assign(LPCWSTR s) {if (s) {size_t bl=wcslen(s); LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_UTF8, 0, s, (int)bl, b, (int)bl, 0, 0));} else erase();} 00255 void assign(LPCWSTR s, size_t l) {size_t bl=l; if (s) {LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_UTF8, 0, s, (int)l, b, (int)bl, 0, 0));} else erase();} 00256 #else // if !UNICODE && !XS_STRING_UTF8 00257 void assign(LPCWSTR s) {if (s) {size_t bl=wcslen(s); LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_ACP, 0, s, (int)bl, b, (int)bl, 0, 0));} else erase();} 00258 void assign(LPCWSTR s, size_t l) {size_t bl=l; if (s) {LPSTR b=(LPSTR)alloca(bl); super::assign(b, WideCharToMultiByte(CP_ACP, 0, s, (int)l, b, (int)bl, 0, 0));} else erase();} 00259 #endif 00260 #endif 00261 00262 XS_String& operator=(LPCXSSTR s) {if (s) super::assign(s); else erase(); return *this;} 00263 XS_String& operator=(const super& s) {super::assign(s); return *this;} 00264 void assign(LPCXSSTR s) {super::assign(s);} 00265 void assign(LPCXSSTR s, size_t l) {super::assign(s, l);} 00266 00267 operator LPCXSSTR() const {return c_str();} 00268 00269 #ifdef XS_STRING_UTF8 00270 operator std::wstring() const {size_t bl=length(); LPWSTR b=(LPWSTR)alloca(sizeof(WCHAR)*bl); return std::wstring(b, MultiByteToWideChar(CP_UTF8, 0, c_str(), bl, b, bl));} 00271 #elif defined(UNICODE) 00272 operator std::string() const {size_t bl=length(); LPSTR b=(LPSTR)alloca(bl); return std::string(b, WideCharToMultiByte(CP_ACP, 0, c_str(), bl, b, bl, 0, 0));} 00273 #else 00274 operator std::wstring() const {size_t bl=length(); LPWSTR b=(LPWSTR)alloca(sizeof(WCHAR)*bl); return std::wstring(b, MultiByteToWideChar(CP_ACP, 0, c_str(), (int)bl, b, (int)bl));} 00275 #endif 00276 00277 XS_String& printf(LPCXSSTR fmt, ...) 00278 { 00279 va_list l; 00280 XS_CHAR b[BUFFER_LEN]; 00281 00282 va_start(l, fmt); 00283 super::assign(b, XS_vsnprintf(b, COUNTOF(b), fmt, l)); 00284 va_end(l); 00285 00286 return *this; 00287 } 00288 00289 XS_String& vprintf(LPCXSSTR fmt, va_list l) 00290 { 00291 XS_CHAR b[BUFFER_LEN]; 00292 00293 super::assign(b, XS_vsnprintf(b, COUNTOF(b), fmt, l)); 00294 00295 return *this; 00296 } 00297 00298 XS_String& appendf(LPCXSSTR fmt, ...) 00299 { 00300 va_list l; 00301 XS_CHAR b[BUFFER_LEN]; 00302 00303 va_start(l, fmt); 00304 super::append(b, XS_vsnprintf(b, COUNTOF(b), fmt, l)); 00305 va_end(l); 00306 00307 return *this; 00308 } 00309 00310 XS_String& vappendf(LPCXSSTR fmt, va_list l) 00311 { 00312 XS_CHAR b[BUFFER_LEN]; 00313 00314 super::append(b, XS_vsnprintf(b, COUNTOF(b), fmt, l)); 00315 00316 return *this; 00317 } 00318 }; 00319 00320 #endif // _STRING_DEFINED, !XS_STRING_UTF8 00321 00322 #endif // XS_String 00323 00324 00325 #define XS_EMPTY_STR XS_TEXT("") 00326 #define XS_TRUE_STR XS_TEXT("true") 00327 #define XS_FALSE_STR XS_TEXT("false") 00328 #define XS_INTFMT_STR XS_TEXT("%d") 00329 #define XS_FLOATFMT_STR XS_TEXT("%f") 00330 00331 // work around GCC's wide string constant bug 00332 #ifdef __GNUC__ 00333 extern const LPCXSSTR XS_EMPTY; 00334 extern const LPCXSSTR XS_TRUE; 00335 extern const LPCXSSTR XS_FALSE; 00336 extern const LPCXSSTR XS_INTFMT; 00337 extern const LPCXSSTR XS_FLOATFMT; 00338 #else 00339 #define XS_EMPTY XS_EMPTY_STR 00340 #define XS_TRUE XS_TRUE_STR 00341 #define XS_FALSE XS_FALSE_STR 00342 #define XS_INTFMT XS_INTFMT_STR 00343 #define XS_FLOATFMT XS_FLOATFMT_STR 00344 #endif 00345 00346 00347 #ifndef XS_STRING_UTF8 00348 00349 // from UTF-8 to XS internal string encoding 00350 inline void assign_utf8(XS_String& s, const char* str, int lutf8) 00351 { 00352 #ifdef UNICODE 00353 LPTSTR buffer = (LPTSTR)alloca(sizeof(TCHAR)*lutf8); 00354 int l = MultiByteToWideChar(CP_UTF8, 0, str, lutf8, buffer, lutf8); 00355 #else 00356 LPWSTR wbuffer = (LPWSTR)alloca(sizeof(WCHAR)*lutf8); 00357 int l = MultiByteToWideChar(CP_UTF8, 0, str, lutf8, wbuffer, lutf8); 00358 00359 int bl=2*l; LPSTR buffer = (LPSTR)alloca(bl); 00360 l = WideCharToMultiByte(CP_ACP, 0, wbuffer, l, buffer, bl, 0, 0); 00361 #endif 00362 00363 s.assign(buffer, l); 00364 } 00365 00366 // from UTF-8 to XS internal string encoding 00367 inline void assign_utf8(XS_String& s, const char* str) 00368 { 00369 assign_utf8(s, str, strlen(str)); 00370 } 00371 00372 // from XS internal string encoding to UTF-8 00373 inline std::string get_utf8(LPCTSTR s, size_t l) 00374 { 00375 #ifdef UNICODE 00376 size_t bl=2*l; LPSTR buffer = (LPSTR)alloca(bl); 00377 l = WideCharToMultiByte(CP_UTF8, 0, s, (int)l, buffer, (int)bl, 0, 0); 00378 #else 00379 LPWSTR wbuffer = (LPWSTR)alloca(sizeof(WCHAR)*l); 00380 l = MultiByteToWideChar(CP_ACP, 0, s, (int)l, wbuffer, (int)l); 00381 00382 size_t bl=2*l; LPSTR buffer = (LPSTR)alloca(bl); 00383 l = WideCharToMultiByte(CP_UTF8, 0, wbuffer, (int)l, buffer, (int)bl, 0, 0); 00384 #endif 00385 00386 return std::string(buffer, l); 00387 } 00388 00389 #ifdef UNICODE 00390 // from XS internal string encoding to UTF-8 00391 inline std::string get_utf8(const char* s, size_t l) 00392 { 00393 LPWSTR wbuffer = (LPWSTR)alloca(sizeof(WCHAR)*l); 00394 l = MultiByteToWideChar(CP_ACP, 0, s, (int)l, wbuffer, (int)l); 00395 00396 size_t bl=2*l; LPSTR buffer = (LPSTR)alloca(bl); 00397 l = WideCharToMultiByte(CP_UTF8, 0, wbuffer, (int)l, buffer, (int)bl, 0, 0); 00398 00399 return std::string(buffer, l); 00400 } 00401 #endif 00402 00403 // from XS internal string encoding to UTF-8 00404 inline std::string get_utf8(const XS_String& s) 00405 { 00406 return get_utf8(s.c_str(), s.length()); 00407 } 00408 00409 #endif // XS_STRING_UTF8 00410 00411 extern std::string EncodeXMLString(const XS_String& str); 00412 extern XS_String DecodeXMLString(const XS_String& str); 00413 00414 00415 #ifdef __GNUC__ 00416 #include <ext/stdio_filebuf.h> 00417 typedef __gnu_cxx::stdio_filebuf<char> STDIO_FILEBUF; 00418 #else 00419 typedef std::filebuf STDIO_FILEBUF; 00420 #endif 00421 00422 struct FileHolder 00423 { 00424 FileHolder(LPCTSTR path, LPCTSTR mode) 00425 { 00426 #ifdef __STDC_WANT_SECURE_LIB__ // secure CRT functions using VS 2005 00427 if (_tfopen_s(&_pfile, path, mode) != 0) 00428 _pfile = NULL; 00429 #else 00430 _pfile = _tfopen(path, mode); 00431 #endif 00432 } 00433 00434 ~FileHolder() 00435 { 00436 if (_pfile) 00437 fclose(_pfile); 00438 } 00439 00440 protected: 00441 FILE* _pfile; 00442 }; 00443 00444 /// input file stream with ANSI/UNICODE file names 00445 struct tifstream : public std::istream, FileHolder 00446 { 00447 typedef std::istream super; 00448 00449 tifstream(LPCTSTR path) 00450 : super(&_buf), 00451 FileHolder(path, TEXT("rb")), // binary mode is important for XMLReader::read_buffer() with MinGW libraries 00452 #ifdef __GNUC__ 00453 _buf(_pfile, std::ios::in) 00454 #else 00455 _buf(_pfile) 00456 #endif 00457 { 00458 } 00459 00460 protected: 00461 STDIO_FILEBUF _buf; 00462 }; 00463 00464 /// output file stream with ANSI/UNICODE file names 00465 struct tofstream : public std::ostream, FileHolder 00466 { 00467 typedef std::ostream super; 00468 00469 tofstream(LPCTSTR path) 00470 : super(&_buf), 00471 FileHolder(path, TEXT("wb")), 00472 #ifdef __GNUC__ 00473 _buf(_pfile, std::ios::out) 00474 #else 00475 _buf(_pfile) 00476 #endif 00477 { 00478 } 00479 00480 ~tofstream() 00481 { 00482 flush(); 00483 } 00484 00485 protected: 00486 STDIO_FILEBUF _buf; 00487 }; 00488 00489 00490 // write XML files with 2 spaces indenting 00491 #define XML_INDENT_SPACE " " 00492 00493 00494 #if defined(XS_USE_XERCES) || defined(XS_USE_EXPAT) 00495 00496 #if defined(XML_UNICODE)/*Expat*/ || defined(XS_USE_XERCES)/*Xerces*/ // Are Expat/Xerces XML strings UTF-16 encoded? 00497 typedef XS_String String_from_XML_Char; 00498 00499 #elif defined(XS_STRING_UTF8) 00500 typedef XS_String String_from_XML_Char; 00501 00502 #else 00503 00504 /// converter from Expat/Xerces strings to XMLStorage internal strings 00505 struct String_from_XML_Char : public XS_String 00506 { 00507 String_from_XML_Char(const XML_Char* str) 00508 { 00509 assign_utf8(*this, str); 00510 } 00511 }; 00512 00513 #endif 00514 00515 #endif // defined(XS_USE_XERCES) || defined(XS_USE_EXPAT) 00516 00517 00518 #if defined(UNICODE) && !defined(XS_STRING_UTF8) 00519 00520 // optimization for faster UNICODE/ASCII string comparison without temporary A/U conversion 00521 inline bool operator==(const XS_String& s1, const char* s2) 00522 { 00523 LPCWSTR p = s1; 00524 const unsigned char* q = (const unsigned char*)s2; 00525 00526 while(*p && *q) 00527 if (*p++ != *q++) 00528 return false; 00529 00530 return *p == *q; 00531 }; 00532 00533 #endif 00534 00535 00536 /// XML Error with message and location 00537 struct XMLError 00538 { 00539 XMLError() 00540 : _line(0), 00541 _column(0), 00542 _error_code(0) 00543 { 00544 } 00545 00546 std::string str() const; 00547 friend std::ostream& operator<<(std::ostream&, const XMLError& err); 00548 00549 XS_String _message; 00550 XS_String _systemId; 00551 int _line; 00552 int _column; 00553 int _error_code; 00554 }; 00555 00556 struct XMLErrorList : public std::list<XMLError> 00557 { 00558 XS_String str() const; 00559 }; 00560 00561 00562 #ifdef XMLNODE_LOCATION 00563 /// location of XML Node including XML file name 00564 struct XMLLocation 00565 { 00566 XMLLocation() 00567 : _pdisplay_path(NULL), 00568 _line(0), 00569 _column(0) 00570 { 00571 } 00572 00573 XMLLocation(const char* display_path, int line, int column) 00574 : _pdisplay_path(display_path), 00575 _line(line), 00576 _column(column) 00577 { 00578 } 00579 00580 std::string str() const; 00581 00582 protected: 00583 const char* _pdisplay_path; // character pointer for fast reference 00584 int _line; 00585 int _column; 00586 }; 00587 #endif 00588 00589 00590 enum PRETTY_FLAGS { 00591 PRETTY_PLAIN = 0, 00592 PRETTY_LINEFEED = 1, 00593 PRETTY_INDENT = 2 00594 }; 00595 00596 00597 struct StyleSheet 00598 { 00599 std::string _href; // CDATA #REQUIRED 00600 std::string _type; // CDATA #REQUIRED 00601 std::string _title; // CDATA #IMPLIED 00602 std::string _media; // CDATA #IMPLIED 00603 std::string _charset; // CDATA #IMPLIED 00604 bool _alternate; // (yes|no) "no" 00605 00606 StyleSheet() : _alternate(false) {} 00607 00608 StyleSheet(const std::string& href, const std::string& type="text/xsl", bool alternate=false) 00609 : _href(href), 00610 _type(type), 00611 _alternate(alternate) 00612 { 00613 } 00614 00615 bool empty() const {return _href.empty();} 00616 void print(std::ostream& out) const; 00617 }; 00618 00619 struct StyleSheetList : public std::list<StyleSheet> 00620 { 00621 void set(const StyleSheet& stylesheet) 00622 { 00623 clear(); 00624 push_back(stylesheet); 00625 } 00626 }; 00627 00628 00629 struct DocType 00630 { 00631 std::string _name; 00632 00633 // External Document Types are noted, but not parsed. 00634 std::string _public; 00635 std::string _system; 00636 00637 // Internal DTDs are not supported. 00638 00639 void parse(const char* str); 00640 bool empty() const {return _name.empty();} 00641 }; 00642 00643 /// Management of XML file headers and formating 00644 struct XMLFormat 00645 { 00646 XMLFormat(PRETTY_FLAGS pretty=PRETTY_INDENT, const std::string& xml_version="1.0", const std::string& encoding="utf-8", const DocType& doctype=DocType()) 00647 : _pretty(pretty), 00648 _endl("\n"), 00649 _version(xml_version), 00650 _encoding(encoding), 00651 _doctype(doctype), 00652 _standalone(-1) 00653 { 00654 } 00655 00656 void print_header(std::ostream& out, bool lf=true) const; 00657 00658 PRETTY_FLAGS _pretty; 00659 const char* _endl; // line ending string: "\n" or "\r\n" 00660 00661 std::string _version; 00662 std::string _encoding; 00663 00664 DocType _doctype; 00665 00666 StyleSheetList _stylesheets; 00667 00668 // std::string _additional; 00669 00670 int _standalone; 00671 }; 00672 00673 00674 enum WRITE_MODE { 00675 FORMAT_PLAIN, /// write XML without any white space 00676 FORMAT_SMART, /// preserve original white space and comments if present; pretty print otherwise 00677 FORMAT_ORIGINAL, /// write XML stream preserving original white space and comments 00678 FORMAT_PRETTY /// pretty print node to stream without preserving original white space 00679 }; 00680 00681 00682 /// in memory representation of an XML node 00683 struct XMLNode : public XS_String 00684 { 00685 #if defined(UNICODE) && !defined(XS_STRING_UTF8) 00686 // optimized read access without temporary A/U conversion when using ASCII attribute names 00687 struct AttributeMap : public std::map<XS_String, XS_String> 00688 { 00689 typedef std::map<XS_String, XS_String> super; 00690 00691 const_iterator find(const char* x) const 00692 { 00693 for(const_iterator it=begin(); it!=end(); ++it) 00694 if (it->first == x) 00695 return it; 00696 00697 return end(); 00698 } 00699 00700 const_iterator find(const key_type& x) const 00701 { 00702 return super::find(x); 00703 } 00704 00705 iterator find(const key_type& x) 00706 { 00707 return super::find(x); 00708 } 00709 00710 XS_String get(const char* x, LPCXSSTR def=XS_EMPTY_STR) const 00711 { 00712 const_iterator found = find(x); 00713 00714 if (found != end()) 00715 return found->second; 00716 else 00717 return def; 00718 } 00719 }; 00720 #else 00721 struct AttributeMap : public std::map<XS_String, XS_String> 00722 { 00723 XS_String get(const char* x, LPCXSSTR def=XS_EMPTY_STR) const 00724 { 00725 const_iterator found = find(x); 00726 00727 if (found != end()) 00728 return found->second; 00729 else 00730 return def; 00731 } 00732 }; 00733 #endif 00734 00735 /// internal children node list 00736 struct Children : public std::list<XMLNode*> 00737 { 00738 void assign(const Children& other) 00739 { 00740 clear(); 00741 00742 for(Children::const_iterator it=other.begin(); it!=other.end(); ++it) 00743 push_back(new XMLNode(**it)); 00744 } 00745 00746 void clear() 00747 { 00748 while(!empty()) { 00749 XMLNode* node = back(); 00750 pop_back(); 00751 00752 node->clear(); 00753 delete node; 00754 } 00755 } 00756 }; 00757 00758 // access to protected class members for XMLPos and XMLReader 00759 friend struct XMLPos; 00760 friend struct const_XMLPos; 00761 friend struct XMLReaderBase; 00762 00763 XMLNode(const XS_String& name) 00764 : XS_String(name) 00765 { 00766 } 00767 00768 XMLNode(const XS_String& name, const std::string& leading) 00769 : XS_String(name), 00770 _leading(leading) 00771 { 00772 } 00773 00774 XMLNode(const XMLNode& other) 00775 : XS_String(other), 00776 _attributes(other._attributes), 00777 _leading(other._leading), 00778 _content(other._content), 00779 _end_leading(other._end_leading), 00780 _trailing(other._trailing) 00781 #ifdef XMLNODE_LOCATION 00782 , _location(other._location) 00783 #endif 00784 { 00785 for(Children::const_iterator it=other._children.begin(); it!=other._children.end(); ++it) 00786 _children.push_back(new XMLNode(**it)); 00787 } 00788 00789 virtual ~XMLNode() 00790 { 00791 while(!_children.empty()) { 00792 delete _children.back(); 00793 _children.pop_back(); 00794 } 00795 } 00796 00797 void clear() 00798 { 00799 _leading.erase(); 00800 _content.erase(); 00801 _end_leading.erase(); 00802 _trailing.erase(); 00803 00804 _attributes.clear(); 00805 _children.clear(); 00806 00807 XS_String::erase(); 00808 } 00809 00810 XMLNode& operator=(const XMLNode& other) 00811 { 00812 _children.assign(other._children); 00813 00814 _attributes = other._attributes; 00815 00816 _leading = other._leading; 00817 _content = other._content; 00818 _end_leading = other._end_leading; 00819 _trailing = other._trailing; 00820 00821 return *this; 00822 } 00823 00824 /// add a new child node 00825 void add_child(XMLNode* child) 00826 { 00827 _children.push_back(child); 00828 } 00829 00830 /// write access to an attribute 00831 void put(const XS_String& attr_name, const XS_String& value) 00832 { 00833 _attributes[attr_name] = value; 00834 } 00835 00836 /// C++ write access to an attribute 00837 XS_String& operator[](const XS_String& attr_name) 00838 { 00839 return _attributes[attr_name]; 00840 } 00841 00842 /// read only access to an attribute 00843 template<typename T> XS_String get(const T& attr_name, LPCXSSTR def=XS_EMPTY_STR) const 00844 { 00845 AttributeMap::const_iterator found = _attributes.find(attr_name); 00846 00847 if (found != _attributes.end()) 00848 return found->second; 00849 else 00850 return def; 00851 } 00852 00853 /// convenient value access in children node 00854 XS_String subvalue(const XS_String& name, const XS_String& attr_name, int n=0) const 00855 { 00856 const XMLNode* node = find(name, n); 00857 00858 if (node) 00859 return node->get(attr_name); 00860 else 00861 return XS_String(); 00862 } 00863 00864 /// convenient storage of distinct values in children node 00865 XS_String& subvalue(const XS_String& name, const XS_String& attr_name, int n=0) 00866 { 00867 XMLNode* node = find(name, n); 00868 00869 if (!node) { 00870 node = new XMLNode(name); 00871 add_child(node); 00872 } 00873 00874 return (*node)[attr_name]; 00875 } 00876 00877 #if defined(UNICODE) && !defined(XS_STRING_UTF8) 00878 /// convenient value access in children node 00879 XS_String subvalue(const char* name, const char* attr_name, int n=0) const 00880 { 00881 const XMLNode* node = find(name, n); 00882 00883 if (node) 00884 return node->get(attr_name); 00885 else 00886 return XS_String(); 00887 } 00888 00889 /// convenient storage of distinct values in children node 00890 XS_String& subvalue(const char* name, const XS_String& attr_name, int n=0) 00891 { 00892 XMLNode* node = find(name, n); 00893 00894 if (!node) { 00895 node = new XMLNode(name); 00896 add_child(node); 00897 } 00898 00899 return (*node)[attr_name]; 00900 } 00901 #endif 00902 00903 const Children& get_children() const 00904 { 00905 return _children; 00906 } 00907 00908 Children& get_children() 00909 { 00910 return _children; 00911 } 00912 00913 const AttributeMap& get_attributes() const 00914 { 00915 return _attributes; 00916 } 00917 00918 AttributeMap& get_attributes() 00919 { 00920 return _attributes; 00921 } 00922 00923 XS_String get_content() const 00924 { 00925 #ifdef XS_STRING_UTF8 00926 const XS_String& ret = _content; 00927 #else 00928 XS_String ret; 00929 assign_utf8(ret, _content.c_str(), _content.length()); 00930 #endif 00931 00932 return DecodeXMLString(ret.c_str()); 00933 } 00934 00935 void set_content(const XS_String& s) 00936 { 00937 _content.assign(EncodeXMLString(s.c_str())); 00938 } 00939 00940 #ifdef XMLNODE_LOCATION 00941 const XMLLocation& get_location() const {return _location;} 00942 #endif 00943 00944 /// write node with children tree to output stream 00945 std::ostream& write(std::ostream& out, const XMLFormat& format, WRITE_MODE mode=FORMAT_SMART, int indent=0) const 00946 { 00947 switch(mode) { 00948 case FORMAT_PLAIN: 00949 plain_write_worker(out); 00950 break; 00951 00952 case FORMAT_PRETTY: 00953 pretty_write_worker(out, format, indent); 00954 break; 00955 00956 case FORMAT_ORIGINAL: 00957 write_worker(out, indent); 00958 break; 00959 00960 default: // FORMAT_SMART 00961 smart_write_worker(out, format, indent); 00962 } 00963 00964 return out; 00965 } 00966 00967 protected: 00968 Children _children; 00969 AttributeMap _attributes; 00970 00971 std::string _leading; // UTF-8 encoded 00972 std::string _content; // UTF-8 and entity encoded, may contain CDATA sections; decode with DecodeXMLString() 00973 std::string _end_leading; // UTF-8 encoded 00974 std::string _trailing; // UTF-8 encoded 00975 00976 #ifdef XMLNODE_LOCATION 00977 XMLLocation _location; 00978 #endif 00979 00980 XMLNode* get_first_child() const 00981 { 00982 if (!_children.empty()) 00983 return _children.front(); 00984 else 00985 return NULL; 00986 } 00987 00988 XMLNode* find(const XS_String& name, int n=0) const 00989 { 00990 for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it) 00991 if (**it == name) 00992 if (!n--) 00993 return *it; 00994 00995 return NULL; 00996 } 00997 00998 XMLNode* find(const XS_String& name, const XS_String& attr_name, const XS_String& attr_value, int n=0) const 00999 { 01000 for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it) { 01001 const XMLNode& node = **it; 01002 01003 if (node==name && node.get(attr_name)==attr_value) 01004 if (!n--) 01005 return *it; 01006 } 01007 01008 return NULL; 01009 } 01010 01011 #if defined(UNICODE) && !defined(XS_STRING_UTF8) 01012 XMLNode* find(const char* name, int n=0) const 01013 { 01014 for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it) 01015 if (**it == name) 01016 if (!n--) 01017 return *it; 01018 01019 return NULL; 01020 } 01021 01022 template<typename T, typename U> 01023 XMLNode* find(const char* name, const T& attr_name, const U& attr_value, int n=0) const 01024 { 01025 for(Children::const_iterator it=_children.begin(); it!=_children.end(); ++it) { 01026 const XMLNode& node = **it; 01027 01028 if (node==name && node.get(attr_name)==attr_value) 01029 if (!n--) 01030 return *it; 01031 } 01032 01033 return NULL; 01034 } 01035 #endif 01036 01037 /// XPath find function (const) 01038 const XMLNode* find_relative(const char* path) const; 01039 01040 /// XPath find function 01041 XMLNode* find_relative(const char* path) 01042 {return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->find_relative(path));} 01043 01044 /// relative XPath create function 01045 XMLNode* create_relative(const char* path); 01046 01047 void write_worker(std::ostream& out, int indent) const; 01048 void plain_write_worker(std::ostream& out) const; 01049 void pretty_write_worker(std::ostream& out, const XMLFormat& format, int indent) const; 01050 void smart_write_worker(std::ostream& out, const XMLFormat& format, int indent) const; 01051 }; 01052 01053 01054 /// iterator access to children nodes with name filtering 01055 struct XMLChildrenFilter 01056 { 01057 XMLChildrenFilter(XMLNode::Children& children, const XS_String& name) 01058 : _begin(children.begin(), children.end(), name), 01059 _end(children.end(), children.end(), name) 01060 { 01061 } 01062 01063 XMLChildrenFilter(XMLNode* node, const XS_String& name) 01064 : _begin(node->get_children().begin(), node->get_children().end(), name), 01065 _end(node->get_children().end(), node->get_children().end(), name) 01066 { 01067 } 01068 01069 /// internal iterator class 01070 struct iterator 01071 { 01072 typedef XMLNode::Children::iterator BaseIterator; 01073 01074 iterator(BaseIterator begin, BaseIterator end, const XS_String& filter_name) 01075 : _cur(begin), 01076 _end(end), 01077 _filter_name(filter_name) 01078 { 01079 search_next(); 01080 } 01081 01082 operator BaseIterator() 01083 { 01084 return _cur; 01085 } 01086 01087 const XMLNode* operator*() const 01088 { 01089 return *_cur; 01090 } 01091 01092 XMLNode* operator*() 01093 { 01094 return *_cur; 01095 } 01096 01097 iterator& operator++() 01098 { 01099 ++_cur; 01100 search_next(); 01101 01102 return *this; 01103 } 01104 01105 iterator operator++(int) 01106 { 01107 iterator ret = *this; 01108 01109 ++_cur; 01110 search_next(); 01111 01112 return ret; 01113 } 01114 01115 bool operator==(const BaseIterator& other) const 01116 { 01117 return _cur == other; 01118 } 01119 01120 bool operator!=(const BaseIterator& other) const 01121 { 01122 return _cur != other; 01123 } 01124 01125 protected: 01126 BaseIterator _cur; 01127 BaseIterator _end; 01128 XS_String _filter_name; 01129 01130 void search_next() 01131 { 01132 while(_cur!=_end && **_cur!=_filter_name) 01133 ++_cur; 01134 } 01135 }; 01136 01137 iterator begin() 01138 { 01139 return _begin; 01140 } 01141 01142 iterator end() 01143 { 01144 return _end; 01145 } 01146 01147 protected: 01148 iterator _begin; 01149 iterator _end; 01150 }; 01151 01152 01153 /// read only iterator access to children nodes with name filtering 01154 struct const_XMLChildrenFilter 01155 { 01156 const_XMLChildrenFilter(const XMLNode::Children& children, const XS_String& name) 01157 : _begin(children.begin(), children.end(), name), 01158 _end(children.end(), children.end(), name) 01159 { 01160 } 01161 01162 const_XMLChildrenFilter(const XMLNode* node, const XS_String& name) 01163 : _begin(node->get_children().begin(), node->get_children().end(), name), 01164 _end(node->get_children().end(), node->get_children().end(), name) 01165 { 01166 } 01167 01168 /// internal iterator class 01169 struct const_iterator 01170 { 01171 typedef XMLNode::Children::const_iterator BaseIterator; 01172 01173 const_iterator(BaseIterator begin, BaseIterator end, const XS_String& filter_name) 01174 : _cur(begin), 01175 _end(end), 01176 _filter_name(filter_name) 01177 { 01178 search_next(); 01179 } 01180 01181 operator BaseIterator() 01182 { 01183 return _cur; 01184 } 01185 01186 const XMLNode* operator*() const 01187 { 01188 return *_cur; 01189 } 01190 01191 const_iterator& operator++() 01192 { 01193 ++_cur; 01194 search_next(); 01195 01196 return *this; 01197 } 01198 01199 const_iterator operator++(int) 01200 { 01201 const_iterator ret = *this; 01202 01203 ++_cur; 01204 search_next(); 01205 01206 return ret; 01207 } 01208 01209 bool operator==(const BaseIterator& other) const 01210 { 01211 return _cur == other; 01212 } 01213 01214 bool operator!=(const BaseIterator& other) const 01215 { 01216 return _cur != other; 01217 } 01218 01219 protected: 01220 BaseIterator _cur; 01221 BaseIterator _end; 01222 XS_String _filter_name; 01223 01224 void search_next() 01225 { 01226 while(_cur!=_end && **_cur!=_filter_name) 01227 ++_cur; 01228 } 01229 }; 01230 01231 const_iterator begin() 01232 { 01233 return _begin; 01234 } 01235 01236 const_iterator end() 01237 { 01238 return _end; 01239 } 01240 01241 protected: 01242 const_iterator _begin; 01243 const_iterator _end; 01244 }; 01245 01246 01247 /// iterator for XML trees 01248 struct XMLPos 01249 { 01250 XMLPos(XMLNode* root) 01251 : _root(root), 01252 _cur(root) 01253 { 01254 } 01255 01256 XMLPos(const XMLPos& other) 01257 : _root(other._root), 01258 _cur(other._cur) 01259 { // don't copy _stack 01260 } 01261 01262 XMLPos(XMLNode* node, const XS_String& name) 01263 : _root(node), 01264 _cur(node) 01265 { 01266 smart_create(name); 01267 } 01268 01269 XMLPos(XMLNode* node, const XS_String& name, const XS_String& attr_name, const XS_String& attr_value) 01270 : _root(node), 01271 _cur(node) 01272 { 01273 smart_create(name, attr_name, attr_value); 01274 } 01275 01276 XMLPos(const XMLPos& other, const XS_String& name) 01277 : _root(other._root), 01278 _cur(other._cur) 01279 { 01280 smart_create(name); 01281 } 01282 01283 XMLPos(const XMLPos& other, const XS_String& name, const XS_String& attr_name, const XS_String& attr_value) 01284 : _root(other._root), 01285 _cur(other._cur) 01286 { 01287 smart_create(name, attr_name, attr_value); 01288 } 01289 01290 /// access to current node 01291 XMLNode& cur() 01292 { 01293 return *_cur; 01294 } 01295 01296 const XMLNode& cur() const 01297 { 01298 return *_cur; 01299 } 01300 01301 /// C++ access to current node 01302 operator const XMLNode*() const {return _cur;} 01303 operator XMLNode*() {return _cur;} 01304 01305 const XMLNode* operator->() const {return _cur;} 01306 XMLNode* operator->() {return _cur;} 01307 01308 const XMLNode& operator*() const {return *_cur;} 01309 XMLNode& operator*() {return *_cur;} 01310 01311 /// attribute access 01312 XS_String get(const XS_String& attr_name) const 01313 { 01314 return _cur->get(attr_name); 01315 } 01316 01317 /// attribute setting 01318 void put(const XS_String& attr_name, const XS_String& value) 01319 { 01320 _cur->put(attr_name, value); 01321 } 01322 01323 /// C++ attribute access 01324 template<typename T> XS_String get(const T& attr_name) const {return (*_cur)[attr_name];} 01325 XS_String& operator[](const XS_String& attr_name) {return (*_cur)[attr_name];} 01326 01327 /// insert children when building tree 01328 void add_down(XMLNode* child) 01329 { 01330 _cur->add_child(child); 01331 go_to(child); 01332 } 01333 01334 /// go back to previous position 01335 bool back() 01336 { 01337 if (!_stack.empty()) { 01338 _cur = _stack.top(); 01339 _stack.pop(); 01340 return true; 01341 } else 01342 return false; 01343 } 01344 01345 /// go down to first child 01346 bool go_down() 01347 { 01348 XMLNode* node = _cur->get_first_child(); 01349 01350 if (node) { 01351 go_to(node); 01352 return true; 01353 } else 01354 return false; 01355 } 01356 01357 /// search for child and go down 01358 bool go_down(const XS_String& name, int n=0) 01359 { 01360 XMLNode* node = _cur->find(name, n); 01361 01362 if (node) { 01363 go_to(node); 01364 return true; 01365 } else 01366 return false; 01367 } 01368 01369 /// move XPath like to position in XML tree 01370 bool go(const char* path); 01371 01372 /// create child nodes using XPath notation and move to the deepest child 01373 bool create_relative(const char* path) 01374 { 01375 XMLNode* node = _cur->create_relative(path); 01376 if (!node) 01377 return false; // invalid path specified 01378 01379 go_to(node); 01380 return true; 01381 } 01382 01383 /// create node and move to it 01384 void create(const XS_String& name) 01385 { 01386 add_down(new XMLNode(name)); 01387 } 01388 01389 /// create node if not already existing and move to it 01390 void smart_create(const XS_String& name) 01391 { 01392 XMLNode* node = _cur->find(name); 01393 01394 if (node) 01395 go_to(node); 01396 else 01397 add_down(new XMLNode(name)); 01398 } 01399 01400 /// search matching child node identified by key name and an attribute value 01401 void smart_create(const XS_String& name, const XS_String& attr_name, const XS_String& attr_value) 01402 { 01403 XMLNode* node = _cur->find(name, attr_name, attr_value); 01404 01405 if (node) 01406 go_to(node); 01407 else { 01408 node = new XMLNode(name); 01409 add_down(node); 01410 (*node)[attr_name] = attr_value; 01411 } 01412 } 01413 01414 #if defined(UNICODE) && !defined(XS_STRING_UTF8) 01415 /// search for child and go down 01416 bool go_down(const char* name, int n=0) 01417 { 01418 XMLNode* node = _cur->find(name, n); 01419 01420 if (node) { 01421 go_to(node); 01422 return true; 01423 } else 01424 return false; 01425 } 01426 01427 /// create node and move to it 01428 void create(const char* name) 01429 { 01430 add_down(new XMLNode(name)); 01431 } 01432 01433 /// create node if not already existing and move to it 01434 void smart_create(const char* name) 01435 { 01436 XMLNode* node = _cur->find(name); 01437 01438 if (node) 01439 go_to(node); 01440 else 01441 add_down(new XMLNode(name)); 01442 } 01443 01444 /// search matching child node identified by key name and an attribute value 01445 template<typename T, typename U> 01446 void smart_create(const char* name, const T& attr_name, const U& attr_value) 01447 { 01448 XMLNode* node = _cur->find(name, attr_name, attr_value); 01449 01450 if (node) 01451 go_to(node); 01452 else { 01453 XMLNode* node = new XMLNode(name); 01454 add_down(node); 01455 (*node)[attr_name] = attr_value; 01456 } 01457 } 01458 #endif 01459 01460 XS_String& str() {return *_cur;} 01461 const XS_String& str() const {return *_cur;} 01462 01463 protected: 01464 XMLNode* _root; 01465 XMLNode* _cur; 01466 std::stack<XMLNode*> _stack; 01467 01468 /// go to specified node 01469 void go_to(XMLNode* child) 01470 { 01471 _stack.push(_cur); 01472 _cur = child; 01473 } 01474 }; 01475 01476 01477 /// iterator for XML trees 01478 struct const_XMLPos 01479 { 01480 const_XMLPos(const XMLNode* root) 01481 : _root(root), 01482 _cur(root) 01483 { 01484 } 01485 01486 const_XMLPos(const const_XMLPos& other) 01487 : _root(other._root), 01488 _cur(other._cur) 01489 { // don't copy _stack 01490 } 01491 01492 /// access to current node 01493 const XMLNode& cur() const 01494 { 01495 return *_cur; 01496 } 01497 01498 /// C++ access to current node 01499 operator const XMLNode*() const {return _cur;} 01500 01501 const XMLNode* operator->() const {return _cur;} 01502 01503 const XMLNode& operator*() const {return *_cur;} 01504 01505 /// attribute access 01506 XS_String get(const XS_String& attr_name) const 01507 { 01508 return _cur->get(attr_name); 01509 } 01510 01511 /// C++ attribute access 01512 template<typename T> XS_String get(const T& attr_name) const {return _cur->get(attr_name);} 01513 01514 /// go back to previous position 01515 bool back() 01516 { 01517 if (!_stack.empty()) { 01518 _cur = _stack.top(); 01519 _stack.pop(); 01520 return true; 01521 } else 01522 return false; 01523 } 01524 01525 /// go down to first child 01526 bool go_down() 01527 { 01528 const XMLNode* node = _cur->get_first_child(); 01529 01530 if (node) { 01531 go_to(node); 01532 return true; 01533 } else 01534 return false; 01535 } 01536 01537 /// search for child and go down 01538 bool go_down(const XS_String& name, int n=0) 01539 { 01540 XMLNode* node = _cur->find(name, n); 01541 01542 if (node) { 01543 go_to(node); 01544 return true; 01545 } else 01546 return false; 01547 } 01548 01549 /// move XPath like to position in XML tree 01550 bool go(const char* path); 01551 01552 #if defined(UNICODE) && !defined(XS_STRING_UTF8) 01553 /// search for child and go down 01554 bool go_down(const char* name, int n=0) 01555 { 01556 XMLNode* node = _cur->find(name, n); 01557 01558 if (node) { 01559 go_to(node); 01560 return true; 01561 } else 01562 return false; 01563 } 01564 #endif 01565 01566 const XS_String& str() const {return *_cur;} 01567 01568 protected: 01569 const XMLNode* _root; 01570 const XMLNode* _cur; 01571 std::stack<const XMLNode*> _stack; 01572 01573 /// go to specified node 01574 void go_to(const XMLNode* child) 01575 { 01576 _stack.push(_cur); 01577 _cur = child; 01578 } 01579 }; 01580 01581 01582 /// type converter for boolean data 01583 struct XMLBool 01584 { 01585 XMLBool(bool value=false) 01586 : _value(value) 01587 { 01588 } 01589 01590 XMLBool(LPCXSSTR value, bool def=false) 01591 { 01592 if (value && *value) 01593 _value = !XS_icmp(value, XS_TRUE); 01594 else 01595 _value = def; 01596 } 01597 01598 XMLBool(const XMLNode* node, const XS_String& attr_name, bool def=false) 01599 { 01600 const XS_String& value = node->get(attr_name); 01601 01602 if (!value.empty()) 01603 _value = !XS_icmp(value.c_str(), XS_TRUE); 01604 else 01605 _value = def; 01606 } 01607 01608 operator bool() const 01609 { 01610 return _value; 01611 } 01612 01613 bool operator!() const 01614 { 01615 return !_value; 01616 } 01617 01618 operator LPCXSSTR() const 01619 { 01620 return _value? XS_TRUE: XS_FALSE; 01621 } 01622 01623 protected: 01624 bool _value; 01625 01626 private: 01627 void operator=(const XMLBool&); // disallow assignment operations 01628 }; 01629 01630 /// type converter for boolean data with write access 01631 struct XMLBoolRef 01632 { 01633 XMLBoolRef(XMLNode* node, const XS_String& attr_name, bool def=false) 01634 : _ref((*node)[attr_name]) 01635 { 01636 if (_ref.empty()) 01637 assign(def); 01638 } 01639 01640 operator bool() const 01641 { 01642 return !XS_icmp(_ref.c_str(), XS_TRUE); 01643 } 01644 01645 bool operator!() const 01646 { 01647 return XS_icmp(_ref.c_str(), XS_TRUE)? true: false; 01648 } 01649 01650 XMLBoolRef& operator=(bool value) 01651 { 01652 assign(value); 01653 01654 return *this; 01655 } 01656 01657 void assign(bool value) 01658 { 01659 _ref.assign(value? XS_TRUE: XS_FALSE); 01660 } 01661 01662 void toggle() 01663 { 01664 assign(!operator bool()); 01665 } 01666 01667 protected: 01668 XS_String& _ref; 01669 }; 01670 01671 01672 /// type converter for integer data 01673 struct XMLInt 01674 { 01675 XMLInt(int value) 01676 : _value(value) 01677 { 01678 } 01679 01680 XMLInt(LPCXSSTR value, int def=0) 01681 { 01682 if (value && *value) 01683 _value = XS_toi(value); 01684 else 01685 _value = def; 01686 } 01687 01688 XMLInt(const XMLNode* node, const XS_String& attr_name, int def=0) 01689 { 01690 const XS_String& value = node->get(attr_name); 01691 01692 if (!value.empty()) 01693 _value = XS_toi(value.c_str()); 01694 else 01695 _value = def; 01696 } 01697 01698 operator int() const 01699 { 01700 return _value; 01701 } 01702 01703 operator XS_String() const 01704 { 01705 XS_CHAR buffer[32]; 01706 XS_snprintf(buffer, COUNTOF(buffer), XS_INTFMT, _value); 01707 return buffer; 01708 } 01709 01710 protected: 01711 int _value; 01712 01713 private: 01714 void operator=(const XMLInt&); // disallow assignment operations 01715 }; 01716 01717 /// type converter for integer data with write access 01718 struct XMLIntRef 01719 { 01720 XMLIntRef(XMLNode* node, const XS_String& attr_name, int def=0) 01721 : _ref((*node)[attr_name]) 01722 { 01723 if (_ref.empty()) 01724 assign(def); 01725 } 01726 01727 XMLIntRef& operator=(int value) 01728 { 01729 assign(value); 01730 01731 return *this; 01732 } 01733 01734 operator int() const 01735 { 01736 return XS_toi(_ref.c_str()); 01737 } 01738 01739 void assign(int value) 01740 { 01741 XS_CHAR buffer[32]; 01742 XS_snprintf(buffer, COUNTOF(buffer), XS_INTFMT, value); 01743 _ref.assign(buffer); 01744 } 01745 01746 protected: 01747 XS_String& _ref; 01748 }; 01749 01750 01751 /// type converter for numeric data 01752 struct XMLDouble 01753 { 01754 XMLDouble(double value) 01755 : _value(value) 01756 { 01757 } 01758 01759 XMLDouble(LPCXSSTR value, double def=0.) 01760 { 01761 LPTSTR end; 01762 01763 if (value && *value) 01764 _value = XS_tod(value, &end); 01765 else 01766 _value = def; 01767 } 01768 01769 XMLDouble(const XMLNode* node, const XS_String& attr_name, double def=0.) 01770 { 01771 LPTSTR end; 01772 const XS_String& value = node->get(attr_name); 01773 01774 if (!value.empty()) 01775 _value = XS_tod(value.c_str(), &end); 01776 else 01777 _value = def; 01778 } 01779 01780 operator double() const 01781 { 01782 return _value; 01783 } 01784 01785 operator XS_String() const 01786 { 01787 XS_CHAR buffer[32]; 01788 XS_snprintf(buffer, COUNTOF(buffer), XS_FLOATFMT, _value); 01789 return buffer; 01790 } 01791 01792 protected: 01793 double _value; 01794 01795 private: 01796 void operator=(const XMLDouble&); // disallow assignment operations 01797 }; 01798 01799 /// type converter for numeric data with write access 01800 struct XMLDoubleRef 01801 { 01802 XMLDoubleRef(XMLNode* node, const XS_String& attr_name, double def=0.) 01803 : _ref((*node)[attr_name]) 01804 { 01805 if (_ref.empty()) 01806 assign(def); 01807 } 01808 01809 XMLDoubleRef& operator=(double value) 01810 { 01811 assign(value); 01812 01813 return *this; 01814 } 01815 01816 operator double() const 01817 { 01818 LPTSTR end; 01819 return XS_tod(_ref.c_str(), &end); 01820 } 01821 01822 void assign(double value) 01823 { 01824 XS_CHAR buffer[32]; 01825 XS_snprintf(buffer, COUNTOF(buffer), XS_FLOATFMT, value); 01826 _ref.assign(buffer); 01827 } 01828 01829 protected: 01830 XS_String& _ref; 01831 }; 01832 01833 01834 /// type converter for string data 01835 struct XMLString 01836 { 01837 XMLString(const XS_String& value) 01838 : _value(value) 01839 { 01840 } 01841 01842 XMLString(LPCXSSTR value, LPCXSSTR def=XS_EMPTY) 01843 { 01844 if (value && *value) 01845 _value = value; 01846 else 01847 _value = def; 01848 } 01849 01850 XMLString(const XMLNode* node, const XS_String& attr_name, LPCXSSTR def=XS_EMPTY) 01851 { 01852 const XS_String& value = node->get(attr_name); 01853 01854 if (!value.empty()) 01855 _value = value; 01856 else 01857 _value = def; 01858 } 01859 01860 operator const XS_String&() const 01861 { 01862 return _value; 01863 } 01864 01865 const XS_String& c_str() const 01866 { 01867 return _value; 01868 } 01869 01870 protected: 01871 XS_String _value; 01872 01873 private: 01874 void operator=(const XMLString&); // disallow assignment operations 01875 }; 01876 01877 /// type converter for string data with write access 01878 struct XMStringRef 01879 { 01880 XMStringRef(XMLNode* node, const XS_String& attr_name, LPCXSSTR def=XS_EMPTY) 01881 : _ref((*node)[attr_name]) 01882 { 01883 if (_ref.empty()) 01884 assign(def); 01885 } 01886 01887 XMStringRef(XMLNode* node, const XS_String& node_name, const XS_String& attr_name, LPCXSSTR def=XS_EMPTY) 01888 : _ref(node->subvalue(node_name, attr_name)) 01889 { 01890 if (_ref.empty()) 01891 assign(def); 01892 } 01893 01894 XMStringRef& operator=(const XS_String& value) 01895 { 01896 assign(value); 01897 01898 return *this; 01899 } 01900 01901 operator const XS_String&() const 01902 { 01903 return _ref; 01904 } 01905 01906 void assign(const XS_String& value) 01907 { 01908 _ref.assign(value); 01909 } 01910 01911 protected: 01912 XS_String& _ref; 01913 }; 01914 01915 01916 template<typename T> 01917 inline void read_option(T& var, const_XMLPos& cfg, LPCXSSTR key) 01918 { 01919 const XS_String& val = cfg.get(key); 01920 01921 if (!val.empty()) 01922 var = val; 01923 } 01924 01925 template<> 01926 inline void read_option(int& var, const_XMLPos& cfg, LPCXSSTR key) 01927 { 01928 const XS_String& val = cfg.get(key); 01929 01930 if (!val.empty()) 01931 var = XS_toi(val.c_str()); 01932 } 01933 01934 01935 #ifdef _MSC_VER 01936 #pragma warning(disable: 4355) 01937 #endif 01938 01939 /// XML reader base class 01940 struct XMLReaderBase 01941 #ifdef XS_USE_XERCES 01942 : public HandlerBase 01943 #endif 01944 { 01945 #ifdef XS_USE_XERCES 01946 01947 XMLReaderBase(XMLNode* node, InputSource* source, bool adoptSource=false); 01948 virtual ~XMLReaderBase(); 01949 01950 void read(); 01951 01952 protected: 01953 SAXParser* _parser; 01954 InputSource* _source; 01955 bool _deleteSource; 01956 01957 virtual void XMLDecl(const XMLCh* const versionStr, const XMLCh* const encodingStr, 01958 const XMLCh* const standaloneStr, const XMLCh* const actualEncodingStr); 01959 01960 // Handlers for the SAX DocumentHandler interface 01961 virtual void setDocumentLocator(const Locator* const locator); 01962 virtual void startElement(const XMLCh* const name, AttributeList& attributes); 01963 virtual void endElement(const XMLCh* const name); 01964 virtual void characters(const XMLCh* const chars, const unsigned int length); 01965 virtual void ignorableWhitespace(const XMLCh* const chars, const unsigned int length); 01966 01967 // Handlers for the SAX ErrorHandler interface 01968 virtual void error(const SAXParseException& e); 01969 virtual void fatalError(const SAXParseException& e); 01970 virtual void warning(const SAXParseException& e); 01971 virtual void resetErrors(); 01972 01973 #elif defined(XS_USE_EXPAT) // !XS_USE_XERCES 01974 01975 XMLReaderBase(XMLNode* node); 01976 virtual ~XMLReaderBase(); 01977 01978 protected: 01979 XML_Parser _parser; 01980 01981 static void XMLCALL XML_XmlDeclHandler(void* userData, const XML_Char* version, const XML_Char* encoding, int standalone=-1); 01982 static void XMLCALL XML_StartElementHandler(void* userData, const XML_Char* name, const XML_Char** atts); 01983 static void XMLCALL XML_EndElementHandler(void* userData, const XML_Char* name); 01984 static void XMLCALL XML_DefaultHandler(void* userData, const XML_Char* s, int len); 01985 01986 static std::string get_expat_error_string(XML_Error error_code); 01987 01988 #else // XS_USE_EXPAT 01989 01990 XMLReaderBase(XMLNode* node) 01991 : _pos(node), 01992 _endl_defined(false), 01993 _utf8(false) 01994 { 01995 _last_tag = TAG_NONE; 01996 } 01997 01998 virtual ~XMLReaderBase(); 01999 02000 bool parse(); 02001 02002 #endif 02003 02004 public: 02005 #ifndef XS_USE_XERCES 02006 void read(); 02007 02008 std::string get_position() const; 02009 #endif 02010 const XMLFormat& get_format() const {return _format;} 02011 const char* get_endl() const {return _endl_defined? _format._endl: "\n";} 02012 02013 const XMLErrorList& get_errors() const {return _errors;} 02014 const XMLErrorList& get_warnings() const {return _warnings;} 02015 02016 void clear_errors() {_errors.clear(); _warnings.clear();} 02017 02018 #ifdef XMLNODE_LOCATION 02019 const char* _display_path; // character pointer for fast reference in XMLLocation 02020 02021 #ifdef XS_USE_XERCES 02022 const Locator* _locator; 02023 #endif 02024 02025 XMLLocation get_location() const; 02026 #endif 02027 02028 protected: 02029 XMLPos _pos; 02030 02031 std::string _content; // UTF-8 encoded 02032 enum {TAG_NONE, TAG_START, TAG_END} _last_tag; 02033 02034 XMLErrorList _errors; 02035 XMLErrorList _warnings; 02036 02037 XMLFormat _format; 02038 bool _endl_defined; 02039 02040 #ifdef XS_USE_XERCES 02041 //@@ 02042 #elif defined(XS_USE_EXPAT) 02043 virtual int read_buffer(char* buffer, int len) = 0; 02044 #else 02045 virtual int get() = 0; 02046 int eat_endl(); 02047 02048 bool _utf8; 02049 #endif 02050 02051 void finish_read(); 02052 02053 virtual void XmlDeclHandler(const char* version, const char* encoding, int standalone); 02054 virtual void StartElementHandler(const XS_String& name, const XMLNode::AttributeMap& attributes); 02055 virtual void EndElementHandler(); 02056 #if defined(XS_USE_XERCES) || defined(XS_USE_EXPAT) 02057 virtual void DefaultHandler(const XML_Char* s, int len); 02058 #else 02059 virtual void DefaultHandler(const std::string& s); 02060 #endif 02061 }; 02062 02063 02064 /// XML file reader 02065 02066 #ifdef XS_USE_XERCES 02067 02068 struct XercesXMLReader : public XMLReaderBase 02069 { 02070 XercesXMLReader(XMLNode* node, InputSource* source, bool adoptSource=false) 02071 : XMLReaderBase(node, source, adoptSource) 02072 { 02073 } 02074 02075 XercesXMLReader(XMLNode* node, LPCTSTR path); 02076 XercesXMLReader(XMLNode* node, const XMLByte* buffer, size_t bytes, const std::string& system_id=std::string()); 02077 }; 02078 02079 #define XMLReader XercesXMLReader 02080 02081 #elif defined(XS_USE_EXPAT) 02082 02083 struct ExpatXMLReader : public XMLReaderBase 02084 { 02085 ExpatXMLReader(XMLNode* node, std::istream& in) 02086 : XMLReaderBase(node), 02087 _in(in) 02088 { 02089 } 02090 02091 /// read XML stream into XML tree below _pos 02092 int read_buffer(char* buffer, int len) 02093 { 02094 if (!_in.good()) 02095 return -1; 02096 02097 _in.read(buffer, len); 02098 02099 return _in.gcount(); 02100 } 02101 02102 protected: 02103 std::istream& _in; 02104 }; 02105 02106 #define XMLReader ExpatXMLReader 02107 02108 #else // XS_USE_XERCES, XS_USE_EXPAT 02109 02110 struct XMLReader : public XMLReaderBase 02111 { 02112 XMLReader(XMLNode* node, std::istream& in) 02113 : XMLReaderBase(node), 02114 _in(in) 02115 { 02116 } 02117 02118 /// read one character from XML stream 02119 int get() 02120 { 02121 return _in.get(); 02122 } 02123 02124 protected: 02125 std::istream& _in; 02126 }; 02127 02128 #endif // XS_USE_XERCES 02129 02130 02131 /// XML document holder 02132 struct XMLDoc : public XMLNode 02133 { 02134 XMLDoc() 02135 : XMLNode("") 02136 { 02137 } 02138 02139 XMLDoc(LPCTSTR path) 02140 : XMLNode("") 02141 { 02142 read(path); 02143 } 02144 02145 #ifdef XS_USE_XERCES 02146 bool read(LPCTSTR path) 02147 { 02148 XMLReader reader(this, path); 02149 02150 #if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8) 02151 return read(reader, std::string(ANS(path))); 02152 #else 02153 return read(reader, XS_String(path)); 02154 #endif 02155 } 02156 02157 bool read(const char* buffer, size_t len, const std::string& system_id=std::string()) 02158 { 02159 XMLReader reader(this, (const XMLByte*)buffer, len, system_id); 02160 02161 return read(reader, system_id); 02162 } 02163 02164 #else // XS_USE_XERCES 02165 02166 bool read(LPCTSTR path) 02167 { 02168 tifstream in(path); 02169 XMLReader reader(this, in); 02170 02171 #if defined(_STRING_DEFINED) && !defined(XS_STRING_UTF8) 02172 return read(reader, std::string(ANS(path))); 02173 #else 02174 return read(reader, XS_String(path)); 02175 #endif 02176 } 02177 02178 bool read(const char* buffer, size_t len, const std::string& system_id=std::string()) 02179 { 02180 std::istringstream in(std::string(buffer, len)); 02181 02182 return read(in, system_id); 02183 } 02184 02185 bool read(std::istream& in, const std::string& system_id=std::string()) 02186 { 02187 XMLReader reader(this, in); 02188 02189 return read(reader, system_id); 02190 } 02191 #endif // XS_USE_XERCES 02192 02193 bool read(XMLReaderBase& reader, const std::string& display_path) 02194 { 02195 #ifdef XMLNODE_LOCATION 02196 // make a string copy to handle temporary string objects 02197 _display_path = display_path; 02198 reader._display_path = _display_path.c_str(); 02199 #endif 02200 02201 reader.clear_errors(); 02202 reader.read(); 02203 02204 _format = reader.get_format(); 02205 _format._endl = reader.get_endl(); 02206 02207 if (!reader.get_errors().empty()) { 02208 _errors = reader.get_errors(); 02209 return false; 02210 } 02211 02212 return true; 02213 } 02214 02215 /// write XML stream preserving previous white space and comments 02216 std::ostream& write(std::ostream& out, WRITE_MODE mode=FORMAT_SMART) const 02217 { 02218 _format.print_header(out, mode!=FORMAT_PLAIN); 02219 02220 if (!_children.empty()) 02221 _children.front()->write(out, _format, mode); 02222 02223 return out; 02224 } 02225 02226 /// write XML stream with formating 02227 std::ostream& write_formating(std::ostream& out) const 02228 { 02229 return write(out, FORMAT_PRETTY); 02230 } 02231 02232 bool write(LPCTSTR path, WRITE_MODE mode=FORMAT_SMART) const 02233 { 02234 tofstream out(path); 02235 02236 return write(out, mode).good(); 02237 } 02238 02239 bool write_formating(LPCTSTR path) const 02240 { 02241 tofstream out(path); 02242 02243 return write_formating(out).good(); 02244 } 02245 02246 XMLFormat _format; 02247 XMLErrorList _errors; 02248 02249 #ifdef XMLNODE_LOCATION 02250 std::string _display_path; 02251 #endif 02252 }; 02253 02254 02255 /// XML message wrapper 02256 struct XMLMessage : public XMLDoc 02257 { 02258 XMLMessage(const char* name) 02259 : _pos(this) 02260 { 02261 _pos.create(name); 02262 } 02263 02264 std::string toString() const 02265 { 02266 std::ostringstream out; 02267 02268 write(out); 02269 02270 return out.str(); 02271 } 02272 02273 XMLPos _pos; 02274 02275 protected: 02276 XMLMessage() 02277 : _pos(this) 02278 { 02279 } 02280 }; 02281 02282 02283 struct XMLMessageFromString : public XMLMessage 02284 { 02285 XMLMessageFromString(const std::string& xml_str, const std::string& system_id=std::string()) 02286 { 02287 read(xml_str.c_str(), xml_str.length(), system_id); 02288 } 02289 }; 02290 02291 02292 /// Reader for XML Messages 02293 struct XMLMessageReader : public XMLPos 02294 { 02295 XMLMessageReader(const std::string& xml_str, const std::string& system_id=std::string()) 02296 : XMLPos(&_msg) 02297 { 02298 _msg.read(xml_str.c_str(), xml_str.length(), system_id); 02299 } 02300 02301 const XMLDoc& get_document() 02302 { 02303 return _msg; 02304 } 02305 02306 protected: 02307 XMLDoc _msg; 02308 }; 02309 02310 02311 struct XMLWriter 02312 { 02313 XMLWriter(std::ostream& out, const XMLFormat& format=XMLFormat()) 02314 : _pofstream(NULL), 02315 _out(out), 02316 _format(format) 02317 { 02318 format.print_header(_out, false); // _format._endl is printed in write_pre() 02319 } 02320 02321 XMLWriter(LPCTSTR path, const XMLFormat& format=XMLFormat()) 02322 : _pofstream(new tofstream(path)), 02323 _out(*_pofstream), 02324 _format(format) 02325 { 02326 format.print_header(_out, false); // _format._endl is printed in write_pre() 02327 } 02328 02329 ~XMLWriter() 02330 { 02331 _out << _format._endl; 02332 delete _pofstream; 02333 } 02334 02335 /// create node and move to it 02336 void create(const XS_String& name) 02337 { 02338 if (!_stack.empty()) { 02339 StackEntry& last = _stack.top(); 02340 02341 if (last._state < PRE_CLOSED) { 02342 write_attributes(last); 02343 close_pre(last); 02344 } 02345 02346 ++last._children; 02347 } 02348 02349 StackEntry entry; 02350 entry._node_name = name; 02351 _stack.push(entry); 02352 02353 write_pre(entry); 02354 } 02355 02356 /// go back to previous position 02357 bool back() 02358 { 02359 if (!_stack.empty()) { 02360 write_post(_stack.top()); 02361 02362 _stack.pop(); 02363 return true; 02364 } else 02365 return false; 02366 } 02367 02368 /// attribute setting 02369 void put(const XS_String& attr_name, const XS_String& value) 02370 { 02371 if (!_stack.empty()) 02372 _stack.top()._attributes[attr_name] = value; 02373 } 02374 02375 /// C++ write access to an attribute 02376 XS_String& operator[](const XS_String& attr_name) 02377 { 02378 if (_stack.empty()) 02379 return s_empty_attr; 02380 02381 return _stack.top()._attributes[attr_name]; 02382 } 02383 02384 void set_content(const XS_String& s) 02385 { 02386 if (!_stack.empty()) 02387 _stack.top()._content = EncodeXMLString(s.c_str()); 02388 } 02389 02390 // public for access in StackEntry 02391 enum WRITESTATE { 02392 NOTHING, /*PRE,*/ ATTRIBUTES, PRE_CLOSED, /*CONTENT,*/ POST 02393 }; 02394 02395 protected: 02396 tofstream* _pofstream; 02397 std::ostream& _out; 02398 const XMLFormat&_format; 02399 02400 typedef XMLNode::AttributeMap AttrMap; 02401 02402 struct StackEntry { 02403 XS_String _node_name; 02404 AttrMap _attributes; 02405 std::string _content; 02406 WRITESTATE _state; 02407 bool _children; 02408 02409 StackEntry() : _state(NOTHING), _children(false) {} 02410 }; 02411 02412 std::stack<StackEntry> _stack; 02413 02414 static XS_String s_empty_attr; 02415 02416 void close_pre(StackEntry& entry) 02417 { 02418 _out << '>'; 02419 02420 entry._state = PRE_CLOSED; 02421 } 02422 02423 void write_pre(StackEntry& entry) 02424 { 02425 if (_format._pretty >= PRETTY_LINEFEED) 02426 _out << _format._endl; 02427 02428 if (_format._pretty == PRETTY_INDENT) 02429 for(size_t i=_stack.size(); --i>0; ) 02430 _out << XML_INDENT_SPACE; 02431 02432 _out << '<' << EncodeXMLString(entry._node_name); 02433 //entry._state = PRE; 02434 } 02435 02436 void write_attributes(StackEntry& entry) 02437 { 02438 for(AttrMap::const_iterator it=entry._attributes.begin(); it!=entry._attributes.end(); ++it) 02439 _out << ' ' << EncodeXMLString(it->first) << "=\"" << EncodeXMLString(it->second) << "\""; 02440 02441 entry._state = ATTRIBUTES; 02442 } 02443 02444 void write_post(StackEntry& entry) 02445 { 02446 if (entry._state < ATTRIBUTES) 02447 write_attributes(entry); 02448 02449 if (entry._children || !entry._content.empty()) { 02450 if (entry._state < PRE_CLOSED) 02451 close_pre(entry); 02452 02453 _out << entry._content; 02454 //entry._state = CONTENT; 02455 02456 if (_format._pretty>=PRETTY_LINEFEED && entry._content.empty()) 02457 _out << _format._endl; 02458 02459 if (_format._pretty==PRETTY_INDENT && entry._content.empty()) 02460 for(size_t i=_stack.size(); --i>0; ) 02461 _out << XML_INDENT_SPACE; 02462 02463 _out << "</" << EncodeXMLString(entry._node_name) << ">"; 02464 } else { 02465 _out << "/>"; 02466 } 02467 02468 entry._state = POST; 02469 } 02470 }; 02471 02472 02473 } // namespace XMLStorage 02474 02475 #define _XMLSTORAGE_H 02476 #endif // _XMLSTORAGE_H
IBrowser Source Code Documentation
generated on 18.09.2008 by |